1
Fork 0

Speed up Parser::expected_token_types.

The parser pushes a `TokenType` to `Parser::expected_token_types` on
every call to the various `check`/`eat` methods, and clears it on every
call to `bump`. Some of those `TokenType` values are full tokens that
require cloning and dropping. This is a *lot* of work for something
that is only used in error messages and it accounts for a significant
fraction of parsing execution time.

This commit overhauls `TokenType` so that `Parser::expected_token_types`
can be implemented as a bitset. This requires changing `TokenType` to a
C-style parameterless enum, and adding `TokenTypeSet` which uses a
`u128` for the bits. (The new `TokenType` has 105 variants.)

The new types `ExpTokenPair` and `ExpKeywordPair` are now arguments to
the `check`/`eat` methods. This is for maximum speed. The elements in
the pairs are always statically known; e.g. a
`token::BinOp(token::Star)` is always paired with a `TokenType::Star`.
So we now compute `TokenType`s in advance and pass them in to
`check`/`eat` rather than the current approach of constructing them on
insertion into `expected_token_types`.

Values of these pair types can be produced by the new `exp!` macro,
which is used at every `check`/`eat` call site. The macro is for
convenience, allowing any pair to be generated from a single identifier.

The ident/keyword filtering in `expected_one_of_not_found` is no longer
necessary. It was there to account for some sloppiness in
`TokenKind`/`TokenType` comparisons.

The existing `TokenType` is moved to a new file `token_type.rs`, and all
its new infrastructure is added to that file. There is more boilerplate
code than I would like, but I can't see how to make it shorter.
This commit is contained in:
Nicholas Nethercote 2024-12-04 15:55:06 +11:00
parent d5370d981f
commit b9bf0b4b10
22 changed files with 1357 additions and 793 deletions

View file

