Skip to content

Commit 90ac96c

Browse files
Don't make pattern nonterminals match statement nonterminals
1 parent ef71f10 commit 90ac96c

File tree

4 files changed

+54
-39
lines changed

4 files changed

+54
-39
lines changed

compiler/rustc_ast/src/token.rs

+31-18
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,9 @@ impl Token {
447447
}
448448

449449
/// Returns `true` if the token can appear at the start of an expression.
450+
///
451+
/// **NB**: Take care when modifying this function, since it will change
452+
/// the stable set of tokens that are allowed to match an expr nonterminal.
450453
pub fn can_begin_expr(&self) -> bool {
451454
match self.uninterpolate().kind {
452455
Ident(name, is_raw) =>
@@ -475,24 +478,34 @@ impl Token {
475478

476479
/// Returns `true` if the token can appear at the start of a pattern.
477480
///
478-
/// Shamelessly borrowed from `can_begin_expr`, only used for diagnostics right now.
479-
pub fn can_begin_pattern(&self) -> bool {
480-
match self.uninterpolate().kind {
481-
Ident(name, is_raw) =>
482-
ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
483-
| OpenDelim(Delimiter::Bracket | Delimiter::Parenthesis) // tuple or array
484-
| Literal(..) // literal
485-
| BinOp(Minus) // unary minus
486-
| BinOp(And) // reference
487-
| AndAnd // double reference
488-
// DotDotDot is no longer supported
489-
| DotDot | DotDotDot | DotDotEq // ranges
490-
| Lt | BinOp(Shl) // associated path
491-
| ModSep => true, // global path
492-
Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
493-
NtPat(..) |
494-
NtBlock(..) |
495-
NtPath(..)),
481+
/// **NB**: Take care when modifying this function, since it will change
482+
/// the stable set of tokens that are allowed to match an pat nonterminal.
483+
pub fn can_begin_pattern(&self, allow_leading_or: bool) -> bool {
484+
match &self.uninterpolate().kind {
485+
Ident(..) | // box, ref, mut, and other identifiers (can stricten)
486+
OpenDelim(Delimiter::Parenthesis) | // tuple pattern
487+
OpenDelim(Delimiter::Bracket) | // slice pattern
488+
BinOp(And) | // reference
489+
BinOp(Minus) | // negative literal
490+
AndAnd | // double reference
491+
Literal(_) | // literal
492+
DotDot | // range pattern (future compat)
493+
DotDotDot | // range pattern (future compat)
494+
ModSep | // path
495+
Lt | // path (UFCS constant)
496+
BinOp(Shl) => true, // path (double UFCS)
497+
// leading vert `|` or-pattern
498+
BinOp(Or) => allow_leading_or,
499+
Interpolated(nt) =>
500+
matches!(&nt.0,
501+
| NtBlock(..)
502+
| NtExpr(..)
503+
| NtLiteral(..)
504+
| NtMeta(..)
505+
| NtPat(..)
506+
| NtPath(..)
507+
| NtTy(..)
508+
),
496509
_ => false,
497510
}
498511
}

compiler/rustc_parse/src/parser/nonterminal.rs

+2-20
Original file line numberDiff line numberDiff line change
@@ -66,26 +66,8 @@ impl<'a> Parser<'a> {
6666
token::Interpolated(nt) => may_be_ident(&nt.0),
6767
_ => false,
6868
},
69-
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => {
70-
match &token.kind {
71-
token::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
72-
token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern
73-
token::OpenDelim(Delimiter::Bracket) | // slice pattern
74-
token::BinOp(token::And) | // reference
75-
token::BinOp(token::Minus) | // negative literal
76-
token::AndAnd | // double reference
77-
token::Literal(_) | // literal
78-
token::DotDot | // range pattern (future compat)
79-
token::DotDotDot | // range pattern (future compat)
80-
token::ModSep | // path
81-
token::Lt | // path (UFCS constant)
82-
token::BinOp(token::Shl) => true, // path (double UFCS)
83-
// leading vert `|` or-pattern
84-
token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr),
85-
token::Interpolated(nt) => may_be_ident(&nt.0),
86-
_ => false,
87-
}
88-
}
69+
NonterminalKind::PatParam { .. } => token.can_begin_pattern(false),
70+
NonterminalKind::PatWithOr => token.can_begin_pattern(true),
8971
NonterminalKind::Lifetime => match &token.kind {
9072
token::Lifetime(_) => true,
9173
token::Interpolated(nt) => {

compiler/rustc_parse/src/parser/pat.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,8 @@ impl<'a> Parser<'a> {
349349

350350
let mut lo = self.token.span;
351351

352-
if self.token.is_keyword(kw::Let) && self.look_ahead(1, |tok| tok.can_begin_pattern()) {
352+
if self.token.is_keyword(kw::Let) && self.look_ahead(1, |tok| tok.can_begin_pattern(false))
353+
{
353354
self.bump();
354355
self.dcx().emit_err(RemoveLet { span: lo });
355356
lo = self.token.span;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// check-pass
2+
3+
// Make sure that a `stmt` nonterminal does not eagerly match against
4+
// a `pat`, since this will always cause a parse error...
5+
6+
macro_rules! m {
7+
($pat:pat) => {};
8+
($stmt:stmt) => {};
9+
}
10+
11+
macro_rules! m2 {
12+
($stmt:stmt) => {
13+
m! { $stmt }
14+
};
15+
}
16+
17+
m2! { let x = 1 }
18+
19+
fn main() {}

0 commit comments

Comments
 (0)