Skip to content

Commit 707382c

Browse files
committed
Auto merge of #14652 - Veykril:pat2021, r=Veykril
fix: Fix pat fragment handling in 2021 edition Fixes #9055 The fix isn't that great, but we are kind of forced to do it the quick and hacky way right now since std has changed the `matches` macro to make use of this now. And for a proper fix we need to track hygiene for identifiers which is a long way off anyways
2 parents 0c0025f + d1ca505 commit 707382c

File tree

8 files changed

+80
-23
lines changed

8 files changed

+80
-23
lines changed

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

+37-3
Original file line numberDiff line numberDiff line change
@@ -1293,19 +1293,53 @@ ok!();
12931293
}
12941294

12951295
#[test]
1296-
fn test_vertical_bar_with_pat() {
1296+
fn test_vertical_bar_with_pat_param() {
12971297
check(
12981298
r#"
1299-
macro_rules! m { (|$pat:pat| ) => { ok!(); } }
1299+
macro_rules! m { (|$pat:pat_param| ) => { ok!(); } }
13001300
m! { |x| }
13011301
"#,
13021302
expect![[r#"
1303-
macro_rules! m { (|$pat:pat| ) => { ok!(); } }
1303+
macro_rules! m { (|$pat:pat_param| ) => { ok!(); } }
13041304
ok!();
13051305
"#]],
13061306
);
13071307
}
13081308

1309+
#[test]
1310+
fn test_new_std_matches() {
1311+
check(
1312+
r#"
1313+
macro_rules! matches {
1314+
($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => {
1315+
match $expression {
1316+
$pattern $(if $guard)? => true,
1317+
_ => false
1318+
}
1319+
};
1320+
}
1321+
fn main() {
1322+
matches!(0, 0 | 1 if true);
1323+
}
1324+
"#,
1325+
expect![[r#"
1326+
macro_rules! matches {
1327+
($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => {
1328+
match $expression {
1329+
$pattern $(if $guard)? => true,
1330+
_ => false
1331+
}
1332+
};
1333+
}
1334+
fn main() {
1335+
match 0 {
1336+
0|1if true =>true , _=>false
1337+
};
1338+
}
1339+
"#]],
1340+
);
1341+
}
1342+
13091343
#[test]
13101344
fn test_dollar_crate_lhs_is_not_meta() {
13111345
check(

crates/hir-expand/src/db.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::sync::Arc;
44

5-
use base_db::{salsa, SourceDatabase};
5+
use base_db::{salsa, Edition, SourceDatabase};
66
use either::Either;
77
use limit::Limit;
88
use mbe::syntax_node_to_token_tree;
@@ -406,21 +406,22 @@ fn macro_def(
406406
) -> Result<Arc<TokenExpander>, mbe::ParseError> {
407407
match id.kind {
408408
MacroDefKind::Declarative(ast_id) => {
409+
let is_2021 = db.crate_graph()[id.krate].edition >= Edition::Edition2021;
409410
let (mac, def_site_token_map) = match ast_id.to_node(db) {
410411
ast::Macro::MacroRules(macro_rules) => {
411412
let arg = macro_rules
412413
.token_tree()
413414
.ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?;
414415
let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax());
415-
let mac = mbe::DeclarativeMacro::parse_macro_rules(&tt)?;
416+
let mac = mbe::DeclarativeMacro::parse_macro_rules(&tt, is_2021)?;
416417
(mac, def_site_token_map)
417418
}
418419
ast::Macro::MacroDef(macro_def) => {
419420
let arg = macro_def
420421
.body()
421422
.ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?;
422423
let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax());
423-
let mac = mbe::DeclarativeMacro::parse_macro2(&tt)?;
424+
let mac = mbe::DeclarativeMacro::parse_macro2(&tt, is_2021)?;
424425
(mac, def_site_token_map)
425426
}
426427
};

crates/mbe/src/benchmark.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ fn benchmark_parse_macro_rules() {
2020
let rules = macro_rules_fixtures_tt();
2121
let hash: usize = {
2222
let _pt = bench("mbe parse macro rules");
23-
rules.values().map(|it| DeclarativeMacro::parse_macro_rules(it).unwrap().rules.len()).sum()
23+
rules
24+
.values()
25+
.map(|it| DeclarativeMacro::parse_macro_rules(it, true).unwrap().rules.len())
26+
.sum()
2427
};
2528
assert_eq!(hash, 1144);
2629
}
@@ -50,7 +53,7 @@ fn benchmark_expand_macro_rules() {
5053
fn macro_rules_fixtures() -> FxHashMap<String, DeclarativeMacro> {
5154
macro_rules_fixtures_tt()
5255
.into_iter()
53-
.map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt).unwrap()))
56+
.map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt, true).unwrap()))
5457
.collect()
5558
}
5659

crates/mbe/src/expander.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ use crate::{parser::MetaVarKind, tt, ExpandError, ExpandResult};
1313
pub(crate) fn expand_rules(
1414
rules: &[crate::Rule],
1515
input: &tt::Subtree,
16+
is_2021: bool,
1617
) -> ExpandResult<tt::Subtree> {
1718
let mut match_: Option<(matcher::Match, &crate::Rule)> = None;
1819
for rule in rules {
19-
let new_match = matcher::match_(&rule.lhs, input);
20+
let new_match = matcher::match_(&rule.lhs, input, is_2021);
2021

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

crates/mbe/src/expander/matcher.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ impl Match {
111111
}
112112

113113
/// Matching errors are added to the `Match`.
114-
pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree) -> Match {
115-
let mut res = match_loop(pattern, input);
114+
pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree, is_2021: bool) -> Match {
115+
let mut res = match_loop(pattern, input, is_2021);
116116
res.bound_count = count(res.bindings.bindings());
117117
return res;
118118

@@ -354,6 +354,7 @@ struct MatchState<'t> {
354354
/// - `eof_items`: the set of items that would be valid if this was the EOF.
355355
/// - `bb_items`: the set of items that are waiting for the black-box parser.
356356
/// - `error_items`: the set of items in errors, used for error-resilient parsing
357+
#[inline]
357358
fn match_loop_inner<'t>(
358359
src: TtIter<'t>,
359360
stack: &[TtIter<'t>],
@@ -364,6 +365,7 @@ fn match_loop_inner<'t>(
364365
next_items: &mut Vec<MatchState<'t>>,
365366
eof_items: &mut SmallVec<[MatchState<'t>; 1]>,
366367
error_items: &mut SmallVec<[MatchState<'t>; 1]>,
368+
is_2021: bool,
367369
) {
368370
macro_rules! try_push {
369371
($items: expr, $it:expr) => {
@@ -474,7 +476,7 @@ fn match_loop_inner<'t>(
474476
OpDelimited::Op(Op::Var { kind, name, .. }) => {
475477
if let &Some(kind) = kind {
476478
let mut fork = src.clone();
477-
let match_res = match_meta_var(kind, &mut fork);
479+
let match_res = match_meta_var(kind, &mut fork, is_2021);
478480
match match_res.err {
479481
None => {
480482
// Some meta variables are optional (e.g. vis)
@@ -583,7 +585,7 @@ fn match_loop_inner<'t>(
583585
}
584586
}
585587

586-
fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
588+
fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree, is_2021: bool) -> Match {
587589
let mut src = TtIter::new(src);
588590
let mut stack: SmallVec<[TtIter<'_>; 1]> = SmallVec::new();
589591
let mut res = Match::default();
@@ -622,6 +624,7 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
622624
&mut next_items,
623625
&mut eof_items,
624626
&mut error_items,
627+
is_2021,
625628
);
626629
stdx::always!(cur_items.is_empty());
627630

@@ -731,14 +734,17 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
731734
}
732735
}
733736

734-
fn match_meta_var(kind: MetaVarKind, input: &mut TtIter<'_>) -> ExpandResult<Option<Fragment>> {
737+
fn match_meta_var(
738+
kind: MetaVarKind,
739+
input: &mut TtIter<'_>,
740+
is_2021: bool,
741+
) -> ExpandResult<Option<Fragment>> {
735742
let fragment = match kind {
736743
MetaVarKind::Path => parser::PrefixEntryPoint::Path,
737744
MetaVarKind::Ty => parser::PrefixEntryPoint::Ty,
738-
// FIXME: These two should actually behave differently depending on the edition.
739-
//
740-
// https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html
741-
MetaVarKind::Pat | MetaVarKind::PatParam => parser::PrefixEntryPoint::Pat,
745+
MetaVarKind::Pat if is_2021 => parser::PrefixEntryPoint::PatTop,
746+
MetaVarKind::Pat => parser::PrefixEntryPoint::Pat,
747+
MetaVarKind::PatParam => parser::PrefixEntryPoint::Pat,
742748
MetaVarKind::Stmt => parser::PrefixEntryPoint::Stmt,
743749
MetaVarKind::Block => parser::PrefixEntryPoint::Block,
744750
MetaVarKind::Meta => parser::PrefixEntryPoint::MetaItem,

crates/mbe/src/lib.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ pub struct DeclarativeMacro {
107107
rules: Vec<Rule>,
108108
/// Highest id of the token we have in TokenMap
109109
shift: Shift,
110+
// This is used for correctly determining the behavior of the pat fragment
111+
// FIXME: This should be tracked by hygiene of the fragment identifier!
112+
is_2021: bool,
110113
}
111114

112115
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -190,7 +193,10 @@ pub enum Origin {
190193

191194
impl DeclarativeMacro {
192195
/// The old, `macro_rules! m {}` flavor.
193-
pub fn parse_macro_rules(tt: &tt::Subtree) -> Result<DeclarativeMacro, ParseError> {
196+
pub fn parse_macro_rules(
197+
tt: &tt::Subtree,
198+
is_2021: bool,
199+
) -> Result<DeclarativeMacro, ParseError> {
194200
// Note: this parsing can be implemented using mbe machinery itself, by
195201
// matching against `$($lhs:tt => $rhs:tt);*` pattern, but implementing
196202
// manually seems easier.
@@ -211,11 +217,11 @@ impl DeclarativeMacro {
211217
validate(lhs)?;
212218
}
213219

214-
Ok(DeclarativeMacro { rules, shift: Shift::new(tt) })
220+
Ok(DeclarativeMacro { rules, shift: Shift::new(tt), is_2021 })
215221
}
216222

217223
/// The new, unstable `macro m {}` flavor.
218-
pub fn parse_macro2(tt: &tt::Subtree) -> Result<DeclarativeMacro, ParseError> {
224+
pub fn parse_macro2(tt: &tt::Subtree, is_2021: bool) -> Result<DeclarativeMacro, ParseError> {
219225
let mut src = TtIter::new(tt);
220226
let mut rules = Vec::new();
221227

@@ -244,14 +250,14 @@ impl DeclarativeMacro {
244250
validate(lhs)?;
245251
}
246252

247-
Ok(DeclarativeMacro { rules, shift: Shift::new(tt) })
253+
Ok(DeclarativeMacro { rules, shift: Shift::new(tt), is_2021 })
248254
}
249255

250256
pub fn expand(&self, tt: &tt::Subtree) -> ExpandResult<tt::Subtree> {
251257
// apply shift
252258
let mut tt = tt.clone();
253259
self.shift.shift_all(&mut tt);
254-
expander::expand_rules(&self.rules, &tt)
260+
expander::expand_rules(&self.rules, &tt, self.is_2021)
255261
}
256262

257263
pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {

crates/parser/src/grammar.rs

+4
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ pub(crate) mod entry {
6666
patterns::pattern_single(p);
6767
}
6868

69+
pub(crate) fn pat_top(p: &mut Parser<'_>) {
70+
patterns::pattern_top(p);
71+
}
72+
6973
pub(crate) fn ty(p: &mut Parser<'_>) {
7074
types::type_(p);
7175
}

crates/parser/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ pub enum PrefixEntryPoint {
131131
Block,
132132
Stmt,
133133
Pat,
134+
PatTop,
134135
Ty,
135136
Expr,
136137
Path,
@@ -145,6 +146,7 @@ impl PrefixEntryPoint {
145146
PrefixEntryPoint::Block => grammar::entry::prefix::block,
146147
PrefixEntryPoint::Stmt => grammar::entry::prefix::stmt,
147148
PrefixEntryPoint::Pat => grammar::entry::prefix::pat,
149+
PrefixEntryPoint::PatTop => grammar::entry::prefix::pat_top,
148150
PrefixEntryPoint::Ty => grammar::entry::prefix::ty,
149151
PrefixEntryPoint::Expr => grammar::entry::prefix::expr,
150152
PrefixEntryPoint::Path => grammar::entry::prefix::path,

0 commit comments

Comments
 (0)