Streamline NamedMatch.

This commit combines `MatchedTokenTree` and `MatchedNonterminal`, which
are often considered together, into a single `MatchedSingle`. It shares
a representation with the newly-parameterized `ParseNtResult`.

This will also make things much simpler if/when variants from
`Interpolated` start being moved to `ParseNtResult`.
This commit is contained in:
Nicholas Nethercote 2024-03-19 13:33:33 +11:00
parent b7f3b714da
commit a94bb2a013
5 changed files with 42 additions and 31 deletions

View File

@ -392,12 +392,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum NamedMatch { pub(crate) enum NamedMatch {
MatchedSeq(Vec<NamedMatch>), MatchedSeq(Vec<NamedMatch>),
MatchedSingle(ParseNtResult<Lrc<(Nonterminal, Span)>>),
// A metavar match of type `tt`.
MatchedTokenTree(rustc_ast::tokenstream::TokenTree),
// A metavar match of any type other than `tt`.
MatchedNonterminal(Lrc<(Nonterminal, rustc_span::Span)>),
} }
/// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison) /// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
@ -691,11 +686,11 @@ impl TtParser {
} }
Ok(nt) => nt, Ok(nt) => nt,
}; };
let m = match nt { mp.push_match(
ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new((nt, span))), next_metavar,
ParseNtResult::Tt(tt) => MatchedTokenTree(tt), seq_depth,
}; MatchedSingle(nt.map_nt(|nt| (Lrc::new((nt, span))))),
mp.push_match(next_metavar, seq_depth, m); );
mp.idx += 1; mp.idx += 1;
} else { } else {
unreachable!() unreachable!()

View File

@ -5,7 +5,7 @@ use crate::mbe;
use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg}; use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
use crate::mbe::macro_check; use crate::mbe::macro_check;
use crate::mbe::macro_parser::{Error, ErrorReported, Failure, Success, TtParser}; use crate::mbe::macro_parser::{Error, ErrorReported, Failure, Success, TtParser};
use crate::mbe::macro_parser::{MatchedSeq, MatchedTokenTree, MatcherLoc}; use crate::mbe::macro_parser::{MatcherLoc, NamedMatch::*};
use crate::mbe::transcribe::transcribe; use crate::mbe::transcribe::transcribe;
use ast::token::IdentIsRaw; use ast::token::IdentIsRaw;
@ -22,7 +22,7 @@ use rustc_lint_defs::builtin::{
RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
}; };
use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::BuiltinLintDiag;
use rustc_parse::parser::{Parser, Recovery}; use rustc_parse::parser::{ParseNtResult, Parser, Recovery};
use rustc_session::parse::ParseSess; use rustc_session::parse::ParseSess;
use rustc_session::Session; use rustc_session::Session;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
@ -479,7 +479,7 @@ pub fn compile_declarative_macro(
MatchedSeq(s) => s MatchedSeq(s) => s
.iter() .iter()
.map(|m| { .map(|m| {
if let MatchedTokenTree(tt) = m { if let MatchedSingle(ParseNtResult::Tt(tt)) = m {
let tt = mbe::quoted::parse( let tt = mbe::quoted::parse(
&TokenStream::new(vec![tt.clone()]), &TokenStream::new(vec![tt.clone()]),
true, true,
@ -505,7 +505,7 @@ pub fn compile_declarative_macro(
MatchedSeq(s) => s MatchedSeq(s) => s
.iter() .iter()
.map(|m| { .map(|m| {
if let MatchedTokenTree(tt) = m { if let MatchedSingle(ParseNtResult::Tt(tt)) = m {
return mbe::quoted::parse( return mbe::quoted::parse(
&TokenStream::new(vec![tt.clone()]), &TokenStream::new(vec![tt.clone()]),
false, false,

View File

@ -3,14 +3,14 @@ use crate::errors::{
CountRepetitionMisplaced, MetaVarExprUnrecognizedVar, MetaVarsDifSeqMatchers, MustRepeatOnce, CountRepetitionMisplaced, MetaVarExprUnrecognizedVar, MetaVarsDifSeqMatchers, MustRepeatOnce,
NoSyntaxVarsExprRepeat, VarStillRepeating, NoSyntaxVarsExprRepeat, VarStillRepeating,
}; };
use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, MatchedTokenTree, NamedMatch}; use crate::mbe::macro_parser::{NamedMatch, NamedMatch::*};
use crate::mbe::{self, KleeneOp, MetaVarExpr}; use crate::mbe::{self, KleeneOp, MetaVarExpr};
use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Diag; use rustc_errors::{pluralize, Diag, PResult};
use rustc_errors::{pluralize, PResult}; use rustc_parse::parser::ParseNtResult;
use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::hygiene::{LocalExpnId, Transparency};
use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent}; use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
use rustc_span::{with_metavar_spans, Span, SyntaxContext}; use rustc_span::{with_metavar_spans, Span, SyntaxContext};
@ -251,12 +251,12 @@ pub(super) fn transcribe<'a>(
let ident = MacroRulesNormalizedIdent::new(original_ident); let ident = MacroRulesNormalizedIdent::new(original_ident);
if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
let tt = match cur_matched { let tt = match cur_matched {
MatchedTokenTree(tt) => { MatchedSingle(ParseNtResult::Tt(tt)) => {
// `tt`s are emitted into the output stream directly as "raw tokens", // `tt`s are emitted into the output stream directly as "raw tokens",
// without wrapping them into groups. // without wrapping them into groups.
maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker) maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker)
} }
MatchedNonterminal(nt) => { MatchedSingle(ParseNtResult::Nt(nt)) => {
// Other variables are emitted into the output stream as groups with // Other variables are emitted into the output stream as groups with
// `Delimiter::Invisible` to maintain parsing priorities. // `Delimiter::Invisible` to maintain parsing priorities.
// `Interpolated` is currently used for such groups in rustc parser. // `Interpolated` is currently used for such groups in rustc parser.
@ -423,7 +423,7 @@ fn lookup_cur_matched<'a>(
interpolations.get(&ident).map(|mut matched| { interpolations.get(&ident).map(|mut matched| {
for &(idx, _) in repeats { for &(idx, _) in repeats {
match matched { match matched {
MatchedTokenTree(_) | MatchedNonterminal(_) => break, MatchedSingle(_) => break,
MatchedSeq(ads) => matched = ads.get(idx).unwrap(), MatchedSeq(ads) => matched = ads.get(idx).unwrap(),
} }
} }
@ -513,7 +513,7 @@ fn lockstep_iter_size(
let name = MacroRulesNormalizedIdent::new(*name); let name = MacroRulesNormalizedIdent::new(*name);
match lookup_cur_matched(name, interpolations, repeats) { match lookup_cur_matched(name, interpolations, repeats) {
Some(matched) => match matched { Some(matched) => match matched {
MatchedTokenTree(_) | MatchedNonterminal(_) => LockstepIterSize::Unconstrained, MatchedSingle(_) => LockstepIterSize::Unconstrained,
MatchedSeq(ads) => LockstepIterSize::Constraint(ads.len(), name), MatchedSeq(ads) => LockstepIterSize::Constraint(ads.len(), name),
}, },
_ => LockstepIterSize::Unconstrained, _ => LockstepIterSize::Unconstrained,
@ -556,7 +556,7 @@ fn count_repetitions<'a>(
// (or at the top-level of `matched` if no depth is given). // (or at the top-level of `matched` if no depth is given).
fn count<'a>(depth_curr: usize, depth_max: usize, matched: &NamedMatch) -> PResult<'a, usize> { fn count<'a>(depth_curr: usize, depth_max: usize, matched: &NamedMatch) -> PResult<'a, usize> {
match matched { match matched {
MatchedTokenTree(_) | MatchedNonterminal(_) => Ok(1), MatchedSingle(_) => Ok(1),
MatchedSeq(named_matches) => { MatchedSeq(named_matches) => {
if depth_curr == depth_max { if depth_curr == depth_max {
Ok(named_matches.len()) Ok(named_matches.len())
@ -570,7 +570,7 @@ fn count_repetitions<'a>(
/// Maximum depth /// Maximum depth
fn depth(counter: usize, matched: &NamedMatch) -> usize { fn depth(counter: usize, matched: &NamedMatch) -> usize {
match matched { match matched {
MatchedTokenTree(_) | MatchedNonterminal(_) => counter, MatchedSingle(_) => counter,
MatchedSeq(named_matches) => { MatchedSeq(named_matches) => {
let rslt = counter + 1; let rslt = counter + 1;
if let Some(elem) = named_matches.first() { depth(rslt, elem) } else { rslt } if let Some(elem) = named_matches.first() { depth(rslt, elem) } else { rslt }
@ -598,7 +598,7 @@ fn count_repetitions<'a>(
} }
} }
if let MatchedTokenTree(_) | MatchedNonterminal(_) = matched { if let MatchedSingle(_) = matched {
return Err(cx.dcx().create_err(CountRepetitionMisplaced { span: sp.entire() })); return Err(cx.dcx().create_err(CountRepetitionMisplaced { span: sp.entire() }));
} }

View File

@ -20,7 +20,7 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
pub use path::PathStyle; pub use path::PathStyle;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind}; use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing}; use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor}; use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
use rustc_ast::util::case::Case; use rustc_ast::util::case::Case;
@ -1572,8 +1572,21 @@ pub enum FlatToken {
Empty, Empty,
} }
#[derive(Debug)] // Metavar captures of various kinds.
pub enum ParseNtResult { #[derive(Clone, Debug)]
Nt(Nonterminal), pub enum ParseNtResult<NtType> {
Tt(TokenTree), Tt(TokenTree),
Nt(NtType),
}
impl<T> ParseNtResult<T> {
pub fn map_nt<F, U>(self, mut f: F) -> ParseNtResult<U>
where
F: FnMut(T) -> U,
{
match self {
ParseNtResult::Tt(tt) => ParseNtResult::Tt(tt),
ParseNtResult::Nt(nt) => ParseNtResult::Nt(f(nt)),
}
}
} }

View File

@ -1,5 +1,5 @@
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token}; use rustc_ast::token::{self, Delimiter, Nonterminal, Nonterminal::*, NonterminalKind, Token};
use rustc_ast::HasTokens; use rustc_ast::HasTokens;
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_errors::PResult; use rustc_errors::PResult;
@ -100,7 +100,10 @@ impl<'a> Parser<'a> {
/// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call
/// site. /// site.
#[inline] #[inline]
pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseNtResult> { pub fn parse_nonterminal(
&mut self,
kind: NonterminalKind,
) -> PResult<'a, ParseNtResult<Nonterminal>> {
// A `macro_rules!` invocation may pass a captured item/expr to a proc-macro, // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
// which requires having captured tokens available. Since we cannot determine // which requires having captured tokens available. Since we cannot determine
// in advance whether or not a proc-macro will be (transitively) invoked, // in advance whether or not a proc-macro will be (transitively) invoked,