Skip to content

Commit afe238f

Browse files
committed
Introduce InvisibleOrigin on invisible delimiters.
It's not used meaningfully yet, but will be needed to get rid of interpolated tokens.
1 parent a1f2999 commit afe238f

File tree

10 files changed

+133
-31
lines changed

10 files changed

+133
-31
lines changed

compiler/rustc_ast/src/attr/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ impl MetaItemKind {
457457
tokens: &mut impl Iterator<Item = &'a TokenTree>,
458458
) -> Option<MetaItemKind> {
459459
match tokens.next() {
460-
Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => {
460+
Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
461461
MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees())
462462
}
463463
Some(TokenTree::Token(token, _)) => {
@@ -605,7 +605,7 @@ impl MetaItemInner {
605605
tokens.next();
606606
return Some(MetaItemInner::Lit(lit));
607607
}
608-
Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => {
608+
Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
609609
tokens.next();
610610
return MetaItemInner::from_tokens(&mut inner_tokens.trees().peekable());
611611
}

compiler/rustc_ast/src/token.rs

+108-6
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,86 @@ pub enum BinOpToken {
4242
Shr,
4343
}
4444

45+
// This type must not implement `Hash` due to the unusual `PartialEq` impl below.
46+
#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)]
47+
pub enum InvisibleOrigin {
48+
// From the expansion of a metavariable in a declarative macro.
49+
MetaVar(MetaVarKind),
50+
51+
// Converted from `proc_macro::Delimiter` in
52+
// `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro.
53+
ProcMacro,
54+
55+
// Converted from `TokenKind::Interpolated` in
56+
// `TokenStream::flatten_token`. Treated similarly to `ProcMacro`.
57+
FlattenToken,
58+
}
59+
60+
impl PartialEq for InvisibleOrigin {
61+
#[inline]
62+
fn eq(&self, _other: &InvisibleOrigin) -> bool {
63+
// When we had AST-based nonterminals we couldn't compare them, and the
64+
// old `Nonterminal` type had an `eq` that always returned false,
65+
// resulting in this restriction:
66+
// https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment
67+
// This `eq` emulates that behaviour. We could consider lifting this
68+
// restriction now but there are still cases involving invisible
69+
// delimiters that make it harder than it first appears.
70+
false
71+
}
72+
}
73+
74+
/// Annoyingly similar to `NonterminalKind`, but the slight differences are important.
75+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
76+
pub enum MetaVarKind {
77+
Item,
78+
Block,
79+
Stmt,
80+
Pat(NtPatKind),
81+
Expr {
82+
kind: NtExprKind,
83+
// This field is needed for `Token::can_begin_literal_maybe_minus`.
84+
can_begin_literal_maybe_minus: bool,
85+
// This field is needed for `Token::can_begin_string_literal`.
86+
can_begin_string_literal: bool,
87+
},
88+
Ty,
89+
Ident,
90+
Lifetime,
91+
Literal,
92+
Meta,
93+
Path,
94+
Vis,
95+
TT,
96+
}
97+
98+
impl fmt::Display for MetaVarKind {
99+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100+
let sym = match self {
101+
MetaVarKind::Item => sym::item,
102+
MetaVarKind::Block => sym::block,
103+
MetaVarKind::Stmt => sym::stmt,
104+
MetaVarKind::Pat(PatParam { inferred: true } | PatWithOr) => sym::pat,
105+
MetaVarKind::Pat(PatParam { inferred: false }) => sym::pat_param,
106+
MetaVarKind::Expr { kind: Expr2021 { inferred: true } | Expr, .. } => sym::expr,
107+
MetaVarKind::Expr { kind: Expr2021 { inferred: false }, .. } => sym::expr_2021,
108+
MetaVarKind::Ty => sym::ty,
109+
MetaVarKind::Ident => sym::ident,
110+
MetaVarKind::Lifetime => sym::lifetime,
111+
MetaVarKind::Literal => sym::literal,
112+
MetaVarKind::Meta => sym::meta,
113+
MetaVarKind::Path => sym::path,
114+
MetaVarKind::Vis => sym::vis,
115+
MetaVarKind::TT => sym::tt,
116+
};
117+
write!(f, "{sym}")
118+
}
119+
}
120+
45121
/// Describes how a sequence of token trees is delimited.
46122
/// Cannot use `proc_macro::Delimiter` directly because this
47123
/// structure should implement some additional traits.
48-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
49-
#[derive(Encodable, Decodable, Hash, HashStable_Generic)]
124+
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
50125
pub enum Delimiter {
51126
/// `( ... )`
52127
Parenthesis,
@@ -59,7 +134,34 @@ pub enum Delimiter {
59134
/// "macro variable" `$var`. It is important to preserve operator priorities in cases like
60135
/// `$var * 3` where `$var` is `1 + 2`.
61136
/// Invisible delimiters might not survive roundtrip of a token stream through a string.
62-
Invisible,
137+
Invisible(InvisibleOrigin),
138+
}
139+
140+
impl Delimiter {
141+
// Should the parser skip these delimiters? Only happens for certain kinds
142+
// of invisible delimiters. Ideally this function will eventually disappear
143+
// and no invisible delimiters will be skipped.
144+
#[inline]
145+
pub fn skip(&self) -> bool {
146+
match self {
147+
Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false,
148+
Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false,
149+
Delimiter::Invisible(InvisibleOrigin::FlattenToken | InvisibleOrigin::ProcMacro) => {
150+
true
151+
}
152+
}
153+
}
154+
155+
// This exists because `InvisibleOrigin`s should be compared. It is only used for assertions.
156+
pub fn eq_ignoring_invisible_origin(&self, other: &Delimiter) -> bool {
157+
match (self, other) {
158+
(Delimiter::Parenthesis, Delimiter::Parenthesis) => true,
159+
(Delimiter::Brace, Delimiter::Brace) => true,
160+
(Delimiter::Bracket, Delimiter::Bracket) => true,
161+
(Delimiter::Invisible(_), Delimiter::Invisible(_)) => true,
162+
_ => false,
163+
}
164+
}
63165
}
64166

65167
// Note that the suffix is *not* considered when deciding the `LitKind` in this
@@ -896,7 +998,7 @@ impl PartialEq<TokenKind> for Token {
896998
}
897999
}
8981000

899-
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
1001+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
9001002
pub enum NtPatKind {
9011003
// Matches or-patterns. Was written using `pat` in edition 2021 or later.
9021004
PatWithOr,
@@ -906,7 +1008,7 @@ pub enum NtPatKind {
9061008
PatParam { inferred: bool },
9071009
}
9081010

909-
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
1011+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
9101012
pub enum NtExprKind {
9111013
// Matches expressions using the post-edition 2024. Was written using
9121014
// `expr` in edition 2024 or later.
@@ -933,7 +1035,7 @@ pub enum Nonterminal {
9331035
NtVis(P<ast::Visibility>),
9341036
}
9351037

936-
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
1038+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
9371039
pub enum NonterminalKind {
9381040
Item,
9391041
Block,

compiler/rustc_ast/src/tokenstream.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym};
2424

2525
use crate::ast::{AttrStyle, StmtKind};
2626
use crate::ast_traits::{HasAttrs, HasTokens};
27-
use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind};
27+
use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind};
2828
use crate::{AttrVec, Attribute};
2929

3030
/// Part of a `TokenStream`.
@@ -484,13 +484,13 @@ impl TokenStream {
484484
token::NtLifetime(ident, is_raw) => TokenTree::Delimited(
485485
DelimSpan::from_single(token.span),
486486
DelimSpacing::new(Spacing::JointHidden, spacing),
487-
Delimiter::Invisible,
487+
Delimiter::Invisible(InvisibleOrigin::FlattenToken),
488488
TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span),
489489
),
490490
token::Interpolated(ref nt) => TokenTree::Delimited(
491491
DelimSpan::from_single(token.span),
492492
DelimSpacing::new(Spacing::JointHidden, spacing),
493-
Delimiter::Invisible,
493+
Delimiter::Invisible(InvisibleOrigin::FlattenToken),
494494
TokenStream::from_nonterminal_ast(&nt).flattened(),
495495
),
496496
_ => TokenTree::Token(token.clone(), spacing),

compiler/rustc_ast_pretty/src/pprust/state.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -942,9 +942,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
942942
token::CloseDelim(Delimiter::Bracket) => "]".into(),
943943
token::OpenDelim(Delimiter::Brace) => "{".into(),
944944
token::CloseDelim(Delimiter::Brace) => "}".into(),
945-
token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => {
946-
"".into()
947-
}
945+
token::OpenDelim(Delimiter::Invisible(_))
946+
| token::CloseDelim(Delimiter::Invisible(_)) => "".into(),
948947
token::Pound => "#".into(),
949948
token::Dollar => "$".into(),
950949
token::Question => "?".into(),

compiler/rustc_expand/src/mbe/macro_rules.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool {
693693
&& let mbe::TokenTree::Token(bang) = bang
694694
&& let TokenKind::Not = bang.kind
695695
&& let mbe::TokenTree::Delimited(.., del) = args
696-
&& del.delim != Delimiter::Invisible
696+
&& !del.delim.skip()
697697
{
698698
true
699699
} else {

compiler/rustc_expand/src/mbe/quoted.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,12 @@ fn parse_tree<'a>(
165165
// during parsing.
166166
let mut next = outer_trees.next();
167167
let mut trees: Box<dyn Iterator<Item = &tokenstream::TokenTree>>;
168-
if let Some(tokenstream::TokenTree::Delimited(.., Delimiter::Invisible, tts)) = next {
169-
trees = Box::new(tts.trees());
170-
next = trees.next();
171-
} else {
172-
trees = Box::new(outer_trees);
168+
match next {
169+
Some(tokenstream::TokenTree::Delimited(.., delim, tts)) if delim.skip() => {
170+
trees = Box::new(tts.trees());
171+
next = trees.next();
172+
}
173+
_ => trees = Box::new(outer_trees),
173174
}
174175

175176
match next {

compiler/rustc_expand/src/proc_macro_server.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl FromInternal<token::Delimiter> for Delimiter {
3838
token::Delimiter::Parenthesis => Delimiter::Parenthesis,
3939
token::Delimiter::Brace => Delimiter::Brace,
4040
token::Delimiter::Bracket => Delimiter::Bracket,
41-
token::Delimiter::Invisible => Delimiter::None,
41+
token::Delimiter::Invisible(_) => Delimiter::None,
4242
}
4343
}
4444
}
@@ -49,7 +49,7 @@ impl ToInternal<token::Delimiter> for Delimiter {
4949
Delimiter::Parenthesis => token::Delimiter::Parenthesis,
5050
Delimiter::Brace => token::Delimiter::Brace,
5151
Delimiter::Bracket => token::Delimiter::Bracket,
52-
Delimiter::None => token::Delimiter::Invisible,
52+
Delimiter::None => token::Delimiter::Invisible(token::InvisibleOrigin::ProcMacro),
5353
}
5454
}
5555
}

compiler/rustc_parse/src/parser/attr_wrapper.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -510,8 +510,8 @@ fn make_attr_token_stream(
510510
FlatToken::Token((Token { kind: TokenKind::CloseDelim(delim), span }, spacing)) => {
511511
let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap());
512512
let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
513-
assert_eq!(
514-
open_delim, delim,
513+
assert!(
514+
open_delim.eq_ignoring_invisible_origin(&delim),
515515
"Mismatched open/close delims: open={open_delim:?} close={span:?}"
516516
);
517517
let dspan = DelimSpan::from_pair(open_sp, span);

compiler/rustc_parse/src/parser/mod.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ impl TokenCursor {
317317
spacing,
318318
delim,
319319
));
320-
if delim != Delimiter::Invisible {
320+
if !delim.skip() {
321321
return (Token::new(token::OpenDelim(delim), sp.open), spacing.open);
322322
}
323323
// No open delimiter to return; continue on to the next iteration.
@@ -326,7 +326,7 @@ impl TokenCursor {
326326
} else if let Some((tree_cursor, span, spacing, delim)) = self.stack.pop() {
327327
// We have exhausted this token stream. Move back to its parent token stream.
328328
self.tree_cursor = tree_cursor;
329-
if delim != Delimiter::Invisible {
329+
if !delim.skip() {
330330
return (Token::new(token::CloseDelim(delim), span.close), spacing.close);
331331
}
332332
// No close delimiter to return; continue on to the next iteration.
@@ -1163,7 +1163,7 @@ impl<'a> Parser<'a> {
11631163
}
11641164
debug_assert!(!matches!(
11651165
next.0.kind,
1166-
token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible)
1166+
token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip()
11671167
));
11681168
self.inlined_bump_with(next)
11691169
}
@@ -1187,7 +1187,7 @@ impl<'a> Parser<'a> {
11871187
match tree {
11881188
TokenTree::Token(token, _) => return looker(token),
11891189
&TokenTree::Delimited(dspan, _, delim, _) => {
1190-
if delim != Delimiter::Invisible {
1190+
if !delim.skip() {
11911191
return looker(&Token::new(token::OpenDelim(delim), dspan.open));
11921192
}
11931193
}
@@ -1197,7 +1197,7 @@ impl<'a> Parser<'a> {
11971197
// The tree cursor lookahead went (one) past the end of the
11981198
// current token tree. Try to return a close delimiter.
11991199
if let Some(&(_, span, _, delim)) = self.token_cursor.stack.last()
1200-
&& delim != Delimiter::Invisible
1200+
&& !delim.skip()
12011201
{
12021202
// We are not in the outermost token stream, so we have
12031203
// delimiters. Also, those delimiters are not skipped.
@@ -1216,7 +1216,7 @@ impl<'a> Parser<'a> {
12161216
token = cursor.next().0;
12171217
if matches!(
12181218
token.kind,
1219-
token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible)
1219+
token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip()
12201220
) {
12211221
continue;
12221222
}

src/tools/rustfmt/src/macros.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ fn delim_token_to_str(
620620
("{ ", " }")
621621
}
622622
}
623-
Delimiter::Invisible => unreachable!(),
623+
Delimiter::Invisible(_) => unreachable!(),
624624
};
625625
if use_multiple_lines {
626626
let indent_str = shape.indent.to_string_with_newline(context.config);

0 commit comments

Comments
 (0)