@ -1,8 +1,7 @@
use rustc_ast::token::{self, Delimiter};
use rustc_ast::{self as ast, Attribute, attr};
use rustc_ast::{self as ast, Attribute, attr, token};
use rustc_errors::codes::*;
use rustc_errors::{Diag, PResult};
use rustc_span::{BytePos, Span, kw};
use rustc_span::{BytePos, Span};
use thin_vec::ThinVec;
use tracing::debug;
@ -10,7 +9,7 @@ use super::{
AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, ParserRange, PathStyle, Trailing,
UsePreAttrPos,
};
use crate::{errors, fluent_generated as fluent, maybe_whole};
use crate::{errors, exp, fluent_generated as fluent, maybe_whole};
// Public for rustfmt usage
#[derive(Debug)]
@ -45,7 +44,7 @@ impl<'a> Parser<'a> {
let mut just_parsed_doc_comment = false;
let start_pos = self.num_bump_calls;
loop {
let attr = if self.check(&token::Pound) {
let attr = if self.check(exp!(Pound)) {
let prev_outer_attr_sp = outer_attrs.last().map(|attr: &Attribute| attr.span);
let inner_error_reason = if just_parsed_doc_comment {
@ -126,14 +125,14 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
// Attributes can't have attributes of their own [Editor's note: not with that attitude]
self.collect_tokens_no_attrs(|this| {
assert!(this.eat(&token::Pound), "parse_attribute called in non-attribute position");
assert!(this.eat(exp!(Pound)), "parse_attribute called in non-attribute position");
let style =
if this.eat(&token::Not) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer };
if this.eat(exp!(Not)) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer };
this.expect(&token::OpenDelim(Delimiter::Bracket))?;
this.expect(exp!(OpenBracket))?;
let item = this.parse_attr_item(ForceCollect::No)?;
this.expect(&token::CloseDelim(Delimiter::Bracket))?;
this.expect(exp!(CloseBracket))?;
let attr_sp = lo.to(this.prev_token.span);
// Emit error if inner attribute is encountered and forbidden.
@ -274,10 +273,10 @@ impl<'a> Parser<'a> {
// Attr items don't have attributes.
self.collect_tokens(None, AttrWrapper::empty(), force_collect, |this, _empty_attrs| {
let is_unsafe = this.eat_keyword(kw::Unsafe);
let is_unsafe = this.eat_keyword(exp!(Unsafe));
let unsafety = if is_unsafe {
let unsafe_span = this.prev_token.span;
this.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
this.expect(exp!(OpenParen))?;
ast::Safety::Unsafe(unsafe_span)
} else {
ast::Safety::Default
@ -286,7 +285,7 @@ impl<'a> Parser<'a> {
let path = this.parse_path(PathStyle::Mod)?;
let args = this.parse_attr_args()?;
if is_unsafe {
this.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
this.expect(exp!(CloseParen))?;
}
Ok((
ast::AttrItem { unsafety, path, args, tokens: None },
@ -306,7 +305,7 @@ impl<'a> Parser<'a> {
loop {
let start_pos = self.num_bump_calls;
// Only try to parse if it is an inner attribute (has `!`).
let attr = if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) {
let attr = if self.check(exp!(Pound)) && self.look_ahead(1, |t| t == &token::Not) {
Some(self.parse_attribute(InnerAttrPolicy::Permitted)?)
} else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
if attr_style == ast::AttrStyle::Inner {
@ -358,7 +357,7 @@ impl<'a> Parser<'a> {
&mut self,
) -> PResult<'a, (ast::MetaItemInner, Vec<(ast::AttrItem, Span)>)> {
let cfg_predicate = self.parse_meta_item_inner()?;
self.expect(&token::Comma)?;
self.expect(exp!(Comma))?;
// Presumably, the majority of the time there will only be one attr.
let mut expanded_attrs = Vec::with_capacity(1);
@ -366,7 +365,7 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
let item = self.parse_attr_item(ForceCollect::Yes)?;
expanded_attrs.push((item, lo.to(self.prev_token.span)));
if !self.eat(&token::Comma) {
if !self.eat(exp!(Comma)) {
break;
}
}
@ -380,7 +379,7 @@ impl<'a> Parser<'a> {
let mut nmis = ThinVec::with_capacity(1);
while self.token != token::Eof {
nmis.push(self.parse_meta_item_inner()?);
if !self.eat(&token::Comma) {
if !self.eat(exp!(Comma)) {
break;
}
}
@ -413,13 +412,13 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
let is_unsafe = if unsafe_allowed == AllowLeadingUnsafe::Yes {
self.eat_keyword(kw::Unsafe)
self.eat_keyword(exp!(Unsafe))
} else {
false
};
let unsafety = if is_unsafe {
let unsafe_span = self.prev_token.span;
self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
self.expect(exp!(OpenParen))?;
ast::Safety::Unsafe(unsafe_span)
} else {
@ -429,7 +428,7 @@ impl<'a> Parser<'a> {
let path = self.parse_path(PathStyle::Mod)?;
let kind = self.parse_meta_item_kind()?;
if is_unsafe {
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
self.expect(exp!(CloseParen))?;
}
let span = lo.to(self.prev_token.span);
@ -437,9 +436,9 @@ impl<'a> Parser<'a> {
}
pub(crate) fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
Ok(if self.eat(&token::Eq) {
Ok(if self.eat(exp!(Eq)) {
ast::MetaItemKind::NameValue(self.parse_unsuffixed_meta_item_lit()?)
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
} else if self.check(exp!(OpenParen)) {
let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
ast::MetaItemKind::List(list)
} else {

View file

@ -29,7 +29,8 @@ use tracing::{debug, trace};
use super::pat::Expected;
use super::{
BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenType,
BlockMode, CommaRecoveryMode, ExpTokenPair, Parser, PathStyle, Restrictions, SemiColonMode,
SeqSep, TokenType,
};
use crate::errors::{
AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion,
@ -47,7 +48,7 @@ use crate::errors::{
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
};
use crate::parser::attr::InnerAttrPolicy;
use crate::{fluent_generated as fluent, parser};
use crate::{exp, fluent_generated as fluent};
/// Creates a placeholder argument.
pub(super) fn dummy_arg(ident: Ident, guar: ErrorGuaranteed) -> Param {
@ -462,8 +463,8 @@ impl<'a> Parser<'a> {
pub(super) fn expected_one_of_not_found(
&mut self,
edible: &[TokenKind],
inedible: &[TokenKind],
edible: &[ExpTokenPair<'_>],
inedible: &[ExpTokenPair<'_>],
) -> PResult<'a, ErrorGuaranteed> {
debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
fn tokens_to_string(tokens: &[TokenType]) -> String {
@ -483,50 +484,17 @@ impl<'a> Parser<'a> {
})
}
self.expected_token_types
.extend(edible.iter().chain(inedible).cloned().map(TokenType::Token));
let mut expected = self
.expected_token_types
.iter()
.filter(|token| {
// Filter out suggestions that suggest the same token which was found and deemed incorrect.
fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool {
if let TokenKind::Ident(current_sym, _) = found
&& let TokenType::Keyword(suggested_sym) = expected
{
return current_sym == suggested_sym;
}
false
}
if **token != parser::TokenType::Token(self.token.kind.clone()) {
let eq = is_ident_eq_keyword(&self.token.kind, &token);
// If the suggestion is a keyword and the found token is an ident,
// the content of which are equal to the suggestion's content,
// we can remove that suggestion (see the `return false` below).
// If this isn't the case however, and the suggestion is a token the
// content of which is the same as the found token's, we remove it as well.
if !eq {
if let TokenType::Token(kind) = token {
if self.token == *kind {
return false;
}
}
return true;
}
}
false
})
.cloned()
.collect::<Vec<_>>();
for exp in edible.iter().chain(inedible.iter()) {
self.expected_token_types.insert(exp.token_type);
}
let mut expected: Vec<_> = self.expected_token_types.iter().collect();
expected.sort_by_cached_key(|x| x.to_string());
expected.dedup();
let sm = self.psess.source_map();
// Special-case "expected `;`" errors.
if expected.contains(&TokenType::Token(token::Semi)) {
if expected.contains(&TokenType::Semi) {
// If the user is trying to write a ternary expression, recover it and
// return an Err to prevent a cascade of irrelevant diagnostics.
if self.prev_token == token::Question
@ -578,7 +546,7 @@ impl<'a> Parser<'a> {
|| (sm.is_multiline(
self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()),
) && t == &token::Pound)
}) && !expected.contains(&TokenType::Token(token::Comma))
}) && !expected.contains(&TokenType::Comma)
{
// Missing semicolon typo. This is triggered if the next token could either start a
// new statement or is a block close. For example:
@ -598,7 +566,7 @@ impl<'a> Parser<'a> {
if self.token == TokenKind::EqEq
&& self.prev_token.is_ident()
&& expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq)))
&& expected.contains(&TokenType::Eq)
{
// Likely typo: `=` → `==` in let expr or enum item
return Err(self.dcx().create_err(UseEqInstead { span: self.token.span }));
@ -637,15 +605,8 @@ impl<'a> Parser<'a> {
// Look for usages of '=>' where '>=' was probably intended
if self.token == token::FatArrow
&& expected
.iter()
.any(|tok| matches!(tok, TokenType::Operator | TokenType::Token(TokenKind::Le)))
&& !expected.iter().any(|tok| {
matches!(
tok,
TokenType::Token(TokenKind::FatArrow) | TokenType::Token(TokenKind::Comma)
)
})
&& expected.iter().any(|tok| matches!(tok, TokenType::Operator | TokenType::Le))
&& !expected.iter().any(|tok| matches!(tok, TokenType::FatArrow | TokenType::Comma))
{
err.span_suggestion(
self.token.span,
@ -742,7 +703,7 @@ impl<'a> Parser<'a> {
};
if self.check_too_many_raw_str_terminators(&mut err) {
if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) {
if expected.contains(&TokenType::Semi) && self.eat(exp!(Semi)) {
let guar = err.emit();
return Ok(guar);
} else {
@ -788,10 +749,8 @@ impl<'a> Parser<'a> {
};
let expected_token_types: &[TokenType] =
expected.len().checked_sub(10).map_or(&expected, |index| &expected[index..]);
let expected_keywords: Vec<Symbol> = expected_token_types
.iter()
.filter_map(|token| if let TokenType::Keyword(kw) = token { Some(*kw) } else { None })
.collect();
let expected_keywords: Vec<Symbol> =
expected_token_types.iter().filter_map(|token| token.is_keyword()).collect();
// When there are a few keywords in the last ten elements of `self.expected_token_types`
// and the current token is an identifier, it's probably a misspelled keyword. This handles
@ -1053,7 +1012,7 @@ impl<'a> Parser<'a> {
(Err(snapshot_err), Err(err)) => {
// We don't know what went wrong, emit the normal error.
snapshot_err.cancel();
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);
Err(err)
}
(Ok(_), Ok(mut tail)) => {
@ -1090,7 +1049,7 @@ impl<'a> Parser<'a> {
Applicability::MaybeIncorrect,
);
let guar = err.emit();
self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]);
self.eat_to_tokens(&[exp!(CloseBrace)]);
guar
}
token::OpenDelim(Delimiter::Parenthesis)
@ -1098,7 +1057,7 @@ impl<'a> Parser<'a> {
{
// We are within a function call or tuple, we can emit the error
// and recover.
self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis), &token::Comma]);
self.eat_to_tokens(&[exp!(CloseParen), exp!(Comma)]);
err.multipart_suggestion_verbose(
"you might have meant to open the body of the closure",
@ -1127,7 +1086,7 @@ impl<'a> Parser<'a> {
/// Eats and discards tokens until one of `closes` is encountered. Respects token trees,
/// passes through any errors encountered. Used for error recovery.
pub(super) fn eat_to_tokens(&mut self, closes: &[&TokenKind]) {
pub(super) fn eat_to_tokens(&mut self, closes: &[ExpTokenPair<'_>]) {
if let Err(err) = self
.parse_seq_to_before_tokens(closes, &[], SeqSep::none(), |p| Ok(p.parse_token_tree()))
{
@ -1148,7 +1107,7 @@ impl<'a> Parser<'a> {
pub(super) fn check_trailing_angle_brackets(
&mut self,
segment: &PathSegment,
end: &[&TokenKind],
end: &[ExpTokenPair<'_>],
) -> Option<ErrorGuaranteed> {
if !self.may_recover() {
return None;
@ -1231,7 +1190,7 @@ impl<'a> Parser<'a> {
// second case.
if self.look_ahead(position, |t| {
trace!("check_trailing_angle_brackets: t={:?}", t);
end.contains(&&t.kind)
end.iter().any(|exp| exp.tok == &t.kind)
}) {
// Eat from where we started until the end token so that parsing can continue
// as if we didn't have those extra angle brackets.
@ -1299,11 +1258,11 @@ impl<'a> Parser<'a> {
) -> PResult<'a, ErrorGuaranteed> {
if let ExprKind::Binary(binop, _, _) = &expr.kind
&& let ast::BinOpKind::Lt = binop.node
&& self.eat(&token::Comma)
&& self.eat(exp!(Comma))
{
let x = self.parse_seq_to_before_end(
&token::Gt,
SeqSep::trailing_allowed(token::Comma),
exp!(Gt),
SeqSep::trailing_allowed(exp!(Comma)),
|p| match p.parse_generic_arg(None)? {
Some(arg) => Ok(arg),
// If we didn't eat a generic arg, then we should error.
@ -1312,7 +1271,7 @@ impl<'a> Parser<'a> {
);
match x {
Ok((_, _, Recovered::No)) => {
if self.eat(&token::Gt) {
if self.eat(exp!(Gt)) {
// We made sense of it. Improve the error message.
e.span_suggestion_verbose(
binop.span.shrink_to_lo(),
@ -1875,7 +1834,7 @@ impl<'a> Parser<'a> {
ty_span: Span,
ty: P<Ty>,
) -> PResult<'a, P<T>> {
self.expect(&token::PathSep)?;
self.expect(exp!(PathSep))?;
let mut path = ast::Path { segments: ThinVec::new(), span: DUMMY_SP, tokens: None };
self.parse_path_segments(&mut path.segments, T::PATH_STYLE, None)?;
@ -1957,10 +1916,10 @@ impl<'a> Parser<'a> {
}
pub(super) fn expect_semi(&mut self) -> PResult<'a, ()> {
if self.eat(&token::Semi) || self.recover_colon_as_semi() {
if self.eat(exp!(Semi)) || self.recover_colon_as_semi() {
return Ok(());
}
self.expect(&token::Semi).map(drop) // Error unconditionally
self.expect(exp!(Semi)).map(drop) // Error unconditionally
}
pub(super) fn recover_colon_as_semi(&mut self) -> bool {
@ -2005,15 +1964,15 @@ impl<'a> Parser<'a> {
}
fn recover_await_macro(&mut self) -> PResult<'a, (Span, P<Expr>, bool)> {
self.expect(&token::Not)?;
self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
self.expect(exp!(Not))?;
self.expect(exp!(OpenParen))?;
let expr = self.parse_expr()?;
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
self.expect(exp!(CloseParen))?;
Ok((self.prev_token.span, expr, false))
}
fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, P<Expr>, bool)> {
let is_question = self.eat(&token::Question); // Handle `await? <expr>`.
let is_question = self.eat(exp!(Question)); // Handle `await? <expr>`.
let expr = if self.token == token::OpenDelim(Delimiter::Brace) {
// Handle `await { <expr> }`.
// This needs to be handled separately from the next arm to avoid
@ -2075,7 +2034,7 @@ impl<'a> Parser<'a> {
let try_span = lo.to(self.token.span); //we take the try!( span
self.bump(); //remove (
let is_empty = self.token == token::CloseDelim(Delimiter::Parenthesis); //check if the block is empty
self.consume_block(Delimiter::Parenthesis, ConsumeClosingDelim::No); //eat the block
self.consume_block(exp!(OpenParen), exp!(CloseParen), ConsumeClosingDelim::No); //eat the block
let hi = self.token.span;
self.bump(); //remove )
let mut err = self.dcx().struct_span_err(lo.to(hi), "use of deprecated `try` macro");
@ -2131,13 +2090,14 @@ impl<'a> Parser<'a> {
pub(super) fn recover_seq_parse_error(
&mut self,
delim: Delimiter,
open: ExpTokenPair<'_>,
close: ExpTokenPair<'_>,
lo: Span,
err: Diag<'a>,
) -> P<Expr> {
let guar = err.emit();
// Recover from parse error, callers expect the closing delim to be consumed.
self.consume_block(delim, ConsumeClosingDelim::Yes);
self.consume_block(open, close, ConsumeClosingDelim::Yes);
self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err(guar))
}
@ -2226,7 +2186,7 @@ impl<'a> Parser<'a> {
}
pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) {
if self.eat_keyword(kw::In) {
if self.eat_keyword(exp!(In)) {
// a common typo: `for _ in in bar {}`
self.dcx().emit_err(InInTypo {
span: self.prev_token.span,
@ -2367,7 +2327,7 @@ impl<'a> Parser<'a> {
pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName), None)?;
self.expect(&token::Colon)?;
self.expect(exp!(Colon))?;
let ty = self.parse_ty()?;
self.dcx().emit_err(PatternMethodParamWithoutBody { span: pat.span });
@ -2385,12 +2345,17 @@ impl<'a> Parser<'a> {
Ok(param)
}
pub(super) fn consume_block(&mut self, delim: Delimiter, consume_close: ConsumeClosingDelim) {
pub(super) fn consume_block(
&mut self,
open: ExpTokenPair<'_>,
close: ExpTokenPair<'_>,
consume_close: ConsumeClosingDelim,
) {
let mut brace_depth = 0;
loop {
if self.eat(&token::OpenDelim(delim)) {
if self.eat(open) {
brace_depth += 1;
} else if self.check(&token::CloseDelim(delim)) {
} else if self.check(close) {
if brace_depth == 0 {
if let ConsumeClosingDelim::Yes = consume_close {
// Some of the callers of this method expect to be able to parse the
@ -2546,7 +2511,7 @@ impl<'a> Parser<'a> {
match self.recover_const_arg(arg.span(), err) {
Ok(arg) => {
args.push(AngleBracketedArg::Arg(arg));
if self.eat(&token::Comma) {
if self.eat(exp!(Comma)) {
return Ok(true); // Continue
}
}
@ -3017,7 +2982,7 @@ impl<'a> Parser<'a> {
/// Check for exclusive ranges written as `..<`
pub(crate) fn maybe_err_dotdotlt_syntax(&self, maybe_lt: Token, mut err: Diag<'a>) -> Diag<'a> {
if maybe_lt == token::Lt
&& (self.expected_token_types.contains(&TokenType::Token(token::Gt))
&& (self.expected_token_types.contains(TokenType::Gt)
|| matches!(self.token.kind, token::Literal(..)))
{
err.span_suggestion(
@ -3147,9 +3112,9 @@ impl<'a> Parser<'a> {
/// Parse and throw away a parenthesized comma separated
/// sequence of patterns until `)` is reached.
fn skip_pat_list(&mut self) -> PResult<'a, ()> {
while !self.check(&token::CloseDelim(Delimiter::Parenthesis)) {
while !self.check(exp!(CloseParen)) {
self.parse_pat_no_top_alt(None, None)?;
if !self.eat(&token::Comma) {
if !self.eat(exp!(Comma)) {
return Ok(());
}
}

View file

@ -35,10 +35,10 @@ use super::diagnostics::SnapshotParser;
use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{
AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
SemiColonMode, SeqSep, TokenType, Trailing, UsePreAttrPos,
AttrWrapper, BlockMode, ClosureSpans, ExpTokenPair, ForceCollect, Parser, PathStyle,
Restrictions, SemiColonMode, SeqSep, TokenType, Trailing, UsePreAttrPos,
};
use crate::{errors, maybe_recover_from_interpolated_ty_qpath};
use crate::{errors, exp, maybe_recover_from_interpolated_ty_qpath};
#[derive(Debug)]
pub(super) enum DestructuredFloat {
@ -153,7 +153,7 @@ impl<'a> Parser<'a> {
return Ok((lhs, parsed_something));
}
self.expected_token_types.push(TokenType::Operator);
self.expected_token_types.insert(TokenType::Operator);
while let Some(op) = self.check_assoc_op() {
let lhs_span = self.interpolated_or_expr_span(&lhs);
let cur_op_span = self.token.span;
@ -873,9 +873,9 @@ impl<'a> Parser<'a> {
/// Parse `mut?` or `raw [ const | mut ]`.
fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {
if self.check_keyword(kw::Raw) && self.look_ahead(1, Token::is_mutability) {
if self.check_keyword(exp!(Raw)) && self.look_ahead(1, Token::is_mutability) {
// `raw [ const | mut ]`.
let found_raw = self.eat_keyword(kw::Raw);
let found_raw = self.eat_keyword(exp!(Raw));
assert!(found_raw);
let mutability = self.parse_const_or_mut().unwrap();
(ast::BorrowKind::Raw, mutability)
@ -908,7 +908,7 @@ impl<'a> Parser<'a> {
// a `return` which could be suggested otherwise.
self.eat_noexpect(&token::Question)
} else {
self.eat(&token::Question)
self.eat(exp!(Question))
};
if has_question {
// `expr?`
@ -926,7 +926,7 @@ impl<'a> Parser<'a> {
self.dcx().emit_err(errors::ExprRArrowCall { span });
true
} else {
self.eat(&token::Dot)
self.eat(exp!(Dot))
};
if has_dot {
// expr.f
@ -1251,7 +1251,7 @@ impl<'a> Parser<'a> {
.map(|args| self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args)));
match self.maybe_recover_struct_lit_bad_delims(lo, open_paren, seq, snapshot) {
Ok(expr) => expr,
Err(err) => self.recover_seq_parse_error(Delimiter::Parenthesis, lo, err),
Err(err) => self.recover_seq_parse_error(exp!(OpenParen), exp!(CloseParen), lo, err),
}
}
@ -1268,10 +1268,8 @@ impl<'a> Parser<'a> {
match (self.may_recover(), seq, snapshot) {
(true, Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
snapshot.bump(); // `(`
match snapshot.parse_struct_fields(path.clone(), false, Delimiter::Parenthesis) {
Ok((fields, ..))
if snapshot.eat(&token::CloseDelim(Delimiter::Parenthesis)) =>
{
match snapshot.parse_struct_fields(path.clone(), false, exp!(CloseParen)) {
Ok((fields, ..)) if snapshot.eat(exp!(CloseParen)) => {
// We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
// `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.
self.restore_snapshot(snapshot);
@ -1328,7 +1326,7 @@ impl<'a> Parser<'a> {
self.bump(); // `[`
let index = self.parse_expr()?;
self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?;
self.expect(&token::CloseDelim(Delimiter::Bracket))?;
self.expect(exp!(CloseBracket))?;
Ok(self.mk_expr(
lo.to(self.prev_token.span),
self.mk_index(base, index, open_delim_span.to(self.prev_token.span)),
@ -1337,12 +1335,12 @@ impl<'a> Parser<'a> {
/// Assuming we have just parsed `.`, continue parsing into an expression.
fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
if self.token.uninterpolated_span().at_least_rust_2018() && self.eat_keyword(kw::Await) {
if self.token.uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Await)) {
return Ok(self.mk_await_expr(self_arg, lo));
}
// Post-fix match
if self.eat_keyword(kw::Match) {
if self.eat_keyword(exp!(Match)) {
let match_span = self.prev_token.span;
self.psess.gated_spans.gate(sym::postfix_match, match_span);
return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);
@ -1350,10 +1348,10 @@ impl<'a> Parser<'a> {
let fn_span_lo = self.token.span;
let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
self.check_trailing_angle_brackets(&seg, &[&token::OpenDelim(Delimiter::Parenthesis)]);
self.check_trailing_angle_brackets(&seg, &[exp!(OpenParen)]);
self.check_turbofish_missing_angle_brackets(&mut seg);
if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
if self.check(exp!(OpenParen)) {
// Method call `expr.f()`
let args = self.parse_expr_paren_seq()?;
let fn_span = fn_span_lo.to(self.prev_token.span);
@ -1415,18 +1413,18 @@ impl<'a> Parser<'a> {
let restrictions = self.restrictions;
self.with_res(restrictions - Restrictions::ALLOW_LET, |this| {
// Note: when adding new syntax here, don't forget to adjust `TokenKind::can_begin_expr()`.
// Note: adding new syntax here? Don't forget to adjust `TokenKind::can_begin_expr()`.
let lo = this.token.span;
if let token::Literal(_) = this.token.kind {
// This match arm is a special-case of the `_` match arm below and
// could be removed without changing functionality, but it's faster
// to have it here, especially for programs with large constants.
this.parse_expr_lit()
} else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
} else if this.check(exp!(OpenParen)) {
this.parse_expr_tuple_parens(restrictions)
} else if this.check(&token::OpenDelim(Delimiter::Brace)) {
} else if this.check(exp!(OpenBrace)) {
this.parse_expr_block(None, lo, BlockCheckMode::Default)
} else if this.check(&token::BinOp(token::Or)) || this.check(&token::OrOr) {
} else if this.check(exp!(Or)) || this.check(exp!(OrOr)) {
this.parse_expr_closure().map_err(|mut err| {
// If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`
// then suggest parens around the lhs.
@ -1435,41 +1433,41 @@ impl<'a> Parser<'a> {
}
err
})
} else if this.check(&token::OpenDelim(Delimiter::Bracket)) {
this.parse_expr_array_or_repeat(Delimiter::Bracket)
} else if this.check(exp!(OpenBracket)) {
this.parse_expr_array_or_repeat(exp!(CloseBracket))
} else if this.is_builtin() {
this.parse_expr_builtin()
} else if this.check_path() {
this.parse_expr_path_start()
} else if this.check_keyword(kw::Move)
|| this.check_keyword(kw::Static)
} else if this.check_keyword(exp!(Move))
|| this.check_keyword(exp!(Static))
|| this.check_const_closure()
{
this.parse_expr_closure()
} else if this.eat_keyword(kw::If) {
} else if this.eat_keyword(exp!(If)) {
this.parse_expr_if()
} else if this.check_keyword(kw::For) {
} else if this.check_keyword(exp!(For)) {
if this.choose_generics_over_qpath(1) {
this.parse_expr_closure()
} else {
assert!(this.eat_keyword(kw::For));
assert!(this.eat_keyword(exp!(For)));
this.parse_expr_for(None, lo)
}
} else if this.eat_keyword(kw::While) {
} else if this.eat_keyword(exp!(While)) {
this.parse_expr_while(None, lo)
} else if let Some(label) = this.eat_label() {
this.parse_expr_labeled(label, true)
} else if this.eat_keyword(kw::Loop) {
} else if this.eat_keyword(exp!(Loop)) {
this.parse_expr_loop(None, lo).map_err(|mut err| {
err.span_label(lo, "while parsing this `loop` expression");
err
})
} else if this.eat_keyword(kw::Match) {
} else if this.eat_keyword(exp!(Match)) {
this.parse_expr_match().map_err(|mut err| {
err.span_label(lo, "while parsing this `match` expression");
err
})
} else if this.eat_keyword(kw::Unsafe) {
} else if this.eat_keyword(exp!(Unsafe)) {
this.parse_expr_block(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err(
|mut err| {
err.span_label(lo, "while parsing this `unsafe` expression");
@ -1481,23 +1479,23 @@ impl<'a> Parser<'a> {
} else if this.may_recover() && this.is_do_catch_block() {
this.recover_do_catch()
} else if this.is_try_block() {
this.expect_keyword(kw::Try)?;
this.expect_keyword(exp!(Try))?;
this.parse_try_block(lo)
} else if this.eat_keyword(kw::Return) {
} else if this.eat_keyword(exp!(Return)) {
this.parse_expr_return()
} else if this.eat_keyword(kw::Continue) {
} else if this.eat_keyword(exp!(Continue)) {
this.parse_expr_continue(lo)
} else if this.eat_keyword(kw::Break) {
} else if this.eat_keyword(exp!(Break)) {
this.parse_expr_break()
} else if this.eat_keyword(kw::Yield) {
} else if this.eat_keyword(exp!(Yield)) {
this.parse_expr_yield()
} else if this.is_do_yeet() {
this.parse_expr_yeet()
} else if this.eat_keyword(kw::Become) {
} else if this.eat_keyword(exp!(Become)) {
this.parse_expr_become()
} else if this.check_keyword(kw::Let) {
} else if this.check_keyword(exp!(Let)) {
this.parse_expr_let(restrictions)
} else if this.eat_keyword(kw::Underscore) {
} else if this.eat_keyword(exp!(Underscore)) {
Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))
} else if this.token.uninterpolated_span().at_least_rust_2018() {
// `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
@ -1505,11 +1503,11 @@ impl<'a> Parser<'a> {
// check for `gen {}` and `gen move {}`
// or `async gen {}` and `async gen move {}`
&& (this.is_gen_block(kw::Gen, 0)
|| (this.check_keyword(kw::Async) && this.is_gen_block(kw::Gen, 1)))
|| (this.check_keyword(exp!(Async)) && this.is_gen_block(kw::Gen, 1)))
{
// FIXME: (async) gen closures aren't yet parsed.
this.parse_gen_block()
} else if this.check_keyword(kw::Async) {
} else if this.check_keyword(exp!(Async)) {
// FIXME(gen_blocks): Parse `gen async` and suggest swap
if this.is_gen_block(kw::Async, 0) {
// Check for `async {` and `async move {`,
@ -1541,15 +1539,20 @@ impl<'a> Parser<'a> {
fn parse_expr_tuple_parens(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
self.expect(exp!(OpenParen))?;
let (es, trailing_comma) = match self.parse_seq_to_end(
&token::CloseDelim(Delimiter::Parenthesis),
SeqSep::trailing_allowed(token::Comma),
exp!(CloseParen),
SeqSep::trailing_allowed(exp!(Comma)),
|p| p.parse_expr_catch_underscore(restrictions.intersection(Restrictions::ALLOW_LET)),
) {
Ok(x) => x,
Err(err) => {
return Ok(self.recover_seq_parse_error(Delimiter::Parenthesis, lo, err));
return Ok(self.recover_seq_parse_error(
exp!(OpenParen),
exp!(CloseParen),
lo,
err,
));
}
};
let kind = if es.len() == 1 && matches!(trailing_comma, Trailing::No) {
@ -1563,25 +1566,24 @@ impl<'a> Parser<'a> {
self.maybe_recover_from_bad_qpath(expr)
}
fn parse_expr_array_or_repeat(&mut self, close_delim: Delimiter) -> PResult<'a, P<Expr>> {
fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair<'_>) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
self.bump(); // `[` or other open delim
let close = &token::CloseDelim(close_delim);
let kind = if self.eat(close) {
// Empty vector
ExprKind::Array(ThinVec::new())
} else {
// Non-empty vector
let first_expr = self.parse_expr()?;
if self.eat(&token::Semi) {
if self.eat(exp!(Semi)) {
// Repeating array syntax: `[ 0; 512 ]`
let count = self.parse_expr_anon_const()?;
self.expect(close)?;
ExprKind::Repeat(first_expr, count)
} else if self.eat(&token::Comma) {
} else if self.eat(exp!(Comma)) {
// Vector with two or more elements.
let sep = SeqSep::trailing_allowed(token::Comma);
let sep = SeqSep::trailing_allowed(exp!(Comma));
let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
exprs.insert(0, first_expr);
ExprKind::Array(exprs)
@ -1615,7 +1617,7 @@ impl<'a> Parser<'a> {
};
// `!`, as an operator, is prefix, so we know this isn't that.
let (span, kind) = if self.eat(&token::Not) {
let (span, kind) = if self.eat(exp!(Not)) {
// MACRO INVOCATION expression
if qself.is_some() {
self.dcx().emit_err(errors::MacroInvocationWithQualifiedPath(path.span));
@ -1623,7 +1625,7 @@ impl<'a> Parser<'a> {
let lo = path.span;
let mac = P(MacCall { path, args: self.parse_delim_args()? });
(lo.to(self.prev_token.span), ExprKind::MacCall(mac))
} else if self.check(&token::OpenDelim(Delimiter::Brace))
} else if self.check(exp!(OpenBrace))
&& let Some(expr) = self.maybe_parse_struct_expr(&qself, &path)
{
if qself.is_some() {
@ -1646,13 +1648,13 @@ impl<'a> Parser<'a> {
) -> PResult<'a, P<Expr>> {
let lo = label_.ident.span;
let label = Some(label_);
let ate_colon = self.eat(&token::Colon);
let ate_colon = self.eat(exp!(Colon));
let tok_sp = self.token.span;
let expr = if self.eat_keyword(kw::While) {
let expr = if self.eat_keyword(exp!(While)) {
self.parse_expr_while(label, lo)
} else if self.eat_keyword(kw::For) {
} else if self.eat_keyword(exp!(For)) {
self.parse_expr_for(label, lo)
} else if self.eat_keyword(kw::Loop) {
} 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()
@ -1958,7 +1960,7 @@ impl<'a> Parser<'a> {
self.psess.gated_spans.gate(sym::builtin_syntax, ident.span);
self.bump();
self.expect(&TokenKind::OpenDelim(Delimiter::Parenthesis))?;
self.expect(exp!(OpenParen))?;
let ret = if let Some(res) = parse(self, lo, ident)? {
Ok(res)
} else {
@ -1968,7 +1970,7 @@ impl<'a> Parser<'a> {
});
return Err(err);
};
self.expect(&TokenKind::CloseDelim(Delimiter::Parenthesis))?;
self.expect(exp!(CloseParen))?;
ret
}
@ -1976,14 +1978,12 @@ impl<'a> Parser<'a> {
/// Built-in macro for `offset_of!` expressions.
pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
let container = self.parse_ty()?;
self.expect(&TokenKind::Comma)?;
self.expect(exp!(Comma))?;
let fields = self.parse_floating_field_access()?;
let trailing_comma = self.eat_noexpect(&TokenKind::Comma);
if let Err(mut e) =
self.expect_one_of(&[], &[TokenKind::CloseDelim(Delimiter::Parenthesis)])
{
if let Err(mut e) = self.expect_one_of(&[], &[exp!(CloseParen)]) {
if trailing_comma {
e.note("unexpected third argument to offset_of");
} else {
@ -2006,7 +2006,7 @@ impl<'a> Parser<'a> {
/// Built-in macro for type ascription expressions.
pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
let expr = self.parse_expr()?;
self.expect(&token::Comma)?;
self.expect(exp!(Comma))?;
let ty = self.parse_ty()?;
let span = lo.to(self.token.span);
Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
@ -2018,7 +2018,7 @@ impl<'a> Parser<'a> {
kind: UnsafeBinderCastKind,
) -> PResult<'a, P<Expr>> {
let expr = self.parse_expr()?;
let ty = if self.eat(&TokenKind::Comma) { Some(self.parse_ty()?) } else { None };
let ty = if self.eat(exp!(Comma)) { Some(self.parse_ty()?) } else { None };
let span = lo.to(self.token.span);
Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty)))
}
@ -2214,7 +2214,7 @@ impl<'a> Parser<'a> {
}
let lo = self.token.span;
let minus_present = self.eat(&token::BinOp(token::Minus));
let minus_present = self.eat(exp!(Minus));
let (token_lit, span) = self.parse_token_lit()?;
let expr = self.mk_expr(span, ExprKind::Lit(token_lit));
@ -2236,7 +2236,7 @@ impl<'a> Parser<'a> {
/// expression.
fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option<P<Expr>> {
let mut snapshot = self.create_snapshot_for_diagnostic();
match snapshot.parse_expr_array_or_repeat(Delimiter::Brace) {
match snapshot.parse_expr_array_or_repeat(exp!(CloseBrace)) {
Ok(arr) => {
let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfSpaces {
span: arr.span,
@ -2272,8 +2272,8 @@ impl<'a> Parser<'a> {
let mut snapshot = self.create_snapshot_for_diagnostic();
snapshot.bump();
match snapshot.parse_seq_to_before_end(
&token::CloseDelim(Delimiter::Bracket),
SeqSep::trailing_allowed(token::Comma),
exp!(CloseBracket),
SeqSep::trailing_allowed(exp!(Comma)),
|p| p.parse_expr(),
) {
Ok(_)
@ -2337,7 +2337,7 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
let before = self.prev_token.clone();
let binder = if self.check_keyword(kw::For) {
let binder = if self.check_keyword(exp!(For)) {
let lo = self.token.span;
let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
let span = lo.to(self.prev_token.span);
@ -2352,7 +2352,7 @@ impl<'a> Parser<'a> {
let constness = self.parse_closure_constness();
let movability =
if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
if self.eat_keyword(exp!(Static)) { Movability::Static } else { Movability::Movable };
let coroutine_kind = if self.token.uninterpolated_span().at_least_rust_2018() {
self.parse_coroutine_kind(Case::Sensitive)
@ -2433,10 +2433,10 @@ impl<'a> Parser<'a> {
/// Parses an optional `move` prefix to a closure-like construct.
fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
if self.eat_keyword(kw::Move) {
if self.eat_keyword(exp!(Move)) {
let move_kw_span = self.prev_token.span;
// Check for `move async` and recover
if self.check_keyword(kw::Async) {
if self.check_keyword(exp!(Async)) {
let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
Err(self
.dcx()
@ -2453,15 +2453,15 @@ impl<'a> Parser<'a> {
fn parse_fn_block_decl(&mut self) -> PResult<'a, (P<FnDecl>, Span)> {
let arg_start = self.token.span.lo();
let inputs = if self.eat(&token::OrOr) {
let inputs = if self.eat(exp!(OrOr)) {
ThinVec::new()
} else {
self.expect(&token::BinOp(token::Or))?;
self.expect(exp!(Or))?;
let args = self
.parse_seq_to_before_tokens(
&[&token::BinOp(token::Or)],
&[exp!(Or)],
&[&token::OrOr],
SeqSep::trailing_allowed(token::Comma),
SeqSep::trailing_allowed(exp!(Comma)),
|p| p.parse_fn_block_param(),
)?
.0;
@ -2481,7 +2481,7 @@ impl<'a> Parser<'a> {
let attrs = self.parse_outer_attributes()?;
self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
let pat = this.parse_pat_no_top_alt(Some(Expected::ParameterName), None)?;
let ty = if this.eat(&token::Colon) {
let ty = if this.eat(exp!(Colon)) {
this.parse_ty()?
} else {
this.mk_ty(pat.span, TyKind::Infer)
@ -2566,7 +2566,7 @@ impl<'a> Parser<'a> {
} else {
let attrs = self.parse_outer_attributes()?; // For recovery.
let maybe_fatarrow = self.token.clone();
let block = if self.check(&token::OpenDelim(Delimiter::Brace)) {
let block = if self.check(exp!(OpenBrace)) {
self.parse_block()?
} else if let Some(block) = recover_block_from_condition(self) {
block
@ -2609,7 +2609,7 @@ impl<'a> Parser<'a> {
self.error_on_if_block_attrs(lo, false, block.span, attrs);
block
};
let els = if self.eat_keyword(kw::Else) { Some(self.parse_expr_else()?) } else { None };
let els = if self.eat_keyword(exp!(Else)) { Some(self.parse_expr_else()?) } else { None };
Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
}
@ -2662,7 +2662,7 @@ impl<'a> Parser<'a> {
});
self.bump();
} else {
self.expect(&token::Eq)?;
self.expect(exp!(Eq))?;
}
let attrs = self.parse_outer_attributes()?;
let (expr, _) =
@ -2675,9 +2675,9 @@ impl<'a> Parser<'a> {
fn parse_expr_else(&mut self) -> PResult<'a, P<Expr>> {
let else_span = self.prev_token.span; // `else`
let attrs = self.parse_outer_attributes()?; // For recovery.
let expr = if self.eat_keyword(kw::If) {
let expr = if self.eat_keyword(exp!(If)) {
ensure_sufficient_stack(|| self.parse_expr_if())?
} else if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) {
} else if self.check(exp!(OpenBrace)) {
self.parse_simple_block()?
} else {
let snapshot = self.create_snapshot_for_diagnostic();
@ -2719,7 +2719,7 @@ impl<'a> Parser<'a> {
// while true {}
// }
// ^
if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
if self.check(exp!(OpenBrace))
&& (classify::expr_requires_semi_to_be_stmt(&cond)
|| matches!(cond.kind, ExprKind::MacCall(..)))
=>
@ -2805,7 +2805,7 @@ impl<'a> Parser<'a> {
begin_paren,
) {
(Ok(pat), _) => pat, // Happy path.
(Err(err), Some((start_span, left))) if self.eat_keyword(kw::In) => {
(Err(err), Some((start_span, left))) if self.eat_keyword(exp!(In)) => {
// We know for sure we have seen `for ($SOMETHING in`. In the happy path this would
// happen right before the return of this method.
let attrs = self.parse_outer_attributes()?;
@ -2839,7 +2839,7 @@ impl<'a> Parser<'a> {
}
(Err(err), _) => return Err(err), // Some other error, bubble up.
};
if !self.eat_keyword(kw::In) {
if !self.eat_keyword(exp!(In)) {
self.error_missing_in_for_loop();
}
self.check_for_for_in_in_typo(self.prev_token.span);
@ -2851,7 +2851,7 @@ impl<'a> Parser<'a> {
/// Parses `for await? <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
let is_await =
self.token.uninterpolated_span().at_least_rust_2018() && self.eat_keyword(kw::Await);
self.token.uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Await));
if is_await {
self.psess.gated_spans.gate(sym::async_for_loop, self.prev_token.span);
@ -2981,7 +2981,7 @@ impl<'a> Parser<'a> {
scrutinee: P<Expr>,
match_kind: MatchKind,
) -> PResult<'a, P<Expr>> {
if let Err(mut e) = self.expect(&token::OpenDelim(Delimiter::Brace)) {
if let Err(mut e) = self.expect(exp!(OpenBrace)) {
if self.token == token::Semi {
e.span_suggestion_short(
match_span,
@ -3121,7 +3121,7 @@ impl<'a> Parser<'a> {
let span_before_body = this.prev_token.span;
let arm_body;
let is_fat_arrow = this.check(&token::FatArrow);
let is_fat_arrow = this.check(exp!(FatArrow));
let is_almost_fat_arrow = TokenKind::FatArrow
.similar_tokens()
.is_some_and(|similar_tokens| similar_tokens.contains(&this.token.kind));
@ -3134,17 +3134,15 @@ impl<'a> Parser<'a> {
let mut result = if armless {
// A pattern without a body, allowed for never patterns.
arm_body = None;
this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)]).map(
|x| {
// Don't gate twice
if !pat.contains_never_pattern() {
this.psess.gated_spans.gate(sym::never_patterns, pat.span);
}
x
},
)
this.expect_one_of(&[exp!(Comma)], &[exp!(CloseBrace)]).map(|x| {
// Don't gate twice
if !pat.contains_never_pattern() {
this.psess.gated_spans.gate(sym::never_patterns, pat.span);
}
x
})
} else {
if let Err(mut err) = this.expect(&token::FatArrow) {
if let Err(mut err) = this.expect(exp!(FatArrow)) {
// We might have a `=>` -> `=` or `->` typo (issue #89396).
if is_almost_fat_arrow {
err.span_suggestion(
@ -3184,7 +3182,7 @@ impl<'a> Parser<'a> {
if !require_comma {
arm_body = Some(expr);
// Eat a comma if it exists, though.
let _ = this.eat(&token::Comma);
let _ = this.eat(exp!(Comma));
Ok(Recovered::No)
} else if let Some((span, guar)) =
this.parse_arm_body_missing_braces(&expr, arrow_span)
@ -3195,42 +3193,40 @@ impl<'a> Parser<'a> {
} else {
let expr_span = expr.span;
arm_body = Some(expr);
this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)])
.map_err(|mut err| {
if this.token == token::FatArrow {
let sm = this.psess.source_map();
if let Ok(expr_lines) = sm.span_to_lines(expr_span)
&& let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
&& arm_start_lines.lines[0].end_col
== expr_lines.lines[0].end_col
&& expr_lines.lines.len() == 2
{
// We check whether there's any trailing code in the parse span,
// if there isn't, we very likely have the following:
//
// X | &Y => "y"
// | -- - missing comma
// | |
// | arrow_span
// X | &X => "x"
// | - ^^ self.token.span
// | |
// | parsed until here as `"y" & X`
err.span_suggestion_short(
arm_start_span.shrink_to_hi(),
"missing a comma here to end this `match` arm",
",",
Applicability::MachineApplicable,
);
}
} else {
err.span_label(
arrow_span,
"while parsing the `match` arm starting here",
this.expect_one_of(&[exp!(Comma)], &[exp!(CloseBrace)]).map_err(|mut err| {
if this.token == token::FatArrow {
let sm = this.psess.source_map();
if let Ok(expr_lines) = sm.span_to_lines(expr_span)
&& let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
&& arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col
&& expr_lines.lines.len() == 2
{
// We check whether there's any trailing code in the parse span,
// if there isn't, we very likely have the following:
//
// X | &Y => "y"
// | -- - missing comma
// | |
// | arrow_span
// X | &X => "x"
// | - ^^ self.token.span
// | |
// | parsed until here as `"y" & X`
err.span_suggestion_short(
arm_start_span.shrink_to_hi(),
"missing a comma here to end this `match` arm",
",",
Applicability::MachineApplicable,
);
}
err
})
} else {
err.span_label(
arrow_span,
"while parsing the `match` arm starting here",
);
}
err
})
}
};
@ -3267,7 +3263,7 @@ impl<'a> Parser<'a> {
)
.map_err(|err| err.cancel())
.is_ok();
if pattern_follows && snapshot.check(&TokenKind::FatArrow) {
if pattern_follows && snapshot.check(exp!(FatArrow)) {
err.cancel();
let guar = this.dcx().emit_err(errors::MissingCommaAfterMatchArm {
span: arm_span.shrink_to_hi(),
@ -3309,7 +3305,7 @@ impl<'a> Parser<'a> {
_ => (false, true),
}
}
if !self.eat_keyword(kw::If) {
if !self.eat_keyword(exp!(If)) {
// No match arm guard present.
return Ok(None);
}
@ -3384,7 +3380,7 @@ impl<'a> Parser<'a> {
// errors.
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
let msg = "you might have meant to start a match arm after the match guard";
if self.eat(&token::CloseDelim(Delimiter::Brace)) {
if self.eat(exp!(CloseBrace)) {
let applicability = if self.token != token::FatArrow {
// We have high confidence that we indeed didn't have a struct
// literal in the match guard, but rather we had some operation
@ -3409,7 +3405,7 @@ impl<'a> Parser<'a> {
/// Parses a `try {...}` expression (`try` token already eaten).
fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
let (attrs, body) = self.parse_inner_attrs_and_block()?;
if self.eat_keyword(kw::Catch) {
if self.eat_keyword(exp!(Catch)) {
Err(self.dcx().create_err(errors::CatchAfterTry { span: self.prev_token.span }))
} else {
let span = span_lo.to(body.span);
@ -3440,10 +3436,10 @@ impl<'a> Parser<'a> {
/// Parses an `async move? {...}` or `gen move? {...}` expression.
fn parse_gen_block(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
let kind = if self.eat_keyword(kw::Async) {
if self.eat_keyword(kw::Gen) { GenBlockKind::AsyncGen } else { GenBlockKind::Async }
let kind = if self.eat_keyword(exp!(Async)) {
if self.eat_keyword(exp!(Gen)) { GenBlockKind::AsyncGen } else { GenBlockKind::Async }
} else {
assert!(self.eat_keyword(kw::Gen));
assert!(self.eat_keyword(exp!(Gen)));
GenBlockKind::Gen
};
match kind {
@ -3504,7 +3500,7 @@ impl<'a> Parser<'a> {
) -> Option<PResult<'a, P<Expr>>> {
let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
if struct_allowed || self.is_certainly_not_a_block() {
if let Err(err) = self.expect(&token::OpenDelim(Delimiter::Brace)) {
if let Err(err) = self.expect(exp!(OpenBrace)) {
return Some(Err(err));
}
let expr = self.parse_expr_struct(qself.clone(), path.clone(), true);
@ -3527,7 +3523,7 @@ impl<'a> Parser<'a> {
&mut self,
pth: ast::Path,
recover: bool,
close_delim: Delimiter,
close: ExpTokenPair<'_>,
) -> PResult<
'a,
(
@ -3546,11 +3542,11 @@ impl<'a> Parser<'a> {
errors::HelpUseLatestEdition::new().add_to_diag(e);
};
while self.token != token::CloseDelim(close_delim) {
if self.eat(&token::DotDot) || self.recover_struct_field_dots(close_delim) {
while self.token != *close.tok {
if self.eat(exp!(DotDot)) || self.recover_struct_field_dots(close.tok) {
let exp_span = self.prev_token.span;
// We permit `.. }` on the left-hand side of a destructuring assignment.
if self.check(&token::CloseDelim(close_delim)) {
if self.check(close) {
base = ast::StructRest::Rest(self.prev_token.span);
break;
}
@ -3625,7 +3621,7 @@ impl<'a> Parser<'a> {
Applicability::MaybeIncorrect,
);
}
if in_if_guard && close_delim == Delimiter::Brace {
if in_if_guard && close.token_type == TokenType::CloseBrace {
return Err(e);
}
@ -3655,9 +3651,9 @@ impl<'a> Parser<'a> {
let is_shorthand = parsed_field.as_ref().is_ok_and(|f| f.is_shorthand);
// A shorthand field can be turned into a full field with `:`.
// We should point this out.
self.check_or_expected(!is_shorthand, TokenType::Token(token::Colon));
self.check_or_expected(!is_shorthand, TokenType::Colon);
match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) {
match self.expect_one_of(&[exp!(Comma)], &[close]) {
Ok(_) => {
if let Ok(f) = parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar))
{
@ -3689,7 +3685,7 @@ impl<'a> Parser<'a> {
fields.push(f);
}
self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
let _ = self.eat(&token::Comma);
let _ = self.eat(exp!(Comma));
}
}
}
@ -3705,9 +3701,9 @@ impl<'a> Parser<'a> {
) -> PResult<'a, P<Expr>> {
let lo = pth.span;
let (fields, base, recovered_async) =
self.parse_struct_fields(pth.clone(), recover, Delimiter::Brace)?;
self.parse_struct_fields(pth.clone(), recover, exp!(CloseBrace))?;
let span = lo.to(self.token.span);
self.expect(&token::CloseDelim(Delimiter::Brace))?;
self.expect(exp!(CloseBrace))?;
let expr = if let Some(guar) = recovered_async {
ExprKind::Err(guar)
} else {
@ -3727,10 +3723,8 @@ impl<'a> Parser<'a> {
self.recover_stmt();
}
fn recover_struct_field_dots(&mut self, close_delim: Delimiter) -> bool {
if !self.look_ahead(1, |t| *t == token::CloseDelim(close_delim))
&& self.eat(&token::DotDotDot)
{
fn recover_struct_field_dots(&mut self, close: &TokenKind) -> bool {
if !self.look_ahead(1, |t| t == close) && self.eat(exp!(DotDotDot)) {
// recover from typo of `...`, suggest `..`
let span = self.prev_token.span;
self.dcx().emit_err(errors::MissingDotDot { token_span: span, sugg_span: span });

View file

@ -13,6 +13,7 @@ use crate::errors::{
UnexpectedSelfInGenericParameters, WhereClauseBeforeTupleStructBody,
WhereClauseBeforeTupleStructBodySugg,
};
use crate::exp;
enum PredicateKindOrStructBody {
PredicateKind(ast::WherePredicateKind),
@ -52,7 +53,7 @@ impl<'a> Parser<'a> {
// Parse optional colon and param bounds.
let mut colon_span = None;
let bounds = if self.eat(&token::Colon) {
let bounds = if self.eat(exp!(Colon)) {
colon_span = Some(self.prev_token.span);
// recover from `impl Trait` in type param bound
if self.token.is_keyword(kw::Impl) {
@ -89,7 +90,7 @@ impl<'a> Parser<'a> {
Vec::new()
};
let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
let default = if self.eat(exp!(Eq)) { Some(self.parse_ty()?) } else { None };
Ok(GenericParam {
ident,
id: ast::DUMMY_NODE_ID,
@ -107,13 +108,13 @@ impl<'a> Parser<'a> {
) -> PResult<'a, GenericParam> {
let const_span = self.token.span;
self.expect_keyword(kw::Const)?;
self.expect_keyword(exp!(Const))?;
let ident = self.parse_ident()?;
self.expect(&token::Colon)?;
self.expect(exp!(Colon))?;
let ty = self.parse_ty()?;
// Parse optional const generics default value.
let default = if self.eat(&token::Eq) { Some(self.parse_const_arg()?) } else { None };
let default = if self.eat(exp!(Eq)) { Some(self.parse_const_arg()?) } else { None };
Ok(GenericParam {
ident,
@ -132,11 +133,11 @@ impl<'a> Parser<'a> {
mistyped_const_ident: Ident,
) -> PResult<'a, GenericParam> {
let ident = self.parse_ident()?;
self.expect(&token::Colon)?;
self.expect(exp!(Colon))?;
let ty = self.parse_ty()?;
// Parse optional const generics default value.
let default = if self.eat(&token::Eq) { Some(self.parse_const_arg()?) } else { None };
let default = if self.eat(exp!(Eq)) { Some(self.parse_const_arg()?) } else { None };
self.dcx()
.struct_span_err(
@ -177,13 +178,13 @@ impl<'a> Parser<'a> {
.emit_err(UnexpectedSelfInGenericParameters { span: this.prev_token.span });
// Eat a trailing comma, if it exists.
let _ = this.eat(&token::Comma);
let _ = this.eat(exp!(Comma));
}
let param = if this.check_lifetime() {
let lifetime = this.expect_lifetime();
// Parse lifetime parameter.
let (colon_span, bounds) = if this.eat(&token::Colon) {
let (colon_span, bounds) = if this.eat(exp!(Colon)) {
(Some(this.prev_token.span), this.parse_lt_param_bounds())
} else {
(None, Vec::new())
@ -209,7 +210,7 @@ impl<'a> Parser<'a> {
is_placeholder: false,
colon_span,
})
} else if this.check_keyword(kw::Const) {
} else if this.check_keyword(exp!(Const)) {
// Parse const parameter.
Some(this.parse_const_param(attrs)?)
} else if this.check_ident() {
@ -246,7 +247,7 @@ impl<'a> Parser<'a> {
return Ok((None, Trailing::No, UsePreAttrPos::No));
};
if !this.eat(&token::Comma) {
if !this.eat(exp!(Comma)) {
done = true;
}
// We just ate the comma, so no need to capture the trailing token.
@ -324,7 +325,7 @@ impl<'a> Parser<'a> {
};
let mut tuple_struct_body = None;
if !self.eat_keyword(kw::Where) {
if !self.eat_keyword(exp!(Where)) {
return Ok((where_clause, None));
}
where_clause.has_where_token = true;
@ -344,7 +345,7 @@ impl<'a> Parser<'a> {
let kind = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) {
let lifetime = self.expect_lifetime();
// Bounds starting with a colon are mandatory, but possibly empty.
self.expect(&token::Colon)?;
self.expect(exp!(Colon))?;
let bounds = self.parse_lt_param_bounds();
ast::WherePredicateKind::RegionPredicate(ast::WhereRegionPredicate {
lifetime,
@ -370,7 +371,7 @@ impl<'a> Parser<'a> {
});
let prev_token = self.prev_token.span;
let ate_comma = self.eat(&token::Comma);
let ate_comma = self.eat(exp!(Comma));
if self.eat_keyword_noexpect(kw::Where) {
self.dcx().emit_err(MultipleWhereClauses {
@ -464,7 +465,7 @@ impl<'a> Parser<'a> {
// Parse type with mandatory colon and (possibly empty) bounds,
// or with mandatory equality sign and the second type.
let ty = self.parse_ty_for_where_clause()?;
if self.eat(&token::Colon) {
if self.eat(exp!(Colon)) {
let bounds = self.parse_generic_bounds()?;
Ok(ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate {
bound_generic_params: lifetime_defs,
@ -473,7 +474,7 @@ impl<'a> Parser<'a> {
}))
// FIXME: Decide what should be used here, `=` or `==`.
// FIXME: We are just dropping the binders in lifetime_defs on the floor here.
} else if self.eat(&token::Eq) || self.eat(&token::EqEq) {
} else if self.eat(exp!(Eq)) || self.eat(exp!(EqEq)) {
let rhs_ty = self.parse_ty()?;
Ok(ast::WherePredicateKind::EqPredicate(ast::WhereEqPredicate { lhs_ty: ty, rhs_ty }))
} else {

View file

@ -20,29 +20,29 @@ use tracing::debug;
use super::diagnostics::{ConsumeClosingDelim, dummy_arg};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{
AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Trailing, UsePreAttrPos,
AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect, Parser, PathStyle,
Trailing, UsePreAttrPos,
};
use crate::errors::{self, MacroExpandsToAdtField};
use crate::{fluent_generated as fluent, maybe_whole};
use crate::{exp, fluent_generated as fluent, maybe_whole};
impl<'a> Parser<'a> {
/// Parses a source module as a crate. This is the main entry point for the parser.
pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
let (attrs, items, spans) = self.parse_mod(&token::Eof)?;
let (attrs, items, spans) = self.parse_mod(exp!(Eof))?;
Ok(ast::Crate { attrs, items, spans, id: DUMMY_NODE_ID, is_placeholder: false })
}
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
fn parse_item_mod(&mut self, attrs: &mut AttrVec) -> PResult<'a, ItemInfo> {
let safety = self.parse_safety(Case::Sensitive);
self.expect_keyword(kw::Mod)?;
self.expect_keyword(exp!(Mod))?;
let id = self.parse_ident()?;
let mod_kind = if self.eat(&token::Semi) {
let mod_kind = if self.eat(exp!(Semi)) {
ModKind::Unloaded
} else {
self.expect(&token::OpenDelim(Delimiter::Brace))?;
let (inner_attrs, items, inner_span) =
self.parse_mod(&token::CloseDelim(Delimiter::Brace))?;
self.expect(exp!(OpenBrace))?;
let (inner_attrs, items, inner_span) = self.parse_mod(exp!(CloseBrace))?;
attrs.extend(inner_attrs);
ModKind::Loaded(items, Inline::Yes, inner_span, Ok(()))
};
@ -55,7 +55,7 @@ impl<'a> Parser<'a> {
/// - `}` for mod items
pub fn parse_mod(
&mut self,
term: &TokenKind,
term: ExpTokenPair<'_>,
) -> PResult<'a, (AttrVec, ThinVec<P<Item>>, ModSpans)> {
let lo = self.token.span;
let attrs = self.parse_inner_attributes()?;
@ -209,15 +209,15 @@ impl<'a> Parser<'a> {
let check_pub = def == &Defaultness::Final;
let mut def_ = || mem::replace(def, Defaultness::Final);
let info = if self.eat_keyword_case(kw::Use, case) {
let info = if self.eat_keyword_case(exp!(Use), case) {
self.parse_use_item()?
} else if self.check_fn_front_matter(check_pub, case) {
// FUNCTION ITEM
let (ident, sig, generics, body) =
self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?;
(ident, ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, body })))
} else if self.eat_keyword(kw::Extern) {
if self.eat_keyword(kw::Crate) {
} else if self.eat_keyword(exp!(Extern)) {
if self.eat_keyword(exp!(Crate)) {
// EXTERN CRATE
self.parse_item_extern_crate()?
} else {
@ -227,7 +227,7 @@ impl<'a> Parser<'a> {
} else if self.is_unsafe_foreign_mod() {
// EXTERN BLOCK
let safety = self.parse_safety(Case::Sensitive);
self.expect_keyword(kw::Extern)?;
self.expect_keyword(exp!(Extern))?;
self.parse_item_foreign_mod(attrs, safety)?
} else if self.is_static_global() {
let safety = self.parse_safety(Case::Sensitive);
@ -255,28 +255,28 @@ impl<'a> Parser<'a> {
})),
)
}
} else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() {
} else if self.check_keyword(exp!(Trait)) || self.check_auto_or_unsafe_trait_item() {
// TRAIT ITEM
self.parse_item_trait(attrs, lo)?
} else if self.check_keyword(kw::Impl)
|| self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Impl])
} else if self.check_keyword(exp!(Impl))
|| self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Impl])
{
// IMPL ITEM
self.parse_item_impl(attrs, def_())?
} else if self.is_reuse_path_item() {
self.parse_item_delegation()?
} else if self.check_keyword(kw::Mod)
|| self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Mod])
} else if self.check_keyword(exp!(Mod))
|| self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Mod])
{
// MODULE ITEM
self.parse_item_mod(attrs)?
} else if self.eat_keyword(kw::Type) {
} else if self.eat_keyword(exp!(Type)) {
// TYPE ITEM
self.parse_type_alias(def_())?
} else if self.eat_keyword(kw::Enum) {
} else if self.eat_keyword(exp!(Enum)) {
// ENUM ITEM
self.parse_item_enum()?
} else if self.eat_keyword(kw::Struct) {
} else if self.eat_keyword(exp!(Struct)) {
// STRUCT ITEM
self.parse_item_struct()?
} else if self.is_kw_followed_by_ident(kw::Union) {
@ -286,7 +286,7 @@ impl<'a> Parser<'a> {
} else if self.is_builtin() {
// BUILTIN# ITEM
return self.parse_item_builtin();
} else if self.eat_keyword(kw::Macro) {
} else if self.eat_keyword(exp!(Macro)) {
// MACROS 2.0 ITEM
self.parse_item_decl_macro(lo)?
} else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {
@ -407,13 +407,13 @@ impl<'a> Parser<'a> {
};
let mut found_generics = false;
if self.check(&token::Lt) {
if self.check(exp!(Lt)) {
found_generics = true;
self.eat_to_tokens(&[&token::Gt]);
self.eat_to_tokens(&[exp!(Gt)]);
self.bump(); // `>`
}
let err = if self.check(&token::OpenDelim(Delimiter::Brace)) {
let err = if self.check(exp!(OpenBrace)) {
// possible struct or enum definition where `struct` or `enum` was forgotten
if self.look_ahead(1, |t| *t == token::CloseDelim(Delimiter::Brace)) {
// `S {}` could be unit enum or struct
@ -426,25 +426,23 @@ impl<'a> Parser<'a> {
} else {
Some(errors::MissingKeywordForItemDefinition::Enum { span, insert_span, ident })
}
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
} else if self.check(exp!(OpenParen)) {
// possible function or tuple struct definition where `fn` or `struct` was forgotten
self.bump(); // `(`
let is_method = self.recover_self_param();
self.consume_block(Delimiter::Parenthesis, ConsumeClosingDelim::Yes);
self.consume_block(exp!(OpenParen), exp!(CloseParen), ConsumeClosingDelim::Yes);
let err = if self.check(&token::RArrow)
|| self.check(&token::OpenDelim(Delimiter::Brace))
{
self.eat_to_tokens(&[&token::OpenDelim(Delimiter::Brace)]);
let err = if self.check(exp!(RArrow)) || self.check(exp!(OpenBrace)) {
self.eat_to_tokens(&[exp!(OpenBrace)]);
self.bump(); // `{`
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);
if is_method {
errors::MissingKeywordForItemDefinition::Method { span, insert_span, ident }
} else {
errors::MissingKeywordForItemDefinition::Function { span, insert_span, ident }
}
} else if is_pub && self.check(&token::Semi) {
} else if is_pub && self.check(exp!(Semi)) {
errors::MissingKeywordForItemDefinition::Struct { span, insert_span, ident }
} else {
errors::MissingKeywordForItemDefinition::Ambiguous {
@ -479,7 +477,7 @@ impl<'a> Parser<'a> {
/// Parses an item macro, e.g., `item!();`.
fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> {
let path = self.parse_path(PathStyle::Mod)?; // `foo::bar`
self.expect(&token::Not)?; // `!`
self.expect(exp!(Not))?; // `!`
match self.parse_delim_args() {
// `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`.
Ok(args) => {
@ -539,7 +537,7 @@ impl<'a> Parser<'a> {
fn parse_polarity(&mut self) -> ast::ImplPolarity {
// Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
if self.check(&token::Not) && self.look_ahead(1, |t| t.can_begin_type()) {
if self.check(exp!(Not)) && self.look_ahead(1, |t| t.can_begin_type()) {
self.bump(); // `!`
ast::ImplPolarity::Negative(self.prev_token.span)
} else {
@ -567,7 +565,7 @@ impl<'a> Parser<'a> {
defaultness: Defaultness,
) -> PResult<'a, ItemInfo> {
let safety = self.parse_safety(Case::Sensitive);
self.expect_keyword(kw::Impl)?;
self.expect_keyword(exp!(Impl))?;
// First, parse generic parameters if necessary.
let mut generics = if self.choose_generics_over_qpath(0) {
@ -617,7 +615,7 @@ impl<'a> Parser<'a> {
};
// If `for` is missing we try to recover.
let has_for = self.eat_keyword(kw::For);
let has_for = self.eat_keyword(exp!(For));
let missing_for_span = self.prev_token.span.between(self.token.span);
let ty_second = if self.token == token::DotDot {
@ -702,7 +700,7 @@ impl<'a> Parser<'a> {
fn parse_item_delegation(&mut self) -> PResult<'a, ItemInfo> {
let span = self.token.span;
self.expect_keyword(kw::Reuse)?;
self.expect_keyword(exp!(Reuse))?;
let (qself, path) = if self.eat_lt() {
let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
@ -712,23 +710,23 @@ impl<'a> Parser<'a> {
};
let rename = |this: &mut Self| {
Ok(if this.eat_keyword(kw::As) { Some(this.parse_ident()?) } else { None })
Ok(if this.eat_keyword(exp!(As)) { Some(this.parse_ident()?) } else { None })
};
let body = |this: &mut Self| {
Ok(if this.check(&token::OpenDelim(Delimiter::Brace)) {
Ok(if this.check(exp!(OpenBrace)) {
Some(this.parse_block()?)
} else {
this.expect(&token::Semi)?;
this.expect(exp!(Semi))?;
None
})
};
let (ident, item_kind) = if self.eat_path_sep() {
let suffixes = if self.eat(&token::BinOp(token::Star)) {
let suffixes = if self.eat(exp!(Star)) {
None
} else {
let parse_suffix = |p: &mut Self| Ok((p.parse_path_segment_ident()?, rename(p)?));
Some(self.parse_delim_comma_seq(Delimiter::Brace, parse_suffix)?.0)
Some(self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), parse_suffix)?.0)
};
let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? };
(Ident::empty(), ItemKind::DelegationMac(Box::new(deleg)))
@ -766,11 +764,11 @@ impl<'a> Parser<'a> {
return Ok(ThinVec::new());
}
self.expect(&token::OpenDelim(Delimiter::Brace))?;
self.expect(exp!(OpenBrace))?;
attrs.extend(self.parse_inner_attributes()?);
let mut items = ThinVec::new();
while !self.eat(&token::CloseDelim(Delimiter::Brace)) {
while !self.eat(exp!(CloseBrace)) {
if self.recover_doc_comment_before_brace() {
continue;
}
@ -811,7 +809,7 @@ impl<'a> Parser<'a> {
let mut err =
self.dcx().struct_span_err(non_item_span, "non-item in item list");
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);
if is_let {
err.span_suggestion_verbose(
non_item_span,
@ -837,7 +835,7 @@ impl<'a> Parser<'a> {
}
Ok(Some(item)) => items.extend(item),
Err(err) => {
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);
err.with_span_label(
open_brace_span,
"while parsing this item list starting here",
@ -880,7 +878,7 @@ impl<'a> Parser<'a> {
// We are interested in `default` followed by another identifier.
// However, we must avoid keywords that occur as binary operators.
// Currently, the only applicable keyword is `as` (`default as Ty`).
if self.check_keyword(kw::Default)
if self.check_keyword(exp!(Default))
&& self.look_ahead(1, |t| t.is_non_raw_ident_where(|i| i.name != kw::As))
{
self.bump(); // `default`
@ -893,33 +891,33 @@ impl<'a> Parser<'a> {
/// Is this an `(unsafe auto? | auto) trait` item?
fn check_auto_or_unsafe_trait_item(&mut self) -> bool {
// auto trait
self.check_keyword(kw::Auto) && self.is_keyword_ahead(1, &[kw::Trait])
self.check_keyword(exp!(Auto)) && self.is_keyword_ahead(1, &[kw::Trait])
// unsafe auto trait
|| self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto])
|| self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto])
}
/// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`.
fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemInfo> {
let safety = self.parse_safety(Case::Sensitive);
// Parse optional `auto` prefix.
let is_auto = if self.eat_keyword(kw::Auto) {
let is_auto = if self.eat_keyword(exp!(Auto)) {
self.psess.gated_spans.gate(sym::auto_traits, self.prev_token.span);
IsAuto::Yes
} else {
IsAuto::No
};
self.expect_keyword(kw::Trait)?;
self.expect_keyword(exp!(Trait))?;
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
// Parse optional colon and supertrait bounds.
let had_colon = self.eat(&token::Colon);
let had_colon = self.eat(exp!(Colon));
let span_at_colon = self.prev_token.span;
let bounds = if had_colon { self.parse_generic_bounds()? } else { Vec::new() };
let span_before_eq = self.prev_token.span;
if self.eat(&token::Eq) {
if self.eat(exp!(Eq)) {
// It's a trait alias.
if had_colon {
let span = span_at_colon.to(span_before_eq);
@ -1007,11 +1005,10 @@ impl<'a> Parser<'a> {
let mut generics = self.parse_generics()?;
// Parse optional colon and param bounds.
let bounds =
if self.eat(&token::Colon) { self.parse_generic_bounds()? } else { Vec::new() };
let bounds = if self.eat(exp!(Colon)) { self.parse_generic_bounds()? } else { Vec::new() };
let before_where_clause = self.parse_where_clause()?;
let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
let ty = if self.eat(exp!(Eq)) { Some(self.parse_ty()?) } else { None };
let after_where_clause = self.parse_where_clause()?;
@ -1064,46 +1061,44 @@ impl<'a> Parser<'a> {
let mut prefix =
ast::Path { segments: ThinVec::new(), span: lo.shrink_to_lo(), tokens: None };
let kind = if self.check(&token::OpenDelim(Delimiter::Brace))
|| self.check(&token::BinOp(token::Star))
|| self.is_import_coupler()
{
// `use *;` or `use ::*;` or `use {...};` or `use ::{...};`
let mod_sep_ctxt = self.token.span.ctxt();
if self.eat_path_sep() {
prefix
.segments
.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
}
self.parse_use_tree_glob_or_nested()?
} else {
// `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;`
prefix = self.parse_path(PathStyle::Mod)?;
if self.eat_path_sep() {
self.parse_use_tree_glob_or_nested()?
} else {
// Recover from using a colon as path separator.
while self.eat_noexpect(&token::Colon) {
self.dcx()
.emit_err(errors::SingleColonImportPath { span: self.prev_token.span });
// We parse the rest of the path and append it to the original prefix.
self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None)?;
prefix.span = lo.to(self.prev_token.span);
let kind =
if self.check(exp!(OpenBrace)) || self.check(exp!(Star)) || self.is_import_coupler() {
// `use *;` or `use ::*;` or `use {...};` or `use ::{...};`
let mod_sep_ctxt = self.token.span.ctxt();
if self.eat_path_sep() {
prefix
.segments
.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
}
UseTreeKind::Simple(self.parse_rename()?)
}
};
self.parse_use_tree_glob_or_nested()?
} else {
// `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;`
prefix = self.parse_path(PathStyle::Mod)?;
if self.eat_path_sep() {
self.parse_use_tree_glob_or_nested()?
} else {
// Recover from using a colon as path separator.
while self.eat_noexpect(&token::Colon) {
self.dcx()
.emit_err(errors::SingleColonImportPath { span: self.prev_token.span });
// We parse the rest of the path and append it to the original prefix.
self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None)?;
prefix.span = lo.to(self.prev_token.span);
}
UseTreeKind::Simple(self.parse_rename()?)
}
};
Ok(UseTree { prefix, kind, span: lo.to(self.prev_token.span) })
}
/// Parses `*` or `{...}`.
fn parse_use_tree_glob_or_nested(&mut self) -> PResult<'a, UseTreeKind> {
Ok(if self.eat(&token::BinOp(token::Star)) {
Ok(if self.eat(exp!(Star)) {
UseTreeKind::Glob
} else {
let lo = self.token.span;
@ -1120,7 +1115,7 @@ impl<'a> Parser<'a> {
/// USE_TREE_LIST = ∅ | (USE_TREE `,`)* USE_TREE [`,`]
/// ```
fn parse_use_tree_list(&mut self) -> PResult<'a, ThinVec<(UseTree, ast::NodeId)>> {
self.parse_delim_comma_seq(Delimiter::Brace, |p| {
self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), |p| {
p.recover_vcs_conflict_marker();
Ok((p.parse_use_tree()?, DUMMY_NODE_ID))
})
@ -1128,7 +1123,11 @@ impl<'a> Parser<'a> {
}
fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
if self.eat_keyword(kw::As) { self.parse_ident_or_underscore().map(Some) } else { Ok(None) }
if self.eat_keyword(exp!(As)) {
self.parse_ident_or_underscore().map(Some)
} else {
Ok(None)
}
}
fn parse_ident_or_underscore(&mut self) -> PResult<'a, Ident> {
@ -1168,15 +1167,15 @@ impl<'a> Parser<'a> {
self.parse_ident()
}?;
let dash = token::BinOp(token::BinOpToken::Minus);
if self.token != dash {
let dash = exp!(Minus);
if self.token != *dash.tok {
return Ok(ident);
}
// Accept `extern crate name-like-this` for better diagnostics.
let mut dashes = vec![];
let mut idents = vec![];
while self.eat(&dash) {
while self.eat(dash) {
dashes.push(self.prev_token.span);
idents.push(self.parse_ident()?);
}
@ -1217,9 +1216,9 @@ impl<'a> Parser<'a> {
&& self.token.is_keyword(kw::Unsafe)
&& self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace))
{
self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err().emit();
self.expect(exp!(OpenBrace)).unwrap_err().emit();
safety = Safety::Unsafe(self.token.span);
let _ = self.eat_keyword(kw::Unsafe);
let _ = self.eat_keyword(exp!(Unsafe));
}
let module = ast::ForeignMod {
extern_span,
@ -1285,7 +1284,7 @@ impl<'a> Parser<'a> {
}
fn is_static_global(&mut self) -> bool {
if self.check_keyword(kw::Static) {
if self.check_keyword(exp!(Static)) {
// Check if this could be a closure.
!self.look_ahead(1, |token| {
if token.is_keyword(kw::Move) {
@ -1294,20 +1293,19 @@ impl<'a> Parser<'a> {
matches!(token.kind, token::BinOp(token::Or) | token::OrOr)
})
} else {
let quals: &[Symbol] = &[kw::Unsafe, kw::Safe];
// `$qual static`
quals.iter().any(|&kw| self.check_keyword(kw))
(self.check_keyword(exp!(Unsafe)) || self.check_keyword(exp!(Safe)))
&& self.look_ahead(1, |t| t.is_keyword(kw::Static))
}
}
/// Recover on `const mut` with `const` already eaten.
fn recover_const_mut(&mut self, const_span: Span) {
if self.eat_keyword(kw::Mut) {
if self.eat_keyword(exp!(Mut)) {
let span = self.prev_token.span;
self.dcx()
.emit_err(errors::ConstGlobalCannotBeMutable { ident_span: span, const_span });
} else if self.eat_keyword(kw::Let) {
} else if self.eat_keyword(exp!(Let)) {
let span = self.prev_token.span;
self.dcx().emit_err(errors::ConstLetMutuallyExclusive { span: const_span.to(span) });
}
@ -1372,14 +1370,13 @@ impl<'a> Parser<'a> {
// Parse the type of a static item. That is, the `":" $ty` fragment.
// FIXME: This could maybe benefit from `.may_recover()`?
let ty = match (self.eat(&token::Colon), self.check(&token::Eq) | self.check(&token::Semi))
{
let ty = match (self.eat(exp!(Colon)), self.check(exp!(Eq)) | self.check(exp!(Semi))) {
(true, false) => self.parse_ty()?,
// If there wasn't a `:` or the colon was followed by a `=` or `;`, recover a missing type.
(colon, _) => self.recover_missing_global_item_type(colon, Some(mutability)),
};
let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
let expr = if self.eat(exp!(Eq)) { Some(self.parse_expr()?) } else { None };
self.expect_semi()?;
@ -1405,8 +1402,8 @@ impl<'a> Parser<'a> {
// Parse the type of a constant item. That is, the `":" $ty` fragment.
// FIXME: This could maybe benefit from `.may_recover()`?
let ty = match (
self.eat(&token::Colon),
self.check(&token::Eq) | self.check(&token::Semi) | self.check_keyword(kw::Where),
self.eat(exp!(Colon)),
self.check(exp!(Eq)) | self.check(exp!(Semi)) | self.check_keyword(exp!(Where)),
) {
(true, false) => self.parse_ty()?,
// If there wasn't a `:` or the colon was followed by a `=`, `;` or `where`, recover a missing type.
@ -1418,7 +1415,7 @@ impl<'a> Parser<'a> {
let before_where_clause =
if self.may_recover() { self.parse_where_clause()? } else { WhereClause::default() };
let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
let expr = if self.eat(exp!(Eq)) { Some(self.parse_expr()?) } else { None };
let after_where_clause = self.parse_where_clause()?;
@ -1531,31 +1528,33 @@ impl<'a> Parser<'a> {
self.bump();
(thin_vec![], Trailing::No)
} else {
self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant(id.span))
.map_err(|mut err| {
err.span_label(id.span, "while parsing this enum");
if self.token == token::Colon {
let snapshot = self.create_snapshot_for_diagnostic();
self.bump();
match self.parse_ty() {
Ok(_) => {
err.span_suggestion_verbose(
prev_span,
"perhaps you meant to use `struct` here",
"struct",
Applicability::MaybeIncorrect,
);
}
Err(e) => {
e.cancel();
}
self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), |p| {
p.parse_enum_variant(id.span)
})
.map_err(|mut err| {
err.span_label(id.span, "while parsing this enum");
if self.token == token::Colon {
let snapshot = self.create_snapshot_for_diagnostic();
self.bump();
match self.parse_ty() {
Ok(_) => {
err.span_suggestion_verbose(
prev_span,
"perhaps you meant to use `struct` here",
"struct",
Applicability::MaybeIncorrect,
);
}
Err(e) => {
e.cancel();
}
self.restore_snapshot(snapshot);
}
self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]);
self.bump(); // }
err
})?
self.restore_snapshot(snapshot);
}
self.eat_to_tokens(&[exp!(CloseBrace)]);
self.bump(); // }
err
})?
};
let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() };
@ -1588,7 +1587,7 @@ impl<'a> Parser<'a> {
return Ok((None, Trailing::from(this.token == token::Comma), UsePreAttrPos::No));
}
let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
let struct_def = if this.check(exp!(OpenBrace)) {
// Parse a struct variant.
let (fields, recovered) =
match this.parse_record_struct_body("struct", ident.span, false) {
@ -1598,7 +1597,7 @@ impl<'a> Parser<'a> {
// We handle `enum` to `struct` suggestion in the caller.
return Err(err);
}
this.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]);
this.eat_to_tokens(&[exp!(CloseBrace)]);
this.bump(); // }
err.span_label(span, "while parsing this enum");
err.help(help);
@ -1607,7 +1606,7 @@ impl<'a> Parser<'a> {
}
};
VariantData::Struct { fields, recovered }
} else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
} else if this.check(exp!(OpenParen)) {
let body = match this.parse_tuple_struct_body() {
Ok(body) => body,
Err(mut err) => {
@ -1615,7 +1614,7 @@ impl<'a> Parser<'a> {
// We handle `enum` to `struct` suggestion in the caller.
return Err(err);
}
this.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis)]);
this.eat_to_tokens(&[exp!(CloseParen)]);
this.bump(); // )
err.span_label(span, "while parsing this enum");
err.help(help);
@ -1629,7 +1628,7 @@ impl<'a> Parser<'a> {
};
let disr_expr =
if this.eat(&token::Eq) { Some(this.parse_expr_anon_const()?) } else { None };
if this.eat(exp!(Eq)) { Some(this.parse_expr_anon_const()?) } else { None };
let vr = ast::Variant {
ident,
@ -1680,7 +1679,7 @@ impl<'a> Parser<'a> {
let body = VariantData::Tuple(body, DUMMY_NODE_ID);
self.expect_semi()?;
body
} else if self.eat(&token::Semi) {
} else if self.eat(exp!(Semi)) {
// If we see a: `struct Foo<T> where T: Copy;` style decl.
VariantData::Unit(DUMMY_NODE_ID)
} else {
@ -1693,7 +1692,7 @@ impl<'a> Parser<'a> {
VariantData::Struct { fields, recovered }
}
// No `where` so: `struct Foo<T>;`
} else if self.eat(&token::Semi) {
} else if self.eat(exp!(Semi)) {
VariantData::Unit(DUMMY_NODE_ID)
// Record-style struct definition
} else if self.token == token::OpenDelim(Delimiter::Brace) {
@ -1762,14 +1761,18 @@ impl<'a> Parser<'a> {
) -> PResult<'a, (ThinVec<FieldDef>, Recovered)> {
let mut fields = ThinVec::new();
let mut recovered = Recovered::No;
if self.eat(&token::OpenDelim(Delimiter::Brace)) {
if self.eat(exp!(OpenBrace)) {
while self.token != token::CloseDelim(Delimiter::Brace) {
match self.parse_field_def(adt_ty) {
Ok(field) => {
fields.push(field);
}
Err(mut err) => {
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::No);
self.consume_block(
exp!(OpenBrace),
exp!(CloseBrace),
ConsumeClosingDelim::No,
);
err.span_label(ident_span, format!("while parsing this {adt_ty}"));
let guar = err.emit();
recovered = Recovered::Yes(guar);
@ -1777,7 +1780,7 @@ impl<'a> Parser<'a> {
}
}
}
self.expect(&token::CloseDelim(Delimiter::Brace))?;
self.expect(exp!(CloseBrace))?;
} else {
let token_str = super::token_descr(&self.token);
let where_str = if parsed_where { "" } else { "`where`, or " };
@ -1792,7 +1795,7 @@ impl<'a> Parser<'a> {
fn parse_unsafe_field(&mut self) -> Safety {
// not using parse_safety as that also accepts `safe`.
if self.eat_keyword(kw::Unsafe) {
if self.eat_keyword(exp!(Unsafe)) {
let span = self.prev_token.span;
self.psess.gated_spans.gate(sym::unsafe_fields, span);
Safety::Unsafe(span)
@ -1900,7 +1903,7 @@ impl<'a> Parser<'a> {
if self.token == token::Comma {
seen_comma = true;
}
if self.eat(&token::Semi) {
if self.eat(exp!(Semi)) {
let sp = self.prev_token.span;
let mut err =
self.dcx().struct_span_err(sp, format!("{adt_ty} fields are separated by `,`"));
@ -1924,7 +1927,7 @@ impl<'a> Parser<'a> {
missing_comma: None,
};
self.bump(); // consume the doc comment
let comma_after_doc_seen = self.eat(&token::Comma);
let comma_after_doc_seen = self.eat(exp!(Comma));
// `seen_comma` is always false, because we are inside doc block
// condition is here to make code more readable
if !seen_comma && comma_after_doc_seen {
@ -1949,13 +1952,13 @@ impl<'a> Parser<'a> {
if let TyKind::Path(_, Path { segments, .. }) = &a_var.ty.kind {
if let Some(last_segment) = segments.last() {
let guar = self.check_trailing_angle_brackets(last_segment, &[
&token::Comma,
&token::CloseDelim(Delimiter::Brace),
exp!(Comma),
exp!(CloseBrace),
]);
if let Some(_guar) = guar {
// Handle a case like `Vec<u8>>,` where we can continue parsing fields
// after the comma
let _ = self.eat(&token::Comma);
let _ = self.eat(exp!(Comma));
// `check_trailing_angle_brackets` already emitted a nicer error, as
// proven by the presence of `_guar`. We can continue parsing.
@ -1988,7 +1991,7 @@ impl<'a> Parser<'a> {
}
fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> {
if let Err(err) = self.expect(&token::Colon) {
if let Err(err) = self.expect(exp!(Colon)) {
let sm = self.psess.source_map();
let eq_typo = self.token == token::Eq && self.look_ahead(1, |t| t.is_path_start());
let semi_typo = self.token == token::Semi
@ -2096,7 +2099,7 @@ impl<'a> Parser<'a> {
self.expected_ident_found_err()
}
}
} else if self.eat_keyword(kw::Struct) {
} else if self.eat_keyword(exp!(Struct)) {
match self.parse_item_struct() {
Ok((ident, _)) => self
.dcx()
@ -2153,12 +2156,12 @@ impl<'a> Parser<'a> {
/// ```
fn parse_item_decl_macro(&mut self, lo: Span) -> PResult<'a, ItemInfo> {
let ident = self.parse_ident()?;
let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
let body = if self.check(exp!(OpenBrace)) {
self.parse_delim_args()? // `MacBody`
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
} else if self.check(exp!(OpenParen)) {
let params = self.parse_token_tree(); // `MacParams`
let pspan = params.span();
if !self.check(&token::OpenDelim(Delimiter::Brace)) {
if !self.check(exp!(OpenBrace)) {
self.unexpected()?;
}
let body = self.parse_token_tree(); // `MacBody`
@ -2178,7 +2181,7 @@ impl<'a> Parser<'a> {
/// Is this a possibly malformed start of a `macro_rules! foo` item definition?
fn is_macro_rules_item(&mut self) -> IsMacroRulesItem {
if self.check_keyword(kw::MacroRules) {
if self.check_keyword(exp!(MacroRules)) {
let macro_rules_span = self.token.span;
if self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) {
@ -2203,14 +2206,14 @@ impl<'a> Parser<'a> {
vis: &Visibility,
has_bang: bool,
) -> PResult<'a, ItemInfo> {
self.expect_keyword(kw::MacroRules)?; // `macro_rules`
self.expect_keyword(exp!(MacroRules))?; // `macro_rules`
if has_bang {
self.expect(&token::Not)?; // `!`
self.expect(exp!(Not))?; // `!`
}
let ident = self.parse_ident()?;
if self.eat(&token::Not) {
if self.eat(exp!(Not)) {
// Handle macro_rules! foo!
let span = self.prev_token.span;
self.dcx().emit_err(errors::MacroNameRemoveBang { span });
@ -2240,7 +2243,7 @@ impl<'a> Parser<'a> {
}
fn eat_semi_for_macro_if_needed(&mut self, args: &DelimArgs) {
if args.need_semicolon() && !self.eat(&token::Semi) {
if args.need_semicolon() && !self.eat(exp!(Semi)) {
self.report_invalid_macro_expansion_item(args);
}
}
@ -2416,11 +2419,8 @@ impl<'a> Parser<'a> {
req_body: bool,
fn_params_end: Option<Span>,
) -> PResult<'a, ErrorGuaranteed> {
let expected = if req_body {
&[token::OpenDelim(Delimiter::Brace)][..]
} else {
&[token::Semi, token::OpenDelim(Delimiter::Brace)]
};
let expected: &[_] =
if req_body { &[exp!(OpenBrace)] } else { &[exp!(Semi), exp!(OpenBrace)] };
match self.expected_one_of_not_found(&[], expected) {
Ok(error_guaranteed) => Ok(error_guaranteed),
Err(mut err) => {
@ -2505,14 +2505,14 @@ impl<'a> Parser<'a> {
self.token == TokenKind::Semi
} else {
// Only include `;` in list of expected tokens if body is not required
self.check(&TokenKind::Semi)
self.check(exp!(Semi))
};
let (inner_attrs, body) = if has_semi {
// Include the trailing semicolon in the span of the signature
self.expect_semi()?;
*sig_hi = self.prev_token.span;
(AttrVec::new(), None)
} else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() {
} else if self.check(exp!(OpenBrace)) || self.token.is_whole_block() {
self.parse_block_common(self.token.span, BlockCheckMode::Default, false)
.map(|(attrs, body)| (attrs, Some(body)))?
} else if self.token == token::Eq {
@ -2540,21 +2540,28 @@ impl<'a> Parser<'a> {
/// `check_pub` adds additional `pub` to the checks in case users place it
/// wrongly, can be used to ensure `pub` never comes after `default`.
pub(super) fn check_fn_front_matter(&mut self, check_pub: bool, case: Case) -> bool {
const ALL_QUALS: &[Symbol] =
&[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern];
const ALL_QUALS: &[ExpKeywordPair] = &[
exp!(Pub),
exp!(Gen),
exp!(Const),
exp!(Async),
exp!(Unsafe),
exp!(Safe),
exp!(Extern),
];
// We use an over-approximation here.
// `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
// `pub` is added in case users got confused with the ordering like `async pub fn`,
// only if it wasn't preceded by `default` as `default pub` is invalid.
let quals: &[Symbol] = if check_pub {
let quals: &[_] = if check_pub {
ALL_QUALS
} else {
&[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern]
&[exp!(Gen), exp!(Const), exp!(Async), exp!(Unsafe), exp!(Safe), exp!(Extern)]
};
self.check_keyword_case(kw::Fn, case) // Definitely an `fn`.
self.check_keyword_case(exp!(Fn), case) // Definitely an `fn`.
// `$qual fn` or `$qual $qual`:
|| quals.iter().any(|&kw| self.check_keyword_case(kw, case))
|| quals.iter().any(|&exp| self.check_keyword_case(exp, case))
&& self.look_ahead(1, |t| {
// `$qual fn`, e.g. `const fn` or `async fn`.
t.is_keyword_case(kw::Fn, case)
@ -2562,12 +2569,14 @@ impl<'a> Parser<'a> {
|| (
(
t.is_non_raw_ident_where(|i|
quals.contains(&i.name)
quals.iter().any(|exp| exp.kw == i.name)
// Rule out 2015 `const async: T = val`.
&& i.is_reserved()
)
|| case == Case::Insensitive
&& t.is_non_raw_ident_where(|i| quals.iter().any(|qual| qual.as_str() == i.name.as_str().to_lowercase()))
&& t.is_non_raw_ident_where(|i| quals.iter().any(|exp| {
exp.kw.as_str() == i.name.as_str().to_lowercase()
}))
)
// Rule out `unsafe extern {`.
&& !self.is_unsafe_foreign_mod()
@ -2575,12 +2584,13 @@ impl<'a> Parser<'a> {
&& !self.is_async_gen_block())
})
// `extern ABI fn`
|| self.check_keyword_case(kw::Extern, case)
|| self.check_keyword_case(exp!(Extern), case)
&& self.look_ahead(1, |t| t.can_begin_string_literal())
&& (self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case)) ||
// this branch is only for better diagnostics; `pub`, `unsafe`, etc. are not allowed here
// This branch is only for better diagnostics; `pub`, `unsafe`, etc. are not
// allowed here.
(self.may_recover()
&& self.look_ahead(2, |t| ALL_QUALS.iter().any(|&kw| t.is_keyword(kw)))
&& self.look_ahead(2, |t| ALL_QUALS.iter().any(|exp| t.is_keyword(exp.kw)))
&& self.look_ahead(3, |t| t.is_keyword_case(kw::Fn, case))))
}
@ -2628,7 +2638,7 @@ impl<'a> Parser<'a> {
Some(CoroutineKind::Async { .. }) | None => {}
}
if !self.eat_keyword_case(kw::Fn, case) {
if !self.eat_keyword_case(exp!(Fn), case) {
// It is possible for `expect_one_of` to recover given the contents of
// `self.expected_token_types`, therefore, do not use `self.unexpected()` which doesn't
// account for this.
@ -2648,7 +2658,7 @@ impl<'a> Parser<'a> {
let mut recover_safety = safety;
// This will allow the machine fix to directly place the keyword in the correct place or to indicate
// that the keyword is already present and the second instance should be removed.
let wrong_kw = if self.check_keyword(kw::Const) {
let wrong_kw = if self.check_keyword(exp!(Const)) {
match constness {
Const::Yes(sp) => Some(WrongKw::Duplicated(sp)),
Const::No => {
@ -2656,7 +2666,7 @@ impl<'a> Parser<'a> {
Some(WrongKw::Misplaced(async_start_sp))
}
}
} else if self.check_keyword(kw::Async) {
} else if self.check_keyword(exp!(Async)) {
match coroutine_kind {
Some(CoroutineKind::Async { span, .. }) => {
Some(WrongKw::Duplicated(span))
@ -2682,7 +2692,7 @@ impl<'a> Parser<'a> {
Some(WrongKw::Misplaced(unsafe_start_sp))
}
}
} else if self.check_keyword(kw::Unsafe) {
} else if self.check_keyword(exp!(Unsafe)) {
match safety {
Safety::Unsafe(sp) => Some(WrongKw::Duplicated(sp)),
Safety::Safe(sp) => {
@ -2694,7 +2704,7 @@ impl<'a> Parser<'a> {
Some(WrongKw::Misplaced(ext_start_sp))
}
}
} else if self.check_keyword(kw::Safe) {
} else if self.check_keyword(exp!(Safe)) {
match safety {
Safety::Safe(sp) => Some(WrongKw::Duplicated(sp)),
Safety::Unsafe(sp) => {
@ -2740,7 +2750,7 @@ impl<'a> Parser<'a> {
}
}
// Recover incorrect visibility order such as `async pub`
else if self.check_keyword(kw::Pub) {
else if self.check_keyword(exp!(Pub)) {
let sp = sp_start.to(self.prev_token.span);
if let Ok(snippet) = self.span_to_snippet(sp) {
let current_vis = match self.parse_visibility(FollowedByType::No) {
@ -2843,7 +2853,7 @@ impl<'a> Parser<'a> {
};
p.restore_snapshot(snapshot);
// Skip every token until next possible arg or end.
p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(Delimiter::Parenthesis)]);
p.eat_to_tokens(&[exp!(Comma), exp!(CloseParen)]);
// Create a placeholder argument for proper arg count (issue #34264).
Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span)), guar))
});
@ -2954,7 +2964,7 @@ impl<'a> Parser<'a> {
let parse_self_possibly_typed = |this: &mut Self, m| {
let eself_ident = expect_self_ident(this);
let eself_hi = this.prev_token.span;
let eself = if this.eat(&token::Colon) {
let eself = if this.eat(exp!(Colon)) {
SelfKind::Explicit(this.parse_ty()?, m)
} else {
SelfKind::Value(m)

View file

@ -8,6 +8,7 @@ mod nonterminal;
mod pat;
mod path;
mod stmt;
pub mod token_type;
mod ty;
use std::assert_matches::debug_assert_matches;
@ -39,11 +40,14 @@ use rustc_index::interval::IntervalSet;
use rustc_session::parse::ParseSess;
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
use thin_vec::ThinVec;
use token_type::TokenTypeSet;
pub use token_type::{ExpKeywordPair, ExpTokenPair, TokenType};
use tracing::debug;
use crate::errors::{
self, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral,
};
use crate::exp;
use crate::lexer::UnmatchedDelim;
#[cfg(test)]
@ -141,7 +145,7 @@ pub struct Parser<'a> {
pub prev_token: Token,
pub capture_cfg: bool,
restrictions: Restrictions,
expected_token_types: Vec<TokenType>,
expected_token_types: TokenTypeSet,
token_cursor: TokenCursor,
// The number of calls to `bump`, i.e. the position in the token stream.
num_bump_calls: u32,
@ -367,48 +371,21 @@ impl TokenCursor {
}
}
#[derive(Debug, Clone, PartialEq)]
enum TokenType {
Token(TokenKind),
Keyword(Symbol),
Operator,
Lifetime,
Ident,
Path,
Type,
Const,
}
impl TokenType {
fn to_string(&self) -> String {
match self {
TokenType::Token(t) => format!("`{}`", pprust::token_kind_to_string(t)),
TokenType::Keyword(kw) => format!("`{kw}`"),
TokenType::Operator => "an operator".to_string(),
TokenType::Lifetime => "lifetime".to_string(),
TokenType::Ident => "identifier".to_string(),
TokenType::Path => "path".to_string(),
TokenType::Type => "type".to_string(),
TokenType::Const => "a const expression".to_string(),
}
}
}
/// A sequence separator.
#[derive(Debug)]
struct SeqSep {
struct SeqSep<'a> {
/// The separator token.
sep: Option<TokenKind>,
sep: Option<ExpTokenPair<'a>>,
/// `true` if a trailing separator is allowed.
trailing_sep_allowed: bool,
}
impl SeqSep {
fn trailing_allowed(t: TokenKind) -> SeqSep {
SeqSep { sep: Some(t), trailing_sep_allowed: true }
impl<'a> SeqSep<'a> {
fn trailing_allowed(sep: ExpTokenPair<'a>) -> SeqSep<'a> {
SeqSep { sep: Some(sep), trailing_sep_allowed: true }
}
fn none() -> SeqSep {
fn none() -> SeqSep<'a> {
SeqSep { sep: None, trailing_sep_allowed: false }
}
}
@ -490,7 +467,7 @@ impl<'a> Parser<'a> {
prev_token: Token::dummy(),
capture_cfg: false,
restrictions: Restrictions::empty(),
expected_token_types: Vec::new(),
expected_token_types: TokenTypeSet::new(),
token_cursor: TokenCursor { curr: TokenTreeCursor::new(stream), stack: Vec::new() },
num_bump_calls: 0,
break_last_token: 0,
@ -553,16 +530,16 @@ impl<'a> Parser<'a> {
}
/// Expects and consumes the token `t`. Signals an error if the next token is not `t`.
pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, Recovered> {
pub fn expect(&mut self, exp: ExpTokenPair<'_>) -> PResult<'a, Recovered> {
if self.expected_token_types.is_empty() {
if self.token == *t {
if self.token == *exp.tok {
self.bump();
Ok(Recovered::No)
} else {
self.unexpected_try_recover(t)
self.unexpected_try_recover(exp.tok)
}
} else {
self.expect_one_of(slice::from_ref(t), &[])
self.expect_one_of(slice::from_ref(&exp), &[])
}
}
@ -571,13 +548,13 @@ impl<'a> Parser<'a> {
/// anything. Signal a fatal error if next token is unexpected.
fn expect_one_of(
&mut self,
edible: &[TokenKind],
inedible: &[TokenKind],
edible: &[ExpTokenPair<'_>],
inedible: &[ExpTokenPair<'_>],
) -> PResult<'a, Recovered> {
if edible.contains(&self.token.kind) {
if edible.iter().any(|exp| exp.tok == &self.token.kind) {
self.bump();
Ok(Recovered::No)
} else if inedible.contains(&self.token.kind) {
} else if inedible.iter().any(|exp| exp.tok == &self.token.kind) {
// leave it in the input
Ok(Recovered::No)
} else if self.token != token::Eof
@ -622,10 +599,10 @@ impl<'a> Parser<'a> {
/// This method will automatically add `tok` to `expected_token_types` if `tok` is not
/// encountered.
#[inline]
fn check(&mut self, tok: &TokenKind) -> bool {
let is_present = self.token == *tok;
fn check(&mut self, exp: ExpTokenPair<'_>) -> bool {
let is_present = self.token == *exp.tok;
if !is_present {
self.expected_token_types.push(TokenType::Token(tok.clone()));
self.expected_token_types.insert(exp.token_type);
}
is_present
}
@ -653,8 +630,8 @@ impl<'a> Parser<'a> {
/// Consumes a token 'tok' if it exists. Returns whether the given token was present.
#[inline]
#[must_use]
pub fn eat(&mut self, tok: &TokenKind) -> bool {
let is_present = self.check(tok);
pub fn eat(&mut self, exp: ExpTokenPair<'_>) -> bool {
let is_present = self.check(exp);
if is_present {
self.bump()
}
@ -665,23 +642,23 @@ impl<'a> Parser<'a> {
/// An expectation is also added for diagnostics purposes.
#[inline]
#[must_use]
fn check_keyword(&mut self, kw: Symbol) -> bool {
let is_keyword = self.token.is_keyword(kw);
fn check_keyword(&mut self, exp: ExpKeywordPair) -> bool {
let is_keyword = self.token.is_keyword(exp.kw);
if !is_keyword {
self.expected_token_types.push(TokenType::Keyword(kw));
self.expected_token_types.insert(exp.token_type);
}
is_keyword
}
#[inline]
#[must_use]
fn check_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
if self.check_keyword(kw) {
fn check_keyword_case(&mut self, exp: ExpKeywordPair, case: Case) -> bool {
if self.check_keyword(exp) {
true
// Do an ASCII case-insensitive match, because all keywords are ASCII.
} else if case == Case::Insensitive
&& let Some((ident, IdentIsRaw::No)) = self.token.ident()
&& ident.as_str().eq_ignore_ascii_case(kw.as_str())
&& ident.as_str().eq_ignore_ascii_case(exp.kw.as_str())
{
true
} else {
@ -694,8 +671,8 @@ impl<'a> Parser<'a> {
// Public for rustc_builtin_macros and rustfmt usage.
#[inline]
#[must_use]
pub fn eat_keyword(&mut self, kw: Symbol) -> bool {
let is_keyword = self.check_keyword(kw);
pub fn eat_keyword(&mut self, exp: ExpKeywordPair) -> bool {
let is_keyword = self.check_keyword(exp);
if is_keyword {
self.bump();
}
@ -707,14 +684,14 @@ impl<'a> Parser<'a> {
/// This is useful for recovery.
#[inline]
#[must_use]
fn eat_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
if self.eat_keyword(kw) {
fn eat_keyword_case(&mut self, exp: ExpKeywordPair, case: Case) -> bool {
if self.eat_keyword(exp) {
true
} else if case == Case::Insensitive
&& let Some((ident, IdentIsRaw::No)) = self.token.ident()
&& ident.as_str().to_lowercase() == kw.as_str().to_lowercase()
&& ident.as_str().to_lowercase() == exp.kw.as_str().to_lowercase()
{
self.dcx().emit_err(errors::KwBadCase { span: ident.span, kw: kw.as_str() });
self.dcx().emit_err(errors::KwBadCase { span: ident.span, kw: exp.kw.as_str() });
self.bump();
true
} else {
@ -738,8 +715,8 @@ impl<'a> Parser<'a> {
/// If the given word is not a keyword, signals an error.
/// If the next token is not the given word, signals an error.
/// Otherwise, eats it.
pub fn expect_keyword(&mut self, kw: Symbol) -> PResult<'a, ()> {
if !self.eat_keyword(kw) { self.unexpected() } else { Ok(()) }
pub fn expect_keyword(&mut self, exp: ExpKeywordPair) -> PResult<'a, ()> {
if !self.eat_keyword(exp) { self.unexpected() } else { Ok(()) }
}
/// Is the given keyword `kw` followed by a non-reserved identifier?
@ -748,9 +725,9 @@ impl<'a> Parser<'a> {
}
#[inline]
fn check_or_expected(&mut self, ok: bool, typ: TokenType) -> bool {
fn check_or_expected(&mut self, ok: bool, token_type: TokenType) -> bool {
if !ok {
self.expected_token_types.push(typ);
self.expected_token_types.insert(token_type);
}
ok
}
@ -795,22 +772,19 @@ impl<'a> Parser<'a> {
/// Otherwise returns `false`.
#[inline]
fn check_plus(&mut self) -> bool {
self.check_or_expected(
self.token.is_like_plus(),
TokenType::Token(token::BinOp(token::Plus)),
)
self.check_or_expected(self.token.is_like_plus(), TokenType::Plus)
}
/// Eats the expected token if it's present possibly breaking
/// compound tokens like multi-character operators in process.
/// Returns `true` if the token was eaten.
fn break_and_eat(&mut self, expected: TokenKind) -> bool {
if self.token == expected {
fn break_and_eat(&mut self, exp: ExpTokenPair<'_>) -> bool {
if self.token == *exp.tok {
self.bump();
return true;
}
match self.token.kind.break_two_token_op(1) {
Some((first, second)) if first == expected => {
Some((first, second)) if first == *exp.tok => {
let first_span = self.psess.source_map().start_point(self.token.span);
let second_span = self.token.span.with_lo(first_span.hi());
self.token = Token::new(first, first_span);
@ -827,7 +801,7 @@ impl<'a> Parser<'a> {
true
}
_ => {
self.expected_token_types.push(TokenType::Token(expected));
self.expected_token_types.insert(exp.token_type);
false
}
}
@ -835,24 +809,24 @@ impl<'a> Parser<'a> {
/// Eats `+` possibly breaking tokens like `+=` in process.
fn eat_plus(&mut self) -> bool {
self.break_and_eat(token::BinOp(token::Plus))
self.break_and_eat(exp!(Plus))
}
/// Eats `&` possibly breaking tokens like `&&` in process.
/// Signals an error if `&` is not eaten.
fn expect_and(&mut self) -> PResult<'a, ()> {
if self.break_and_eat(token::BinOp(token::And)) { Ok(()) } else { self.unexpected() }
if self.break_and_eat(exp!(And)) { Ok(()) } else { self.unexpected() }
}
/// Eats `|` possibly breaking tokens like `||` in process.
/// Signals an error if `|` was not eaten.
fn expect_or(&mut self) -> PResult<'a, ()> {
if self.break_and_eat(token::BinOp(token::Or)) { Ok(()) } else { self.unexpected() }
if self.break_and_eat(exp!(Or)) { Ok(()) } else { self.unexpected() }
}
/// Eats `<` possibly breaking tokens like `<<` in process.
fn eat_lt(&mut self) -> bool {
let ate = self.break_and_eat(token::Lt);
let ate = self.break_and_eat(exp!(Lt));
if ate {
// See doc comment for `unmatched_angle_bracket_count`.
self.unmatched_angle_bracket_count += 1;
@ -870,7 +844,7 @@ impl<'a> Parser<'a> {
/// Eats `>` possibly breaking tokens like `>>` in process.
/// Signals an error if `>` was not eaten.
fn expect_gt(&mut self) -> PResult<'a, ()> {
if self.break_and_eat(token::Gt) {
if self.break_and_eat(exp!(Gt)) {
// See doc comment for `unmatched_angle_bracket_count`.
if self.unmatched_angle_bracket_count > 0 {
self.unmatched_angle_bracket_count -= 1;
@ -885,10 +859,10 @@ impl<'a> Parser<'a> {
/// Checks if the next token is contained within `closes`, and returns `true` if so.
fn expect_any_with_type(
&mut self,
closes_expected: &[&TokenKind],
closes_expected: &[ExpTokenPair<'_>],
closes_not_expected: &[&TokenKind],
) -> bool {
closes_expected.iter().any(|k| self.check(k))
closes_expected.iter().any(|&close| self.check(close))
|| closes_not_expected.iter().any(|k| self.check_noexpect(k))
}
@ -897,9 +871,9 @@ impl<'a> Parser<'a> {
/// closing bracket.
fn parse_seq_to_before_tokens<T>(
&mut self,
closes_expected: &[&TokenKind],
closes_expected: &[ExpTokenPair<'_>],
closes_not_expected: &[&TokenKind],
sep: SeqSep,
sep: SeqSep<'_>,
mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> {
let mut first = true;
@ -911,13 +885,13 @@ impl<'a> Parser<'a> {
if let token::CloseDelim(..) | token::Eof = self.token.kind {
break;
}
if let Some(t) = &sep.sep {
if let Some(exp) = sep.sep {
if first {
// no separator for the first element
first = false;
} else {
// check for separator
match self.expect(t) {
match self.expect(exp) {
Ok(Recovered::No) => {
self.current_closure.take();
}
@ -928,7 +902,7 @@ impl<'a> Parser<'a> {
}
Err(mut expect_err) => {
let sp = self.prev_token.span.shrink_to_hi();
let token_str = pprust::token_kind_to_string(t);
let token_str = pprust::token_kind_to_string(exp.tok);
match self.current_closure.take() {
Some(closure_spans) if self.token == TokenKind::Semi => {
@ -948,7 +922,7 @@ impl<'a> Parser<'a> {
_ => {
// Attempt to keep parsing if it was a similar separator.
if let Some(tokens) = t.similar_tokens() {
if let Some(tokens) = exp.tok.similar_tokens() {
if tokens.contains(&self.token.kind) {
self.bump();
}
@ -998,15 +972,17 @@ impl<'a> Parser<'a> {
// Parsing failed, therefore it must be something more serious
// than just a missing separator.
for xx in &e.children {
// propagate the help message from sub error 'e' to main error 'expect_err;
// Propagate the help message from sub error `e` to main
// error `expect_err`.
expect_err.children.push(xx.clone());
}
e.cancel();
if self.token == token::Colon {
// we will try to recover in `maybe_recover_struct_lit_bad_delims`
// We will try to recover in
// `maybe_recover_struct_lit_bad_delims`.
return Err(expect_err);
} else if let [token::CloseDelim(Delimiter::Parenthesis)] =
closes_expected
} else if let [exp] = closes_expected
&& exp.token_type == TokenType::CloseParen
{
return Err(expect_err);
} else {
@ -1040,7 +1016,7 @@ impl<'a> Parser<'a> {
) -> PResult<'a, ()> {
let initial_semicolon = self.token.span;
while self.eat(&TokenKind::Semi) {
while self.eat(exp!(Semi)) {
let _ = self.parse_stmt_without_recovery(false, ForceCollect::No).unwrap_or_else(|e| {
e.cancel();
None
@ -1096,8 +1072,8 @@ impl<'a> Parser<'a> {
/// closing bracket.
fn parse_seq_to_before_end<T>(
&mut self,
close: &TokenKind,
sep: SeqSep,
close: ExpTokenPair<'_>,
sep: SeqSep<'_>,
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> {
self.parse_seq_to_before_tokens(&[close], &[], sep, f)
@ -1108,8 +1084,8 @@ impl<'a> Parser<'a> {
/// closing bracket.
fn parse_seq_to_end<T>(
&mut self,
close: &TokenKind,
sep: SeqSep,
close: ExpTokenPair<'_>,
sep: SeqSep<'_>,
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (ThinVec<T>, Trailing)> {
let (val, trailing, recovered) = self.parse_seq_to_before_end(close, sep, f)?;
@ -1127,9 +1103,9 @@ impl<'a> Parser<'a> {
/// closing bracket.
fn parse_unspanned_seq<T>(
&mut self,
open: &TokenKind,
close: &TokenKind,
sep: SeqSep,
open: ExpTokenPair<'_>,
close: ExpTokenPair<'_>,
sep: SeqSep<'_>,
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (ThinVec<T>, Trailing)> {
self.expect(open)?;
@ -1141,15 +1117,11 @@ impl<'a> Parser<'a> {
/// closing bracket.
fn parse_delim_comma_seq<T>(
&mut self,
delim: Delimiter,
open: ExpTokenPair<'_>,
close: ExpTokenPair<'_>,
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (ThinVec<T>, Trailing)> {
self.parse_unspanned_seq(
&token::OpenDelim(delim),
&token::CloseDelim(delim),
SeqSep::trailing_allowed(token::Comma),
f,
)
self.parse_unspanned_seq(open, close, SeqSep::trailing_allowed(exp!(Comma)), f)
}
/// Parses a comma-separated sequence delimited by parentheses (e.g. `(x, y)`).
@ -1159,7 +1131,7 @@ impl<'a> Parser<'a> {
&mut self,
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, (ThinVec<T>, Trailing)> {
self.parse_delim_comma_seq(Delimiter::Parenthesis, f)
self.parse_delim_comma_seq(exp!(OpenParen), exp!(CloseParen), f)
}
/// Advance the parser by one token using provided token as the next one.
@ -1265,11 +1237,11 @@ impl<'a> Parser<'a> {
/// Parses asyncness: `async` or nothing.
fn parse_coroutine_kind(&mut self, case: Case) -> Option<CoroutineKind> {
let span = self.token.uninterpolated_span();
if self.eat_keyword_case(kw::Async, case) {
if self.eat_keyword_case(exp!(Async), case) {
// FIXME(gen_blocks): Do we want to unconditionally parse `gen` and then
// error if edition <= 2024, like we do with async and edition <= 2018?
if self.token.uninterpolated_span().at_least_rust_2024()
&& self.eat_keyword_case(kw::Gen, case)
&& self.eat_keyword_case(exp!(Gen), case)
{
let gen_span = self.prev_token.uninterpolated_span();
Some(CoroutineKind::AsyncGen {
@ -1285,7 +1257,7 @@ impl<'a> Parser<'a> {
})
}
} else if self.token.uninterpolated_span().at_least_rust_2024()
&& self.eat_keyword_case(kw::Gen, case)
&& self.eat_keyword_case(exp!(Gen), case)
{
Some(CoroutineKind::Gen {
span,
@ -1299,9 +1271,9 @@ impl<'a> Parser<'a> {
/// Parses fn unsafety: `unsafe`, `safe` or nothing.
fn parse_safety(&mut self, case: Case) -> Safety {
if self.eat_keyword_case(kw::Unsafe, case) {
if self.eat_keyword_case(exp!(Unsafe), case) {
Safety::Unsafe(self.prev_token.uninterpolated_span())
} else if self.eat_keyword_case(kw::Safe, case) {
} else if self.eat_keyword_case(exp!(Safe), case) {
Safety::Safe(self.prev_token.uninterpolated_span())
} else {
Safety::Default
@ -1327,7 +1299,7 @@ impl<'a> Parser<'a> {
if (self.check_const_closure() == is_closure)
&& !self
.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
&& self.eat_keyword_case(kw::Const, case)
&& self.eat_keyword_case(exp!(Const), case)
{
Const::Yes(self.prev_token.uninterpolated_span())
} else {
@ -1340,7 +1312,7 @@ impl<'a> Parser<'a> {
if pat {
self.psess.gated_spans.gate(sym::inline_const_pat, span);
}
self.expect_keyword(kw::Const)?;
self.expect_keyword(exp!(Const))?;
let (attrs, blk) = self.parse_inner_attrs_and_block()?;
let anon_const = AnonConst {
id: DUMMY_NODE_ID,
@ -1352,19 +1324,19 @@ impl<'a> Parser<'a> {
/// Parses mutability (`mut` or nothing).
fn parse_mutability(&mut self) -> Mutability {
if self.eat_keyword(kw::Mut) { Mutability::Mut } else { Mutability::Not }
if self.eat_keyword(exp!(Mut)) { Mutability::Mut } else { Mutability::Not }
}
/// Parses reference binding mode (`ref`, `ref mut`, or nothing).
fn parse_byref(&mut self) -> ByRef {
if self.eat_keyword(kw::Ref) { ByRef::Yes(self.parse_mutability()) } else { ByRef::No }
if self.eat_keyword(exp!(Ref)) { ByRef::Yes(self.parse_mutability()) } else { ByRef::No }
}
/// Possibly parses mutability (`const` or `mut`).
fn parse_const_or_mut(&mut self) -> Option<Mutability> {
if self.eat_keyword(kw::Mut) {
if self.eat_keyword(exp!(Mut)) {
Some(Mutability::Mut)
} else if self.eat_keyword(kw::Const) {
} else if self.eat_keyword(exp!(Const)) {
Some(Mutability::Not)
} else {
None
@ -1395,7 +1367,7 @@ impl<'a> Parser<'a> {
fn parse_attr_args(&mut self) -> PResult<'a, AttrArgs> {
Ok(if let Some(args) = self.parse_delim_args_inner() {
AttrArgs::Delimited(args)
} else if self.eat(&token::Eq) {
} else if self.eat(exp!(Eq)) {
let eq_span = self.prev_token.span;
AttrArgs::Eq { eq_span, expr: self.parse_expr_force_collect()? }
} else {
@ -1404,9 +1376,9 @@ impl<'a> Parser<'a> {
}
fn parse_delim_args_inner(&mut self) -> Option<DelimArgs> {
let delimited = self.check(&token::OpenDelim(Delimiter::Parenthesis))
|| self.check(&token::OpenDelim(Delimiter::Bracket))
|| self.check(&token::OpenDelim(Delimiter::Brace));
let delimited = self.check(exp!(OpenParen))
|| self.check(exp!(OpenBracket))
|| self.check(exp!(OpenBrace));
delimited.then(|| {
let TokenTree::Delimited(dspan, _, delim, tokens) = self.parse_token_tree() else {
@ -1485,7 +1457,7 @@ impl<'a> Parser<'a> {
pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> {
maybe_whole!(self, NtVis, |vis| vis.into_inner());
if !self.eat_keyword(kw::Pub) {
if !self.eat_keyword(exp!(Pub)) {
// We need a span for our `Spanned<VisibilityKind>`, but there's inherently no
// keyword to grab a span from for inherited visibility; an empty span at the
// beginning of the current token would seem to be the "Schelling span".
@ -1497,7 +1469,7 @@ impl<'a> Parser<'a> {
}
let lo = self.prev_token.span;
if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
if self.check(exp!(OpenParen)) {
// We don't `self.bump()` the `(` yet because this might be a struct definition where
// `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`.
// Because of this, we only `bump` the `(` if we're assured it is appropriate to do so
@ -1507,7 +1479,7 @@ impl<'a> Parser<'a> {
self.bump(); // `(`
self.bump(); // `in`
let path = self.parse_path(PathStyle::Mod)?; // `path`
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
self.expect(exp!(CloseParen))?; // `)`
let vis = VisibilityKind::Restricted {
path: P(path),
id: ast::DUMMY_NODE_ID,
@ -1524,7 +1496,7 @@ impl<'a> Parser<'a> {
// Parse `pub(crate)`, `pub(self)`, or `pub(super)`.
self.bump(); // `(`
let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self`
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
self.expect(exp!(CloseParen))?; // `)`
let vis = VisibilityKind::Restricted {
path: P(path),
id: ast::DUMMY_NODE_ID,
@ -1550,7 +1522,7 @@ impl<'a> Parser<'a> {
fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> {
self.bump(); // `(`
let path = self.parse_path(PathStyle::Mod)?;
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
self.expect(exp!(CloseParen))?; // `)`
let path_str = pprust::path_to_string(&path);
self.dcx()
@ -1561,7 +1533,7 @@ impl<'a> Parser<'a> {
/// Parses `extern string_literal?`.
fn parse_extern(&mut self, case: Case) -> Extern {
if self.eat_keyword_case(kw::Extern, case) {
if self.eat_keyword_case(exp!(Extern), case) {
let mut extern_span = self.prev_token.span;
let abi = self.parse_abi();
if let Some(abi) = abi {
@ -1601,7 +1573,7 @@ impl<'a> Parser<'a> {
/// Checks for `::` or, potentially, `:::` and then look ahead after it.
fn check_path_sep_and_look_ahead(&mut self, looker: impl Fn(&Token) -> bool) -> bool {
if self.check(&token::PathSep) {
if self.check(exp!(PathSep)) {
if self.may_recover() && self.look_ahead(1, |t| t.kind == token::Colon) {
debug_assert!(!self.look_ahead(1, &looker), "Looker must not match on colon");
self.look_ahead(2, looker)

View file

@ -30,7 +30,7 @@ use crate::errors::{
UnexpectedVertVertInPattern, WrapInParens,
};
use crate::parser::expr::{DestructuredFloat, could_be_unclosed_char_literal};
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use crate::{exp, maybe_recover_from_interpolated_ty_qpath, maybe_whole};
#[derive(PartialEq, Copy, Clone)]
pub enum Expected {
@ -110,7 +110,7 @@ impl<'a> Parser<'a> {
) -> PResult<'a, P<Pat>> {
let pat = self.parse_pat_no_top_guard(expected, rc, ra, rt)?;
if self.eat_keyword(kw::If) {
if self.eat_keyword(exp!(If)) {
let cond = self.parse_expr()?;
// Feature-gate guard patterns
self.psess.gated_spans.gate(sym::guard_patterns, cond.span);
@ -193,7 +193,7 @@ impl<'a> Parser<'a> {
// If the next token is not a `|`,
// this is not an or-pattern and we should exit here.
if !self.check(&token::BinOp(token::Or)) && self.token != token::OrOr {
if !self.check(exp!(Or)) && self.token != token::OrOr {
// If we parsed a leading `|` which should be gated,
// then we should really gate the leading `|`.
// This complicated procedure is done purely for diagnostics UX.
@ -263,7 +263,7 @@ impl<'a> Parser<'a> {
CommaRecoveryMode::LikelyTuple,
Some(syntax_loc),
)?;
let colon = self.eat(&token::Colon);
let colon = self.eat(exp!(Colon));
if let PatKind::Or(pats) = &pat.kind {
let span = pat.span;
@ -327,7 +327,7 @@ impl<'a> Parser<'a> {
self.dcx().emit_err(UnexpectedVertVertInPattern { span: self.token.span, start: lo });
self.bump();
EatOrResult::AteOr
} else if self.eat(&token::BinOp(token::Or)) {
} else if self.eat(exp!(Or)) {
EatOrResult::AteOr
} else {
EatOrResult::None
@ -714,40 +714,41 @@ impl<'a> Parser<'a> {
lo = self.token.span;
}
let pat = if self.check(&token::BinOp(token::And)) || self.token == token::AndAnd {
let pat = if self.check(exp!(And)) || self.token == token::AndAnd {
self.parse_pat_deref(expected)?
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
} else if self.check(exp!(OpenParen)) {
self.parse_pat_tuple_or_parens()?
} else if self.check(&token::OpenDelim(Delimiter::Bracket)) {
} else if self.check(exp!(OpenBracket)) {
// Parse `[pat, pat,...]` as a slice pattern.
let (pats, _) = self.parse_delim_comma_seq(Delimiter::Bracket, |p| {
p.parse_pat_allow_top_guard(
None,
RecoverComma::No,
RecoverColon::No,
CommaRecoveryMode::EitherTupleOrPipe,
)
})?;
let (pats, _) =
self.parse_delim_comma_seq(exp!(OpenBracket), exp!(CloseBracket), |p| {
p.parse_pat_allow_top_guard(
None,
RecoverComma::No,
RecoverColon::No,
CommaRecoveryMode::EitherTupleOrPipe,
)
})?;
PatKind::Slice(pats)
} else if self.check(&token::DotDot) && !self.is_pat_range_end_start(1) {
} else if self.check(exp!(DotDot)) && !self.is_pat_range_end_start(1) {
// A rest pattern `..`.
self.bump(); // `..`
PatKind::Rest
} else if self.check(&token::DotDotDot) && !self.is_pat_range_end_start(1) {
} else if self.check(exp!(DotDotDot)) && !self.is_pat_range_end_start(1) {
self.recover_dotdotdot_rest_pat(lo)
} else if let Some(form) = self.parse_range_end() {
self.parse_pat_range_to(form)? // `..=X`, `...X`, or `..X`.
} else if self.eat(&token::Not) {
} else if self.eat(exp!(Not)) {
// Parse `!`
self.psess.gated_spans.gate(sym::never_patterns, self.prev_token.span);
PatKind::Never
} else if self.eat_keyword(kw::Underscore) {
} else if self.eat_keyword(exp!(Underscore)) {
// Parse `_`
PatKind::Wild
} else if self.eat_keyword(kw::Mut) {
} else if self.eat_keyword(exp!(Mut)) {
self.parse_pat_ident_mut()?
} else if self.eat_keyword(kw::Ref) {
if self.check_keyword(kw::Box) {
} else if self.eat_keyword(exp!(Ref)) {
if self.check_keyword(exp!(Box)) {
// Suggest `box ref`.
let span = self.prev_token.span.to(self.token.span);
self.bump();
@ -756,7 +757,7 @@ impl<'a> Parser<'a> {
// Parse ref ident @ pat / ref mut ident @ pat
let mutbl = self.parse_mutability();
self.parse_pat_ident(BindingMode(ByRef::Yes(mutbl), Mutability::Not), syntax_loc)?
} else if self.eat_keyword(kw::Box) {
} else if self.eat_keyword(exp!(Box)) {
self.parse_pat_box()?
} else if self.check_inline_const(0) {
// Parse `const pat`
@ -793,14 +794,14 @@ impl<'a> Parser<'a> {
};
let span = lo.to(self.prev_token.span);
if qself.is_none() && self.check(&token::Not) {
if qself.is_none() && self.check(exp!(Not)) {
self.parse_pat_mac_invoc(path)?
} else if let Some(form) = self.parse_range_end() {
let begin = self.mk_expr(span, ExprKind::Path(qself, path));
self.parse_pat_range_begin_with(begin, form)?
} else if self.check(&token::OpenDelim(Delimiter::Brace)) {
} else if self.check(exp!(OpenBrace)) {
self.parse_pat_struct(qself, path)?
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
} else if self.check(exp!(OpenParen)) {
self.parse_pat_tuple_struct(qself, path)?
} else {
match self.maybe_recover_trailing_expr(span, false) {
@ -1106,7 +1107,7 @@ impl<'a> Parser<'a> {
/// Eat any extraneous `mut`s and error + recover if we ate any.
fn recover_additional_muts(&mut self) {
let lo = self.token.span;
while self.eat_keyword(kw::Mut) {}
while self.eat_keyword(exp!(Mut)) {}
if lo == self.token.span {
return;
}
@ -1147,11 +1148,11 @@ impl<'a> Parser<'a> {
/// Parses the range pattern end form `".." | "..." | "..=" ;`.
fn parse_range_end(&mut self) -> Option<Spanned<RangeEnd>> {
let re = if self.eat(&token::DotDotDot) {
let re = if self.eat(exp!(DotDotDot)) {
RangeEnd::Included(RangeSyntax::DotDotDot)
} else if self.eat(&token::DotDotEq) {
} else if self.eat(exp!(DotDotEq)) {
RangeEnd::Included(RangeSyntax::DotDotEq)
} else if self.eat(&token::DotDot) {
} else if self.eat(exp!(DotDot)) {
RangeEnd::Excluded
} else {
return None;
@ -1271,7 +1272,7 @@ impl<'a> Parser<'a> {
// recover trailing `)`
if let Some(open_paren) = open_paren {
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
self.expect(exp!(CloseParen))?;
self.dcx().emit_err(UnexpectedParenInRangePat {
span: vec![open_paren, self.prev_token.span],
@ -1331,7 +1332,7 @@ impl<'a> Parser<'a> {
}));
}
let sub = if self.eat(&token::At) {
let sub = if self.eat(exp!(At)) {
Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern), None)?)
} else {
None
@ -1447,7 +1448,7 @@ impl<'a> Parser<'a> {
// We cannot use `parse_pat_ident()` since it will complain `box`
// is not an identifier.
let sub = if self.eat(&token::At) {
let sub = if self.eat(exp!(At)) {
Some(self.parse_pat_no_top_alt(Some(Expected::BindingPattern), None)?)
} else {
None
@ -1504,9 +1505,9 @@ impl<'a> Parser<'a> {
}
ate_comma = false;
if self.check(&token::DotDot)
if self.check(exp!(DotDot))
|| self.check_noexpect(&token::DotDotDot)
|| self.check_keyword(kw::Underscore)
|| self.check_keyword(exp!(Underscore))
{
etc = PatFieldsRest::Rest;
let mut etc_sp = self.token.span;
@ -1594,7 +1595,7 @@ impl<'a> Parser<'a> {
return Err(err);
}
}?;
ate_comma = this.eat(&token::Comma);
ate_comma = this.eat(exp!(Comma));
last_non_comma_dotdot_span = Some(this.prev_token.span);
@ -1706,7 +1707,7 @@ impl<'a> Parser<'a> {
(pat, fieldname, false)
} else {
// Parsing a pattern of the form `(box) (ref) (mut) fieldname`.
let is_box = self.eat_keyword(kw::Box);
let is_box = self.eat_keyword(exp!(Box));
let boxed_span = self.token.span;
let mutability = self.parse_mutability();
let by_ref = self.parse_byref();

View file

@ -17,7 +17,7 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{Parser, Restrictions, TokenType};
use crate::errors::{PathSingleColon, PathTripleColon};
use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma};
use crate::{errors, maybe_whole};
use crate::{errors, exp, maybe_whole};
/// Specifies how to parse a path.
#[derive(Copy, Clone, PartialEq)]
@ -80,7 +80,7 @@ impl<'a> Parser<'a> {
// above). `path_span` has the span of that path, or an empty
// span in the case of something like `<T>::Bar`.
let (mut path, path_span);
if self.eat_keyword(kw::As) {
if self.eat_keyword(exp!(As)) {
let path_lo = self.token.span;
path = self.parse_path(PathStyle::Type)?;
path_span = path_lo.to(self.prev_token.span);
@ -90,7 +90,7 @@ impl<'a> Parser<'a> {
}
// See doc comment for `unmatched_angle_bracket_count`.
self.expect(&token::Gt)?;
self.expect(exp!(Gt))?;
if self.unmatched_angle_bracket_count > 0 {
self.unmatched_angle_bracket_count -= 1;
debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count);
@ -98,7 +98,7 @@ impl<'a> Parser<'a> {
let is_import_coupler = self.is_import_coupler();
if !is_import_coupler && !self.recover_colon_before_qpath_proj() {
self.expect(&token::PathSep)?;
self.expect(exp!(PathSep))?;
}
let qself = P(QSelf { ty, path_span, position: path.segments.len() });
@ -242,7 +242,7 @@ impl<'a> Parser<'a> {
// `PathStyle::Expr` is only provided at the root invocation and never in
// `parse_path_segment` to recurse and therefore can be checked to maintain
// this invariant.
self.check_trailing_angle_brackets(&segment, &[&token::PathSep]);
self.check_trailing_angle_brackets(&segment, &[exp!(PathSep)]);
}
segments.push(segment);
@ -275,7 +275,7 @@ impl<'a> Parser<'a> {
/// Eat `::` or, potentially, `:::`.
#[must_use]
pub(super) fn eat_path_sep(&mut self) -> bool {
let result = self.eat(&token::PathSep);
let result = self.eat(exp!(PathSep));
if result && self.may_recover() {
if self.eat_noexpect(&token::Colon) {
self.dcx().emit_err(PathTripleColon { span: self.prev_token.span });
@ -300,10 +300,8 @@ impl<'a> Parser<'a> {
)
};
let check_args_start = |this: &mut Self| {
this.expected_token_types.extend_from_slice(&[
TokenType::Token(token::Lt),
TokenType::Token(token::OpenDelim(Delimiter::Parenthesis)),
]);
this.expected_token_types.insert(TokenType::Lt);
this.expected_token_types.insert(TokenType::OpenParen);
is_args_start(&this.token)
};
@ -367,7 +365,7 @@ impl<'a> Parser<'a> {
{
self.bump(); // (
self.bump(); // ..
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
self.expect(exp!(CloseParen))?;
let span = lo.to(self.prev_token.span);
self.psess.gated_spans.gate(sym::return_type_notation, span);
@ -661,12 +659,12 @@ impl<'a> Parser<'a> {
let mut args = ThinVec::new();
while let Some(arg) = self.parse_angle_arg(ty_generics)? {
args.push(arg);
if !self.eat(&token::Comma) {
if !self.eat(exp!(Comma)) {
if self.check_noexpect(&TokenKind::Semi)
&& self.look_ahead(1, |t| t.is_ident() || t.is_lifetime())
{
// Add `>` to the list of expected tokens.
self.check(&token::Gt);
self.check(exp!(Gt));
// Handle `,` to `;` substitution
let mut err = self.unexpected().unwrap_err();
self.bump();
@ -705,7 +703,7 @@ impl<'a> Parser<'a> {
// is present and then use that info to push the other token onto the tokens list
let separated =
self.check_noexpect(&token::Colon) || self.check_noexpect(&token::Eq);
if separated && (self.check(&token::Colon) | self.check(&token::Eq)) {
if separated && (self.check(exp!(Colon)) | self.check(exp!(Eq))) {
let arg_span = arg.span();
let (binder, ident, gen_args) = match self.get_ident_from_generic_arg(&arg) {
Ok(ident_gen_args) => ident_gen_args,
@ -720,9 +718,9 @@ impl<'a> Parser<'a> {
"`for<...>` is not allowed on associated type bounds",
));
}
let kind = if self.eat(&token::Colon) {
let kind = if self.eat(exp!(Colon)) {
AssocItemConstraintKind::Bound { bounds: self.parse_generic_bounds()? }
} else if self.eat(&token::Eq) {
} else if self.eat(exp!(Eq)) {
self.parse_assoc_equality_term(
ident,
gen_args.as_ref(),
@ -743,8 +741,8 @@ impl<'a> Parser<'a> {
if self.prev_token.is_ident()
&& (self.token.is_ident() || self.look_ahead(1, |token| token.is_ident()))
{
self.check(&token::Colon);
self.check(&token::Eq);
self.check(exp!(Colon));
self.check(exp!(Eq));
}
Ok(Some(AngleBracketedArg::Arg(arg)))
}

View file

@ -24,7 +24,7 @@ use super::{
Trailing, UsePreAttrPos,
};
use crate::errors::MalformedLoopLabel;
use crate::{errors, maybe_whole};
use crate::{errors, exp, maybe_whole};
impl<'a> Parser<'a> {
/// Parses a statement. This stops just before trailing semicolons on everything but items.
@ -71,7 +71,7 @@ impl<'a> Parser<'a> {
let stmt = if self.token.is_keyword(kw::Let) {
self.collect_tokens(None, attrs, force_collect, |this, attrs| {
this.expect_keyword(kw::Let)?;
this.expect_keyword(exp!(Let))?;
let local = this.parse_local(attrs)?;
let trailing = Trailing::from(capture_semi && this.token == token::Semi);
Ok((
@ -140,7 +140,7 @@ impl<'a> Parser<'a> {
force_collect,
)? {
self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
} else if self.eat(&token::Semi) {
} else if self.eat(exp!(Semi)) {
// Do not attempt to parse an expression if we're done here.
self.error_outer_attrs(attrs);
self.mk_stmt(lo, StmtKind::Empty)
@ -156,7 +156,7 @@ impl<'a> Parser<'a> {
Ok((expr, Trailing::No, UsePreAttrPos::Yes))
},
)?;
if matches!(e.kind, ExprKind::Assign(..)) && self.eat_keyword(kw::Else) {
if matches!(e.kind, ExprKind::Assign(..)) && self.eat_keyword(exp!(Else)) {
let bl = self.parse_block()?;
// Destructuring assignment ... else.
// This is not allowed, but point it out in a nice way.
@ -176,7 +176,7 @@ impl<'a> Parser<'a> {
let stmt = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
let path = this.parse_path(PathStyle::Expr)?;
if this.eat(&token::Not) {
if this.eat(exp!(Not)) {
let stmt_mac = this.parse_stmt_mac(lo, attrs, path)?;
return Ok((
stmt_mac,
@ -185,7 +185,7 @@ impl<'a> Parser<'a> {
));
}
let expr = if this.eat(&token::OpenDelim(Delimiter::Brace)) {
let expr = if this.eat(exp!(OpenBrace)) {
this.parse_expr_struct(None, path, true)?
} else {
let hi = this.prev_token.span;
@ -370,7 +370,7 @@ impl<'a> Parser<'a> {
let kind = match init {
None => LocalKind::Decl,
Some(init) => {
if self.eat_keyword(kw::Else) {
if self.eat_keyword(exp!(Else)) {
if self.token.is_keyword(kw::If) {
// `let...else if`. Emit the same error that `parse_block()` would,
// but explicitly point out that this pattern is not allowed.
@ -449,7 +449,7 @@ impl<'a> Parser<'a> {
self.bump();
true
}
_ => self.eat(&token::Eq),
_ => self.eat(exp!(Eq)),
};
Ok(if eq_consumed || eq_optional { Some(self.parse_expr()?) } else { None })
@ -509,7 +509,7 @@ impl<'a> Parser<'a> {
Ok(Some(Stmt { kind: StmtKind::Empty, .. })) => {}
Ok(Some(stmt)) => {
let stmt_own_line = self.psess.source_map().is_line_before_span_empty(sp);
let stmt_span = if stmt_own_line && self.eat(&token::Semi) {
let stmt_span = if stmt_own_line && self.eat(exp!(Semi)) {
// Expand the span to include the semicolon.
stmt.span.with_hi(self.prev_token.span.hi())
} else {
@ -651,7 +651,7 @@ impl<'a> Parser<'a> {
let maybe_ident = self.prev_token.clone();
self.maybe_recover_unexpected_block_label();
if !self.eat(&token::OpenDelim(Delimiter::Brace)) {
if !self.eat(exp!(OpenBrace)) {
return self.error_block_no_opening_brace();
}
@ -678,7 +678,7 @@ impl<'a> Parser<'a> {
) -> PResult<'a, P<Block>> {
let mut stmts = ThinVec::new();
let mut snapshot = None;
while !self.eat(&token::CloseDelim(Delimiter::Brace)) {
while !self.eat(exp!(CloseBrace)) {
if self.token == token::Eof {
break;
}
@ -781,8 +781,7 @@ impl<'a> Parser<'a> {
{
// Just check for errors and recover; do not eat semicolon yet.
let expect_result =
self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]);
let expect_result = self.expect_one_of(&[], &[exp!(Semi), exp!(CloseBrace)]);
// Try to both emit a better diagnostic, and avoid further errors by replacing
// the `expr` with `ExprKind::Err`.
@ -930,7 +929,7 @@ impl<'a> Parser<'a> {
}
}
if add_semi_to_stmt || (eat_semi && self.eat(&token::Semi)) {
if add_semi_to_stmt || (eat_semi && self.eat(exp!(Semi))) {
stmt = stmt.add_trailing_semicolon();
}

View file

@ -0,0 +1,620 @@
use rustc_ast::token::TokenKind;
use rustc_span::symbol::{Symbol, kw, sym};
/// Used in "expected"/"expected one of" error messages. Tokens are added here
/// as necessary. Tokens with values (e.g. literals, identifiers) are
/// represented by a single variant (e.g. `Literal`, `Ident`).
///
/// It's an awkward representation, but it's important for performance. It's a
/// C-style parameterless enum so that `TokenTypeSet` can be a bitset. This is
/// important because `Parser::expected_token_types` is very hot. `TokenType`
/// used to have variants with parameters (e.g. all the keywords were in a
/// single `Keyword` variant with a `Symbol` parameter) and
/// `Parser::expected_token_types` was a `Vec<TokenType>` which was much slower
/// to manipulate.
///
/// We really want to keep the number of variants to 128 or fewer, so that
/// `TokenTypeSet` can be implemented with a `u128`.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TokenType {
// Expression-operator symbols
Eq,
Lt,
Le,
EqEq,
Gt,
AndAnd,
OrOr,
Not,
Tilde,
// BinOps
Plus,
Minus,
Star,
And,
Or,
// Structural symbols
At,
Dot,
DotDot,
DotDotDot,
DotDotEq,
Comma,
Semi,
Colon,
PathSep,
RArrow,
FatArrow,
Pound,
Question,
OpenParen,
CloseParen,
OpenBrace,
CloseBrace,
OpenBracket,
CloseBracket,
Eof,
// Token types with some details elided.
/// Any operator.
Operator,
/// Any identifier token.
Ident,
/// Any lifetime token.
Lifetime,
/// Any token that can start a path.
Path,
/// Any token that can start a type.
Type,
/// Any token that can start a const expression.
Const,
// Keywords
// tidy-alphabetical-start
KwAs,
KwAsync,
KwAuto,
KwAwait,
KwBecome,
KwBox,
KwBreak,
KwCatch,
KwConst,
KwContinue,
KwCrate,
KwDefault,
KwDyn,
KwElse,
KwEnum,
KwExtern,
KwFn,
KwFor,
KwGen,
KwIf,
KwImpl,
KwIn,
KwLet,
KwLoop,
KwMacro,
KwMacroRules,
KwMatch,
KwMod,
KwMove,
KwMut,
KwPub,
KwRaw,
KwRef,
KwReturn,
KwReuse,
KwSafe,
KwSelfUpper,
KwStatic,
KwStruct,
KwTrait,
KwTry,
KwType,
KwUnderscore,
KwUnsafe,
KwUse,
KwWhere,
KwWhile,
KwYield,
// tidy-alphabetical-end
// Keyword-like symbols.
// tidy-alphabetical-start
SymAttSyntax,
SymClobberAbi,
SymInlateout,
SymInout,
SymIs,
SymLabel,
SymLateout,
SymMayUnwind,
SymNomem,
SymNoreturn,
SymNostack,
SymOptions,
SymOut,
SymPreservesFlags,
SymPure,
SymReadonly,
SymSym,
// tidy-alphabetical-end
}
impl TokenType {
fn from_u32(val: u32) -> TokenType {
let token_type = match val {
0 => TokenType::Eq,
1 => TokenType::Lt,
2 => TokenType::Le,
3 => TokenType::EqEq,
4 => TokenType::Gt,
5 => TokenType::AndAnd,
6 => TokenType::OrOr,
7 => TokenType::Not,
8 => TokenType::Tilde,
9 => TokenType::Plus,
10 => TokenType::Minus,
11 => TokenType::Star,
12 => TokenType::And,
13 => TokenType::Or,
14 => TokenType::At,
15 => TokenType::Dot,
16 => TokenType::DotDot,
17 => TokenType::DotDotDot,
18 => TokenType::DotDotEq,
19 => TokenType::Comma,
20 => TokenType::Semi,
21 => TokenType::Colon,
22 => TokenType::PathSep,
23 => TokenType::RArrow,
24 => TokenType::FatArrow,
25 => TokenType::Pound,
26 => TokenType::Question,
27 => TokenType::OpenParen,
28 => TokenType::CloseParen,
29 => TokenType::OpenBrace,
30 => TokenType::CloseBrace,
31 => TokenType::OpenBracket,
32 => TokenType::CloseBracket,
33 => TokenType::Eof,
34 => TokenType::Operator,
35 => TokenType::Ident,
36 => TokenType::Lifetime,
37 => TokenType::Path,
38 => TokenType::Type,
39 => TokenType::Const,
40 => TokenType::KwAs,
41 => TokenType::KwAsync,
42 => TokenType::KwAuto,
43 => TokenType::KwAwait,
44 => TokenType::KwBecome,
45 => TokenType::KwBox,
46 => TokenType::KwBreak,
47 => TokenType::KwCatch,
48 => TokenType::KwConst,
49 => TokenType::KwContinue,
50 => TokenType::KwCrate,
51 => TokenType::KwDefault,
52 => TokenType::KwDyn,
53 => TokenType::KwElse,
54 => TokenType::KwEnum,
55 => TokenType::KwExtern,
56 => TokenType::KwFn,
57 => TokenType::KwFor,
58 => TokenType::KwGen,
59 => TokenType::KwIf,
60 => TokenType::KwImpl,
61 => TokenType::KwIn,
62 => TokenType::KwLet,
63 => TokenType::KwLoop,
64 => TokenType::KwMacro,
65 => TokenType::KwMacroRules,
66 => TokenType::KwMatch,
67 => TokenType::KwMod,
68 => TokenType::KwMove,
69 => TokenType::KwMut,
70 => TokenType::KwPub,
71 => TokenType::KwRaw,
72 => TokenType::KwRef,
73 => TokenType::KwReturn,
74 => TokenType::KwReuse,
75 => TokenType::KwSafe,
76 => TokenType::KwSelfUpper,
77 => TokenType::KwStatic,
78 => TokenType::KwStruct,
79 => TokenType::KwTrait,
80 => TokenType::KwTry,
81 => TokenType::KwType,
82 => TokenType::KwUnderscore,
83 => TokenType::KwUnsafe,
84 => TokenType::KwUse,
85 => TokenType::KwWhere,
86 => TokenType::KwWhile,
87 => TokenType::KwYield,
88 => TokenType::SymAttSyntax,
89 => TokenType::SymClobberAbi,
90 => TokenType::SymInlateout,
91 => TokenType::SymInout,
92 => TokenType::SymIs,
93 => TokenType::SymLabel,
94 => TokenType::SymLateout,
95 => TokenType::SymMayUnwind,
96 => TokenType::SymNomem,
97 => TokenType::SymNoreturn,
98 => TokenType::SymNostack,
99 => TokenType::SymOptions,
100 => TokenType::SymOut,
101 => TokenType::SymPreservesFlags,
102 => TokenType::SymPure,
103 => TokenType::SymReadonly,
104 => TokenType::SymSym,
_ => panic!("unhandled value: {val}"),
};
// This assertion will detect if this method and the type definition get out of sync.
assert_eq!(token_type as u32, val);
token_type
}
pub(super) fn is_keyword(&self) -> Option<Symbol> {
match self {
TokenType::KwAs => Some(kw::As),
TokenType::KwAsync => Some(kw::Async),
TokenType::KwAuto => Some(kw::Auto),
TokenType::KwAwait => Some(kw::Await),
TokenType::KwBecome => Some(kw::Become),
TokenType::KwBox => Some(kw::Box),
TokenType::KwBreak => Some(kw::Break),
TokenType::KwCatch => Some(kw::Catch),
TokenType::KwConst => Some(kw::Const),
TokenType::KwContinue => Some(kw::Continue),
TokenType::KwCrate => Some(kw::Crate),
TokenType::KwDefault => Some(kw::Default),
TokenType::KwDyn => Some(kw::Dyn),
TokenType::KwElse => Some(kw::Else),
TokenType::KwEnum => Some(kw::Enum),
TokenType::KwExtern => Some(kw::Extern),
TokenType::KwFn => Some(kw::Fn),
TokenType::KwFor => Some(kw::For),
TokenType::KwGen => Some(kw::Gen),
TokenType::KwIf => Some(kw::If),
TokenType::KwImpl => Some(kw::Impl),
TokenType::KwIn => Some(kw::In),
TokenType::KwLet => Some(kw::Let),
TokenType::KwLoop => Some(kw::Loop),
TokenType::KwMacroRules => Some(kw::MacroRules),
TokenType::KwMacro => Some(kw::Macro),
TokenType::KwMatch => Some(kw::Match),
TokenType::KwMod => Some(kw::Mod),
TokenType::KwMove => Some(kw::Move),
TokenType::KwMut => Some(kw::Mut),
TokenType::KwPub => Some(kw::Pub),
TokenType::KwRaw => Some(kw::Raw),
TokenType::KwRef => Some(kw::Ref),
TokenType::KwReturn => Some(kw::Return),
TokenType::KwReuse => Some(kw::Reuse),
TokenType::KwSafe => Some(kw::Safe),
TokenType::KwSelfUpper => Some(kw::SelfUpper),
TokenType::KwStatic => Some(kw::Static),
TokenType::KwStruct => Some(kw::Struct),
TokenType::KwTrait => Some(kw::Trait),
TokenType::KwTry => Some(kw::Try),
TokenType::KwType => Some(kw::Type),
TokenType::KwUnderscore => Some(kw::Underscore),
TokenType::KwUnsafe => Some(kw::Unsafe),
TokenType::KwUse => Some(kw::Use),
TokenType::KwWhere => Some(kw::Where),
TokenType::KwWhile => Some(kw::While),
TokenType::KwYield => Some(kw::Yield),
TokenType::SymAttSyntax => Some(sym::att_syntax),
TokenType::SymClobberAbi => Some(sym::clobber_abi),
TokenType::SymInlateout => Some(sym::inlateout),
TokenType::SymInout => Some(sym::inout),
TokenType::SymIs => Some(sym::is),
TokenType::SymLabel => Some(sym::label),
TokenType::SymLateout => Some(sym::lateout),
TokenType::SymMayUnwind => Some(sym::may_unwind),
TokenType::SymNomem => Some(sym::nomem),
TokenType::SymNoreturn => Some(sym::noreturn),
TokenType::SymNostack => Some(sym::nostack),
TokenType::SymOptions => Some(sym::options),
TokenType::SymOut => Some(sym::out),
TokenType::SymPreservesFlags => Some(sym::preserves_flags),
TokenType::SymPure => Some(sym::pure),
TokenType::SymReadonly => Some(sym::readonly),
TokenType::SymSym => Some(sym::sym),
_ => None,
}
}
// The output should be the same as that produced by
// `rustc_ast_pretty::pprust::token_to_string`.
pub(super) fn to_string(&self) -> String {
match self {
TokenType::Eq => "`=`",
TokenType::Lt => "`<`",
TokenType::Le => "`<=`",
TokenType::EqEq => "`==`",
TokenType::Gt => "`>`",
TokenType::AndAnd => "`&&`",
TokenType::OrOr => "`||`",
TokenType::Not => "`!`",
TokenType::Tilde => "`~`",
TokenType::Plus => "`+`",
TokenType::Minus => "`-`",
TokenType::Star => "`*`",
TokenType::And => "`&`",
TokenType::Or => "`|`",
TokenType::At => "`@`",
TokenType::Dot => "`.`",
TokenType::DotDot => "`..`",
TokenType::DotDotDot => "`...`",
TokenType::DotDotEq => "`..=`",
TokenType::Comma => "`,`",
TokenType::Semi => "`;`",
TokenType::Colon => "`:`",
TokenType::PathSep => "`::`",
TokenType::RArrow => "`->`",
TokenType::FatArrow => "`=>`",
TokenType::Pound => "`#`",
TokenType::Question => "`?`",
TokenType::OpenParen => "`(`",
TokenType::CloseParen => "`)`",
TokenType::OpenBrace => "`{`",
TokenType::CloseBrace => "`}`",
TokenType::OpenBracket => "`[`",
TokenType::CloseBracket => "`]`",
TokenType::Eof => "<eof>",
TokenType::Operator => "an operator",
TokenType::Ident => "identifier",
TokenType::Lifetime => "lifetime",
TokenType::Path => "path",
TokenType::Type => "type",
TokenType::Const => "a const expression",
_ => return format!("`{}`", self.is_keyword().unwrap()),
}
.to_string()
}
}
/// Used by various `Parser` methods such as `check` and `eat`. The first field
/// is always by used those methods. The second field is only used when the
/// first field doesn't match.
#[derive(Clone, Copy, Debug)]
pub struct ExpTokenPair<'a> {
pub tok: &'a TokenKind,
pub token_type: TokenType,
}
/// Used by various `Parser` methods such as `check_keyword` and `eat_keyword`.
/// The first field is always used by those methods. The second field is only
/// used when the first field doesn't match.
#[derive(Clone, Copy)]
pub struct ExpKeywordPair {
pub kw: Symbol,
pub token_type: TokenType,
}
// Gets a statically-known `ExpTokenPair` pair (for non-keywords) or
// `ExpKeywordPair` (for keywords), as used with various `check`/`expect`
// methods in `Parser`.
//
// The name is short because it's used a lot.
#[macro_export]
// We don't use the normal `#[rustfmt::skip]` here because that triggers a
// bogus "macro-expanded `macro_export` macros from the current crate cannot be
// referred to by absolute paths" error, ugh. See #52234.
#[cfg_attr(rustfmt, rustfmt::skip)]
macro_rules! exp {
// `ExpTokenPair` helper rules.
(@tok, $tok:ident) => {
$crate::parser::token_type::ExpTokenPair {
tok: &rustc_ast::token::$tok,
token_type: $crate::parser::token_type::TokenType::$tok
}
};
(@binop, $op:ident) => {
$crate::parser::token_type::ExpTokenPair {
tok: &rustc_ast::token::BinOp(rustc_ast::token::BinOpToken::$op),
token_type: $crate::parser::token_type::TokenType::$op,
}
};
(@open, $delim:ident, $token_type:ident) => {
$crate::parser::token_type::ExpTokenPair {
tok: &rustc_ast::token::OpenDelim(rustc_ast::token::Delimiter::$delim),
token_type: $crate::parser::token_type::TokenType::$token_type,
}
};
(@close, $delim:ident, $token_type:ident) => {
$crate::parser::token_type::ExpTokenPair {
tok: &rustc_ast::token::CloseDelim(rustc_ast::token::Delimiter::$delim),
token_type: $crate::parser::token_type::TokenType::$token_type,
}
};
// `ExpKeywordPair` helper rules.
(@kw, $kw:ident, $token_type:ident) => {
$crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::$kw,
token_type: $crate::parser::token_type::TokenType::$token_type,
}
};
(@sym, $kw:ident, $token_type:ident) => {
$crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::sym::$kw,
token_type: $crate::parser::token_type::TokenType::$token_type,
}
};
(Eq) => { exp!(@tok, Eq) };
(Lt) => { exp!(@tok, Lt) };
(Le) => { exp!(@tok, Le) };
(EqEq) => { exp!(@tok, EqEq) };
(Gt) => { exp!(@tok, Gt) };
(AndAnd) => { exp!(@tok, AndAnd) };
(OrOr) => { exp!(@tok, OrOr) };
(Not) => { exp!(@tok, Not) };
(Tilde) => { exp!(@tok, Tilde) };
(At) => { exp!(@tok, At) };
(Dot) => { exp!(@tok, Dot) };
(DotDot) => { exp!(@tok, DotDot) };
(DotDotDot) => { exp!(@tok, DotDotDot) };
(DotDotEq) => { exp!(@tok, DotDotEq) };
(Comma) => { exp!(@tok, Comma) };
(Semi) => { exp!(@tok, Semi) };
(Colon) => { exp!(@tok, Colon) };
(PathSep) => { exp!(@tok, PathSep) };
(RArrow) => { exp!(@tok, RArrow) };
(FatArrow) => { exp!(@tok, FatArrow) };
(Pound) => { exp!(@tok, Pound) };
(Question) => { exp!(@tok, Question) };
(Eof) => { exp!(@tok, Eof) };
(Plus) => { exp!(@binop, Plus) };
(Minus) => { exp!(@binop, Minus) };
(Star) => { exp!(@binop, Star) };
(And) => { exp!(@binop, And) };
(Or) => { exp!(@binop, Or) };
(OpenParen) => { exp!(@open, Parenthesis, OpenParen) };
(OpenBrace) => { exp!(@open, Brace, OpenBrace) };
(OpenBracket) => { exp!(@open, Bracket, OpenBracket) };
(CloseParen) => { exp!(@close, Parenthesis, CloseParen) };
(CloseBrace) => { exp!(@close, Brace, CloseBrace) };
(CloseBracket) => { exp!(@close, Bracket, CloseBracket) };
(As) => { exp!(@kw, As, KwAs) };
(Async) => { exp!(@kw, Async, KwAsync) };
(Auto) => { exp!(@kw, Auto, KwAuto) };
(Await) => { exp!(@kw, Await, KwAwait) };
(Become) => { exp!(@kw, Become, KwBecome) };
(Box) => { exp!(@kw, Box, KwBox) };
(Break) => { exp!(@kw, Break, KwBreak) };
(Catch) => { exp!(@kw, Catch, KwCatch) };
(Const) => { exp!(@kw, Const, KwConst) };
(Continue) => { exp!(@kw, Continue, KwContinue) };
(Crate) => { exp!(@kw, Crate, KwCrate) };
(Default) => { exp!(@kw, Default, KwDefault) };
(Dyn) => { exp!(@kw, Dyn, KwDyn) };
(Else) => { exp!(@kw, Else, KwElse) };
(Enum) => { exp!(@kw, Enum, KwEnum) };
(Extern) => { exp!(@kw, Extern, KwExtern) };
(Fn) => { exp!(@kw, Fn, KwFn) };
(For) => { exp!(@kw, For, KwFor) };
(Gen) => { exp!(@kw, Gen, KwGen) };
(If) => { exp!(@kw, If, KwIf) };
(Impl) => { exp!(@kw, Impl, KwImpl) };
(In) => { exp!(@kw, In, KwIn) };
(Let) => { exp!(@kw, Let, KwLet) };
(Loop) => { exp!(@kw, Loop, KwLoop) };
(Macro) => { exp!(@kw, Macro, KwMacro) };
(MacroRules) => { exp!(@kw, MacroRules, KwMacroRules) };
(Match) => { exp!(@kw, Match, KwMatch) };
(Mod) => { exp!(@kw, Mod, KwMod) };
(Move) => { exp!(@kw, Move, KwMove) };
(Mut) => { exp!(@kw, Mut, KwMut) };
(Pub) => { exp!(@kw, Pub, KwPub) };
(Raw) => { exp!(@kw, Raw, KwRaw) };
(Ref) => { exp!(@kw, Ref, KwRef) };
(Return) => { exp!(@kw, Return, KwReturn) };
(Reuse) => { exp!(@kw, Reuse, KwReuse) };
(Safe) => { exp!(@kw, Safe, KwSafe) };
(SelfUpper) => { exp!(@kw, SelfUpper, KwSelfUpper) };
(Static) => { exp!(@kw, Static, KwStatic) };
(Struct) => { exp!(@kw, Struct, KwStruct) };
(Trait) => { exp!(@kw, Trait, KwTrait) };
(Try) => { exp!(@kw, Try, KwTry) };
(Type) => { exp!(@kw, Type, KwType) };
(Underscore) => { exp!(@kw, Underscore, KwUnderscore) };
(Unsafe) => { exp!(@kw, Unsafe, KwUnsafe) };
(Use) => { exp!(@kw, Use, KwUse) };
(Where) => { exp!(@kw, Where, KwWhere) };
(While) => { exp!(@kw, While, KwWhile) };
(Yield) => { exp!(@kw, Yield, KwYield) };
(AttSyntax) => { exp!(@sym, att_syntax, SymAttSyntax) };
(ClobberAbi) => { exp!(@sym, clobber_abi, SymClobberAbi) };
(Inlateout) => { exp!(@sym, inlateout, SymInlateout) };
(Inout) => { exp!(@sym, inout, SymInout) };
(Is) => { exp!(@sym, is, SymIs) };
(Label) => { exp!(@sym, label, SymLabel) };
(Lateout) => { exp!(@sym, lateout, SymLateout) };
(MayUnwind) => { exp!(@sym, may_unwind, SymMayUnwind) };
(Nomem) => { exp!(@sym, nomem, SymNomem) };
(Noreturn) => { exp!(@sym, noreturn, SymNoreturn) };
(Nostack) => { exp!(@sym, nostack, SymNostack) };
(Options) => { exp!(@sym, options, SymOptions) };
(Out) => { exp!(@sym, out, SymOut) };
(PreservesFlags) => { exp!(@sym, preserves_flags, SymPreservesFlags) };
(Pure) => { exp!(@sym, pure, SymPure) };
(Readonly) => { exp!(@sym, readonly, SymReadonly) };
(Sym) => { exp!(@sym, sym, SymSym) };
}
/// A bitset type designed specifically for `Parser::expected_token_types`,
/// which is very hot. `u128` is the smallest integer that will fit every
/// `TokenType` value.
#[derive(Clone, Copy)]
pub(super) struct TokenTypeSet(u128);
impl TokenTypeSet {
pub(super) fn new() -> TokenTypeSet {
TokenTypeSet(0)
}
pub(super) fn is_empty(&self) -> bool {
self.0 == 0
}
pub(super) fn insert(&mut self, token_type: TokenType) {
self.0 = self.0 | (1u128 << token_type as u32)
}
pub(super) fn clear(&mut self) {
self.0 = 0
}
pub(super) fn contains(&self, token_type: TokenType) -> bool {
self.0 & (1u128 << token_type as u32) != 0
}
pub(super) fn iter(&self) -> TokenTypeSetIter {
TokenTypeSetIter(*self)
}
}
// The `TokenTypeSet` is a copy of the set being iterated. It initially holds
// the entire set. Each bit is cleared as it is returned. We have finished once
// it is all zeroes.
pub(super) struct TokenTypeSetIter(TokenTypeSet);
impl Iterator for TokenTypeSetIter {
type Item = TokenType;
fn next(&mut self) -> Option<TokenType> {
let num_bits: u32 = (std::mem::size_of_val(&self.0.0) * 8) as u32;
assert_eq!(num_bits, 128);
let z = self.0.0.trailing_zeros();
if z == num_bits {
None
} else {
self.0.0 &= !(1 << z); // clear the trailing 1 bit
Some(TokenType::from_u32(z))
}
}
}

View file

@ -18,7 +18,7 @@ use crate::errors::{
HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
NestedCVariadicType, ReturnTypesUseThinArrow,
};
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
use crate::{exp, maybe_recover_from_interpolated_ty_qpath, maybe_whole};
/// Signals whether parsing a type should allow `+`.
///
@ -203,7 +203,7 @@ impl<'a> Parser<'a> {
recover_return_sign: RecoverReturnSign,
) -> PResult<'a, FnRetTy> {
let lo = self.prev_token.span;
Ok(if self.eat(&token::RArrow) {
Ok(if self.eat(exp!(RArrow)) {
// FIXME(Centril): Can we unconditionally `allow_plus`?
let ty = self.parse_ty_common(
allow_plus,
@ -251,28 +251,28 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
let mut impl_dyn_multi = false;
let kind = if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
let kind = if self.check(exp!(OpenParen)) {
self.parse_ty_tuple_or_parens(lo, allow_plus)?
} else if self.eat(&token::Not) {
} else if self.eat(exp!(Not)) {
// Never type `!`
TyKind::Never
} else if self.eat(&token::BinOp(token::Star)) {
} else if self.eat(exp!(Star)) {
self.parse_ty_ptr()?
} else if self.eat(&token::OpenDelim(Delimiter::Bracket)) {
} else if self.eat(exp!(OpenBracket)) {
self.parse_array_or_slice_ty()?
} else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) {
} else if self.check(exp!(And)) || self.check(exp!(AndAnd)) {
// Reference
self.expect_and()?;
self.parse_borrowed_pointee()?
} else if self.eat_keyword_noexpect(kw::Typeof) {
self.parse_typeof_ty()?
} else if self.eat_keyword(kw::Underscore) {
} else if self.eat_keyword(exp!(Underscore)) {
// A type to be inferred `_`
TyKind::Infer
} else if self.check_fn_front_matter(false, Case::Sensitive) {
// Function pointer type
self.parse_ty_bare_fn(lo, ThinVec::new(), None, recover_return_sign)?
} else if self.check_keyword(kw::For) {
} else if self.check_keyword(exp!(For)) {
// Function pointer type or bound list (trait object type) starting with a poly-trait.
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
@ -324,7 +324,7 @@ impl<'a> Parser<'a> {
self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?
}
}
} else if self.eat_keyword(kw::Impl) {
} else if self.eat_keyword(exp!(Impl)) {
self.parse_impl_ty(&mut impl_dyn_multi)?
} else if self.is_explicit_dyn_type() {
self.parse_dyn_ty(&mut impl_dyn_multi)?
@ -336,7 +336,7 @@ impl<'a> Parser<'a> {
self.parse_path_start_ty(lo, allow_plus, ty_generics)?
} else if self.can_begin_bound() {
self.parse_bare_trait_object(lo, allow_plus)?
} else if self.eat(&token::DotDotDot) {
} else if self.eat(exp!(DotDotDot)) {
match allow_c_variadic {
AllowCVariadic::Yes => TyKind::CVarArgs,
AllowCVariadic::No => {
@ -347,7 +347,7 @@ impl<'a> Parser<'a> {
TyKind::Err(guar)
}
}
} else if self.check_keyword(kw::Unsafe)
} else if self.check_keyword(exp!(Unsafe))
&& self.look_ahead(1, |tok| matches!(tok.kind, token::Lt))
{
self.parse_unsafe_binder_ty()?
@ -374,7 +374,7 @@ impl<'a> Parser<'a> {
fn parse_unsafe_binder_ty(&mut self) -> PResult<'a, TyKind> {
let lo = self.token.span;
assert!(self.eat_keyword(kw::Unsafe));
assert!(self.eat_keyword(exp!(Unsafe)));
self.expect_lt()?;
let generic_params = self.parse_generic_params()?;
self.expect_gt()?;
@ -487,16 +487,16 @@ impl<'a> Parser<'a> {
Err(err) => return Err(err),
};
let ty = if self.eat(&token::Semi) {
let ty = if self.eat(exp!(Semi)) {
let mut length = self.parse_expr_anon_const()?;
if let Err(e) = self.expect(&token::CloseDelim(Delimiter::Bracket)) {
if let Err(e) = self.expect(exp!(CloseBracket)) {
// Try to recover from `X<Y, ...>` when `X::<Y, ...>` works
self.check_mistyped_turbofish_with_multiple_type_params(e, &mut length.value)?;
self.expect(&token::CloseDelim(Delimiter::Bracket))?;
self.expect(exp!(CloseBracket))?;
}
TyKind::Array(elt_ty, length)
} else {
self.expect(&token::CloseDelim(Delimiter::Bracket))?;
self.expect(exp!(CloseBracket))?;
TyKind::Slice(elt_ty)
};
@ -579,9 +579,9 @@ impl<'a> Parser<'a> {
// Parses the `typeof(EXPR)`.
// To avoid ambiguity, the type is surrounded by parentheses.
fn parse_typeof_ty(&mut self) -> PResult<'a, TyKind> {
self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
self.expect(exp!(OpenParen))?;
let expr = self.parse_expr_anon_const()?;
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
self.expect(exp!(CloseParen))?;
Ok(TyKind::Typeof(expr))
}
@ -697,15 +697,15 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
self.expect_lt()?;
let (args, _, _) = self.parse_seq_to_before_tokens(
&[&TokenKind::Gt],
&[exp!(Gt)],
&[
&TokenKind::Ge,
&TokenKind::BinOp(BinOpToken::Shr),
&TokenKind::BinOpEq(BinOpToken::Shr),
],
SeqSep::trailing_allowed(token::Comma),
SeqSep::trailing_allowed(exp!(Comma)),
|self_| {
if self_.check_keyword(kw::SelfUpper) {
if self_.check_keyword(exp!(SelfUpper)) {
self_.bump();
Ok(PreciseCapturingArg::Arg(
ast::Path::from_ident(self_.prev_token.ident().unwrap().0),
@ -729,7 +729,7 @@ impl<'a> Parser<'a> {
/// Is a `dyn B0 + ... + Bn` type allowed here?
fn is_explicit_dyn_type(&mut self) -> bool {
self.check_keyword(kw::Dyn)
self.check_keyword(exp!(Dyn))
&& (self.token.uninterpolated_span().at_least_rust_2018()
|| self.look_ahead(1, |t| {
(can_begin_dyn_bound_in_edition_2015(t) || *t == TokenKind::BinOp(token::Star))
@ -745,7 +745,7 @@ impl<'a> Parser<'a> {
self.bump(); // `dyn`
// parse dyn* types
let syntax = if self.eat(&TokenKind::BinOp(token::Star)) {
let syntax = if self.eat(exp!(Star)) {
self.psess.gated_spans.gate(sym::dyn_star, lo.to(self.prev_token.span));
TraitObjectSyntax::DynStar
} else {
@ -772,7 +772,7 @@ impl<'a> Parser<'a> {
) -> PResult<'a, TyKind> {
// Simple path
let path = self.parse_path_inner(PathStyle::Type, ty_generics)?;
if self.eat(&token::Not) {
if self.eat(exp!(Not)) {
// Macro invocation in type position
Ok(TyKind::MacCall(P(MacCall { path, args: self.parse_delim_args()? })))
} else if allow_plus == AllowPlus::Yes && self.check_plus() {
@ -825,14 +825,14 @@ impl<'a> Parser<'a> {
fn can_begin_bound(&mut self) -> bool {
self.check_path()
|| self.check_lifetime()
|| self.check(&token::Not)
|| self.check(&token::Question)
|| self.check(&token::Tilde)
|| self.check_keyword(kw::For)
|| self.check(&token::OpenDelim(Delimiter::Parenthesis))
|| self.check_keyword(kw::Const)
|| self.check_keyword(kw::Async)
|| self.check_keyword(kw::Use)
|| self.check(exp!(Not))
|| self.check(exp!(Question))
|| self.check(exp!(Tilde))
|| self.check_keyword(exp!(For))
|| self.check(exp!(OpenParen))
|| self.check_keyword(exp!(Const))
|| self.check_keyword(exp!(Async))
|| self.check_keyword(exp!(Use))
}
/// Parses a bound according to the grammar:
@ -842,11 +842,11 @@ impl<'a> Parser<'a> {
fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
let lo = self.token.span;
let leading_token = self.prev_token.clone();
let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis));
let has_parens = self.eat(exp!(OpenParen));
let bound = if self.token.is_lifetime() {
self.parse_generic_lt_bound(lo, has_parens)?
} else if self.eat_keyword(kw::Use) {
} else if self.eat_keyword(exp!(Use)) {
// parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of
// lifetimes and ident params (including SelfUpper). These are validated later
// for order, duplication, and whether they actually reference params.
@ -919,7 +919,7 @@ impl<'a> Parser<'a> {
/// Recover on `('lifetime)` with `(` already eaten.
fn recover_paren_lifetime(&mut self, lo: Span) -> PResult<'a, ()> {
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
self.expect(exp!(CloseParen))?;
let span = lo.to(self.prev_token.span);
let sugg = errors::RemoveParens { lo, hi: self.prev_token.span };
@ -940,13 +940,13 @@ impl<'a> Parser<'a> {
/// See `parse_generic_ty_bound` for the complete grammar of trait bound modifiers.
fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {
let modifier_lo = self.token.span;
let constness = if self.eat(&token::Tilde) {
let constness = if self.eat(exp!(Tilde)) {
let tilde = self.prev_token.span;
self.expect_keyword(kw::Const)?;
self.expect_keyword(exp!(Const))?;
let span = tilde.to(self.prev_token.span);
self.psess.gated_spans.gate(sym::const_trait_impl, span);
BoundConstness::Maybe(span)
} else if self.eat_keyword(kw::Const) {
} else if self.eat_keyword(exp!(Const)) {
self.psess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span);
BoundConstness::Always(self.prev_token.span)
} else {
@ -954,7 +954,7 @@ impl<'a> Parser<'a> {
};
let asyncness = if self.token.uninterpolated_span().at_least_rust_2018()
&& self.eat_keyword(kw::Async)
&& self.eat_keyword(exp!(Async))
{
self.psess.gated_spans.gate(sym::async_trait_bounds, self.prev_token.span);
BoundAsyncness::Async(self.prev_token.span)
@ -974,9 +974,9 @@ impl<'a> Parser<'a> {
};
let modifier_hi = self.prev_token.span;
let polarity = if self.eat(&token::Question) {
let polarity = if self.eat(exp!(Question)) {
BoundPolarity::Maybe(self.prev_token.span)
} else if self.eat(&token::Not) {
} else if self.eat(exp!(Not)) {
self.psess.gated_spans.gate(sym::negative_bounds, self.prev_token.span);
BoundPolarity::Negative(self.prev_token.span)
} else {
@ -1122,7 +1122,7 @@ impl<'a> Parser<'a> {
if self.token.is_like_plus() && leading_token.is_keyword(kw::Dyn) {
let bounds = vec![];
self.parse_remaining_bounds(bounds, true)?;
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
self.expect(exp!(CloseParen))?;
self.dcx().emit_err(errors::IncorrectParensTraitBounds {
span: vec![lo, self.prev_token.span],
sugg: errors::IncorrectParensTraitBoundsSugg {
@ -1131,7 +1131,7 @@ impl<'a> Parser<'a> {
},
});
} else {
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
self.expect(exp!(CloseParen))?;
}
}
@ -1176,7 +1176,7 @@ impl<'a> Parser<'a> {
pub(super) fn parse_late_bound_lifetime_defs(
&mut self,
) -> PResult<'a, (ThinVec<GenericParam>, Option<Span>)> {
if self.eat_keyword(kw::For) {
if self.eat_keyword(exp!(For)) {
let lo = self.token.span;
self.expect_lt()?;
let params = self.parse_generic_params()?;
@ -1280,7 +1280,7 @@ impl<'a> Parser<'a> {
}
pub(super) fn check_lifetime(&mut self) -> bool {
self.expected_token_types.push(TokenType::Lifetime);
self.expected_token_types.insert(TokenType::Lifetime);
self.token.is_lifetime()
}