Remove NtBlock
, Nonterminal
, and TokenKind::Interpolated
.
`NtBlock` is the last remaining variant of `Nonterminal`, so once it is gone then `Nonterminal` can be removed as well.
This commit is contained in:
parent
70dab5a27c
commit
bb495d6d3e
18 changed files with 108 additions and 388 deletions
|
@ -637,9 +637,7 @@ impl<'a> Parser<'a> {
|
|||
/// Returns the span of expr if it was not interpolated, or the span of the interpolated token.
|
||||
fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
|
||||
match self.prev_token.kind {
|
||||
TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) | TokenKind::Interpolated(..) => {
|
||||
self.prev_token.span
|
||||
}
|
||||
TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) => self.prev_token.span,
|
||||
TokenKind::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => {
|
||||
// `expr.span` is the interpolated span, because invisible open
|
||||
// and close delims both get marked with the same span, one
|
||||
|
@ -1386,15 +1384,7 @@ impl<'a> Parser<'a> {
|
|||
maybe_recover_from_interpolated_ty_qpath!(self, true);
|
||||
|
||||
let span = self.token.span;
|
||||
if let token::Interpolated(nt) = &self.token.kind {
|
||||
match &**nt {
|
||||
token::NtBlock(block) => {
|
||||
let block = block.clone();
|
||||
self.bump();
|
||||
return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None)));
|
||||
}
|
||||
};
|
||||
} else if let Some(expr) = self.eat_metavar_seq_with_matcher(
|
||||
if let Some(expr) = self.eat_metavar_seq_with_matcher(
|
||||
|mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }),
|
||||
|this| {
|
||||
// Force collection (as opposed to just `parse_expr`) is required to avoid the
|
||||
|
@ -1415,9 +1405,13 @@ impl<'a> Parser<'a> {
|
|||
self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
|
||||
{
|
||||
return Ok(lit);
|
||||
} else if let Some(path) = self.eat_metavar_seq(MetaVarKind::Path, |this| {
|
||||
this.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))
|
||||
}) {
|
||||
} else if let Some(block) =
|
||||
self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block())
|
||||
{
|
||||
return Ok(self.mk_expr(span, ExprKind::Block(block, None)));
|
||||
} else if let Some(path) =
|
||||
self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type))
|
||||
{
|
||||
return Ok(self.mk_expr(span, ExprKind::Path(None, path)));
|
||||
}
|
||||
|
||||
|
@ -1671,7 +1665,7 @@ impl<'a> Parser<'a> {
|
|||
} else if self.eat_keyword(exp!(Loop)) {
|
||||
self.parse_expr_loop(label, lo)
|
||||
} else if self.check_noexpect(&token::OpenDelim(Delimiter::Brace))
|
||||
|| self.token.is_whole_block()
|
||||
|| self.token.is_metavar_block()
|
||||
{
|
||||
self.parse_expr_block(label, lo, BlockCheckMode::Default)
|
||||
} else if !ate_colon
|
||||
|
@ -2349,7 +2343,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if self.token.is_whole_block() {
|
||||
if self.token.is_metavar_block() {
|
||||
self.dcx().emit_err(errors::InvalidBlockMacroSegment {
|
||||
span: self.token.span,
|
||||
context: lo.to(self.token.span),
|
||||
|
@ -2472,7 +2466,7 @@ impl<'a> Parser<'a> {
|
|||
if self.may_recover()
|
||||
&& self.token.can_begin_expr()
|
||||
&& !matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace))
|
||||
&& !self.token.is_whole_block()
|
||||
&& !self.token.is_metavar_block()
|
||||
{
|
||||
let snapshot = self.create_snapshot_for_diagnostic();
|
||||
let restrictions =
|
||||
|
@ -3519,7 +3513,7 @@ impl<'a> Parser<'a> {
|
|||
self.token.is_keyword(kw::Do)
|
||||
&& self.is_keyword_ahead(1, &[kw::Catch])
|
||||
&& self
|
||||
.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
|
||||
.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block())
|
||||
&& !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
|
||||
}
|
||||
|
||||
|
@ -3530,7 +3524,7 @@ impl<'a> Parser<'a> {
|
|||
fn is_try_block(&self) -> bool {
|
||||
self.token.is_keyword(kw::Try)
|
||||
&& self
|
||||
.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
|
||||
.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block())
|
||||
&& self.token_uninterpolated_span().at_least_rust_2018()
|
||||
}
|
||||
|
||||
|
@ -3564,12 +3558,12 @@ impl<'a> Parser<'a> {
|
|||
// `async move {`
|
||||
self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
|
||||
&& self.look_ahead(lookahead + 2, |t| {
|
||||
*t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()
|
||||
*t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()
|
||||
})
|
||||
) || (
|
||||
// `async {`
|
||||
self.look_ahead(lookahead + 1, |t| {
|
||||
*t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()
|
||||
*t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()
|
||||
})
|
||||
))
|
||||
}
|
||||
|
|
|
@ -2543,7 +2543,7 @@ impl<'a> Parser<'a> {
|
|||
self.expect_semi()?;
|
||||
*sig_hi = self.prev_token.span;
|
||||
(AttrVec::new(), None)
|
||||
} else if self.check(exp!(OpenBrace)) || self.token.is_whole_block() {
|
||||
} else if self.check(exp!(OpenBrace)) || self.token.is_metavar_block() {
|
||||
self.parse_block_common(self.token.span, BlockCheckMode::Default, None)
|
||||
.map(|(attrs, body)| (attrs, Some(body)))?
|
||||
} else if self.token == token::Eq {
|
||||
|
|
|
@ -13,7 +13,6 @@ mod ty;
|
|||
|
||||
use std::assert_matches::debug_assert_matches;
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
use std::{fmt, mem, slice};
|
||||
|
||||
use attr_wrapper::{AttrWrapper, UsePreAttrPos};
|
||||
|
@ -24,8 +23,8 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
|
|||
use path::PathStyle;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{
|
||||
self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, NtExprKind, NtPatKind,
|
||||
Token, TokenKind,
|
||||
self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token,
|
||||
TokenKind,
|
||||
};
|
||||
use rustc_ast::tokenstream::{AttrsTarget, Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::util::case::Case;
|
||||
|
@ -98,21 +97,6 @@ pub enum ForceCollect {
|
|||
No,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! maybe_whole {
|
||||
($p:expr, $constructor:ident, |$x:ident| $e:expr) => {
|
||||
#[allow(irrefutable_let_patterns)] // FIXME: temporary
|
||||
if let token::Interpolated(nt) = &$p.token.kind
|
||||
&& let token::$constructor(x) = &**nt
|
||||
{
|
||||
#[allow(unused_mut)]
|
||||
let mut $x = x.clone();
|
||||
$p.bump();
|
||||
return Ok($e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`.
|
||||
#[macro_export]
|
||||
macro_rules! maybe_recover_from_interpolated_ty_qpath {
|
||||
|
@ -459,7 +443,6 @@ pub fn token_descr(token: &Token) -> String {
|
|||
(Some(TokenDescription::MetaVar(kind)), _) => format!("`{kind}` metavariable"),
|
||||
(None, TokenKind::NtIdent(..)) => format!("identifier `{s}`"),
|
||||
(None, TokenKind::NtLifetime(..)) => format!("lifetime `{s}`"),
|
||||
(None, TokenKind::Interpolated(node)) => format!("{} `{s}`", node.descr()),
|
||||
(None, _) => format!("`{s}`"),
|
||||
}
|
||||
}
|
||||
|
@ -828,8 +811,10 @@ impl<'a> Parser<'a> {
|
|||
fn check_inline_const(&self, dist: usize) -> bool {
|
||||
self.is_keyword_ahead(dist, &[kw::Const])
|
||||
&& self.look_ahead(dist + 1, |t| match &t.kind {
|
||||
token::Interpolated(nt) => matches!(&**nt, token::NtBlock(..)),
|
||||
token::OpenDelim(Delimiter::Brace) => true,
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Block,
|
||||
))) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
@ -1375,7 +1360,7 @@ impl<'a> Parser<'a> {
|
|||
// Avoid const blocks and const closures to be parsed as const items
|
||||
if (self.check_const_closure() == is_closure)
|
||||
&& !self
|
||||
.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
|
||||
.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block())
|
||||
&& self.eat_keyword_case(exp!(Const), case)
|
||||
{
|
||||
Const::Yes(self.prev_token_uninterpolated_span())
|
||||
|
@ -1732,7 +1717,6 @@ impl<'a> Parser<'a> {
|
|||
pub fn token_uninterpolated_span(&self) -> Span {
|
||||
match &self.token.kind {
|
||||
token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span,
|
||||
token::Interpolated(nt) => nt.use_span(),
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => {
|
||||
self.look_ahead(1, |t| t.span)
|
||||
}
|
||||
|
@ -1744,7 +1728,6 @@ impl<'a> Parser<'a> {
|
|||
pub fn prev_token_uninterpolated_span(&self) -> Span {
|
||||
match &self.prev_token.kind {
|
||||
token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span,
|
||||
token::Interpolated(nt) => nt.use_span(),
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => {
|
||||
self.look_ahead(0, |t| t.span)
|
||||
}
|
||||
|
@ -1801,6 +1784,7 @@ pub enum ParseNtResult {
|
|||
Ident(Ident, IdentIsRaw),
|
||||
Lifetime(Ident, IdentIsRaw),
|
||||
Item(P<ast::Item>),
|
||||
Block(P<ast::Block>),
|
||||
Stmt(P<ast::Stmt>),
|
||||
Pat(P<ast::Pat>, NtPatKind),
|
||||
Expr(P<ast::Expr>, NtExprKind),
|
||||
|
@ -1809,7 +1793,4 @@ pub enum ParseNtResult {
|
|||
Meta(P<ast::AttrItem>),
|
||||
Path(P<ast::Path>),
|
||||
Vis(P<ast::Visibility>),
|
||||
|
||||
/// This variant will eventually be removed, along with `Token::Interpolate`.
|
||||
Nt(Arc<Nonterminal>),
|
||||
}
|
||||
|
|
|
@ -1,14 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::HasTokens;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::Nonterminal::*;
|
||||
use rustc_ast::token::NtExprKind::*;
|
||||
use rustc_ast::token::NtPatKind::*;
|
||||
use rustc_ast::token::{
|
||||
self, Delimiter, InvisibleOrigin, MetaVarKind, Nonterminal, NonterminalKind, Token,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, NonterminalKind, Token};
|
||||
use rustc_errors::PResult;
|
||||
use rustc_span::{Ident, kw};
|
||||
|
||||
|
@ -45,13 +38,6 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Old variant of `may_be_ident`. Being phased out.
|
||||
fn nt_may_be_ident(nt: &Nonterminal) -> bool {
|
||||
match nt {
|
||||
NtBlock(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
match kind {
|
||||
// `expr_2021` and earlier
|
||||
NonterminalKind::Expr(Expr2021 { .. }) => {
|
||||
|
@ -83,16 +69,12 @@ impl<'a> Parser<'a> {
|
|||
| token::Ident(..)
|
||||
| token::NtIdent(..)
|
||||
| token::NtLifetime(..)
|
||||
| token::Interpolated(_)
|
||||
| token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => true,
|
||||
_ => token.can_begin_type(),
|
||||
},
|
||||
NonterminalKind::Block => match &token.kind {
|
||||
token::OpenDelim(Delimiter::Brace) => true,
|
||||
token::NtLifetime(..) => true,
|
||||
token::Interpolated(nt) => match &**nt {
|
||||
NtBlock(_) => true,
|
||||
},
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k {
|
||||
MetaVarKind::Block
|
||||
| MetaVarKind::Stmt
|
||||
|
@ -112,7 +94,6 @@ impl<'a> Parser<'a> {
|
|||
},
|
||||
NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
|
||||
token::PathSep | token::Ident(..) | token::NtIdent(..) => true,
|
||||
token::Interpolated(nt) => nt_may_be_ident(nt),
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => {
|
||||
may_be_ident(*kind)
|
||||
}
|
||||
|
@ -136,62 +117,52 @@ impl<'a> Parser<'a> {
|
|||
// A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
|
||||
// which requires having captured tokens available. Since we cannot determine
|
||||
// in advance whether or not a proc-macro will be (transitively) invoked,
|
||||
// we always capture tokens for any `Nonterminal` which needs them.
|
||||
let mut nt = match kind {
|
||||
// we always capture tokens for any nonterminal that needs them.
|
||||
match kind {
|
||||
// Note that TT is treated differently to all the others.
|
||||
NonterminalKind::TT => return Ok(ParseNtResult::Tt(self.parse_token_tree())),
|
||||
NonterminalKind::TT => Ok(ParseNtResult::Tt(self.parse_token_tree())),
|
||||
NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
|
||||
Some(item) => return Ok(ParseNtResult::Item(item)),
|
||||
None => {
|
||||
return Err(self
|
||||
.dcx()
|
||||
.create_err(UnexpectedNonterminal::Item(self.token.span)));
|
||||
}
|
||||
Some(item) => Ok(ParseNtResult::Item(item)),
|
||||
None => Err(self.dcx().create_err(UnexpectedNonterminal::Item(self.token.span))),
|
||||
},
|
||||
NonterminalKind::Block => {
|
||||
// While a block *expression* may have attributes (e.g. `#[my_attr] { ... }`),
|
||||
// the ':block' matcher does not support them
|
||||
NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?)
|
||||
Ok(ParseNtResult::Block(self.collect_tokens_no_attrs(|this| this.parse_block())?))
|
||||
}
|
||||
NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? {
|
||||
Some(stmt) => return Ok(ParseNtResult::Stmt(P(stmt))),
|
||||
Some(stmt) => Ok(ParseNtResult::Stmt(P(stmt))),
|
||||
None => {
|
||||
return Err(self
|
||||
.dcx()
|
||||
.create_err(UnexpectedNonterminal::Statement(self.token.span)));
|
||||
Err(self.dcx().create_err(UnexpectedNonterminal::Statement(self.token.span)))
|
||||
}
|
||||
},
|
||||
NonterminalKind::Pat(pat_kind) => {
|
||||
return Ok(ParseNtResult::Pat(
|
||||
self.collect_tokens_no_attrs(|this| match pat_kind {
|
||||
PatParam { .. } => this.parse_pat_no_top_alt(None, None),
|
||||
PatWithOr => this.parse_pat_no_top_guard(
|
||||
None,
|
||||
RecoverComma::No,
|
||||
RecoverColon::No,
|
||||
CommaRecoveryMode::EitherTupleOrPipe,
|
||||
),
|
||||
})?,
|
||||
pat_kind,
|
||||
));
|
||||
}
|
||||
NonterminalKind::Pat(pat_kind) => Ok(ParseNtResult::Pat(
|
||||
self.collect_tokens_no_attrs(|this| match pat_kind {
|
||||
PatParam { .. } => this.parse_pat_no_top_alt(None, None),
|
||||
PatWithOr => this.parse_pat_no_top_guard(
|
||||
None,
|
||||
RecoverComma::No,
|
||||
RecoverColon::No,
|
||||
CommaRecoveryMode::EitherTupleOrPipe,
|
||||
),
|
||||
})?,
|
||||
pat_kind,
|
||||
)),
|
||||
NonterminalKind::Expr(expr_kind) => {
|
||||
return Ok(ParseNtResult::Expr(self.parse_expr_force_collect()?, expr_kind));
|
||||
Ok(ParseNtResult::Expr(self.parse_expr_force_collect()?, expr_kind))
|
||||
}
|
||||
NonterminalKind::Literal => {
|
||||
// The `:literal` matcher does not support attributes.
|
||||
return Ok(ParseNtResult::Literal(
|
||||
Ok(ParseNtResult::Literal(
|
||||
self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?,
|
||||
));
|
||||
))
|
||||
}
|
||||
NonterminalKind::Ty => {
|
||||
return Ok(ParseNtResult::Ty(
|
||||
self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?,
|
||||
));
|
||||
}
|
||||
// this could be handled like a token, since it is one
|
||||
NonterminalKind::Ty => Ok(ParseNtResult::Ty(
|
||||
self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?,
|
||||
)),
|
||||
// This could be handled like a token, since it is one.
|
||||
NonterminalKind::Ident => {
|
||||
return if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
|
||||
if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
|
||||
self.bump();
|
||||
Ok(ParseNtResult::Ident(ident, is_raw))
|
||||
} else {
|
||||
|
@ -199,25 +170,22 @@ impl<'a> Parser<'a> {
|
|||
span: self.token.span,
|
||||
token: self.token.clone(),
|
||||
}))
|
||||
};
|
||||
}
|
||||
NonterminalKind::Path => {
|
||||
return Ok(ParseNtResult::Path(P(
|
||||
self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?
|
||||
)));
|
||||
}
|
||||
}
|
||||
NonterminalKind::Path => Ok(ParseNtResult::Path(P(
|
||||
self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?
|
||||
))),
|
||||
NonterminalKind::Meta => {
|
||||
return Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?)));
|
||||
Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?)))
|
||||
}
|
||||
NonterminalKind::Vis => {
|
||||
return Ok(ParseNtResult::Vis(P(self.collect_tokens_no_attrs(|this| {
|
||||
this.parse_visibility(FollowedByType::Yes)
|
||||
})?)));
|
||||
Ok(ParseNtResult::Vis(P(self
|
||||
.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?)))
|
||||
}
|
||||
NonterminalKind::Lifetime => {
|
||||
// We want to keep `'keyword` parsing, just like `keyword` is still
|
||||
// an ident for nonterminal purposes.
|
||||
return if let Some((ident, is_raw)) = self.token.lifetime() {
|
||||
if let Some((ident, is_raw)) = self.token.lifetime() {
|
||||
self.bump();
|
||||
Ok(ParseNtResult::Lifetime(ident, is_raw))
|
||||
} else {
|
||||
|
@ -225,21 +193,9 @@ impl<'a> Parser<'a> {
|
|||
span: self.token.span,
|
||||
token: self.token.clone(),
|
||||
}))
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// If tokens are supported at all, they should be collected.
|
||||
if matches!(nt.tokens_mut(), Some(None)) {
|
||||
panic!(
|
||||
"Missing tokens for nt {:?} at {:?}: {:?}",
|
||||
nt,
|
||||
nt.use_span(),
|
||||
pprust::nonterminal_to_string(&nt)
|
||||
);
|
||||
}
|
||||
|
||||
Ok(ParseNtResult::Nt(Arc::new(nt)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ use super::{
|
|||
AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode,
|
||||
Trailing, UsePreAttrPos,
|
||||
};
|
||||
use crate::errors::MalformedLoopLabel;
|
||||
use crate::{errors, exp, maybe_whole};
|
||||
use crate::errors::{self, MalformedLoopLabel};
|
||||
use crate::exp;
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
/// Parses a statement. This stops just before trailing semicolons on everything but items.
|
||||
|
@ -681,7 +681,9 @@ impl<'a> Parser<'a> {
|
|||
blk_mode: BlockCheckMode,
|
||||
loop_header: Option<Span>,
|
||||
) -> PResult<'a, (AttrVec, P<Block>)> {
|
||||
maybe_whole!(self, NtBlock, |block| (AttrVec::new(), block));
|
||||
if let Some(block) = self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block()) {
|
||||
return Ok((AttrVec::new(), block));
|
||||
}
|
||||
|
||||
let maybe_ident = self.prev_token.clone();
|
||||
self.maybe_recover_unexpected_block_label(loop_header);
|
||||
|
@ -896,7 +898,7 @@ impl<'a> Parser<'a> {
|
|||
{
|
||||
if self.token == token::Colon
|
||||
&& self.look_ahead(1, |token| {
|
||||
token.is_whole_block()
|
||||
token.is_metavar_block()
|
||||
|| matches!(
|
||||
token.kind,
|
||||
token::Ident(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue