Skip to content

Commit cee88f7

Browse files
committed
Prepare for invisible delimiters.
Current places where `Interpolated` is used are going to change to instead use invisible delimiters. This prepares for that. - It adds invisible delimiter cases to the `can_begin_*`/`may_be_*` methods and the `failed_to_match_macro` that are equivalent to the existing `Interpolated` cases. - It adds panics/asserts in some places where invisible delimiters should never occur. - In `Parser::parse_struct_fields` it excludes an ident + invisible delimiter from special consideration in an error message, because that's quite different to an ident + paren/brace/bracket.
1 parent cfafa93 commit cee88f7

File tree

5 files changed

+108
-14
lines changed

5 files changed

+108
-14
lines changed

Diff for: compiler/rustc_ast/src/token.rs

+36-2
Original file line numberDiff line numberDiff line change
@@ -598,10 +598,11 @@ impl Token {
598598
/// **NB**: Take care when modifying this function, since it will change
599599
/// the stable set of tokens that are allowed to match an expr nonterminal.
600600
pub fn can_begin_expr(&self) -> bool {
601+
use Delimiter::*;
601602
match self.uninterpolate().kind {
602603
Ident(name, is_raw) =>
603604
ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
604-
OpenDelim(..) | // tuple, array or block
605+
OpenDelim(Parenthesis | Brace | Bracket) | // tuple, array or block
605606
Literal(..) | // literal
606607
Not | // operator not
607608
BinOp(Minus) | // unary minus
@@ -612,7 +613,7 @@ impl Token {
612613
// DotDotDot is no longer supported, but we need some way to display the error
613614
DotDot | DotDotDot | DotDotEq | // range notation
614615
Lt | BinOp(Shl) | // associated path
615-
PathSep | // global path
616+
PathSep | // global path
616617
Lifetime(..) | // labeled loop
617618
Pound => true, // expression attributes
618619
Interpolated(ref nt) =>
@@ -622,6 +623,12 @@ impl Token {
622623
NtLiteral(..) |
623624
NtPath(..)
624625
),
626+
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
627+
MetaVarKind::Block |
628+
MetaVarKind::Expr { .. } |
629+
MetaVarKind::Literal |
630+
MetaVarKind::Path
631+
))) => true,
625632
_ => false,
626633
}
627634
}
@@ -655,6 +662,14 @@ impl Token {
655662
| NtPath(..)
656663
| NtTy(..)
657664
),
665+
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
666+
MetaVarKind::Expr { .. } |
667+
MetaVarKind::Literal |
668+
MetaVarKind::Meta |
669+
MetaVarKind::Pat(_) |
670+
MetaVarKind::Path |
671+
MetaVarKind::Ty
672+
))) => true,
658673
_ => false,
659674
}
660675
}
@@ -675,6 +690,10 @@ impl Token {
675690
Lt | BinOp(Shl) | // associated path
676691
PathSep => true, // global path
677692
Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)),
693+
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
694+
MetaVarKind::Ty |
695+
MetaVarKind::Path
696+
))) => true,
678697
// For anonymous structs or unions, which only appear in specific positions
679698
// (type of struct fields or union fields), we don't consider them as regular types
680699
_ => false,
@@ -687,6 +706,9 @@ impl Token {
687706
OpenDelim(Delimiter::Brace) | Literal(..) | BinOp(Minus) => true,
688707
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
689708
Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
709+
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
710+
MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal,
711+
))) => true,
690712
_ => false,
691713
}
692714
}
@@ -743,6 +765,13 @@ impl Token {
743765
},
744766
_ => false,
745767
},
768+
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
769+
MetaVarKind::Literal => true,
770+
MetaVarKind::Expr { can_begin_literal_maybe_minus, .. } => {
771+
can_begin_literal_maybe_minus
772+
}
773+
_ => false,
774+
},
746775
_ => false,
747776
}
748777
}
@@ -758,6 +787,11 @@ impl Token {
758787
},
759788
_ => false,
760789
},
790+
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
791+
MetaVarKind::Literal => true,
792+
MetaVarKind::Expr { can_begin_string_literal, .. } => can_begin_string_literal,
793+
_ => false,
794+
},
761795
_ => false,
762796
}
763797
}

Diff for: compiler/rustc_expand/src/mbe/diagnostics.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::borrow::Cow;
22

