From 2e00214b3efbdfeefaa0fe9e8b8fd519de7adc35 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:50 +0200 Subject: Merging upstream version 1.69.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_parse/src/parser/expr.rs | 543 ++++++++++++++++++-------------- 1 file changed, 307 insertions(+), 236 deletions(-) (limited to 'compiler/rustc_parse/src/parser/expr.rs') diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index bf93a89f0..95a7ca80d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,29 +1,12 @@ use super::diagnostics::SnapshotParser; -use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED}; +use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken, }; -use crate::errors::{ - ArrayBracketsInsteadOfSpaces, ArrayBracketsInsteadOfSpacesSugg, AsyncMoveOrderIncorrect, - BracesForStructLiteral, CatchAfterTry, CommaAfterBaseStruct, ComparisonInterpretedAsGeneric, - ComparisonOrShiftInterpretedAsGenericSugg, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, - ExpectedElseBlock, ExpectedEqForLetExpr, ExpectedExpressionFoundLet, - FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt, - IfExpressionMissingCondition, IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub, - InvalidBlockMacroSegment, InvalidComparisonOperator, InvalidComparisonOperatorSub, - InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex, InvalidLogicalOperator, - InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported, LeftArrowOperator, - LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, MalformedLoopLabel, - MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm, - MissingDotDot, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray, - NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub, - OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields, - RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere, - StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf, - UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses, -}; + +use crate::errors; use crate::maybe_recover_from_interpolated_ty_qpath; use core::mem; use rustc_ast::ptr::P; @@ -39,8 +22,8 @@ use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, R use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind}; use rustc_ast_pretty::pprust; use rustc_errors::{ - Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, PResult, - StashKey, + AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, + PResult, StashKey, }; use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; @@ -48,6 +31,7 @@ use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::source_map::{self, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Pos}; +use thin_vec::{thin_vec, ThinVec}; /// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression /// dropped into the token stream, which happens while parsing the result of @@ -119,7 +103,7 @@ impl<'a> Parser<'a> { self.collect_tokens_no_attrs(|this| this.parse_expr()) } - pub fn parse_anon_const_expr(&mut self) -> PResult<'a, AnonConst> { + pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> { self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value }) } @@ -141,7 +125,7 @@ impl<'a> Parser<'a> { } /// Parses a sequence of expressions delimited by parentheses. - fn parse_paren_expr_seq(&mut self) -> PResult<'a, Vec>> { + fn parse_expr_paren_seq(&mut self) -> PResult<'a, ThinVec>> { self.parse_paren_comma_seq(|p| p.parse_expr_catch_underscore()).map(|(r, _)| r) } @@ -152,7 +136,7 @@ impl<'a> Parser<'a> { r: Restrictions, already_parsed_attrs: Option, ) -> PResult<'a, P> { - self.with_res(r, |this| this.parse_assoc_expr(already_parsed_attrs)) + self.with_res(r, |this| this.parse_expr_assoc(already_parsed_attrs)) } /// Parses an associative expression. @@ -160,15 +144,15 @@ impl<'a> Parser<'a> { /// This parses an expression accounting for associativity and precedence of the operators in /// the expression. #[inline] - fn parse_assoc_expr( + fn parse_expr_assoc( &mut self, already_parsed_attrs: Option, ) -> PResult<'a, P> { - self.parse_assoc_expr_with(0, already_parsed_attrs.into()) + self.parse_expr_assoc_with(0, already_parsed_attrs.into()) } /// Parses an associative expression with operators of at least `min_prec` precedence. - pub(super) fn parse_assoc_expr_with( + pub(super) fn parse_expr_assoc_with( &mut self, min_prec: usize, lhs: LhsExpr, @@ -183,9 +167,9 @@ impl<'a> Parser<'a> { _ => None, }; if self.token.is_range_separator() { - return self.parse_prefix_range_expr(attrs); + return self.parse_expr_prefix_range(attrs); } else { - self.parse_prefix_expr(attrs)? + self.parse_expr_prefix(attrs)? } }; let last_type_ascription_set = self.last_type_ascription.is_some(); @@ -243,10 +227,10 @@ impl<'a> Parser<'a> { } .into(); let invalid = format!("{}=", &sugg); - self.sess.emit_err(InvalidComparisonOperator { + self.sess.emit_err(errors::InvalidComparisonOperator { span: sp, invalid: invalid.clone(), - sub: InvalidComparisonOperatorSub::Correctable { + sub: errors::InvalidComparisonOperatorSub::Correctable { span: sp, invalid, correct: sugg, @@ -261,10 +245,10 @@ impl<'a> Parser<'a> { && self.prev_token.span.hi() == self.token.span.lo() { let sp = op.span.to(self.token.span); - self.sess.emit_err(InvalidComparisonOperator { + self.sess.emit_err(errors::InvalidComparisonOperator { span: sp, invalid: "<>".into(), - sub: InvalidComparisonOperatorSub::Correctable { + sub: errors::InvalidComparisonOperatorSub::Correctable { span: sp, invalid: "<>".into(), correct: "!=".into(), @@ -279,10 +263,10 @@ impl<'a> Parser<'a> { && self.prev_token.span.hi() == self.token.span.lo() { let sp = op.span.to(self.token.span); - self.sess.emit_err(InvalidComparisonOperator { + self.sess.emit_err(errors::InvalidComparisonOperator { span: sp, invalid: "<=>".into(), - sub: InvalidComparisonOperatorSub::Spaceship(sp), + sub: errors::InvalidComparisonOperatorSub::Spaceship(sp), }); self.bump(); } @@ -298,6 +282,18 @@ impl<'a> Parser<'a> { continue; } + if self.prev_token == token::BinOp(token::Minus) + && self.token == token::BinOp(token::Minus) + && self.prev_token.span.between(self.token.span).is_empty() + && !self.look_ahead(1, |tok| tok.can_begin_expr()) + { + let op_span = self.prev_token.span.to(self.token.span); + // Eat the second `-` + self.bump(); + lhs = self.recover_from_postfix_decrement(lhs, op_span, starts_stmt)?; + continue; + } + let op = op.node; // Special cases: if op == AssocOp::As { @@ -309,7 +305,7 @@ impl<'a> Parser<'a> { } else if op == AssocOp::DotDot || op == AssocOp::DotDotEq { // If we didn't have to handle `x..`/`x..=`, it would be pretty easy to // generalise it to the Fixity::None code. - lhs = self.parse_range_expr(prec, lhs, op, cur_op_span)?; + lhs = self.parse_expr_range(prec, lhs, op, cur_op_span)?; break; } @@ -322,7 +318,7 @@ impl<'a> Parser<'a> { Fixity::None => 1, }; let rhs = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| { - this.parse_assoc_expr_with(prec + prec_adjustment, LhsExpr::NotYetParsed) + this.parse_expr_assoc_with(prec + prec_adjustment, LhsExpr::NotYetParsed) })?; let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span); @@ -419,7 +415,7 @@ impl<'a> Parser<'a> { /// but the next token implies this should be parsed as an expression. /// For example: `if let Some(x) = x { x } else { 0 } / 2`. fn error_found_expr_would_be_stmt(&self, lhs: &Expr) { - self.sess.emit_err(FoundExprWouldBeStmt { + self.sess.emit_err(errors::FoundExprWouldBeStmt { span: self.token.span, token: self.token.clone(), suggestion: ExprParenthesesNeeded::surrounding(lhs.span), @@ -446,18 +442,18 @@ impl<'a> Parser<'a> { } (Some(op), _) => (op, self.token.span), (None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => { - self.sess.emit_err(InvalidLogicalOperator { + self.sess.emit_err(errors::InvalidLogicalOperator { span: self.token.span, incorrect: "and".into(), - sub: InvalidLogicalOperatorSub::Conjunction(self.token.span), + sub: errors::InvalidLogicalOperatorSub::Conjunction(self.token.span), }); (AssocOp::LAnd, span) } (None, Some((Ident { name: sym::or, span }, false))) if self.may_recover() => { - self.sess.emit_err(InvalidLogicalOperator { + self.sess.emit_err(errors::InvalidLogicalOperator { span: self.token.span, incorrect: "or".into(), - sub: InvalidLogicalOperatorSub::Disjunction(self.token.span), + sub: errors::InvalidLogicalOperatorSub::Disjunction(self.token.span), }); (AssocOp::LOr, span) } @@ -474,7 +470,7 @@ impl<'a> Parser<'a> { /// Parses `x..y`, `x..=y`, and `x..`/`x..=`. /// The other two variants are handled in `parse_prefix_range_expr` below. - fn parse_range_expr( + fn parse_expr_range( &mut self, prec: usize, lhs: P, @@ -482,7 +478,7 @@ impl<'a> Parser<'a> { cur_op_span: Span, ) -> PResult<'a, P> { let rhs = if self.is_at_start_of_range_notation_rhs() { - Some(self.parse_assoc_expr_with(prec + 1, LhsExpr::NotYetParsed)?) + Some(self.parse_expr_assoc_with(prec + 1, LhsExpr::NotYetParsed)?) } else { None }; @@ -507,7 +503,7 @@ impl<'a> Parser<'a> { } /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`. - fn parse_prefix_range_expr(&mut self, attrs: Option) -> PResult<'a, P> { + fn parse_expr_prefix_range(&mut self, attrs: Option) -> PResult<'a, P> { // Check for deprecated `...` syntax. if self.token == token::DotDotDot { self.err_dotdotdot_syntax(self.token.span); @@ -534,7 +530,7 @@ impl<'a> Parser<'a> { this.bump(); let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() { // RHS must be parsed with more associativity than the dots. - this.parse_assoc_expr_with(op.unwrap().precedence() + 1, LhsExpr::NotYetParsed) + this.parse_expr_assoc_with(op.unwrap().precedence() + 1, LhsExpr::NotYetParsed) .map(|x| (lo.to(x.span), Some(x)))? } else { (lo, None) @@ -545,7 +541,7 @@ impl<'a> Parser<'a> { } /// Parses a prefix-unary-operator expr. - fn parse_prefix_expr(&mut self, attrs: Option) -> PResult<'a, P> { + fn parse_expr_prefix(&mut self, attrs: Option) -> PResult<'a, P> { let attrs = self.parse_or_use_outer_attributes(attrs)?; let lo = self.token.span; @@ -563,25 +559,28 @@ impl<'a> Parser<'a> { // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr() match this.token.uninterpolate().kind { // `!expr` - token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)), + token::Not => make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Not)), // `~expr` token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)), // `-expr` token::BinOp(token::Minus) => { - make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Neg)) + make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Neg)) } // `*expr` token::BinOp(token::Star) => { - make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Deref)) + make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Deref)) } // `&expr` and `&&expr` token::BinOp(token::And) | token::AndAnd => { - make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo)) + make_it!(this, attrs, |this, _| this.parse_expr_borrow(lo)) } // `+lit` token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => { - let mut err = - LeadingPlusNotSupported { span: lo, remove_plus: None, add_parentheses: None }; + let mut err = errors::LeadingPlusNotSupported { + span: lo, + remove_plus: None, + add_parentheses: None, + }; // a block on the LHS might have been intended to be an expression instead if let Some(sp) = this.sess.ambiguous_block_expr_parse.borrow().get(&lo) { @@ -592,7 +591,7 @@ impl<'a> Parser<'a> { this.sess.emit_err(err); this.bump(); - this.parse_prefix_expr(None) + this.parse_expr_prefix(None) } // Recover from `++x`: token::BinOp(token::Plus) @@ -605,41 +604,41 @@ impl<'a> Parser<'a> { this.bump(); this.bump(); - let operand_expr = this.parse_dot_or_call_expr(Default::default())?; + let operand_expr = this.parse_expr_dot_or_call(Default::default())?; this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt) } token::Ident(..) if this.token.is_keyword(kw::Box) => { - make_it!(this, attrs, |this, _| this.parse_box_expr(lo)) + make_it!(this, attrs, |this, _| this.parse_expr_box(lo)) } token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => { make_it!(this, attrs, |this, _| this.recover_not_expr(lo)) } - _ => return this.parse_dot_or_call_expr(Some(attrs)), + _ => return this.parse_expr_dot_or_call(Some(attrs)), } } - fn parse_prefix_expr_common(&mut self, lo: Span) -> PResult<'a, (Span, P)> { + fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, P)> { self.bump(); - let expr = self.parse_prefix_expr(None); + let expr = self.parse_expr_prefix(None); let (span, expr) = self.interpolated_or_expr_span(expr)?; Ok((lo.to(span), expr)) } - fn parse_unary_expr(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> { - let (span, expr) = self.parse_prefix_expr_common(lo)?; + fn parse_expr_unary(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> { + let (span, expr) = self.parse_expr_prefix_common(lo)?; Ok((span, self.mk_unary(op, expr))) } /// Recover on `~expr` in favor of `!expr`. fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { - self.sess.emit_err(TildeAsUnaryOperator(lo)); + self.sess.emit_err(errors::TildeAsUnaryOperator(lo)); - self.parse_unary_expr(lo, UnOp::Not) + self.parse_expr_unary(lo, UnOp::Not) } /// Parse `box expr`. - fn parse_box_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { - let (span, expr) = self.parse_prefix_expr_common(lo)?; + fn parse_expr_box(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { + let (span, expr) = self.parse_expr_prefix_common(lo)?; self.sess.gated_spans.gate(sym::box_syntax, span); Ok((span, ExprKind::Box(expr))) } @@ -660,14 +659,14 @@ impl<'a> Parser<'a> { let negated_token = self.look_ahead(1, |t| t.clone()); let sub_diag = if negated_token.is_numeric_lit() { - NotAsNegationOperatorSub::SuggestNotBitwise + errors::NotAsNegationOperatorSub::SuggestNotBitwise } else if negated_token.is_bool_lit() { - NotAsNegationOperatorSub::SuggestNotLogical + errors::NotAsNegationOperatorSub::SuggestNotLogical } else { - NotAsNegationOperatorSub::SuggestNotDefault + errors::NotAsNegationOperatorSub::SuggestNotDefault }; - self.sess.emit_err(NotAsNegationOperator { + self.sess.emit_err(errors::NotAsNegationOperator { negated: negated_token.span, negated_desc: super::token_descr(&negated_token), // Span the `not` plus trailing whitespace to avoid @@ -677,7 +676,7 @@ impl<'a> Parser<'a> { ), }); - self.parse_unary_expr(lo, UnOp::Not) + self.parse_expr_unary(lo, UnOp::Not) } /// Returns the span of expr, if it was not interpolated or the span of the interpolated token. @@ -735,10 +734,10 @@ impl<'a> Parser<'a> { segments[0].ident.span, ), }; - match self.parse_labeled_expr(label, false) { + match self.parse_expr_labeled(label, false) { Ok(expr) => { type_err.cancel(); - self.sess.emit_err(MalformedLoopLabel { + self.sess.emit_err(errors::MalformedLoopLabel { span: label.ident.span, correct_label: label.ident, }); @@ -763,20 +762,22 @@ impl<'a> Parser<'a> { ); let args_span = self.look_ahead(1, |t| t.span).to(span_after_type); - let suggestion = ComparisonOrShiftInterpretedAsGenericSugg { + let suggestion = errors::ComparisonOrShiftInterpretedAsGenericSugg { left: expr.span.shrink_to_lo(), right: expr.span.shrink_to_hi(), }; match self.token.kind { - token::Lt => self.sess.emit_err(ComparisonInterpretedAsGeneric { - comparison: self.token.span, - r#type: path, - args: args_span, - suggestion, - }), + token::Lt => { + self.sess.emit_err(errors::ComparisonInterpretedAsGeneric { + comparison: self.token.span, + r#type: path, + args: args_span, + suggestion, + }) + } token::BinOp(token::Shl) => { - self.sess.emit_err(ShiftInterpretedAsGeneric { + self.sess.emit_err(errors::ShiftInterpretedAsGeneric { shift: self.token.span, r#type: path, args: args_span, @@ -827,7 +828,7 @@ impl<'a> Parser<'a> { ("cast", None) }; - let with_postfix = self.parse_dot_or_call_expr_with_(cast_expr, span)?; + let with_postfix = self.parse_expr_dot_or_call_with_(cast_expr, span)?; // Check if an illegal postfix operator has been added after the cast. // If the resulting expression is not a cast, it is an illegal postfix operator. @@ -898,15 +899,15 @@ impl<'a> Parser<'a> { } /// Parse `& mut? ` or `& raw [ const | mut ] `. - fn parse_borrow_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { + fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { self.expect_and()?; let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon); let lifetime = has_lifetime.then(|| self.expect_lifetime()); // For recovery, see below. let (borrow_kind, mutbl) = self.parse_borrow_modifiers(lo); let expr = if self.token.is_range_separator() { - self.parse_prefix_range_expr(None) + self.parse_expr_prefix_range(None) } else { - self.parse_prefix_expr(None) + self.parse_expr_prefix(None) }; let (hi, expr) = self.interpolated_or_expr_span(expr)?; let span = lo.to(hi); @@ -917,7 +918,7 @@ impl<'a> Parser<'a> { } fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) { - self.sess.emit_err(LifetimeInBorrowExpression { span, lifetime_span: lt_span }); + self.sess.emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span }); } /// Parse `mut?` or `raw [ const | mut ]`. @@ -936,16 +937,16 @@ impl<'a> Parser<'a> { } /// Parses `a.b` or `a(13)` or `a[4]` or just `a`. - fn parse_dot_or_call_expr(&mut self, attrs: Option) -> PResult<'a, P> { + fn parse_expr_dot_or_call(&mut self, attrs: Option) -> PResult<'a, P> { let attrs = self.parse_or_use_outer_attributes(attrs)?; self.collect_tokens_for_expr(attrs, |this, attrs| { - let base = this.parse_bottom_expr(); + let base = this.parse_expr_bottom(); let (span, base) = this.interpolated_or_expr_span(base)?; - this.parse_dot_or_call_expr_with(base, span, attrs) + this.parse_expr_dot_or_call_with(base, span, attrs) }) } - pub(super) fn parse_dot_or_call_expr_with( + pub(super) fn parse_expr_dot_or_call_with( &mut self, e0: P, lo: Span, @@ -954,7 +955,7 @@ impl<'a> Parser<'a> { // Stitch the list of outer attributes onto the return value. // A little bit ugly, but the best way given the current code // structure - let res = self.parse_dot_or_call_expr_with_(e0, lo); + let res = self.parse_expr_dot_or_call_with_(e0, lo); if attrs.is_empty() { res } else { @@ -968,7 +969,7 @@ impl<'a> Parser<'a> { } } - fn parse_dot_or_call_expr_with_(&mut self, mut e: P, lo: Span) -> PResult<'a, P> { + fn parse_expr_dot_or_call_with_(&mut self, mut e: P, lo: Span) -> PResult<'a, P> { loop { let has_question = if self.prev_token.kind == TokenKind::Ident(kw::Return, false) { // we are using noexpect here because we don't expect a `?` directly after a `return` @@ -991,15 +992,15 @@ impl<'a> Parser<'a> { }; if has_dot { // expr.f - e = self.parse_dot_suffix_expr(lo, e)?; + e = self.parse_expr_dot_suffix(lo, e)?; continue; } if self.expr_is_complete(&e) { return Ok(e); } e = match self.token.kind { - token::OpenDelim(Delimiter::Parenthesis) => self.parse_fn_call_expr(lo, e), - token::OpenDelim(Delimiter::Bracket) => self.parse_index_expr(lo, e)?, + token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e), + token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?, _ => return Ok(e), } } @@ -1011,14 +1012,14 @@ impl<'a> Parser<'a> { && self.look_ahead(3, |t| t.can_begin_expr()) } - fn parse_dot_suffix_expr(&mut self, lo: Span, base: P) -> PResult<'a, P> { + fn parse_expr_dot_suffix(&mut self, lo: Span, base: P) -> PResult<'a, P> { match self.token.uninterpolate().kind { token::Ident(..) => self.parse_dot_suffix(base, lo), token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => { - Ok(self.parse_tuple_field_access_expr(lo, base, symbol, suffix, None)) + Ok(self.parse_expr_tuple_field_access(lo, base, symbol, suffix, None)) } token::Literal(token::Lit { kind: token::Float, symbol, suffix }) => { - Ok(self.parse_tuple_field_access_expr_float(lo, base, symbol, suffix)) + Ok(self.parse_expr_tuple_field_access_float(lo, base, symbol, suffix)) } _ => { self.error_unexpected_after_dot(); @@ -1030,7 +1031,7 @@ impl<'a> Parser<'a> { fn error_unexpected_after_dot(&self) { // FIXME Could factor this out into non_fatal_unexpected or something. let actual = pprust::token_to_string(&self.token); - self.struct_span_err(self.token.span, &format!("unexpected token: `{actual}`")).emit(); + self.sess.emit_err(errors::UnexpectedTokenAfterDot { span: self.token.span, actual }); } // We need an identifier or integer, but the next token is a float. @@ -1040,7 +1041,7 @@ impl<'a> Parser<'a> { // support pushing "future tokens" (would be also helpful to `break_and_eat`), or // we should break everything including floats into more basic proc-macro style // tokens in the lexer (probably preferable). - fn parse_tuple_field_access_expr_float( + fn parse_expr_tuple_field_access_float( &mut self, lo: Span, base: P, @@ -1083,7 +1084,7 @@ impl<'a> Parser<'a> { match &*components { // 1e2 [IdentLike(i)] => { - self.parse_tuple_field_access_expr(lo, base, Symbol::intern(&i), suffix, None) + self.parse_expr_tuple_field_access(lo, base, Symbol::intern(&i), suffix, None) } // 1. [IdentLike(i), Punct('.')] => { @@ -1099,7 +1100,7 @@ impl<'a> Parser<'a> { let symbol = Symbol::intern(&i); self.token = Token::new(token::Ident(symbol, false), ident_span); let next_token = (Token::new(token::Dot, dot_span), self.token_spacing); - self.parse_tuple_field_access_expr(lo, base, symbol, None, Some(next_token)) + self.parse_expr_tuple_field_access(lo, base, symbol, None, Some(next_token)) } // 1.2 | 1.2e3 [IdentLike(i1), Punct('.'), IdentLike(i2)] => { @@ -1120,11 +1121,11 @@ impl<'a> Parser<'a> { // See issue #76399 and PR #76285 for more details let next_token1 = (Token::new(token::Dot, dot_span), Spacing::Alone); let base1 = - self.parse_tuple_field_access_expr(lo, base, symbol1, None, Some(next_token1)); + self.parse_expr_tuple_field_access(lo, base, symbol1, None, Some(next_token1)); let symbol2 = Symbol::intern(&i2); let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span); self.bump_with((next_token2, self.token_spacing)); // `.` - self.parse_tuple_field_access_expr(lo, base1, symbol2, suffix, None) + self.parse_expr_tuple_field_access(lo, base1, symbol2, suffix, None) } // 1e+ | 1e- (recovered) [IdentLike(_), Punct('+' | '-')] | @@ -1142,7 +1143,7 @@ impl<'a> Parser<'a> { } } - fn parse_tuple_field_access_expr( + fn parse_expr_tuple_field_access( &mut self, lo: Span, base: P, @@ -1163,7 +1164,7 @@ impl<'a> Parser<'a> { } /// Parse a function call expression, `expr(...)`. - fn parse_fn_call_expr(&mut self, lo: Span, fun: P) -> P { + fn parse_expr_fn_call(&mut self, lo: Span, fun: P) -> P { let snapshot = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) && self.look_ahead_type_ascription_as_field() { @@ -1174,7 +1175,7 @@ impl<'a> Parser<'a> { let open_paren = self.token.span; let mut seq = self - .parse_paren_expr_seq() + .parse_expr_paren_seq() .map(|args| self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args))); if let Some(expr) = self.maybe_recover_struct_lit_bad_delims(lo, open_paren, &mut seq, snapshot) @@ -1209,16 +1210,21 @@ impl<'a> Parser<'a> { // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`. self.restore_snapshot(snapshot); let close_paren = self.prev_token.span; - let span = lo.to(self.prev_token.span); - if !fields.is_empty() { - let mut replacement_err = ParenthesesWithStructFields { + let span = lo.to(close_paren); + if !fields.is_empty() && + // `token.kind` should not be compared here. + // This is because the `snapshot.token.kind` is treated as the same as + // that of the open delim in `TokenTreesReader::parse_token_tree`, even if they are different. + self.span_to_snippet(close_paren).map_or(false, |snippet| snippet == ")") + { + let mut replacement_err = errors::ParenthesesWithStructFields { span, r#type: path, - braces_for_struct: BracesForStructLiteral { + braces_for_struct: errors::BracesForStructLiteral { first: open_paren, second: close_paren, }, - no_fields_for_fn: NoFieldsForFnCall { + no_fields_for_fn: errors::NoFieldsForFnCall { fields: fields .into_iter() .map(|field| field.span.until(field.expr.span)) @@ -1247,7 +1253,7 @@ impl<'a> Parser<'a> { } /// Parse an indexing expression `expr[...]`. - fn parse_index_expr(&mut self, lo: Span, base: P) -> PResult<'a, P> { + fn parse_expr_index(&mut self, lo: Span, base: P) -> PResult<'a, P> { let prev_span = self.prev_token.span; let open_delim_span = self.token.span; self.bump(); // `[` @@ -1270,7 +1276,7 @@ impl<'a> Parser<'a> { if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { // Method call `expr.f()` - let args = self.parse_paren_expr_seq()?; + let args = self.parse_expr_paren_seq()?; let fn_span = fn_span_lo.to(self.prev_token.span); let span = lo.to(self.prev_token.span); Ok(self.mk_expr( @@ -1285,7 +1291,7 @@ impl<'a> Parser<'a> { } else { // Field access `expr.f` if let Some(args) = seg.args { - self.sess.emit_err(FieldExpressionWithGeneric(args.span())); + self.sess.emit_err(errors::FieldExpressionWithGeneric(args.span())); } let span = lo.to(self.prev_token.span); @@ -1298,7 +1304,7 @@ impl<'a> Parser<'a> { /// /// N.B., this does not parse outer attributes, and is private because it only works /// correctly if called from `parse_dot_or_call_expr()`. - fn parse_bottom_expr(&mut self) -> PResult<'a, P> { + fn parse_expr_bottom(&mut self) -> PResult<'a, P> { maybe_recover_from_interpolated_ty_qpath!(self, true); maybe_whole_expr!(self); @@ -1311,13 +1317,13 @@ impl<'a> Parser<'a> { // 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. - self.parse_lit_expr() + self.parse_expr_lit() } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { - self.parse_tuple_parens_expr() + self.parse_expr_tuple_parens() } else if self.check(&token::OpenDelim(Delimiter::Brace)) { - self.parse_block_expr(None, lo, BlockCheckMode::Default) + self.parse_expr_block(None, lo, BlockCheckMode::Default) } else if self.check(&token::BinOp(token::Or)) || self.check(&token::OrOr) { - self.parse_closure_expr().map_err(|mut err| { + self.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. if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&lo) { @@ -1326,42 +1332,42 @@ impl<'a> Parser<'a> { err }) } else if self.check(&token::OpenDelim(Delimiter::Bracket)) { - self.parse_array_or_repeat_expr(Delimiter::Bracket) + self.parse_expr_array_or_repeat(Delimiter::Bracket) } else if self.check_path() { - self.parse_path_start_expr() + self.parse_expr_path_start() } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) || self.check_const_closure() { - self.parse_closure_expr() + self.parse_expr_closure() } else if self.eat_keyword(kw::If) { - self.parse_if_expr() + self.parse_expr_if() } else if self.check_keyword(kw::For) { if self.choose_generics_over_qpath(1) { - self.parse_closure_expr() + self.parse_expr_closure() } else { assert!(self.eat_keyword(kw::For)); - self.parse_for_expr(None, self.prev_token.span) + self.parse_expr_for(None, self.prev_token.span) } } else if self.eat_keyword(kw::While) { - self.parse_while_expr(None, self.prev_token.span) + self.parse_expr_while(None, self.prev_token.span) } else if let Some(label) = self.eat_label() { - self.parse_labeled_expr(label, true) + self.parse_expr_labeled(label, true) } else if self.eat_keyword(kw::Loop) { let sp = self.prev_token.span; - self.parse_loop_expr(None, self.prev_token.span).map_err(|mut err| { + self.parse_expr_loop(None, self.prev_token.span).map_err(|mut err| { err.span_label(sp, "while parsing this `loop` expression"); err }) } else if self.eat_keyword(kw::Match) { let match_sp = self.prev_token.span; - self.parse_match_expr().map_err(|mut err| { + self.parse_expr_match().map_err(|mut err| { err.span_label(match_sp, "while parsing this `match` expression"); err }) } else if self.eat_keyword(kw::Unsafe) { let sp = self.prev_token.span; - self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err( + self.parse_expr_block(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err( |mut err| { err.span_label(sp, "while parsing this `unsafe` expression"); err @@ -1375,17 +1381,17 @@ impl<'a> Parser<'a> { self.expect_keyword(kw::Try)?; self.parse_try_block(lo) } else if self.eat_keyword(kw::Return) { - self.parse_return_expr() + self.parse_expr_return() } else if self.eat_keyword(kw::Continue) { - self.parse_continue_expr(lo) + self.parse_expr_continue(lo) } else if self.eat_keyword(kw::Break) { - self.parse_break_expr() + self.parse_expr_break() } else if self.eat_keyword(kw::Yield) { - self.parse_yield_expr() + self.parse_expr_yield() } else if self.is_do_yeet() { - self.parse_yeet_expr() + self.parse_expr_yeet() } else if self.check_keyword(kw::Let) { - self.parse_let_expr() + self.parse_expr_let() } else if self.eat_keyword(kw::Underscore) { Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore)) } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { @@ -1408,19 +1414,19 @@ impl<'a> Parser<'a> { // Check for `async {` and `async move {`. self.parse_async_block() } else { - self.parse_closure_expr() + self.parse_expr_closure() } } else if self.eat_keyword(kw::Await) { self.recover_incorrect_await_syntax(lo, self.prev_token.span) } else { - self.parse_lit_expr() + self.parse_expr_lit() } } else { - self.parse_lit_expr() + self.parse_expr_lit() } } - fn parse_lit_expr(&mut self) -> PResult<'a, P> { + fn parse_expr_lit(&mut self) -> PResult<'a, P> { let lo = self.token.span; match self.parse_opt_token_lit() { Some((token_lit, _)) => { @@ -1431,7 +1437,7 @@ impl<'a> Parser<'a> { } } - fn parse_tuple_parens_expr(&mut self) -> PResult<'a, P> { + fn parse_expr_tuple_parens(&mut self) -> PResult<'a, P> { let lo = self.token.span; self.expect(&token::OpenDelim(Delimiter::Parenthesis))?; let (es, trailing_comma) = match self.parse_seq_to_end( @@ -1455,20 +1461,20 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr) } - fn parse_array_or_repeat_expr(&mut self, close_delim: Delimiter) -> PResult<'a, P> { + fn parse_expr_array_or_repeat(&mut self, close_delim: Delimiter) -> PResult<'a, P> { 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(Vec::new()) + ExprKind::Array(ThinVec::new()) } else { // Non-empty vector let first_expr = self.parse_expr()?; if self.eat(&token::Semi) { // Repeating array syntax: `[ 0; 512 ]` - let count = self.parse_anon_const_expr()?; + let count = self.parse_expr_anon_const()?; self.expect(close)?; ExprKind::Repeat(first_expr, count) } else if self.eat(&token::Comma) { @@ -1480,14 +1486,14 @@ impl<'a> Parser<'a> { } else { // Vector with one element self.expect(close)?; - ExprKind::Array(vec![first_expr]) + ExprKind::Array(thin_vec![first_expr]) } }; let expr = self.mk_expr(lo.to(self.prev_token.span), kind); self.maybe_recover_from_bad_qpath(expr) } - fn parse_path_start_expr(&mut self) -> PResult<'a, P> { + fn parse_expr_path_start(&mut self) -> PResult<'a, P> { let (qself, path) = if self.eat_lt() { let (qself, path) = self.parse_qpath(PathStyle::Expr)?; (Some(qself), path) @@ -1499,7 +1505,7 @@ impl<'a> Parser<'a> { let (span, kind) = if self.eat(&token::Not) { // MACRO INVOCATION expression if qself.is_some() { - self.sess.emit_err(MacroInvocationWithQualifiedPath(path.span)); + self.sess.emit_err(errors::MacroInvocationWithQualifiedPath(path.span)); } let lo = path.span; let mac = P(MacCall { @@ -1524,7 +1530,7 @@ impl<'a> Parser<'a> { } /// Parse `'label: $expr`. The label is already parsed. - fn parse_labeled_expr( + fn parse_expr_labeled( &mut self, label_: Label, mut consume_colon: bool, @@ -1533,15 +1539,15 @@ impl<'a> Parser<'a> { let label = Some(label_); let ate_colon = self.eat(&token::Colon); let expr = if self.eat_keyword(kw::While) { - self.parse_while_expr(label, lo) + self.parse_expr_while(label, lo) } else if self.eat_keyword(kw::For) { - self.parse_for_expr(label, lo) + self.parse_expr_for(label, lo) } else if self.eat_keyword(kw::Loop) { - self.parse_loop_expr(label, lo) + self.parse_expr_loop(label, lo) } else if self.check_noexpect(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() { - self.parse_block_expr(label, lo, BlockCheckMode::Default) + self.parse_expr_block(label, lo, BlockCheckMode::Default) } else if !ate_colon && self.may_recover() && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma) @@ -1549,7 +1555,7 @@ impl<'a> Parser<'a> { { let (lit, _) = self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| { - self_.sess.create_err(UnexpectedTokenAfterLabel { + self_.sess.create_err(errors::UnexpectedTokenAfterLabel { span: self_.token.span, remove_label: None, enclose_in_block: None, @@ -1561,7 +1567,7 @@ impl<'a> Parser<'a> { && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt)) { // We're probably inside of a `Path<'a>` that needs a turbofish - self.sess.emit_err(UnexpectedTokenAfterLabel { + self.sess.emit_err(errors::UnexpectedTokenAfterLabel { span: self.token.span, remove_label: None, enclose_in_block: None, @@ -1569,7 +1575,7 @@ impl<'a> Parser<'a> { consume_colon = false; Ok(self.mk_expr_err(lo)) } else { - let mut err = UnexpectedTokenAfterLabel { + let mut err = errors::UnexpectedTokenAfterLabel { span: self.token.span, remove_label: None, enclose_in_block: None, @@ -1605,14 +1611,14 @@ impl<'a> Parser<'a> { return expr; } - err.enclose_in_block = Some(UnexpectedTokenAfterLabelSugg { + err.enclose_in_block = Some(errors::UnexpectedTokenAfterLabelSugg { left: span.shrink_to_lo(), right: span.shrink_to_hi(), }); // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`. let stmt = self.mk_stmt(span, StmtKind::Expr(expr)); - let blk = self.mk_block(vec![stmt], BlockCheckMode::Default, span); + let blk = self.mk_block(thin_vec![stmt], BlockCheckMode::Default, span); self.mk_expr(span, ExprKind::Block(blk, label)) }); @@ -1621,7 +1627,7 @@ impl<'a> Parser<'a> { }?; if !ate_colon && consume_colon { - self.sess.emit_err(RequireColonAfterLabeledExpression { + self.sess.emit_err(errors::RequireColonAfterLabeledExpression { span: expr.span, label: lo, label_end: lo.shrink_to_hi(), @@ -1670,7 +1676,7 @@ impl<'a> Parser<'a> { self.bump(); // `catch` let span = lo.to(self.prev_token.span); - self.sess.emit_err(DoCatchSyntaxRemoved { span }); + self.sess.emit_err(errors::DoCatchSyntaxRemoved { span }); self.parse_try_block(lo) } @@ -1681,7 +1687,7 @@ impl<'a> Parser<'a> { } /// Parse `"return" expr?`. - fn parse_return_expr(&mut self) -> PResult<'a, P> { + fn parse_expr_return(&mut self) -> PResult<'a, P> { let lo = self.prev_token.span; let kind = ExprKind::Ret(self.parse_expr_opt()?); let expr = self.mk_expr(lo.to(self.prev_token.span), kind); @@ -1689,7 +1695,7 @@ impl<'a> Parser<'a> { } /// Parse `"do" "yeet" expr?`. - fn parse_yeet_expr(&mut self) -> PResult<'a, P> { + fn parse_expr_yeet(&mut self) -> PResult<'a, P> { let lo = self.token.span; self.bump(); // `do` @@ -1711,16 +1717,16 @@ impl<'a> Parser<'a> { /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value /// expression only gets a warning for compatibility reasons; and a labeled break /// with a labeled loop does not even get a warning because there is no ambiguity. - fn parse_break_expr(&mut self) -> PResult<'a, P> { + fn parse_expr_break(&mut self) -> PResult<'a, P> { let lo = self.prev_token.span; let mut label = self.eat_label(); let kind = if self.token == token::Colon && let Some(label) = label.take() { // The value expression can be a labeled loop, see issue #86948, e.g.: // `loop { break 'label: loop { break 'label 42; }; }` - let lexpr = self.parse_labeled_expr(label, true)?; - self.sess.emit_err(LabeledLoopInBreak { + let lexpr = self.parse_expr_labeled(label, true)?; + self.sess.emit_err(errors::LabeledLoopInBreak { span: lexpr.span, - sub: WrapExpressionInParentheses { + sub: errors::WrapExpressionInParentheses { left: lexpr.span.shrink_to_lo(), right: lexpr.span.shrink_to_hi(), }, @@ -1770,7 +1776,7 @@ impl<'a> Parser<'a> { } /// Parse `"continue" label?`. - fn parse_continue_expr(&mut self, lo: Span) -> PResult<'a, P> { + fn parse_expr_continue(&mut self, lo: Span) -> PResult<'a, P> { let mut label = self.eat_label(); // Recover `continue label` -> `continue 'label` @@ -1787,7 +1793,7 @@ impl<'a> Parser<'a> { } /// Parse `"yield" expr?`. - fn parse_yield_expr(&mut self) -> PResult<'a, P> { + fn parse_expr_yield(&mut self) -> PResult<'a, P> { let lo = self.prev_token.span; let kind = ExprKind::Yield(self.parse_expr_opt()?); let span = lo.to(self.prev_token.span); @@ -1840,7 +1846,7 @@ impl<'a> Parser<'a> { }; if let Some(expr) = expr { if matches!(expr.kind, ExprKind::Err) { - let mut err = InvalidInterpolatedExpression { span: self.token.span } + let mut err = errors::InvalidInterpolatedExpression { span: self.token.span } .into_diagnostic(&self.sess.span_diagnostic); err.downgrade_to_delayed_bug(); return Err(err); @@ -1882,7 +1888,16 @@ impl<'a> Parser<'a> { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = next_token.kind { - if self.token.span.hi() == next_token.span.lo() { + // If this integer looks like a float, then recover as such. + // + // We will never encounter the exponent part of a floating + // point literal here, since there's no use of the exponent + // syntax that also constitutes a valid integer, so we need + // not check for that. + if suffix.map_or(true, |s| s == sym::f32 || s == sym::f64) + && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_') + && self.token.span.hi() == next_token.span.lo() + { let s = String::from("0.") + symbol.as_str(); let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix); return Some(Token::new(kind, self.token.span.to(next_token.span))); @@ -1892,7 +1907,7 @@ impl<'a> Parser<'a> { }); if let Some(token) = &recovered { self.bump(); - self.sess.emit_err(FloatLiteralRequiresIntegerPart { + self.sess.emit_err(errors::FloatLiteralRequiresIntegerPart { span: token.span, correct: pprust::token_to_string(token).into_owned(), }); @@ -1953,13 +1968,17 @@ impl<'a> Parser<'a> { if [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suffix) { // #59553: warn instead of reject out of hand to allow the fix to percolate // through the ecosystem when people fix their macros - self.sess.emit_warning(InvalidLiteralSuffixOnTupleIndex { + self.sess.emit_warning(errors::InvalidLiteralSuffixOnTupleIndex { span, suffix, exception: Some(()), }); } else { - self.sess.emit_err(InvalidLiteralSuffixOnTupleIndex { span, suffix, exception: None }); + self.sess.emit_err(errors::InvalidLiteralSuffixOnTupleIndex { + span, + suffix, + exception: None, + }); } } @@ -1991,11 +2010,11 @@ impl<'a> Parser<'a> { /// expression. fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option> { let mut snapshot = self.create_snapshot_for_diagnostic(); - match snapshot.parse_array_or_repeat_expr(Delimiter::Brace) { + match snapshot.parse_expr_array_or_repeat(Delimiter::Brace) { Ok(arr) => { - self.sess.emit_err(ArrayBracketsInsteadOfSpaces { + self.sess.emit_err(errors::ArrayBracketsInsteadOfSpaces { span: arr.span, - sub: ArrayBracketsInsteadOfSpacesSugg { + sub: errors::ArrayBracketsInsteadOfSpacesSugg { left: lo, right: snapshot.prev_token.span, }, @@ -2041,7 +2060,7 @@ impl<'a> Parser<'a> { .span_to_snippet(snapshot.token.span) .map_or(false, |snippet| snippet == "]") => { - return Err(MissingSemicolonBeforeArray { + return Err(errors::MissingSemicolonBeforeArray { open_delim: open_delim_span, semicolon: prev_span.shrink_to_hi(), }.into_diagnostic(&self.sess.span_diagnostic)); @@ -2054,7 +2073,7 @@ impl<'a> Parser<'a> { } /// Parses a block or unsafe block. - pub(super) fn parse_block_expr( + pub(super) fn parse_expr_block( &mut self, opt_label: Option