Skip to content

Commit 1bc2747

Browse files
committed
Allow concat in repetitions
1 parent 52f3c71 commit 1bc2747

File tree

4 files changed

+77
-42
lines changed

4 files changed

+77
-42
lines changed

compiler/rustc_expand/src/mbe/macro_check.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -352,10 +352,10 @@ fn check_occurrences(
352352
check_ops_is_prefix(psess, node_id, macros, binders, ops, span, name);
353353
}
354354
TokenTree::MetaVarExpr(dl, ref mve) => {
355-
let Some(name) = mve.ident().map(MacroRulesNormalizedIdent::new) else {
356-
return;
357-
};
358-
check_ops_is_prefix(psess, node_id, macros, binders, ops, dl.entire(), name);
355+
mve.metavars((), |_, ident| {
356+
let name = MacroRulesNormalizedIdent::new(*ident);
357+
check_ops_is_prefix(psess, node_id, macros, binders, ops, dl.entire(), name);
358+
});
359359
}
360360
TokenTree::Delimited(.., ref del) => {
361361
check_nested_occurrences(psess, node_id, &del.tts, macros, binders, ops, guar);

compiler/rustc_expand/src/mbe/metavar_expr.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,18 @@ impl MetaVarExpr {
111111
Ok(rslt)
112112
}
113113

114-
pub(crate) fn ident(&self) -> Option<Ident> {
115-
match *self {
116-
MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident),
117-
MetaVarExpr::Concat { .. } | MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None,
114+
pub(crate) fn metavars<A>(&self, mut aux: A, mut cb: impl FnMut(A, &Ident) -> A) -> A {
115+
match self {
116+
MetaVarExpr::Concat(elems) => {
117+
for elem in elems {
118+
if let MetaVarExprConcatElem::Var(ident) = elem {
119+
aux = cb(aux, ident)
120+
}
121+
}
122+
aux
123+
}
124+
MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => cb(aux, ident),
125+
MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => aux,
118126
}
119127
}
120128
}

compiler/rustc_expand/src/mbe/transcribe.rs

+43-34
Original file line numberDiff line numberDiff line change
@@ -557,17 +557,13 @@ fn lockstep_iter_size(
557557
}
558558
}
559559
TokenTree::MetaVarExpr(_, expr) => {
560-
let default_rslt = LockstepIterSize::Unconstrained;
561-
let Some(ident) = expr.ident() else {
562-
return default_rslt;
563-
};
564-
let name = MacroRulesNormalizedIdent::new(ident);
565-
match lookup_cur_matched(name, interpolations, repeats) {
566-
Some(MatchedSeq(ads)) => {
567-
default_rslt.with(LockstepIterSize::Constraint(ads.len(), name))
568-
}
569-
_ => default_rslt,
570-
}
560+
expr.metavars(LockstepIterSize::Unconstrained, |lis, ident| {
561+
lis.with(lockstep_iter_size(
562+
&TokenTree::MetaVar(ident.span, *ident),
563+
interpolations,
564+
repeats,
565+
))
566+
})
571567
}
572568
TokenTree::Token(..) => LockstepIterSize::Unconstrained,
573569
}
@@ -695,7 +691,22 @@ fn transcribe_metavar_expr<'a>(
695691
let symbol = match element {
696692
MetaVarExprConcatElem::Ident(elem) => elem.name,
697693
MetaVarExprConcatElem::Literal(elem) => *elem,
698-
MetaVarExprConcatElem::Var(elem) => extract_var_symbol(dcx, *elem, interp)?,
694+
MetaVarExprConcatElem::Var(ident) => {
695+
match matched_from_ident(dcx, *ident, interp)? {
696+
NamedMatch::MatchedSeq(named_matches) => {
697+
let curr_idx = repeats.last().unwrap().0;
698+
match &named_matches[curr_idx] {
699+
MatchedSeq(_) => unimplemented!(),
700+
MatchedSingle(pnr) => {
701+
extract_symbol_from_pnr(dcx, *ident, pnr)?
702+
}
703+
}
704+
}
705+
NamedMatch::MatchedSingle(pnr) => {
706+
extract_symbol_from_pnr(dcx, *ident, pnr)?
707+
}
708+
}
709+
}
699710
};
700711
concatenated.push_str(symbol.as_str());
701712
}
@@ -752,39 +763,37 @@ fn transcribe_metavar_expr<'a>(
752763
}
753764

754765
/// Extracts an metavariable symbol that can be an identifier, a token tree or a literal.
755-
fn extract_var_symbol<'a>(
766+
fn extract_symbol_from_pnr<'a>(
756767
dcx: DiagCtxtHandle<'a>,
757768
ident: Ident,
758-
interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
769+
pnr: &ParseNtResult,
759770
) -> PResult<'a, Symbol> {
760-
if let NamedMatch::MatchedSingle(pnr) = matched_from_ident(dcx, ident, interp)? {
761-
if let ParseNtResult::Ident(nt_ident, is_raw) = pnr {
762-
if let IdentIsRaw::Yes = is_raw {
763-
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
764-
}
765-
return Ok(nt_ident.name);
771+
if let ParseNtResult::Ident(nt_ident, is_raw) = pnr {
772+
if let IdentIsRaw::Yes = is_raw {
773+
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
766774
}
775+
return Ok(nt_ident.name);
776+
}
767777

768-
if let ParseNtResult::Tt(TokenTree::Token(Token { kind, .. }, _)) = pnr {
769-
if let TokenKind::Ident(symbol, is_raw) = kind {
770-
if let IdentIsRaw::Yes = is_raw {
771-
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
772-
}
773-
return Ok(*symbol);
774-
}
775-
776-
if let TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }) = kind {
777-
return Ok(*symbol);
778+
if let ParseNtResult::Tt(TokenTree::Token(Token { kind, .. }, _)) = pnr {
779+
if let TokenKind::Ident(symbol, is_raw) = kind {
780+
if let IdentIsRaw::Yes = is_raw {
781+
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
778782
}
783+
return Ok(*symbol);
779784
}
780785

781-
if let ParseNtResult::Nt(nt) = pnr
782-
&& let Nonterminal::NtLiteral(expr) = &**nt
783-
&& let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind
784-
{
786+
if let TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }) = kind {
785787
return Ok(*symbol);
786788
}
787789
}
790+
791+
if let ParseNtResult::Nt(nt) = pnr
792+
&& let Nonterminal::NtLiteral(expr) = &**nt
793+
&& let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind
794+
{
795+
return Ok(*symbol);
796+
}
788797
Err(dcx
789798
.struct_err("metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`")
790799
.with_note("currently only string literals are supported")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//@ run-pass
2+
3+
#![feature(macro_metavar_expr_concat)]
4+
5+
macro_rules! one_rep {
6+
( $($a:ident)* ) => {
7+
$(
8+
const ${concat($a, Z)}: i32 = 3;
9+
)*
10+
};
11+
}
12+
13+
fn main() {
14+
one_rep!(A B C);
15+
assert_eq!(AZ, 3);
16+
assert_eq!(BZ, 3);
17+
assert_eq!(CZ, 3);
18+
}

0 commit comments

Comments
 (0)