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:
parent
d5370d981f
commit
b9bf0b4b10
22 changed files with 1357 additions and 793 deletions
|
@ -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 });
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue