Skip to content

Commit 6d10719

Browse files
committed
Resolve whether $pat is $pat_param or not via 🌟hygiene🌟
1 parent 7e88fa5 commit 6d10719

File tree

7 files changed

+158
-54
lines changed

7 files changed

+158
-54
lines changed

crates/hir-def/src/macro_expansion_tests/mbe.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1449,6 +1449,7 @@ ok!();
14491449
#[test]
14501450
fn test_new_std_matches() {
14511451
check(
1452+
//- edition:2021
14521453
r#"
14531454
macro_rules! matches {
14541455
($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => {
@@ -1480,6 +1481,90 @@ fn main() {
14801481
);
14811482
}
14821483

1484+
#[test]
1485+
fn test_hygienic_pat() {
1486+
check(
1487+
r#"
1488+
//- /new.rs crate:new deps:old edition:2015
1489+
old::make!();
1490+
fn main() {
1491+
matches!(0, 0 | 1 if true);
1492+
}
1493+
//- /old.rs crate:old edition:2021
1494+
#[macro_export]
1495+
macro_rules! make {
1496+
() => {
1497+
macro_rules! matches {
1498+
($expression:expr, $pattern:pat if $guard:expr ) => {
1499+
match $expression {
1500+
$pattern if $guard => true,
1501+
_ => false
1502+
}
1503+
};
1504+
}
1505+
}
1506+
}
1507+
"#,
1508+
expect![[r#"
1509+
macro_rules !matches {
1510+
($expression: expr, $pattern: pat if $guard: expr) = > {
1511+
match $expression {
1512+
$pattern if $guard = > true , _ = > false
1513+
}
1514+
}
1515+
;
1516+
}
1517+
fn main() {
1518+
match 0 {
1519+
0|1 if true =>true , _=>false
1520+
};
1521+
}
1522+
"#]],
1523+
);
1524+
check(
1525+
r#"
1526+
//- /new.rs crate:new deps:old edition:2021
1527+
old::make!();
1528+
fn main() {
1529+
matches/*+errors*/!(0, 0 | 1 if true);
1530+
}
1531+
//- /old.rs crate:old edition:2015
1532+
#[macro_export]
1533+
macro_rules! make {
1534+
() => {
1535+
macro_rules! matches {
1536+
($expression:expr, $pattern:pat if $guard:expr ) => {
1537+
match $expression {
1538+
$pattern if $guard => true,
1539+
_ => false
1540+
}
1541+
};
1542+
}
1543+
}
1544+
}
1545+
"#,
1546+
expect![[r#"
1547+
macro_rules !matches {
1548+
($expression: expr, $pattern: pat if $guard: expr) = > {
1549+
match $expression {
1550+
$pattern if $guard = > true , _ = > false
1551+
}
1552+
}
1553+
;
1554+
}
1555+
fn main() {
1556+
/* error: unexpected token in input *//* parse error: expected expression */
1557+
/* parse error: expected FAT_ARROW */
1558+
/* parse error: expected `,` */
1559+
/* parse error: expected pattern */
1560+
match 0 {
1561+
0 if $guard=>true , _=>false
1562+
};
1563+
}
1564+
"#]],
1565+
);
1566+
}
1567+
14831568
#[test]
14841569
fn test_dollar_crate_lhs_is_not_meta() {
14851570
check(

crates/hir-expand/src/declarative.rs

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
use std::sync::OnceLock;
33

44
use base_db::{CrateId, VersionReq};
5-
use span::{Edition, MacroCallId, Span};
5+
use span::{MacroCallId, Span, SyntaxContextId};
66
use syntax::{ast, AstNode};
77
use triomphe::Arc;
88

99
use crate::{
1010
attrs::RawAttrs,
1111
db::ExpandDatabase,
1212
hygiene::{apply_mark, Transparency},
13-
tt, AstId, ExpandError, ExpandResult,
13+
tt, AstId, ExpandError, ExpandResult, Lookup,
1414
};
1515

1616
/// Old-style `macro_rules` or the new macros 2.0
@@ -94,8 +94,6 @@ impl DeclarativeMacroExpander {
9494
def_crate: CrateId,
9595
id: AstId<ast::Macro>,
9696
) -> Arc<DeclarativeMacroExpander> {
97-
let crate_data = &db.crate_graph()[def_crate];
98-
let is_2021 = crate_data.edition >= Edition::Edition2021;
9997
let (root, map) = crate::db::parse_with_map(db, id.file_id);
10098
let root = root.syntax_node();
10199

@@ -133,6 +131,16 @@ impl DeclarativeMacroExpander {
133131
)
134132
});
135133

134+
let edition = |ctx: SyntaxContextId| {
135+
let crate_graph = db.crate_graph();
136+
if ctx.is_root() {
137+
crate_graph[def_crate].edition
138+
} else {
139+
let data = db.lookup_intern_syntax_context(ctx);
140+
// UNWRAP-SAFETY: Only the root context has no outer expansion
141+
crate_graph[data.outer_expn.unwrap().lookup(db).def.krate].edition
142+
}
143+
};
136144
let (mac, transparency) = match id.to_ptr(db).to_node(&root) {
137145
ast::Macro::MacroRules(macro_rules) => (
138146
match macro_rules.token_tree() {
@@ -145,12 +153,11 @@ impl DeclarativeMacroExpander {
145153
),
146154
);
147155

148-
mbe::DeclarativeMacro::parse_macro_rules(&tt, is_2021, new_meta_vars)
156+
mbe::DeclarativeMacro::parse_macro_rules(&tt, edition, new_meta_vars)
149157
}
150-
None => mbe::DeclarativeMacro::from_err(
151-
mbe::ParseError::Expected("expected a token tree".into()),
152-
is_2021,
153-
),
158+
None => mbe::DeclarativeMacro::from_err(mbe::ParseError::Expected(
159+
"expected a token tree".into(),
160+
)),
154161
},
155162
transparency(&macro_rules).unwrap_or(Transparency::SemiTransparent),
156163
),
@@ -163,12 +170,11 @@ impl DeclarativeMacroExpander {
163170
map.span_for_range(macro_def.macro_token().unwrap().text_range()),
164171
);
165172

166-
mbe::DeclarativeMacro::parse_macro2(&tt, is_2021, new_meta_vars)
173+
mbe::DeclarativeMacro::parse_macro2(&tt, edition, new_meta_vars)
167174
}
168-
None => mbe::DeclarativeMacro::from_err(
169-
mbe::ParseError::Expected("expected a token tree".into()),
170-
is_2021,
171-
),
175+
None => mbe::DeclarativeMacro::from_err(mbe::ParseError::Expected(
176+
"expected a token tree".into(),
177+
)),
172178
},
173179
transparency(&macro_def).unwrap_or(Transparency::Opaque),
174180
),

crates/mbe/src/benchmark.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ fn benchmark_parse_macro_rules() {
2323
let _pt = bench("mbe parse macro rules");
2424
rules
2525
.values()
26-
.map(|it| DeclarativeMacro::parse_macro_rules(it, true, true).rules.len())
26+
.map(|it| {
27+
DeclarativeMacro::parse_macro_rules(it, |_| span::Edition::CURRENT, true)
28+
.rules
29+
.len()
30+
})
2731
.sum()
2832
};
2933
assert_eq!(hash, 1144);
@@ -54,7 +58,9 @@ fn benchmark_expand_macro_rules() {
5458
fn macro_rules_fixtures() -> FxHashMap<String, DeclarativeMacro> {
5559
macro_rules_fixtures_tt()
5660
.into_iter()
57-
.map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt, true, true)))
61+
.map(|(id, tt)| {
62+
(id, DeclarativeMacro::parse_macro_rules(&tt, |_| span::Edition::CURRENT, true))
63+
})
5864
.collect()
5965
}
6066

crates/mbe/src/expander.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@ pub(crate) fn expand_rules(
1515
rules: &[crate::Rule],
1616
input: &tt::Subtree<Span>,
1717
marker: impl Fn(&mut Span) + Copy,
18-
is_2021: bool,
1918
new_meta_vars: bool,
2019
call_site: Span,
2120
) -> ExpandResult<tt::Subtree<Span>> {
2221
let mut match_: Option<(matcher::Match, &crate::Rule)> = None;
2322
for rule in rules {
24-
let new_match = matcher::match_(&rule.lhs, input, is_2021);
23+
let new_match = matcher::match_(&rule.lhs, input);
2524

2625
if new_match.err.is_none() {
2726
// If we find a rule that applies without errors, we're done.

crates/mbe/src/expander/matcher.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ impl Match {
108108
}
109109

110110
/// Matching errors are added to the `Match`.
111-
pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree<Span>, is_2021: bool) -> Match {
112-
let mut res = match_loop(pattern, input, is_2021);
111+
pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree<Span>) -> Match {
112+
let mut res = match_loop(pattern, input);
113113
res.bound_count = count(res.bindings.bindings());
114114
return res;
115115

@@ -362,7 +362,6 @@ fn match_loop_inner<'t>(
362362
next_items: &mut Vec<MatchState<'t>>,
363363
eof_items: &mut SmallVec<[MatchState<'t>; 1]>,
364364
error_items: &mut SmallVec<[MatchState<'t>; 1]>,
365-
is_2021: bool,
366365
delim_span: tt::DelimSpan<Span>,
367366
) {
368367
macro_rules! try_push {
@@ -474,7 +473,7 @@ fn match_loop_inner<'t>(
474473
OpDelimited::Op(Op::Var { kind, name, .. }) => {
475474
if let &Some(kind) = kind {
476475
let mut fork = src.clone();
477-
let match_res = match_meta_var(kind, &mut fork, is_2021, delim_span);
476+
let match_res = match_meta_var(kind, &mut fork, delim_span);
478477
match match_res.err {
479478
None => {
480479
// Some meta variables are optional (e.g. vis)
@@ -587,7 +586,7 @@ fn match_loop_inner<'t>(
587586
}
588587
}
589588

590-
fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>, is_2021: bool) -> Match {
589+
fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>) -> Match {
591590
let span = src.delimiter.delim_span();
592591
let mut src = TtIter::new(src);
593592
let mut stack: SmallVec<[TtIter<'_, Span>; 1]> = SmallVec::new();
@@ -627,7 +626,6 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>, is_2021: bool) ->
627626
&mut next_items,
628627
&mut eof_items,
629628
&mut error_items,
630-
is_2021,
631629
span,
632630
);
633631
stdx::always!(cur_items.is_empty());
@@ -741,7 +739,6 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>, is_2021: bool) ->
741739
fn match_meta_var(
742740
kind: MetaVarKind,
743741
input: &mut TtIter<'_, Span>,
744-
is_2021: bool,
745742
delim_span: DelimSpan<Span>,
746743
) -> ExpandResult<Option<Fragment>> {
747744
let fragment = match kind {
@@ -751,8 +748,7 @@ fn match_meta_var(
751748
});
752749
}
753750
MetaVarKind::Ty => parser::PrefixEntryPoint::Ty,
754-
MetaVarKind::Pat if is_2021 => parser::PrefixEntryPoint::PatTop,
755-
MetaVarKind::Pat => parser::PrefixEntryPoint::Pat,
751+
MetaVarKind::Pat => parser::PrefixEntryPoint::PatTop,
756752
MetaVarKind::PatParam => parser::PrefixEntryPoint::Pat,
757753
MetaVarKind::Stmt => parser::PrefixEntryPoint::Stmt,
758754
MetaVarKind::Block => parser::PrefixEntryPoint::Block,

crates/mbe/src/lib.rs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ mod tt_iter;
1717
#[cfg(test)]
1818
mod benchmark;
1919

20-
use span::Span;
20+
use span::{Edition, Span, SyntaxContextId};
2121
use stdx::impl_from;
2222

2323
use std::fmt;
@@ -129,9 +129,6 @@ impl fmt::Display for CountError {
129129
#[derive(Clone, Debug, PartialEq, Eq)]
130130
pub struct DeclarativeMacro {
131131
rules: Box<[Rule]>,
132-
// This is used for correctly determining the behavior of the pat fragment
133-
// FIXME: This should be tracked by hygiene of the fragment identifier!
134-
is_2021: bool,
135132
err: Option<Box<ParseError>>,
136133
}
137134

@@ -142,14 +139,14 @@ struct Rule {
142139
}
143140

144141
impl DeclarativeMacro {
145-
pub fn from_err(err: ParseError, is_2021: bool) -> DeclarativeMacro {
146-
DeclarativeMacro { rules: Box::default(), is_2021, err: Some(Box::new(err)) }
142+
pub fn from_err(err: ParseError) -> DeclarativeMacro {
143+
DeclarativeMacro { rules: Box::default(), err: Some(Box::new(err)) }
147144
}
148145

149146
/// The old, `macro_rules! m {}` flavor.
150147
pub fn parse_macro_rules(
151148
tt: &tt::Subtree<Span>,
152-
is_2021: bool,
149+
edition: impl Copy + Fn(SyntaxContextId) -> Edition,
153150
// FIXME: Remove this once we drop support for rust 1.76 (defaults to true then)
154151
new_meta_vars: bool,
155152
) -> DeclarativeMacro {
@@ -161,7 +158,7 @@ impl DeclarativeMacro {
161158
let mut err = None;
162159

163160
while src.len() > 0 {
164-
let rule = match Rule::parse(&mut src, true, new_meta_vars) {
161+
let rule = match Rule::parse(edition, &mut src, true, new_meta_vars) {
165162
Ok(it) => it,
166163
Err(e) => {
167164
err = Some(Box::new(e));
@@ -184,13 +181,13 @@ impl DeclarativeMacro {
184181
}
185182
}
186183

187-
DeclarativeMacro { rules: rules.into_boxed_slice(), is_2021, err }
184+
DeclarativeMacro { rules: rules.into_boxed_slice(), err }
188185
}
189186

190187
/// The new, unstable `macro m {}` flavor.
191188
pub fn parse_macro2(
192189
tt: &tt::Subtree<Span>,
193-
is_2021: bool,
190+
edition: impl Copy + Fn(SyntaxContextId) -> Edition,
194191
// FIXME: Remove this once we drop support for rust 1.76 (defaults to true then)
195192
new_meta_vars: bool,
196193
) -> DeclarativeMacro {
@@ -201,7 +198,7 @@ impl DeclarativeMacro {
201198
if tt::DelimiterKind::Brace == tt.delimiter.kind {
202199
cov_mark::hit!(parse_macro_def_rules);
203200
while src.len() > 0 {
204-
let rule = match Rule::parse(&mut src, true, new_meta_vars) {
201+
let rule = match Rule::parse(edition, &mut src, true, new_meta_vars) {
205202
Ok(it) => it,
206203
Err(e) => {
207204
err = Some(Box::new(e));
@@ -220,7 +217,7 @@ impl DeclarativeMacro {
220217
}
221218
} else {
222219
cov_mark::hit!(parse_macro_def_simple);
223-
match Rule::parse(&mut src, false, new_meta_vars) {
220+
match Rule::parse(edition, &mut src, false, new_meta_vars) {
224221
Ok(rule) => {
225222
if src.len() != 0 {
226223
err = Some(Box::new(ParseError::expected("remaining tokens in macro def")));
@@ -240,7 +237,7 @@ impl DeclarativeMacro {
240237
}
241238
}
242239

243-
DeclarativeMacro { rules: rules.into_boxed_slice(), is_2021, err }
240+
DeclarativeMacro { rules: rules.into_boxed_slice(), err }
244241
}
245242

246243
pub fn err(&self) -> Option<&ParseError> {
@@ -254,12 +251,13 @@ impl DeclarativeMacro {
254251
new_meta_vars: bool,
255252
call_site: Span,
256253
) -> ExpandResult<tt::Subtree<Span>> {
257-
expander::expand_rules(&self.rules, tt, marker, self.is_2021, new_meta_vars, call_site)
254+
expander::expand_rules(&self.rules, tt, marker, new_meta_vars, call_site)
258255
}
259256
}
260257

261258
impl Rule {
262259
fn parse(
260+
edition: impl Copy + Fn(SyntaxContextId) -> Edition,
263261
src: &mut TtIter<'_, Span>,
264262
expect_arrow: bool,
265263
new_meta_vars: bool,
@@ -271,8 +269,8 @@ impl Rule {
271269
}
272270
let rhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?;
273271

274-
let lhs = MetaTemplate::parse_pattern(lhs)?;
275-
let rhs = MetaTemplate::parse_template(rhs, new_meta_vars)?;
272+
let lhs = MetaTemplate::parse_pattern(edition, lhs)?;
273+
let rhs = MetaTemplate::parse_template(edition, rhs, new_meta_vars)?;
276274

277275
Ok(crate::Rule { lhs, rhs })
278276
}

0 commit comments

Comments
 (0)