Skip to content

Commit 8a160d6

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 03ee484 commit 8a160d6

File tree

10 files changed

+134
-31
lines changed

10 files changed

+134
-31
lines changed

compiler/rustc_ast/src/attr/mod.rs

Lines changed: 2 additions & 2 deletions
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

Lines changed: 109 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,87 @@ 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+
use MetaVarKind::*;
101+
let sym = match self {
102+
Item => sym::item,
103+
Block => sym::block,
104+
Stmt => sym::stmt,
105+
Pat(PatParam { inferred: true } | PatWithOr) => sym::pat,
106+
Pat(PatParam { inferred: false }) => sym::pat_param,
107+
Expr { kind: Expr2021 { inferred: true } | Expr, .. } => sym::expr,
108+
Expr { kind: Expr2021 { inferred: false }, .. } => sym::expr_2021,
109+
Ty => sym::ty,
110+
Ident => sym::ident,
111+
Lifetime => sym::lifetime,
112+
Literal => sym::literal,
113+
Meta => sym::meta,
114+
Path => sym::path,
115+
Vis => sym::vis,
116+
TT => sym::tt,
117+
};
118+
write!(f, "{sym}")
119+
}
120+
}
121+
45122
/// Describes how a sequence of token trees is delimited.
46123
/// Cannot use `proc_macro::Delimiter` directly because this
47124
/// structure should implement some additional traits.
48-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
49-
#[derive(Encodable, Decodable, Hash, HashStable_Generic)]
125+
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
50126
pub enum Delimiter {
51127
/// `( ... )`
52128
Parenthesis,
@@ -59,7 +135,34 @@ pub enum Delimiter {
59135
/// "macro variable" `$var`. It is important to preserve operator priorities in cases like
60136
/// `$var * 3` where `$var` is `1 + 2`.
61137
/// Invisible delimiters might not survive roundtrip of a token stream through a string.
62-
Invisible,
138+
Invisible(InvisibleOrigin),
139+
}
140+
141+
impl Delimiter {
142+
// Should the parser skip these delimiters? Only happens for certain kinds
143+
// of invisible delimiters. Ideally this function will eventually disappear
144+
// and no invisible delimiters will be skipped.
145+
#[inline]
146+
pub fn skip(&self) -> bool {
147+
match self {
148+
Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false,
149+
Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false,
150+
Delimiter::Invisible(InvisibleOrigin::FlattenToken | InvisibleOrigin::ProcMacro) => {
151+
true
152+
}
153+
}
154+
}
155+
156+
// This exists because `InvisibleOrigin`s should be compared. It is only used for assertions.
157+
pub fn eq_ignoring_invisible_origin(&self, other: &Delimiter) -> bool {
158+
match (self, other) {
159+
(Delimiter::Parenthesis, Delimiter::Parenthesis) => true,
160+
(Delimiter::Brace, Delimiter::Brace) => true,
161+
(Delimiter::Bracket, Delimiter::Bracket) => true,
162+
(Delimiter::Invisible(_), Delimiter::Invisible(_)) => true,
163+
_ => false,
164+
}
165+
}
63166
}
64167

65168
// Note that the suffix is *not* considered when deciding the `LitKind` in this
@@ -896,7 +999,7 @@ impl PartialEq<TokenKind> for Token {
896999
}
8971000
}
8981001

899-
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
1002+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
9001003
pub enum NtPatKind {
9011004
// Matches or-patterns. Was written using `pat` in edition 2021 or later.
9021005
PatWithOr,
@@ -906,7 +1009,7 @@ pub enum NtPatKind {
9061009
PatParam { inferred: bool },
9071010
}
9081011

909-
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
1012+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
9101013
pub enum NtExprKind {
9111014
// Matches expressions using the post-edition 2024. Was written using
9121015
// `expr` in edition 2024 or later.
@@ -933,7 +1036,7 @@ pub enum Nonterminal {
9331036
NtVis(P<ast::Visibility>),
9341037
}
9351038

936-
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
1039+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
9371040
pub enum NonterminalKind {
9381041
Item,
9391042
Block,

compiler/rustc_ast/src/tokenstream.rs

Lines changed: 3 additions & 3 deletions
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

Lines changed: 2 additions & 3 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 6 additions & 5 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 6 additions & 6 deletions
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.
@@ -1162,7 +1162,7 @@ impl<'a> Parser<'a> {
11621162
}
11631163
debug_assert!(!matches!(
11641164
next.0.kind,
1165-
token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible)
1165+
token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip()
11661166
));
11671167
self.inlined_bump_with(next)
11681168
}
@@ -1186,7 +1186,7 @@ impl<'a> Parser<'a> {
11861186
match tree {
11871187
TokenTree::Token(token, _) => return looker(token),
11881188
&TokenTree::Delimited(dspan, _, delim, _) => {
1189-
if delim != Delimiter::Invisible {
1189+
if !delim.skip() {
11901190
return looker(&Token::new(token::OpenDelim(delim), dspan.open));
11911191
}
11921192
}
@@ -1196,7 +1196,7 @@ impl<'a> Parser<'a> {
11961196
// The tree cursor lookahead went (one) past the end of the
11971197
// current token tree. Try to return a close delimiter.
11981198
if let Some(&(_, span, _, delim)) = self.token_cursor.stack.last()
1199-
&& delim != Delimiter::Invisible
1199+
&& !delim.skip()
12001200
{
12011201
// We are not in the outermost token stream, so we have
12021202
// delimiters. Also, those delimiters are not skipped.
@@ -1215,7 +1215,7 @@ impl<'a> Parser<'a> {
12151215
token = cursor.next().0;
12161216
if matches!(
12171217
token.kind,
1218-
token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible)
1218+
token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip()
12191219
) {
12201220
continue;
12211221
}

src/tools/rustfmt/src/macros.rs

Lines changed: 1 addition & 1 deletion
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)