3-
use rustc_ast::token::{self, Token, TokenKind};
3+
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
44
use rustc_ast::tokenstream::TokenStream;
55
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
66
use rustc_macros::Subdiagnostic;
@@ -68,7 +68,9 @@ pub(super) fn failed_to_match_macro(
6868

6969
if let MatcherLoc::Token { token: expected_token } = &remaining_matcher
7070
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
71-
|| matches!(token.kind, TokenKind::Interpolated(_)))
71+
|| matches!(token.kind, TokenKind::Interpolated(_))
72+
|| matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))
73+
|| matches!(token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))))
7274
{
7375
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
7476
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");

Diff for: compiler/rustc_parse/src/lexer/tokentrees.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,19 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
4343
let mut buf = Vec::new();
4444
loop {
4545
match self.token.kind {
46-
token::OpenDelim(delim) => buf.push(match self.lex_token_tree_open_delim(delim) {
47-
Ok(val) => val,
48-
Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)),
49-
}),
46+
token::OpenDelim(delim) => {
47+
// Invisible delimiters cannot occur here because `TokenTreesReader` parses
48+
// code directly from strings, with no macro expansion involved.
49+
debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
50+
buf.push(match self.lex_token_tree_open_delim(delim) {
51+
Ok(val) => val,
52+
Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)),
53+
})
54+
}
5055
token::CloseDelim(delim) => {
56+
// Invisible delimiters cannot occur here because `TokenTreesReader` parses
57+
// code directly from strings, with no macro expansion involved.
58+
debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
5159
return (
5260
open_spacing,
5361
TokenStream::new(buf),

Diff for: compiler/rustc_parse/src/parser/expr.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -3591,11 +3591,19 @@ impl<'a> Parser<'a> {
35913591
&& !self.token.is_reserved_ident()
35923592
&& self.look_ahead(1, |t| {
35933593
AssocOp::from_token(t).is_some()
3594-
|| matches!(t.kind, token::OpenDelim(_))
3594+
|| matches!(
3595+
t.kind,
3596+
token::OpenDelim(
3597+
Delimiter::Parenthesis
3598+
| Delimiter::Bracket
3599+
| Delimiter::Brace
3600+
)
3601+
)
35953602
|| *t == token::Dot
35963603
})
35973604
{
3598-
// Looks like they tried to write a shorthand, complex expression.
3605+
// Looks like they tried to write a shorthand, complex expression,
3606+
// E.g.: `n + m`, `f(a)`, `a[i]`, `S { x: 3 }`, or `x.y`.
35993607
e.span_suggestion_verbose(
36003608
self.token.span.shrink_to_lo(),
36013609
"try naming a field",

Diff for: compiler/rustc_parse/src/parser/nonterminal.rs

+46-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use rustc_ast::ptr::P;
33
use rustc_ast::token::Nonterminal::*;
44
use rustc_ast::token::NtExprKind::*;
55
use rustc_ast::token::NtPatKind::*;
6-
use rustc_ast::token::{self, Delimiter, NonterminalKind, Token};
6+
use rustc_ast::token::{
7+
self, Delimiter, InvisibleOrigin, MetaVarKind, Nonterminal, NonterminalKind, Token,
8+
};
79
use rustc_ast_pretty::pprust;
810
use rustc_data_structures::sync::Lrc;
911
use rustc_errors::PResult;
@@ -22,7 +24,28 @@ impl<'a> Parser<'a> {
2224
#[inline]
2325
pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool {
2426
/// Checks whether the non-terminal may contain a single (non-keyword) identifier.
25-
fn may_be_ident(nt: &token::Nonterminal) -> bool {
27+
fn may_be_ident(kind: MetaVarKind) -> bool {
28+
match kind {
29+
MetaVarKind::Stmt
30+
| MetaVarKind::Pat(_)
31+
| MetaVarKind::Expr { .. }
32+
| MetaVarKind::Ty
33+
| MetaVarKind::Literal // `true`, `false`
34+
| MetaVarKind::Meta
35+
| MetaVarKind::Path => true,
36+
37+
MetaVarKind::Item
38+
| MetaVarKind::Block
39+
| MetaVarKind::Vis => false,
40+
41+
MetaVarKind::Ident
42+
| MetaVarKind::Lifetime
43+
| MetaVarKind::TT => unreachable!(),
44+
}
45+
}
46+
47+
/// Old variant of `may_be_ident`. Being phased out.
48+
fn nt_may_be_ident(nt: &Nonterminal) -> bool {
2649
match nt {
2750
NtStmt(_)
2851
| NtPat(_)
@@ -69,7 +92,8 @@ impl<'a> Parser<'a> {
6992
| token::Ident(..)
7093
| token::NtIdent(..)
7194
| token::NtLifetime(..)
72-
| token::Interpolated(_) => true,
95+
| token::Interpolated(_)
96+
| token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => true,
7397
_ => token.can_begin_type(),
7498
},
7599
NonterminalKind::Block => match &token.kind {
@@ -79,11 +103,29 @@ impl<'a> Parser<'a> {
79103
NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
80104
NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) | NtVis(_) => false,
81105
},
106+
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k {
107+
MetaVarKind::Block
108+
| MetaVarKind::Stmt
109+
| MetaVarKind::Expr { .. }
110+
| MetaVarKind::Literal => true,
111+
MetaVarKind::Item
112+
| MetaVarKind::Pat(_)
113+
| MetaVarKind::Ty
114+
| MetaVarKind::Meta
115+
| MetaVarKind::Path
116+
| MetaVarKind::Vis => false,
117+
MetaVarKind::Lifetime | MetaVarKind::Ident | MetaVarKind::TT => {
118+
unreachable!()
119+
}
120+
},
82121
_ => false,
83122
},
84123
NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
85124
token::PathSep | token::Ident(..) | token::NtIdent(..) => true,
86-
token::Interpolated(nt) => may_be_ident(nt),
125+
token::Interpolated(nt) => nt_may_be_ident(nt),
126+
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => {
127+
may_be_ident(*kind)
128+
}
87129
_ => false,
88130
},
89131
NonterminalKind::Pat(pat_kind) => token.can_begin_pattern(pat_kind),

0 commit comments

Comments
 (0)