1use std::mem;
2
3use rustc_ast::token::{
4 self, Delimiter, IdentKind, InvisibleOrigin, Lit, LitKind, MetaVarKind, Token, TokenKind,
5};
6use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
7use rustc_ast::{ExprKind, StmtKind, TyKind, UnOp};
8use rustc_data_structures::fx::FxHashMap;
9use rustc_errors::{Diag, DiagCtxtHandle, PResult, listify, pluralize};
10use rustc_parse::lexer::nfc_normalize;
11use rustc_parse::parser::ParseNtResult;
12use rustc_session::parse::ParseSess;
13use rustc_span::hygiene::{LocalExpnId, Transparency};
14use rustc_span::{
15 BytePos, Ident, MacroRulesNormalizedIdent, Span, Symbol, SyntaxContext, kw, sym,
16 with_metavar_spans,
17};
18use smallvec::{SmallVec, smallvec};
19
20use crate::diagnostics::{
21 ConcatInvalidIdent, CountRepetitionMisplaced, InvalidIdentReason, MacroVarStillRepeating,
22 MetaVarsDifSeqMatchers, MustRepeatOnce, MveUnrecognizedVar, NoRepeatableVar,
23 NoSyntaxVarsExprRepeat, VarNoTypo, VarTypoSuggestionRepeatable, VarTypoSuggestionUnrepeatable,
24 VarTypoSuggestionUnrepeatableLabel,
25};
26use crate::mbe::macro_parser::NamedMatch;
27use crate::mbe::macro_parser::NamedMatch::*;
28use crate::mbe::metavar_expr::{MetaVarExprConcatElem, validate_ident_kind};
29use crate::mbe::{self, KleeneOp, MetaVarExpr};
30
31struct TranscrCtx<'psess, 'itp> {
33 psess: &'psess ParseSess,
34
35 interp: &'itp FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
37
38 marker: Marker,
40
41 stack: SmallVec<[Frame<'itp>; 1]>,
47
48 repeats: Vec<(usize, usize)>,
54
55 result: Vec<TokenTree>,
68
69 result_stack: Vec<Vec<TokenTree>>,
72}
73
74impl<'psess> TranscrCtx<'psess, '_> {
75 fn visited_dspan(&mut self, dspan: DelimSpan) -> Span {
77 let mut span = dspan.entire();
78 self.marker.mark_span(&mut span);
79 span
80 }
81}
82
83struct Marker {
85 expand_id: LocalExpnId,
86 transparency: Transparency,
87 cache: Option<(SyntaxContext, SyntaxContext)>,
90 fallback_cache: FxHashMap<SyntaxContext, SyntaxContext>,
91}
92
93impl Marker {
94 fn mark_span(&mut self, span: &mut Span) {
96 *span = span.map_ctxt(|ctxt| match self.cache {
101 Some((original, marked)) if original == ctxt => marked,
102 None => {
103 let marked = ctxt.apply_mark(self.expand_id.to_expn_id(), self.transparency);
104 self.cache = Some((ctxt, marked));
105 marked
106 }
107 _ => *self
108 .fallback_cache
109 .entry(ctxt)
110 .or_insert_with(|| ctxt.apply_mark(self.expand_id.to_expn_id(), self.transparency)),
111 });
112 }
113}
114
115struct Frame<'a> {
117 tts: &'a [mbe::TokenTree],
118 idx: usize,
119 kind: FrameKind,
120}
121
122enum FrameKind {
123 Delimited { delim: Delimiter, span: DelimSpan, spacing: DelimSpacing },
124 Sequence { sep: Option<Token>, kleene_op: KleeneOp },
125}
126
127impl<'a> Frame<'a> {
128 fn new_delimited(src: &'a mbe::Delimited, span: DelimSpan, spacing: DelimSpacing) -> Frame<'a> {
129 Frame {
130 tts: &src.tts,
131 idx: 0,
132 kind: FrameKind::Delimited { delim: src.delim, span, spacing },
133 }
134 }
135
136 fn new_sequence(
137 src: &'a mbe::SequenceRepetition,
138 sep: Option<Token>,
139 kleene_op: KleeneOp,
140 ) -> Frame<'a> {
141 Frame { tts: &src.tts, idx: 0, kind: FrameKind::Sequence { sep, kleene_op } }
142 }
143}
144
145impl<'a> Iterator for Frame<'a> {
146 type Item = &'a mbe::TokenTree;
147
148 fn next(&mut self) -> Option<&'a mbe::TokenTree> {
149 let res = self.tts.get(self.idx);
150 self.idx += 1;
151 res
152 }
153}
154
155pub(super) fn transcribe<'a>(
176 psess: &'a ParseSess,
177 interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
178 src: &mbe::Delimited,
179 src_span: DelimSpan,
180 transparency: Transparency,
181 expand_id: LocalExpnId,
182) -> PResult<'a, TokenStream> {
183 if src.tts.is_empty() {
185 return Ok(TokenStream::default());
186 }
187
188 let mut tscx = TranscrCtx {
189 psess,
190 interp,
191 marker: Marker { expand_id, transparency, cache: None, fallback_cache: Default::default() },
192 repeats: Vec::new(),
193 stack: {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push(Frame::new_delimited(src, src_span,
DelimSpacing::new(Spacing::Alone, Spacing::Alone)));
vec
} else {
::smallvec::SmallVec::from_vec(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[Frame::new_delimited(src, src_span,
DelimSpacing::new(Spacing::Alone, Spacing::Alone))])))
}
}smallvec![Frame::new_delimited(
194 src,
195 src_span,
196 DelimSpacing::new(Spacing::Alone, Spacing::Alone)
197 )],
198 result: Vec::new(),
199 result_stack: Vec::new(),
200 };
201
202 loop {
203 let Some(tree) = tscx.stack.last_mut().unwrap().next() else {
206 let frame = tscx.stack.last_mut().unwrap();
211 if let FrameKind::Sequence { sep, .. } = &frame.kind {
212 let (repeat_idx, repeat_len) = tscx.repeats.last_mut().unwrap();
213 *repeat_idx += 1;
214 if repeat_idx < repeat_len {
215 frame.idx = 0;
216 if let Some(sep) = sep {
217 tscx.result.push(TokenTree::Token(*sep, Spacing::Alone));
218 }
219 continue;
220 }
221 }
222
223 match tscx.stack.pop().unwrap().kind {
227 FrameKind::Sequence { .. } => {
229 tscx.repeats.pop();
230 }
231
232 FrameKind::Delimited { delim, span, mut spacing, .. } => {
236 if delim == Delimiter::Bracket {
239 spacing.close = Spacing::Alone;
240 }
241 if tscx.result_stack.is_empty() {
242 return Ok(TokenStream::new(tscx.result));
244 }
245
246 let tree =
248 TokenTree::Delimited(span, spacing, delim, TokenStream::new(tscx.result));
249 tscx.result = tscx.result_stack.pop().unwrap();
250 tscx.result.push(tree);
251 }
252 }
253 continue;
254 };
255
256 match tree {
259 seq @ mbe::TokenTree::Sequence(_, seq_rep) => {
261 transcribe_sequence(&mut tscx, seq, seq_rep, interp)?;
262 }
263
264 &mbe::TokenTree::MetaVar(sp, original_ident) => {
266 transcribe_metavar(&mut tscx, sp, original_ident)?;
267 }
268
269 mbe::TokenTree::MetaVarExpr(dspan, expr) => {
271 transcribe_metavar_expr(&mut tscx, *dspan, expr)?;
272 }
273
274 &mbe::TokenTree::Delimited(mut span, ref spacing, ref delimited) => {
280 tscx.marker.mark_span(&mut span.open);
281 tscx.marker.mark_span(&mut span.close);
282 tscx.stack.push(Frame::new_delimited(delimited, span, *spacing));
283 tscx.result_stack.push(mem::take(&mut tscx.result));
284 }
285
286 &mbe::TokenTree::Token(mut token) => {
289 tscx.marker.mark_span(&mut token.span);
290 if let token::NtIdent(ident, _) | token::NtLifetime(ident, _) = &mut token.kind {
291 tscx.marker.mark_span(&mut ident.span);
292 }
293 let tt = TokenTree::Token(token, Spacing::Alone);
294 tscx.result.push(tt);
295 }
296
297 mbe::TokenTree::MetaVarDecl { .. } => {
::core::panicking::panic_fmt(format_args!("unexpected `TokenTree::MetaVarDecl`"));
}panic!("unexpected `TokenTree::MetaVarDecl`"),
299 }
300 }
301}
302
303fn transcribe_sequence<'tx, 'itp>(
305 tscx: &mut TranscrCtx<'tx, 'itp>,
306 seq: &mbe::TokenTree,
307 seq_rep: &'itp mbe::SequenceRepetition,
308 interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
310) -> PResult<'tx, ()> {
311 let dcx = tscx.psess.dcx();
312
313 match lockstep_iter_size(seq, tscx.interp, &tscx.repeats) {
317 LockstepIterSize::Unconstrained => {
318 let mut repeatables = Vec::new();
319 let mut non_repeatables = Vec::new();
320
321 #[allow(rustc::potential_query_instability)]
322 for (name, matcher) in interp.iter() {
323 if matcher.is_repeatable() {
324 repeatables.push(name);
325 } else {
326 non_repeatables.push(name);
327 }
328 }
329
330 let repeatable_names: Vec<Symbol> =
331 repeatables.iter().map(|&name| name.symbol()).collect();
332 let non_repeatable_names: Vec<Symbol> =
333 non_repeatables.iter().map(|&name| name.symbol()).collect();
334 let mut meta_vars = ::alloc::vec::Vec::new()vec![];
335 seq.meta_vars(&mut meta_vars);
336 let mut typo_repeatable = None;
337 let mut typo_unrepeatable = None;
338 let mut typo_unrepeatable_label = None;
339 let mut var_no_typo = None;
340 let mut no_repeatable_var = None;
341
342 for ident in meta_vars {
343 if let Some(name) = rustc_span::edit_distance::find_best_match_for_name(
344 &repeatable_names[..],
345 ident.name,
346 None,
347 ) {
348 typo_repeatable = Some(VarTypoSuggestionRepeatable { span: ident.span, name });
349 } else if let Some(name) = rustc_span::edit_distance::find_best_match_for_name(
350 &non_repeatable_names[..],
351 ident.name,
352 None,
353 ) {
354 typo_unrepeatable = Some(VarTypoSuggestionUnrepeatable { span: ident.span });
355 if let Some(&orig_ident) = non_repeatables.iter().find(|n| n.symbol() == name) {
356 typo_unrepeatable_label = Some(VarTypoSuggestionUnrepeatableLabel {
357 span: orig_ident.ident().span,
358 });
359 }
360 } else {
361 if !repeatable_names.is_empty()
362 && let Some(msg) = listify(&repeatable_names, |s| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`${0}`", s))
})format!("`${s}`"))
363 {
364 var_no_typo = Some(VarNoTypo { span: ident.span, msg });
365 } else {
366 no_repeatable_var = Some(NoRepeatableVar { span: ident.span });
367 }
368 }
369 }
370 return Err(dcx.create_err(NoSyntaxVarsExprRepeat {
371 span: seq.span(),
372 typo_unrepeatable,
373 typo_repeatable,
374 typo_unrepeatable_label,
375 var_no_typo,
376 no_repeatable_var,
377 }));
378 }
379
380 LockstepIterSize::Contradiction(msg) => {
381 return Err(dcx.create_err(MetaVarsDifSeqMatchers { span: seq.span(), msg }));
386 }
387
388 LockstepIterSize::Constraint(len, _) => {
389 let mbe::TokenTree::Sequence(sp, seq) = seq else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
392
393 if len == 0 {
395 if seq.kleene.op == KleeneOp::OneOrMore {
396 return Err(dcx.create_err(MustRepeatOnce { span: sp.entire() }));
400 }
401 } else {
402 tscx.repeats.push((0, len));
405
406 tscx.stack.push(Frame::new_sequence(seq_rep, seq.separator, seq.kleene.op));
410 }
411 }
412 }
413
414 Ok(())
415}
416
417fn transcribe_metavar<'tx>(
434 tscx: &mut TranscrCtx<'tx, '_>,
435 mut sp: Span,
436 mut original_ident: Ident,
437) -> PResult<'tx, ()> {
438 let dcx = tscx.psess.dcx();
439
440 let ident = MacroRulesNormalizedIdent::new(original_ident);
441 let Some(cur_matched) = lookup_cur_matched(ident, tscx.interp, &tscx.repeats) else {
442 tscx.marker.mark_span(&mut sp);
445 tscx.marker.mark_span(&mut original_ident.span);
446 tscx.result.push(TokenTree::token_joint_hidden(token::Dollar, sp));
447 tscx.result.push(TokenTree::Token(Token::from_ast_ident(original_ident), Spacing::Alone));
448 return Ok(());
449 };
450
451 let MatchedSingle(pnr) = cur_matched else {
452 return Err(dcx.create_err(MacroVarStillRepeating { span: sp, ident }));
454 };
455
456 transcribe_pnr(tscx, sp, pnr)
457}
458
459fn transcribe_pnr<'tx>(
460 tscx: &mut TranscrCtx<'tx, '_>,
461 mut sp: Span,
462 pnr: &ParseNtResult,
463) -> PResult<'tx, ()> {
464 let mut mk_delimited = |mk_span, mv_kind, mut stream: TokenStream| {
469 if stream.len() == 1 {
470 let tree = stream.iter().next().unwrap();
471 if let TokenTree::Delimited(_, _, delim, inner) = tree
472 && let Delimiter::Invisible(InvisibleOrigin::MetaVar(mvk)) = delim
473 && mv_kind == *mvk
474 {
475 stream = inner.clone();
476 }
477 }
478
479 tscx.marker.mark_span(&mut sp);
482 with_metavar_spans(|mspans| mspans.insert(mk_span, sp));
483 TokenTree::Delimited(
486 DelimSpan::from_single(sp),
487 DelimSpacing::new(Spacing::Alone, Spacing::Alone),
488 Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)),
489 stream,
490 )
491 };
492
493 let tt = match pnr {
494 ParseNtResult::Tt(tt) => {
495 maybe_use_metavar_location(tscx.psess, &tscx.stack, sp, tt, &mut tscx.marker)
500 }
501 ParseNtResult::Ident(ident, kind) => {
502 tscx.marker.mark_span(&mut sp);
503 with_metavar_spans(|mspans| mspans.insert(ident.span, sp));
504 let kind = token::NtIdent(*ident, *kind);
505 TokenTree::token_alone(kind, sp)
506 }
507 ParseNtResult::Lifetime(ident, is_raw) => {
508 tscx.marker.mark_span(&mut sp);
509 with_metavar_spans(|mspans| mspans.insert(ident.span, sp));
510 let kind = token::NtLifetime(*ident, *is_raw);
511 TokenTree::token_alone(kind, sp)
512 }
513 ParseNtResult::Item(item) => {
514 mk_delimited(item.span, MetaVarKind::Item, TokenStream::from_ast(item))
515 }
516 ParseNtResult::Block(block) => {
517 mk_delimited(block.node.span, MetaVarKind::Block, TokenStream::from_ast(block))
518 }
519 ParseNtResult::Stmt(stmt) => {
520 let stream = if let StmtKind::Empty = stmt.kind {
521 TokenStream::token_alone(token::Semi, stmt.span)
523 } else {
524 TokenStream::from_ast(stmt)
525 };
526 mk_delimited(stmt.span, MetaVarKind::Stmt, stream)
527 }
528 ParseNtResult::Pat(pat, pat_kind) => {
529 mk_delimited(pat.node.span, MetaVarKind::Pat(*pat_kind), TokenStream::from_ast(pat))
530 }
531 ParseNtResult::Expr(expr, kind) => {
532 let (can_begin_literal_maybe_minus, can_begin_string_literal) = match &expr.kind {
533 ExprKind::Lit(_) => (true, true),
534 ExprKind::Unary(UnOp::Neg, e) if #[allow(non_exhaustive_omitted_patterns)] match &e.kind {
ExprKind::Lit(_) => true,
_ => false,
}matches!(&e.kind, ExprKind::Lit(_)) => {
535 (true, false)
536 }
537 _ => (false, false),
538 };
539 mk_delimited(
540 expr.span,
541 MetaVarKind::Expr {
542 kind: *kind,
543 can_begin_literal_maybe_minus,
544 can_begin_string_literal,
545 },
546 TokenStream::from_ast(expr),
547 )
548 }
549 ParseNtResult::Literal(lit) => {
550 mk_delimited(lit.span, MetaVarKind::Literal, TokenStream::from_ast(lit))
551 }
552 ParseNtResult::Ty(ty) => {
553 let is_path = #[allow(non_exhaustive_omitted_patterns)] match &ty.node.kind {
TyKind::Path(None, _path) => true,
_ => false,
}matches!(&ty.node.kind, TyKind::Path(None, _path));
554 mk_delimited(ty.node.span, MetaVarKind::Ty { is_path }, TokenStream::from_ast(ty))
555 }
556 ParseNtResult::Meta(attr_item) => {
557 let has_meta_form = attr_item.node.meta_kind().is_some();
558 mk_delimited(
559 attr_item.node.span,
560 MetaVarKind::Meta { has_meta_form },
561 TokenStream::from_ast(attr_item),
562 )
563 }
564 ParseNtResult::Path(path) => {
565 mk_delimited(path.node.span, MetaVarKind::Path, TokenStream::from_ast(path))
566 }
567 ParseNtResult::Vis(vis) => {
568 mk_delimited(vis.node.span, MetaVarKind::Vis, TokenStream::from_ast(vis))
569 }
570 ParseNtResult::Guard(guard) => {
571 let leading_if_span =
576 guard.span_with_leading_if.with_hi(guard.span_with_leading_if.lo() + BytePos(2));
577 let ts = std::iter::once(TokenTree::token_alone(
578 token::Ident(kw::If, IdentKind::Normal),
579 leading_if_span,
580 ))
581 .chain(TokenStream::from_ast(&guard.cond).iter().cloned())
582 .collect();
583
584 mk_delimited(guard.span_with_leading_if, MetaVarKind::Guard, ts)
585 }
586 };
587
588 tscx.result.push(tt);
589 Ok(())
590}
591
592fn transcribe_metavar_expr<'tx>(
594 tscx: &mut TranscrCtx<'tx, '_>,
595 dspan: DelimSpan,
596 expr: &MetaVarExpr,
597) -> PResult<'tx, ()> {
598 let dcx = tscx.psess.dcx();
599 let tt = match *expr {
600 MetaVarExpr::ConcatIdent(ref elements) => metavar_expr_concat_ident(tscx, dspan, elements)?,
601 MetaVarExpr::ConcatStr(ref elements) => metavar_expr_concat_str(tscx, dspan, elements)?,
602 MetaVarExpr::Count(original_ident, depth) => {
603 let matched = matched_from_ident(dcx, original_ident, tscx.interp)?;
604 let count = count_repetitions(dcx, depth, matched, &tscx.repeats, &dspan)?;
605 TokenTree::token_alone(
606 TokenKind::lit(token::Integer, sym::integer(count), None),
607 tscx.visited_dspan(dspan),
608 )
609 }
610 MetaVarExpr::Ignore(original_ident) => {
611 let _ = matched_from_ident(dcx, original_ident, tscx.interp)?;
613 return Ok(());
614 }
615 MetaVarExpr::Index(depth) => match tscx.repeats.iter().nth_back(depth) {
616 Some((index, _)) => TokenTree::token_alone(
617 TokenKind::lit(token::Integer, sym::integer(*index), None),
618 tscx.visited_dspan(dspan),
619 ),
620 None => {
621 return Err(out_of_bounds_err(dcx, tscx.repeats.len(), dspan.entire(), "index"));
622 }
623 },
624 MetaVarExpr::Len(depth) => match tscx.repeats.iter().nth_back(depth) {
625 Some((_, length)) => TokenTree::token_alone(
626 TokenKind::lit(token::Integer, sym::integer(*length), None),
627 tscx.visited_dspan(dspan),
628 ),
629 None => {
630 return Err(out_of_bounds_err(dcx, tscx.repeats.len(), dspan.entire(), "len"));
631 }
632 },
633 };
634 tscx.result.push(tt);
635 Ok(())
636}
637
638fn metavar_expr_concat_ident<'tx>(
640 tscx: &mut TranscrCtx<'tx, '_>,
641 dspan: DelimSpan,
642 elements: &[MetaVarExprConcatElem],
643) -> PResult<'tx, TokenTree> {
644 let (symbol, concatenated_span) = metavar_expr_concat(tscx, dspan, elements)?;
645 if !rustc_lexer::is_ident(symbol.as_str()) {
646 return Err(tscx.psess.dcx().create_err(ConcatInvalidIdent {
647 span: concatenated_span,
648 reason: InvalidIdentReason::new(symbol),
649 }));
650 }
651 tscx.psess.symbol_gallery.insert(symbol, concatenated_span);
652
653 Ok(TokenTree::Token(
657 Token::from_ast_ident(Ident::new(symbol, concatenated_span)),
658 Spacing::Alone,
659 ))
660}
661
662fn metavar_expr_concat_str<'tx>(
664 tscx: &mut TranscrCtx<'tx, '_>,
665 dspan: DelimSpan,
666 elements: &[MetaVarExprConcatElem],
667) -> PResult<'tx, TokenTree> {
668 let (symbol, concatenated_span) = metavar_expr_concat(tscx, dspan, elements)?;
669
670 Ok(TokenTree::Token(
674 Token::new(TokenKind::lit(LitKind::Str, symbol, None), concatenated_span),
675 Spacing::Alone,
676 ))
677}
678
679fn metavar_expr_concat<'tx>(
681 tscx: &mut TranscrCtx<'tx, '_>,
682 dspan: DelimSpan,
683 elements: &[MetaVarExprConcatElem],
684) -> PResult<'tx, (Symbol, Span)> {
685 let dcx = tscx.psess.dcx();
686 let mut concatenated = String::new();
687 for element in elements {
688 let symbol = match element {
689 MetaVarExprConcatElem::Ident(elem) => elem.name,
690 MetaVarExprConcatElem::Literal(elem) => *elem,
691 MetaVarExprConcatElem::Var(ident) => {
692 let key = MacroRulesNormalizedIdent::new(*ident);
693 match lookup_cur_matched(key, tscx.interp, &tscx.repeats) {
694 Some(NamedMatch::MatchedSingle(pnr)) => {
695 extract_symbol_from_pnr(dcx, pnr, ident.span)?
696 }
697 Some(NamedMatch::MatchedSeq(..)) => {
698 return Err(dcx.struct_span_err(
699 ident.span,
700 "`${concat(...)}` variable is still repeating at this depth",
701 ));
702 }
703 None => {
704 return Err(dcx.create_err(MveUnrecognizedVar { span: ident.span, key }));
705 }
706 }
707 }
708 };
709 concatenated.push_str(symbol.as_str());
710 }
711 let symbol = nfc_normalize(&concatenated);
712 let concatenated_span = tscx.visited_dspan(dspan);
713 Ok((symbol, concatenated_span))
714}
715
716fn maybe_use_metavar_location(
747 psess: &ParseSess,
748 stack: &[Frame<'_>],
749 mut metavar_span: Span,
750 orig_tt: &TokenTree,
751 marker: &mut Marker,
752) -> TokenTree {
753 let undelimited_seq = #[allow(non_exhaustive_omitted_patterns)] match stack.last() {
Some(Frame {
tts: [_],
kind: FrameKind::Sequence {
sep: None, kleene_op: KleeneOp::ZeroOrMore | KleeneOp::OneOrMore,
..
}, .. }) => true,
_ => false,
}matches!(
754 stack.last(),
755 Some(Frame {
756 tts: [_],
757 kind: FrameKind::Sequence {
758 sep: None,
759 kleene_op: KleeneOp::ZeroOrMore | KleeneOp::OneOrMore,
760 ..
761 },
762 ..
763 })
764 );
765 if undelimited_seq {
766 return orig_tt.clone();
768 }
769
770 marker.mark_span(&mut metavar_span);
771 let no_collision = match orig_tt {
772 TokenTree::Token(token, ..) => {
773 with_metavar_spans(|mspans| mspans.insert(token.span, metavar_span))
774 }
775 TokenTree::Delimited(dspan, ..) => with_metavar_spans(|mspans| {
776 mspans.insert(dspan.open, metavar_span)
777 && mspans.insert(dspan.close, metavar_span)
778 && mspans.insert(dspan.entire(), metavar_span)
779 }),
780 };
781 if no_collision || psess.source_map().is_imported(metavar_span) {
782 return orig_tt.clone();
783 }
784
785 match orig_tt {
788 TokenTree::Token(Token { kind, span }, spacing) => {
789 let span = metavar_span.with_ctxt(span.ctxt());
790 with_metavar_spans(|mspans| mspans.insert(span, metavar_span));
791 TokenTree::Token(Token { kind: *kind, span }, *spacing)
792 }
793 TokenTree::Delimited(dspan, dspacing, delimiter, tts) => {
794 let open = metavar_span.with_ctxt(dspan.open.ctxt());
795 let close = metavar_span.with_ctxt(dspan.close.ctxt());
796 with_metavar_spans(|mspans| {
797 mspans.insert(open, metavar_span) && mspans.insert(close, metavar_span)
798 });
799 let dspan = DelimSpan::from_pair(open, close);
800 TokenTree::Delimited(dspan, *dspacing, *delimiter, tts.clone())
801 }
802 }
803}
804
805fn lookup_cur_matched<'a>(
812 ident: MacroRulesNormalizedIdent,
813 interpolations: &'a FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
814 repeats: &[(usize, usize)],
815) -> Option<&'a NamedMatch> {
816 interpolations.get(&ident).map(|mut matched| {
817 for &(idx, _) in repeats {
818 match matched {
819 MatchedSingle(_) => break,
820 MatchedSeq(ads) => matched = ads.get(idx).unwrap(),
821 }
822 }
823
824 matched
825 })
826}
827
828#[derive(#[automatically_derived]
impl ::core::clone::Clone for LockstepIterSize {
#[inline]
fn clone(&self) -> Self {
match self {
Self::Unconstrained => Self::Unconstrained,
Self::Constraint(__self_0, __self_1) =>
Self::Constraint(::core::clone::Clone::clone(__self_0),
::core::clone::Clone::clone(__self_1)),
Self::Contradiction(__self_0) =>
Self::Contradiction(::core::clone::Clone::clone(__self_0)),
}
}
}Clone)]
833enum LockstepIterSize {
834 Unconstrained,
837
838 Constraint(usize, MacroRulesNormalizedIdent),
841
842 Contradiction(String),
844}
845
846impl LockstepIterSize {
847 fn with(self, other: LockstepIterSize) -> LockstepIterSize {
852 match self {
853 LockstepIterSize::Unconstrained => other,
854 LockstepIterSize::Contradiction(_) => self,
855 LockstepIterSize::Constraint(l_len, l_id) => match other {
856 LockstepIterSize::Unconstrained => self,
857 LockstepIterSize::Contradiction(_) => other,
858 LockstepIterSize::Constraint(r_len, _) if l_len == r_len => self,
859 LockstepIterSize::Constraint(r_len, r_id) => {
860 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("meta-variable `{0}` repeats {1} time{2}, but `{3}` repeats {4} time{5}",
l_id, l_len, if l_len == 1 { "" } else { "s" }, r_id, r_len,
if r_len == 1 { "" } else { "s" }))
})format!(
861 "meta-variable `{}` repeats {} time{}, but `{}` repeats {} time{}",
862 l_id,
863 l_len,
864 pluralize!(l_len),
865 r_id,
866 r_len,
867 pluralize!(r_len),
868 );
869 LockstepIterSize::Contradiction(msg)
870 }
871 },
872 }
873 }
874}
875
876fn lockstep_iter_size(
889 tree: &mbe::TokenTree,
890 interpolations: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
891 repeats: &[(usize, usize)],
892) -> LockstepIterSize {
893 use mbe::TokenTree;
894 match tree {
895 TokenTree::Delimited(.., delimited) => {
896 delimited.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
897 size.with(lockstep_iter_size(tt, interpolations, repeats))
898 })
899 }
900 TokenTree::Sequence(_, seq) => {
901 seq.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
902 size.with(lockstep_iter_size(tt, interpolations, repeats))
903 })
904 }
905 TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl { name, .. } => {
906 let name = MacroRulesNormalizedIdent::new(*name);
907 match lookup_cur_matched(name, interpolations, repeats) {
908 Some(matched) => match matched {
909 MatchedSingle(_) => LockstepIterSize::Unconstrained,
910 MatchedSeq(ads) => LockstepIterSize::Constraint(ads.len(), name),
911 },
912 _ => LockstepIterSize::Unconstrained,
913 }
914 }
915 TokenTree::MetaVarExpr(_, expr) => {
916 expr.for_each_metavar(LockstepIterSize::Unconstrained, |lis, ident| {
917 lis.with(lockstep_iter_size(
918 &TokenTree::MetaVar(ident.span, *ident),
919 interpolations,
920 repeats,
921 ))
922 })
923 }
924 TokenTree::Token(..) => LockstepIterSize::Unconstrained,
925 }
926}
927
928fn count_repetitions<'dx>(
938 dcx: DiagCtxtHandle<'dx>,
939 depth_user: usize,
940 mut matched: &NamedMatch,
941 repeats: &[(usize, usize)],
942 sp: &DelimSpan,
943) -> PResult<'dx, usize> {
944 fn count<'a>(depth_curr: usize, depth_max: usize, matched: &NamedMatch) -> PResult<'a, usize> {
947 match matched {
948 MatchedSingle(_) => Ok(1),
949 MatchedSeq(named_matches) => {
950 if depth_curr == depth_max {
951 Ok(named_matches.len())
952 } else {
953 named_matches.iter().map(|elem| count(depth_curr + 1, depth_max, elem)).sum()
954 }
955 }
956 }
957 }
958
959 fn depth(counter: usize, matched: &NamedMatch) -> usize {
961 match matched {
962 MatchedSingle(_) => counter,
963 MatchedSeq(named_matches) => {
964 let rslt = counter + 1;
965 if let Some(elem) = named_matches.first() { depth(rslt, elem) } else { rslt }
966 }
967 }
968 }
969
970 let depth_max = depth(0, matched)
971 .checked_sub(1)
972 .and_then(|el| el.checked_sub(repeats.len()))
973 .unwrap_or_default();
974 if depth_user > depth_max {
975 return Err(out_of_bounds_err(dcx, depth_max + 1, sp.entire(), "count"));
976 }
977
978 for &(idx, _) in repeats {
985 if let MatchedSeq(ads) = matched {
986 matched = &ads[idx];
987 }
988 }
989
990 if let MatchedSingle(_) = matched {
991 return Err(dcx.create_err(CountRepetitionMisplaced { span: sp.entire() }));
992 }
993
994 count(depth_user, depth_max, matched)
995}
996
997fn matched_from_ident<'ctx, 'interp, 'rslt>(
999 dcx: DiagCtxtHandle<'ctx>,
1000 ident: Ident,
1001 interp: &'interp FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
1002) -> PResult<'ctx, &'rslt NamedMatch>
1003where
1004 'interp: 'rslt,
1005{
1006 let span = ident.span;
1007 let key = MacroRulesNormalizedIdent::new(ident);
1008 interp.get(&key).ok_or_else(|| dcx.create_err(MveUnrecognizedVar { span, key }))
1009}
1010
1011fn out_of_bounds_err<'a>(dcx: DiagCtxtHandle<'a>, max: usize, span: Span, ty: &str) -> Diag<'a> {
1014 let msg = if max == 0 {
1015 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("meta-variable expression `{0}` with depth parameter must be called inside of a macro repetition",
ty))
})format!(
1016 "meta-variable expression `{ty}` with depth parameter \
1017 must be called inside of a macro repetition"
1018 )
1019 } else {
1020 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("depth parameter of meta-variable expression `{0}` must be less than {1}",
ty, max))
})format!(
1021 "depth parameter of meta-variable expression `{ty}` \
1022 must be less than {max}"
1023 )
1024 };
1025 dcx.struct_span_err(span, msg)
1026}
1027
1028fn extract_symbol_from_pnr<'a>(
1030 dcx: DiagCtxtHandle<'a>,
1031 pnr: &ParseNtResult,
1032 span_err: Span,
1033) -> PResult<'a, Symbol> {
1034 match pnr {
1035 ParseNtResult::Ident(nt_ident, kind) => {
1036 validate_ident_kind(dcx, *kind, span_err)?;
1037 Ok(nt_ident.name)
1038 }
1039 ParseNtResult::Tt(TokenTree::Token(
1040 Token { kind: TokenKind::Ident(symbol, kind), .. },
1041 _,
1042 )) => {
1043 validate_ident_kind(dcx, *kind, span_err)?;
1044 Ok(*symbol)
1045 }
1046 ParseNtResult::Tt(TokenTree::Token(
1047 Token {
1048 kind: TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }),
1049 ..
1050 },
1051 _,
1052 )) => Ok(*symbol),
1053 ParseNtResult::Literal(expr)
1054 if let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind =>
1055 {
1056 Ok(*symbol)
1057 }
1058 ParseNtResult::Literal(expr)
1059 if let ExprKind::Lit(lit @ Lit { kind: LitKind::Integer, symbol, suffix }) =
1060 &expr.kind =>
1061 {
1062 if lit.is_semantic_float() {
1063 Err(dcx
1064 .struct_err("floats are not supported as metavariables of `${concat(..)}`")
1065 .with_span(span_err))
1066 } else if suffix.is_none() {
1067 Ok(*symbol)
1068 } else {
1069 Err(dcx
1070 .struct_err("integer metavariables of `${concat(..)}` must not be suffixed")
1071 .with_span(span_err))
1072 }
1073 }
1074 _ => Err(dcx
1075 .struct_err(
1076 "metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`",
1077 )
1078 .with_note("currently only string and integer literals are supported")
1079 .with_span(span_err)),
1080 }
1081}