]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_expand/src/mbe/macro_parser.rs
Store `ErrorGuaranteed` in `ErrorReported`
[rust.git] / compiler / rustc_expand / src / mbe / macro_parser.rs
1 //! This is an NFA-based parser, which calls out to the main Rust parser for named non-terminals
2 //! (which it commits to fully when it hits one in a grammar). There's a set of current NFA threads
3 //! and a set of next ones. Instead of NTs, we have a special case for Kleene star. The big-O, in
4 //! pathological cases, is worse than traditional use of NFA or Earley parsing, but it's an easier
5 //! fit for Macro-by-Example-style rules.
6 //!
7 //! (In order to prevent the pathological case, we'd need to lazily construct the resulting
8 //! `NamedMatch`es at the very end. It'd be a pain, and require more memory to keep around old
9 //! matcher positions, but it would also save overhead)
10 //!
11 //! We don't say this parser uses the Earley algorithm, because it's unnecessarily inaccurate.
12 //! The macro parser restricts itself to the features of finite state automata. Earley parsers
13 //! can be described as an extension of NFAs with completion rules, prediction rules, and recursion.
14 //!
15 //! Quick intro to how the parser works:
16 //!
17 //! A "matcher position" (a.k.a. "position" or "mp") is a dot in the middle of a matcher, usually
18 //! written as a `·`. For example `· a $( a )* a b` is one, as is `a $( · a )* a b`.
19 //!
20 //! The parser walks through the input a token at a time, maintaining a list
21 //! of threads consistent with the current position in the input string: `cur_mps`.
22 //!
23 //! As it processes them, it fills up `eof_mps` with threads that would be valid if
24 //! the macro invocation is now over, `bb_mps` with threads that are waiting on
25 //! a Rust non-terminal like `$e:expr`, and `next_mps` with threads that are waiting
26 //! on a particular token. Most of the logic concerns moving the · through the
27 //! repetitions indicated by Kleene stars. The rules for moving the · without
28 //! consuming any input are called epsilon transitions. It only advances or calls
29 //! out to the real Rust parser when no `cur_mps` threads remain.
30 //!
31 //! Example:
32 //!
33 //! ```text, ignore
34 //! Start parsing a a a a b against [· a $( a )* a b].
35 //!
36 //! Remaining input: a a a a b
37 //! next: [· a $( a )* a b]
38 //!
39 //! - - - Advance over an a. - - -
40 //!
41 //! Remaining input: a a a b
42 //! cur: [a · $( a )* a b]
43 //! Descend/Skip (first position).
44 //! next: [a $( · a )* a b]  [a $( a )* · a b].
45 //!
46 //! - - - Advance over an a. - - -
47 //!
48 //! Remaining input: a a b
49 //! cur: [a $( a · )* a b]  [a $( a )* a · b]
50 //! Follow epsilon transition: Finish/Repeat (first position)
51 //! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
52 //!
53 //! - - - Advance over an a. - - - (this looks exactly like the last step)
54 //!
55 //! Remaining input: a b
56 //! cur: [a $( a · )* a b]  [a $( a )* a · b]
57 //! Follow epsilon transition: Finish/Repeat (first position)
58 //! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
59 //!
60 //! - - - Advance over an a. - - - (this looks exactly like the last step)
61 //!
62 //! Remaining input: b
63 //! cur: [a $( a · )* a b]  [a $( a )* a · b]
64 //! Follow epsilon transition: Finish/Repeat (first position)
65 //! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
66 //!
67 //! - - - Advance over a b. - - -
68 //!
69 //! Remaining input: ''
70 //! eof: [a $( a )* a b ·]
71 //! ```
72
73 pub(crate) use NamedMatch::*;
74 pub(crate) use ParseResult::*;
75 use rustc_errors::ErrorGuaranteed;
76
77 use crate::mbe::{KleeneOp, TokenTree};
78
79 use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token};
80 use rustc_lint_defs::pluralize;
81 use rustc_parse::parser::{NtOrTt, Parser};
82 use rustc_span::symbol::MacroRulesNormalizedIdent;
83 use rustc_span::Span;
84
85 use rustc_data_structures::fx::FxHashMap;
86 use rustc_data_structures::sync::Lrc;
87 use rustc_span::symbol::Ident;
88 use std::borrow::Cow;
89 use std::collections::hash_map::Entry::{Occupied, Vacant};
90
91 /// A unit within a matcher that a `MatcherPos` can refer to. Similar to (and derived from)
92 /// `mbe::TokenTree`, but designed specifically for fast and easy traversal during matching.
93 /// Notable differences to `mbe::TokenTree`:
94 /// - It is non-recursive, i.e. there is no nesting.
95 /// - The end pieces of each sequence (the separator, if present, and the Kleene op) are
96 ///   represented explicitly, as is the very end of the matcher.
97 ///
98 /// This means a matcher can be represented by `&[MatcherLoc]`, and traversal mostly involves
99 /// simply incrementing the current matcher position index by one.
100 pub(super) enum MatcherLoc {
101     Token {
102         token: Token,
103     },
104     Delimited,
105     Sequence {
106         op: KleeneOp,
107         num_metavar_decls: usize,
108         idx_first_after: usize,
109         next_metavar: usize,
110         seq_depth: usize,
111     },
112     SequenceKleeneOpNoSep {
113         op: KleeneOp,
114         idx_first: usize,
115     },
116     SequenceSep {
117         separator: Token,
118     },
119     SequenceKleeneOpAfterSep {
120         idx_first: usize,
121     },
122     MetaVarDecl {
123         span: Span,
124         bind: Ident,
125         kind: Option<NonterminalKind>,
126         next_metavar: usize,
127         seq_depth: usize,
128     },
129     Eof,
130 }
131
132 pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> {
133     fn inner(
134         tts: &[TokenTree],
135         locs: &mut Vec<MatcherLoc>,
136         next_metavar: &mut usize,
137         seq_depth: usize,
138     ) {
139         for tt in tts {
140             match tt {
141                 TokenTree::Token(token) => {
142                     locs.push(MatcherLoc::Token { token: token.clone() });
143                 }
144                 TokenTree::Delimited(span, delimited) => {
145                     let open_token = Token::new(token::OpenDelim(delimited.delim), span.open);
146                     let close_token = Token::new(token::CloseDelim(delimited.delim), span.close);
147
148                     locs.push(MatcherLoc::Delimited);
149                     locs.push(MatcherLoc::Token { token: open_token });
150                     inner(&delimited.tts, locs, next_metavar, seq_depth);
151                     locs.push(MatcherLoc::Token { token: close_token });
152                 }
153                 TokenTree::Sequence(_, seq) => {
154                     // We can't determine `idx_first_after` and construct the final
155                     // `MatcherLoc::Sequence` until after `inner()` is called and the sequence end
156                     // pieces are processed. So we push a dummy value (`Eof` is cheapest to
157                     // construct) now, and overwrite it with the proper value below.
158                     let dummy = MatcherLoc::Eof;
159                     locs.push(dummy);
160
161                     let next_metavar_orig = *next_metavar;
162                     let op = seq.kleene.op;
163                     let idx_first = locs.len();
164                     let idx_seq = idx_first - 1;
165                     inner(&seq.tts, locs, next_metavar, seq_depth + 1);
166
167                     if let Some(separator) = &seq.separator {
168                         locs.push(MatcherLoc::SequenceSep { separator: separator.clone() });
169                         locs.push(MatcherLoc::SequenceKleeneOpAfterSep { idx_first });
170                     } else {
171                         locs.push(MatcherLoc::SequenceKleeneOpNoSep { op, idx_first });
172                     }
173
174                     // Overwrite the dummy value pushed above with the proper value.
175                     locs[idx_seq] = MatcherLoc::Sequence {
176                         op,
177                         num_metavar_decls: seq.num_captures,
178                         idx_first_after: locs.len(),
179                         next_metavar: next_metavar_orig,
180                         seq_depth,
181                     };
182                 }
183                 &TokenTree::MetaVarDecl(span, bind, kind) => {
184                     locs.push(MatcherLoc::MetaVarDecl {
185                         span,
186                         bind,
187                         kind,
188                         next_metavar: *next_metavar,
189                         seq_depth,
190                     });
191                     *next_metavar += 1;
192                 }
193                 TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
194             }
195         }
196     }
197
198     let mut locs = vec![];
199     let mut next_metavar = 0;
200     inner(matcher, &mut locs, &mut next_metavar, /* seq_depth */ 0);
201
202     // A final entry is needed for eof.
203     locs.push(MatcherLoc::Eof);
204
205     locs
206 }
207
208 /// A single matcher position, representing the state of matching.
209 struct MatcherPos {
210     /// The index into `TtParser::locs`, which represents the "dot".
211     idx: usize,
212
213     /// The matches made against metavar decls so far. On a successful match, this vector ends up
214     /// with one element per metavar decl in the matcher. Each element records token trees matched
215     /// against the relevant metavar by the black box parser. An element will be a `MatchedSeq` if
216     /// the corresponding metavar decl is within a sequence.
217     ///
218     /// It is critical to performance that this is an `Lrc`, because it gets cloned frequently when
219     /// processing sequences. Mostly for sequence-ending possibilities that must be tried but end
220     /// up failing.
221     matches: Lrc<Vec<NamedMatch>>,
222 }
223
224 // This type is used a lot. Make sure it doesn't unintentionally get bigger.
225 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
226 rustc_data_structures::static_assert_size!(MatcherPos, 16);
227
228 impl MatcherPos {
229     /// Adds `m` as a named match for the `metavar_idx`-th metavar. There are only two call sites,
230     /// and both are hot enough to be always worth inlining.
231     #[inline(always)]
232     fn push_match(&mut self, metavar_idx: usize, seq_depth: usize, m: NamedMatch) {
233         let matches = Lrc::make_mut(&mut self.matches);
234         match seq_depth {
235             0 => {
236                 // We are not within a sequence. Just append `m`.
237                 assert_eq!(metavar_idx, matches.len());
238                 matches.push(m);
239             }
240             _ => {
241                 // We are within a sequence. Find the final `MatchedSeq` at the appropriate depth
242                 // and append `m` to its vector.
243                 let mut curr = &mut matches[metavar_idx];
244                 for _ in 0..seq_depth - 1 {
245                     match curr {
246                         MatchedSeq(seq) => curr = seq.last_mut().unwrap(),
247                         _ => unreachable!(),
248                     }
249                 }
250                 match curr {
251                     MatchedSeq(seq) => seq.push(m),
252                     _ => unreachable!(),
253                 }
254             }
255         }
256     }
257 }
258
259 enum EofMatcherPositions {
260     None,
261     One(MatcherPos),
262     Multiple,
263 }
264
265 /// Represents the possible results of an attempted parse.
266 pub(crate) enum ParseResult<T> {
267     /// Parsed successfully.
268     Success(T),
269     /// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected
270     /// end of macro invocation. Otherwise, it indicates that no rules expected the given token.
271     Failure(Token, &'static str),
272     /// Fatal error (malformed macro?). Abort compilation.
273     Error(rustc_span::Span, String),
274     ErrorReported(ErrorGuaranteed),
275 }
276
277 /// A `ParseResult` where the `Success` variant contains a mapping of
278 /// `MacroRulesNormalizedIdent`s to `NamedMatch`es. This represents the mapping
279 /// of metavars to the token trees they bind to.
280 pub(crate) type NamedParseResult = ParseResult<FxHashMap<MacroRulesNormalizedIdent, NamedMatch>>;
281
282 /// Count how many metavars declarations are in `matcher`.
283 pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
284     matcher
285         .iter()
286         .map(|tt| match tt {
287             TokenTree::MetaVarDecl(..) => 1,
288             TokenTree::Sequence(_, seq) => seq.num_captures,
289             TokenTree::Delimited(_, delim) => count_metavar_decls(&delim.tts),
290             TokenTree::Token(..) => 0,
291             TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
292         })
293         .sum()
294 }
295
296 /// `NamedMatch` is a pattern-match result for a single metavar. All
297 /// `MatchedNonterminal`s in the `NamedMatch` have the same non-terminal type
298 /// (expr, item, etc).
299 ///
300 /// The in-memory structure of a particular `NamedMatch` represents the match
301 /// that occurred when a particular subset of a matcher was applied to a
302 /// particular token tree.
303 ///
304 /// The width of each `MatchedSeq` in the `NamedMatch`, and the identity of
305 /// the `MatchedNtNonTts`s, will depend on the token tree it was applied
306 /// to: each `MatchedSeq` corresponds to a single repetition in the originating
307 /// token tree. The depth of the `NamedMatch` structure will therefore depend
308 /// only on the nesting depth of repetitions in the originating token tree it
309 /// was derived from.
310 ///
311 /// In layperson's terms: `NamedMatch` will form a tree representing nested matches of a particular
312 /// meta variable. For example, if we are matching the following macro against the following
313 /// invocation...
314 ///
315 /// ```rust
316 /// macro_rules! foo {
317 ///   ($($($x:ident),+);+) => {}
318 /// }
319 ///
320 /// foo!(a, b, c, d; a, b, c, d, e);
321 /// ```
322 ///
323 /// Then, the tree will have the following shape:
324 ///
325 /// ```ignore (private-internal)
326 /// # use NamedMatch::*;
327 /// MatchedSeq([
328 ///   MatchedSeq([
329 ///     MatchedNonterminal(a),
330 ///     MatchedNonterminal(b),
331 ///     MatchedNonterminal(c),
332 ///     MatchedNonterminal(d),
333 ///   ]),
334 ///   MatchedSeq([
335 ///     MatchedNonterminal(a),
336 ///     MatchedNonterminal(b),
337 ///     MatchedNonterminal(c),
338 ///     MatchedNonterminal(d),
339 ///     MatchedNonterminal(e),
340 ///   ])
341 /// ])
342 /// ```
343 #[derive(Debug, Clone)]
344 pub(crate) enum NamedMatch {
345     MatchedSeq(Vec<NamedMatch>),
346
347     // A metavar match of type `tt`.
348     MatchedTokenTree(rustc_ast::tokenstream::TokenTree),
349
350     // A metavar match of any type other than `tt`.
351     MatchedNonterminal(Lrc<Nonterminal>),
352 }
353
354 /// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
355 fn token_name_eq(t1: &Token, t2: &Token) -> bool {
356     if let (Some((ident1, is_raw1)), Some((ident2, is_raw2))) = (t1.ident(), t2.ident()) {
357         ident1.name == ident2.name && is_raw1 == is_raw2
358     } else if let (Some(ident1), Some(ident2)) = (t1.lifetime(), t2.lifetime()) {
359         ident1.name == ident2.name
360     } else {
361         t1.kind == t2.kind
362     }
363 }
364
365 // Note: the vectors could be created and dropped within `parse_tt`, but to avoid excess
366 // allocations we have a single vector for each kind that is cleared and reused repeatedly.
367 pub struct TtParser {
368     macro_name: Ident,
369
370     /// The set of current mps to be processed. This should be empty by the end of a successful
371     /// execution of `parse_tt_inner`.
372     cur_mps: Vec<MatcherPos>,
373
374     /// The set of newly generated mps. These are used to replenish `cur_mps` in the function
375     /// `parse_tt`.
376     next_mps: Vec<MatcherPos>,
377
378     /// The set of mps that are waiting for the black-box parser.
379     bb_mps: Vec<MatcherPos>,
380
381     /// Pre-allocate an empty match array, so it can be cloned cheaply for macros with many rules
382     /// that have no metavars.
383     empty_matches: Lrc<Vec<NamedMatch>>,
384 }
385
386 impl TtParser {
387     pub(super) fn new(macro_name: Ident) -> TtParser {
388         TtParser {
389             macro_name,
390             cur_mps: vec![],
391             next_mps: vec![],
392             bb_mps: vec![],
393             empty_matches: Lrc::new(vec![]),
394         }
395     }
396
397     /// Process the matcher positions of `cur_mps` until it is empty. In the process, this will
398     /// produce more mps in `next_mps` and `bb_mps`.
399     ///
400     /// # Returns
401     ///
402     /// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept
403     /// track of through the mps generated.
404     fn parse_tt_inner(
405         &mut self,
406         matcher: &[MatcherLoc],
407         token: &Token,
408     ) -> Option<NamedParseResult> {
409         // Matcher positions that would be valid if the macro invocation was over now. Only
410         // modified if `token == Eof`.
411         let mut eof_mps = EofMatcherPositions::None;
412
413         while let Some(mut mp) = self.cur_mps.pop() {
414             match &matcher[mp.idx] {
415                 MatcherLoc::Token { token: t } => {
416                     // If it's a doc comment, we just ignore it and move on to the next tt in the
417                     // matcher. This is a bug, but #95267 showed that existing programs rely on
418                     // this behaviour, and changing it would require some care and a transition
419                     // period.
420                     //
421                     // If the token matches, we can just advance the parser.
422                     //
423                     // Otherwise, this match has failed, there is nothing to do, and hopefully
424                     // another mp in `cur_mps` will match.
425                     if matches!(t, Token { kind: DocComment(..), .. }) {
426                         mp.idx += 1;
427                         self.cur_mps.push(mp);
428                     } else if token_name_eq(&t, token) {
429                         mp.idx += 1;
430                         self.next_mps.push(mp);
431                     }
432                 }
433                 MatcherLoc::Delimited => {
434                     // Entering the delimiter is trivial.
435                     mp.idx += 1;
436                     self.cur_mps.push(mp);
437                 }
438                 &MatcherLoc::Sequence {
439                     op,
440                     num_metavar_decls,
441                     idx_first_after,
442                     next_metavar,
443                     seq_depth,
444                 } => {
445                     // Install an empty vec for each metavar within the sequence.
446                     for metavar_idx in next_metavar..next_metavar + num_metavar_decls {
447                         mp.push_match(metavar_idx, seq_depth, MatchedSeq(vec![]));
448                     }
449
450                     if op == KleeneOp::ZeroOrMore || op == KleeneOp::ZeroOrOne {
451                         // Try zero matches of this sequence, by skipping over it.
452                         self.cur_mps.push(MatcherPos {
453                             idx: idx_first_after,
454                             matches: mp.matches.clone(), // a cheap clone
455                         });
456                     }
457
458                     // Try one or more matches of this sequence, by entering it.
459                     mp.idx += 1;
460                     self.cur_mps.push(mp);
461                 }
462                 &MatcherLoc::SequenceKleeneOpNoSep { op, idx_first } => {
463                     // We are past the end of a sequence with no separator. Try ending the
464                     // sequence. If that's not possible, `ending_mp` will fail quietly when it is
465                     // processed next time around the loop.
466                     let ending_mp = MatcherPos {
467                         idx: mp.idx + 1,             // +1 skips the Kleene op
468                         matches: mp.matches.clone(), // a cheap clone
469                     };
470                     self.cur_mps.push(ending_mp);
471
472                     if op != KleeneOp::ZeroOrOne {
473                         // Try another repetition.
474                         mp.idx = idx_first;
475                         self.cur_mps.push(mp);
476                     }
477                 }
478                 MatcherLoc::SequenceSep { separator } => {
479                     // We are past the end of a sequence with a separator but we haven't seen the
480                     // separator yet. Try ending the sequence. If that's not possible, `ending_mp`
481                     // will fail quietly when it is processed next time around the loop.
482                     let ending_mp = MatcherPos {
483                         idx: mp.idx + 2,             // +2 skips the separator and the Kleene op
484                         matches: mp.matches.clone(), // a cheap clone
485                     };
486                     self.cur_mps.push(ending_mp);
487
488                     if token_name_eq(token, separator) {
489                         // The separator matches the current token. Advance past it.
490                         mp.idx += 1;
491                         self.next_mps.push(mp);
492                     }
493                 }
494                 &MatcherLoc::SequenceKleeneOpAfterSep { idx_first } => {
495                     // We are past the sequence separator. This can't be a `?` Kleene op, because
496                     // they don't permit separators. Try another repetition.
497                     mp.idx = idx_first;
498                     self.cur_mps.push(mp);
499                 }
500                 &MatcherLoc::MetaVarDecl { span, kind, .. } => {
501                     // Built-in nonterminals never start with these tokens, so we can eliminate
502                     // them from consideration. We use the span of the metavariable declaration
503                     // to determine any edition-specific matching behavior for non-terminals.
504                     if let Some(kind) = kind {
505                         if Parser::nonterminal_may_begin_with(kind, token) {
506                             self.bb_mps.push(mp);
507                         }
508                     } else {
509                         // E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used.
510                         // Both this check and the one in `nameize` are necessary, surprisingly.
511                         return Some(Error(span, "missing fragment specifier".to_string()));
512                     }
513                 }
514                 MatcherLoc::Eof => {
515                     // We are past the matcher's end, and not in a sequence. Try to end things.
516                     debug_assert_eq!(mp.idx, matcher.len() - 1);
517                     if *token == token::Eof {
518                         eof_mps = match eof_mps {
519                             EofMatcherPositions::None => EofMatcherPositions::One(mp),
520                             EofMatcherPositions::One(_) | EofMatcherPositions::Multiple => {
521                                 EofMatcherPositions::Multiple
522                             }
523                         }
524                     }
525                 }
526             }
527         }
528
529         // If we reached the end of input, check that there is EXACTLY ONE possible matcher.
530         // Otherwise, either the parse is ambiguous (which is an error) or there is a syntax error.
531         if *token == token::Eof {
532             Some(match eof_mps {
533                 EofMatcherPositions::One(mut eof_mp) => {
534                     // Need to take ownership of the matches from within the `Lrc`.
535                     Lrc::make_mut(&mut eof_mp.matches);
536                     let matches = Lrc::try_unwrap(eof_mp.matches).unwrap().into_iter();
537                     self.nameize(matcher, matches)
538                 }
539                 EofMatcherPositions::Multiple => {
540                     Error(token.span, "ambiguity: multiple successful parses".to_string())
541                 }
542                 EofMatcherPositions::None => Failure(
543                     Token::new(
544                         token::Eof,
545                         if token.span.is_dummy() { token.span } else { token.span.shrink_to_hi() },
546                     ),
547                     "missing tokens in macro arguments",
548                 ),
549             })
550         } else {
551             None
552         }
553     }
554
555     /// Match the token stream from `parser` against `matcher`.
556     pub(super) fn parse_tt(
557         &mut self,
558         parser: &mut Cow<'_, Parser<'_>>,
559         matcher: &[MatcherLoc],
560     ) -> NamedParseResult {
561         // A queue of possible matcher positions. We initialize it with the matcher position in
562         // which the "dot" is before the first token of the first token tree in `matcher`.
563         // `parse_tt_inner` then processes all of these possible matcher positions and produces
564         // possible next positions into `next_mps`. After some post-processing, the contents of
565         // `next_mps` replenish `cur_mps` and we start over again.
566         self.cur_mps.clear();
567         self.cur_mps.push(MatcherPos { idx: 0, matches: self.empty_matches.clone() });
568
569         loop {
570             self.next_mps.clear();
571             self.bb_mps.clear();
572
573             // Process `cur_mps` until either we have finished the input or we need to get some
574             // parsing from the black-box parser done.
575             if let Some(res) = self.parse_tt_inner(matcher, &parser.token) {
576                 return res;
577             }
578
579             // `parse_tt_inner` handled all of `cur_mps`, so it's empty.
580             assert!(self.cur_mps.is_empty());
581
582             // Error messages here could be improved with links to original rules.
583             match (self.next_mps.len(), self.bb_mps.len()) {
584                 (0, 0) => {
585                     // There are no possible next positions AND we aren't waiting for the black-box
586                     // parser: syntax error.
587                     return Failure(
588                         parser.token.clone(),
589                         "no rules expected this token in macro call",
590                     );
591                 }
592
593                 (_, 0) => {
594                     // Dump all possible `next_mps` into `cur_mps` for the next iteration. Then
595                     // process the next token.
596                     self.cur_mps.append(&mut self.next_mps);
597                     parser.to_mut().bump();
598                 }
599
600                 (0, 1) => {
601                     // We need to call the black-box parser to get some nonterminal.
602                     let mut mp = self.bb_mps.pop().unwrap();
603                     let loc = &matcher[mp.idx];
604                     if let &MatcherLoc::MetaVarDecl {
605                         span,
606                         kind: Some(kind),
607                         next_metavar,
608                         seq_depth,
609                         ..
610                     } = loc
611                     {
612                         // We use the span of the metavariable declaration to determine any
613                         // edition-specific matching behavior for non-terminals.
614                         let nt = match parser.to_mut().parse_nonterminal(kind) {
615                             Err(mut err) => {
616                                 let guarantee = err.span_label(
617                                     span,
618                                     format!(
619                                         "while parsing argument for this `{kind}` macro fragment"
620                                     ),
621                                 )
622                                 .emit();
623                                 return ErrorReported(guarantee);
624                             }
625                             Ok(nt) => nt,
626                         };
627                         let m = match nt {
628                             NtOrTt::Nt(nt) => MatchedNonterminal(Lrc::new(nt)),
629                             NtOrTt::Tt(tt) => MatchedTokenTree(tt),
630                         };
631                         mp.push_match(next_metavar, seq_depth, m);
632                         mp.idx += 1;
633                     } else {
634                         unreachable!()
635                     }
636                     self.cur_mps.push(mp);
637                 }
638
639                 (_, _) => {
640                     // Too many possibilities!
641                     return self.ambiguity_error(matcher, parser.token.span);
642                 }
643             }
644
645             assert!(!self.cur_mps.is_empty());
646         }
647     }
648
649     fn ambiguity_error(
650         &self,
651         matcher: &[MatcherLoc],
652         token_span: rustc_span::Span,
653     ) -> NamedParseResult {
654         let nts = self
655             .bb_mps
656             .iter()
657             .map(|mp| match &matcher[mp.idx] {
658                 MatcherLoc::MetaVarDecl { bind, kind: Some(kind), .. } => {
659                     format!("{} ('{}')", kind, bind)
660                 }
661                 _ => unreachable!(),
662             })
663             .collect::<Vec<String>>()
664             .join(" or ");
665
666         Error(
667             token_span,
668             format!(
669                 "local ambiguity when calling macro `{}`: multiple parsing options: {}",
670                 self.macro_name,
671                 match self.next_mps.len() {
672                     0 => format!("built-in NTs {}.", nts),
673                     n => format!("built-in NTs {} or {n} other option{s}.", nts, s = pluralize!(n)),
674                 }
675             ),
676         )
677     }
678
679     fn nameize<I: Iterator<Item = NamedMatch>>(
680         &self,
681         matcher: &[MatcherLoc],
682         mut res: I,
683     ) -> NamedParseResult {
684         // Make that each metavar has _exactly one_ binding. If so, insert the binding into the
685         // `NamedParseResult`. Otherwise, it's an error.
686         let mut ret_val = FxHashMap::default();
687         for loc in matcher {
688             if let &MatcherLoc::MetaVarDecl { span, bind, kind, .. } = loc {
689                 if kind.is_some() {
690                     match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) {
691                         Vacant(spot) => spot.insert(res.next().unwrap()),
692                         Occupied(..) => {
693                             return Error(span, format!("duplicated bind name: {}", bind));
694                         }
695                     };
696                 } else {
697                     // E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used.
698                     // Both this check and the one in `parse_tt_inner` are necessary, surprisingly.
699                     return Error(span, "missing fragment specifier".to_string());
700                 }
701             }
702         }
703         Success(ret_val)
704     }
705 }