mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-16 17:03:35 +00:00
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.
This commit is contained in:
parent
cfafa9380b
commit
cee88f7a3f
@ -598,10 +598,11 @@ impl Token {
|
|||||||
/// **NB**: Take care when modifying this function, since it will change
|
/// **NB**: Take care when modifying this function, since it will change
|
||||||
/// the stable set of tokens that are allowed to match an expr nonterminal.
|
/// the stable set of tokens that are allowed to match an expr nonterminal.
|
||||||
pub fn can_begin_expr(&self) -> bool {
|
pub fn can_begin_expr(&self) -> bool {
|
||||||
|
use Delimiter::*;
|
||||||
match self.uninterpolate().kind {
|
match self.uninterpolate().kind {
|
||||||
Ident(name, is_raw) =>
|
Ident(name, is_raw) =>
|
||||||
ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
|
ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
|
||||||
OpenDelim(..) | // tuple, array or block
|
OpenDelim(Parenthesis | Brace | Bracket) | // tuple, array or block
|
||||||
Literal(..) | // literal
|
Literal(..) | // literal
|
||||||
Not | // operator not
|
Not | // operator not
|
||||||
BinOp(Minus) | // unary minus
|
BinOp(Minus) | // unary minus
|
||||||
@ -612,7 +613,7 @@ impl Token {
|
|||||||
// DotDotDot is no longer supported, but we need some way to display the error
|
// DotDotDot is no longer supported, but we need some way to display the error
|
||||||
DotDot | DotDotDot | DotDotEq | // range notation
|
DotDot | DotDotDot | DotDotEq | // range notation
|
||||||
Lt | BinOp(Shl) | // associated path
|
Lt | BinOp(Shl) | // associated path
|
||||||
PathSep | // global path
|
PathSep | // global path
|
||||||
Lifetime(..) | // labeled loop
|
Lifetime(..) | // labeled loop
|
||||||
Pound => true, // expression attributes
|
Pound => true, // expression attributes
|
||||||
Interpolated(ref nt) =>
|
Interpolated(ref nt) =>
|
||||||
@ -622,6 +623,12 @@ impl Token {
|
|||||||
NtLiteral(..) |
|
NtLiteral(..) |
|
||||||
NtPath(..)
|
NtPath(..)
|
||||||
),
|
),
|
||||||
|
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||||
|
MetaVarKind::Block |
|
||||||
|
MetaVarKind::Expr { .. } |
|
||||||
|
MetaVarKind::Literal |
|
||||||
|
MetaVarKind::Path
|
||||||
|
))) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -655,6 +662,14 @@ impl Token {
|
|||||||
| NtPath(..)
|
| NtPath(..)
|
||||||
| NtTy(..)
|
| NtTy(..)
|
||||||
),
|
),
|
||||||
|
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||||
|
MetaVarKind::Expr { .. } |
|
||||||
|
MetaVarKind::Literal |
|
||||||
|
MetaVarKind::Meta |
|
||||||
|
MetaVarKind::Pat(_) |
|
||||||
|
MetaVarKind::Path |
|
||||||
|
MetaVarKind::Ty
|
||||||
|
))) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -675,6 +690,10 @@ impl Token {
|
|||||||
Lt | BinOp(Shl) | // associated path
|
Lt | BinOp(Shl) | // associated path
|
||||||
PathSep => true, // global path
|
PathSep => true, // global path
|
||||||
Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)),
|
Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)),
|
||||||
|
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||||
|
MetaVarKind::Ty |
|
||||||
|
MetaVarKind::Path
|
||||||
|
))) => true,
|
||||||
// For anonymous structs or unions, which only appear in specific positions
|
// For anonymous structs or unions, which only appear in specific positions
|
||||||
// (type of struct fields or union fields), we don't consider them as regular types
|
// (type of struct fields or union fields), we don't consider them as regular types
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -687,6 +706,9 @@ impl Token {
|
|||||||
OpenDelim(Delimiter::Brace) | Literal(..) | BinOp(Minus) => true,
|
OpenDelim(Delimiter::Brace) | Literal(..) | BinOp(Minus) => true,
|
||||||
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
|
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
|
||||||
Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
|
Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
|
||||||
|
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||||
|
MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal,
|
||||||
|
))) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -743,6 +765,13 @@ impl Token {
|
|||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
|
||||||
|
MetaVarKind::Literal => true,
|
||||||
|
MetaVarKind::Expr { can_begin_literal_maybe_minus, .. } => {
|
||||||
|
can_begin_literal_maybe_minus
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -758,6 +787,11 @@ impl Token {
|
|||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
|
||||||
|
MetaVarKind::Literal => true,
|
||||||
|
MetaVarKind::Expr { can_begin_string_literal, .. } => can_begin_string_literal,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use rustc_ast::token::{self, Token, TokenKind};
|
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||||
use rustc_ast::tokenstream::TokenStream;
|
use rustc_ast::tokenstream::TokenStream;
|
||||||
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
|
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
|
||||||
use rustc_macros::Subdiagnostic;
|
use rustc_macros::Subdiagnostic;
|
||||||
@ -68,7 +68,9 @@ pub(super) fn failed_to_match_macro(
|
|||||||
|
|
||||||
if let MatcherLoc::Token { token: expected_token } = &remaining_matcher
|
if let MatcherLoc::Token { token: expected_token } = &remaining_matcher
|
||||||
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|
||||||
|| matches!(token.kind, TokenKind::Interpolated(_)))
|
|| matches!(token.kind, TokenKind::Interpolated(_))
|
||||||
|
|| matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))
|
||||||
|
|| matches!(token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))))
|
||||||
{
|
{
|
||||||
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
|
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
|
||||||
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
|
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
|
||||||
|
@ -43,11 +43,19 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
|
|||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
match self.token.kind {
|
match self.token.kind {
|
||||||
token::OpenDelim(delim) => buf.push(match self.lex_token_tree_open_delim(delim) {
|
token::OpenDelim(delim) => {
|
||||||
Ok(val) => val,
|
// Invisible delimiters cannot occur here because `TokenTreesReader` parses
|
||||||
Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)),
|
// code directly from strings, with no macro expansion involved.
|
||||||
}),
|
debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
|
||||||
|
buf.push(match self.lex_token_tree_open_delim(delim) {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)),
|
||||||
|
})
|
||||||
|
}
|
||||||
token::CloseDelim(delim) => {
|
token::CloseDelim(delim) => {
|
||||||
|
// Invisible delimiters cannot occur here because `TokenTreesReader` parses
|
||||||
|
// code directly from strings, with no macro expansion involved.
|
||||||
|
debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
|
||||||
return (
|
return (
|
||||||
open_spacing,
|
open_spacing,
|
||||||
TokenStream::new(buf),
|
TokenStream::new(buf),
|
||||||
|
@ -3591,11 +3591,19 @@ impl<'a> Parser<'a> {
|
|||||||
&& !self.token.is_reserved_ident()
|
&& !self.token.is_reserved_ident()
|
||||||
&& self.look_ahead(1, |t| {
|
&& self.look_ahead(1, |t| {
|
||||||
AssocOp::from_token(t).is_some()
|
AssocOp::from_token(t).is_some()
|
||||||
|| matches!(t.kind, token::OpenDelim(_))
|
|| matches!(
|
||||||
|
t.kind,
|
||||||
|
token::OpenDelim(
|
||||||
|
Delimiter::Parenthesis
|
||||||
|
| Delimiter::Bracket
|
||||||
|
| Delimiter::Brace
|
||||||
|
)
|
||||||
|
)
|
||||||
|| *t == token::Dot
|
|| *t == token::Dot
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
// Looks like they tried to write a shorthand, complex expression.
|
// Looks like they tried to write a shorthand, complex expression,
|
||||||
|
// E.g.: `n + m`, `f(a)`, `a[i]`, `S { x: 3 }`, or `x.y`.
|
||||||
e.span_suggestion_verbose(
|
e.span_suggestion_verbose(
|
||||||
self.token.span.shrink_to_lo(),
|
self.token.span.shrink_to_lo(),
|
||||||
"try naming a field",
|
"try naming a field",
|
||||||
|
@ -3,7 +3,9 @@ use rustc_ast::ptr::P;
|
|||||||
use rustc_ast::token::Nonterminal::*;
|
use rustc_ast::token::Nonterminal::*;
|
||||||
use rustc_ast::token::NtExprKind::*;
|
use rustc_ast::token::NtExprKind::*;
|
||||||
use rustc_ast::token::NtPatKind::*;
|
use rustc_ast::token::NtPatKind::*;
|
||||||
use rustc_ast::token::{self, Delimiter, NonterminalKind, Token};
|
use rustc_ast::token::{
|
||||||
|
self, Delimiter, InvisibleOrigin, MetaVarKind, Nonterminal, NonterminalKind, Token,
|
||||||
|
};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::PResult;
|
use rustc_errors::PResult;
|
||||||
@ -22,7 +24,28 @@ impl<'a> Parser<'a> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool {
|
pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool {
|
||||||
/// Checks whether the non-terminal may contain a single (non-keyword) identifier.
|
/// Checks whether the non-terminal may contain a single (non-keyword) identifier.
|
||||||
fn may_be_ident(nt: &token::Nonterminal) -> bool {
|
fn may_be_ident(kind: MetaVarKind) -> bool {
|
||||||
|
match kind {
|
||||||
|
MetaVarKind::Stmt
|
||||||
|
| MetaVarKind::Pat(_)
|
||||||
|
| MetaVarKind::Expr { .. }
|
||||||
|
| MetaVarKind::Ty
|
||||||
|
| MetaVarKind::Literal // `true`, `false`
|
||||||
|
| MetaVarKind::Meta
|
||||||
|
| MetaVarKind::Path => true,
|
||||||
|
|
||||||
|
MetaVarKind::Item
|
||||||
|
| MetaVarKind::Block
|
||||||
|
| MetaVarKind::Vis => false,
|
||||||
|
|
||||||
|
MetaVarKind::Ident
|
||||||
|
| MetaVarKind::Lifetime
|
||||||
|
| MetaVarKind::TT => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Old variant of `may_be_ident`. Being phased out.
|
||||||
|
fn nt_may_be_ident(nt: &Nonterminal) -> bool {
|
||||||
match nt {
|
match nt {
|
||||||
NtStmt(_)
|
NtStmt(_)
|
||||||
| NtPat(_)
|
| NtPat(_)
|
||||||
@ -69,7 +92,8 @@ impl<'a> Parser<'a> {
|
|||||||
| token::Ident(..)
|
| token::Ident(..)
|
||||||
| token::NtIdent(..)
|
| token::NtIdent(..)
|
||||||
| token::NtLifetime(..)
|
| token::NtLifetime(..)
|
||||||
| token::Interpolated(_) => true,
|
| token::Interpolated(_)
|
||||||
|
| token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => true,
|
||||||
_ => token.can_begin_type(),
|
_ => token.can_begin_type(),
|
||||||
},
|
},
|
||||||
NonterminalKind::Block => match &token.kind {
|
NonterminalKind::Block => match &token.kind {
|
||||||
@ -79,11 +103,29 @@ impl<'a> Parser<'a> {
|
|||||||
NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
|
NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
|
||||||
NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) | NtVis(_) => false,
|
NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) | NtVis(_) => false,
|
||||||
},
|
},
|
||||||
|
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k {
|
||||||
|
MetaVarKind::Block
|
||||||
|
| MetaVarKind::Stmt
|
||||||
|
| MetaVarKind::Expr { .. }
|
||||||
|
| MetaVarKind::Literal => true,
|
||||||
|
MetaVarKind::Item
|
||||||
|
| MetaVarKind::Pat(_)
|
||||||
|
| MetaVarKind::Ty
|
||||||
|
| MetaVarKind::Meta
|
||||||
|
| MetaVarKind::Path
|
||||||
|
| MetaVarKind::Vis => false,
|
||||||
|
MetaVarKind::Lifetime | MetaVarKind::Ident | MetaVarKind::TT => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
|
NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
|
||||||
token::PathSep | token::Ident(..) | token::NtIdent(..) => true,
|
token::PathSep | token::Ident(..) | token::NtIdent(..) => true,
|
||||||
token::Interpolated(nt) => may_be_ident(nt),
|
token::Interpolated(nt) => nt_may_be_ident(nt),
|
||||||
|
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => {
|
||||||
|
may_be_ident(*kind)
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
NonterminalKind::Pat(pat_kind) => token.can_begin_pattern(pat_kind),
|
NonterminalKind::Pat(pat_kind) => token.can_begin_pattern(pat_kind),
|
||||||
|
Loading…
Reference in New Issue
Block a user