1 use super::diagnostics
::SnapshotParser
;
2 use super::pat
::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED}
;
3 use super::ty
::{AllowPlus, RecoverQPath, RecoverReturnSign}
;
5 AttrWrapper
, BlockMode
, ClosureSpans
, ForceCollect
, Parser
, PathStyle
, Restrictions
,
6 SemiColonMode
, SeqSep
, TokenExpectType
, TokenType
, TrailingToken
,
9 ArrayBracketsInsteadOfSpaces
, ArrayBracketsInsteadOfSpacesSugg
, AsyncMoveOrderIncorrect
,
10 BracesForStructLiteral
, CatchAfterTry
, CommaAfterBaseStruct
, ComparisonInterpretedAsGeneric
,
11 ComparisonOrShiftInterpretedAsGenericSugg
, DoCatchSyntaxRemoved
, DotDotDot
, EqFieldInit
,
12 ExpectedElseBlock
, ExpectedEqForLetExpr
, ExpectedExpressionFoundLet
,
13 FieldExpressionWithGeneric
, FloatLiteralRequiresIntegerPart
, FoundExprWouldBeStmt
,
14 IfExpressionMissingCondition
, IfExpressionMissingThenBlock
, IfExpressionMissingThenBlockSub
,
15 InvalidBlockMacroSegment
, InvalidComparisonOperator
, InvalidComparisonOperatorSub
,
16 InvalidInterpolatedExpression
, InvalidLiteralSuffixOnTupleIndex
, InvalidLogicalOperator
,
17 InvalidLogicalOperatorSub
, LabeledLoopInBreak
, LeadingPlusNotSupported
, LeftArrowOperator
,
18 LifetimeInBorrowExpression
, MacroInvocationWithQualifiedPath
, MalformedLoopLabel
,
19 MatchArmBodyWithoutBraces
, MatchArmBodyWithoutBracesSugg
, MissingCommaAfterMatchArm
,
20 MissingDotDot
, MissingInInForLoop
, MissingInInForLoopSub
, MissingSemicolonBeforeArray
,
21 NoFieldsForFnCall
, NotAsNegationOperator
, NotAsNegationOperatorSub
,
22 OuterAttributeNotAllowedOnIfElse
, ParenthesesWithStructFields
,
23 RequireColonAfterLabeledExpression
, ShiftInterpretedAsGeneric
, StructLiteralNotAllowedHere
,
24 StructLiteralNotAllowedHereSugg
, TildeAsUnaryOperator
, UnexpectedIfWithIf
,
25 UnexpectedTokenAfterLabel
, UnexpectedTokenAfterLabelSugg
, WrapExpressionInParentheses
,
27 use crate::maybe_recover_from_interpolated_ty_qpath
;
29 use rustc_ast
::ptr
::P
;
30 use rustc_ast
::token
::{self, Delimiter, Token, TokenKind}
;
31 use rustc_ast
::tokenstream
::Spacing
;
32 use rustc_ast
::util
::case
::Case
;
33 use rustc_ast
::util
::classify
;
34 use rustc_ast
::util
::parser
::{prec_let_scrutinee_needs_par, AssocOp, Fixity}
;
35 use rustc_ast
::visit
::Visitor
;
36 use rustc_ast
::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, UnOp, DUMMY_NODE_ID}
;
37 use rustc_ast
::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind}
;
38 use rustc_ast
::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}
;
39 use rustc_ast
::{ClosureBinder, MetaItemLit, StmtKind}
;
40 use rustc_ast_pretty
::pprust
;
42 Applicability
, Diagnostic
, DiagnosticBuilder
, ErrorGuaranteed
, IntoDiagnostic
, PResult
,
45 use rustc_session
::errors
::{report_lit_error, ExprParenthesesNeeded}
;
46 use rustc_session
::lint
::builtin
::BREAK_WITH_LABEL_AND_LOOP
;
47 use rustc_session
::lint
::BuiltinLintDiagnostics
;
48 use rustc_span
::source_map
::{self, Span, Spanned}
;
49 use rustc_span
::symbol
::{kw, sym, Ident, Symbol}
;
50 use rustc_span
::{BytePos, Pos}
;
52 /// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression
53 /// dropped into the token stream, which happens while parsing the result of
54 /// macro expansion). Placement of these is not as complex as I feared it would
55 /// be. The important thing is to make sure that lookahead doesn't balk at
56 /// `token::Interpolated` tokens.
57 macro_rules
! maybe_whole_expr
{
59 if let token
::Interpolated(nt
) = &$p
.token
.kind
{
61 token
::NtExpr(e
) | token
::NtLiteral(e
) => {
66 token
::NtPath(path
) => {
67 let path
= (**path
).clone();
69 return Ok($p
.mk_expr($p
.prev_token
.span
, ExprKind
::Path(None
, path
)));
71 token
::NtBlock(block
) => {
72 let block
= block
.clone();
74 return Ok($p
.mk_expr($p
.prev_token
.span
, ExprKind
::Block(block
, None
)));
83 pub(super) enum LhsExpr
{
85 AttributesParsed(AttrWrapper
),
86 AlreadyParsed(P
<Expr
>),
89 impl From
<Option
<AttrWrapper
>> for LhsExpr
{
90 /// Converts `Some(attrs)` into `LhsExpr::AttributesParsed(attrs)`
91 /// and `None` into `LhsExpr::NotYetParsed`.
93 /// This conversion does not allocate.
94 fn from(o
: Option
<AttrWrapper
>) -> Self {
95 if let Some(attrs
) = o { LhsExpr::AttributesParsed(attrs) }
else { LhsExpr::NotYetParsed }
99 impl From
<P
<Expr
>> for LhsExpr
{
100 /// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed(expr)`.
102 /// This conversion does not allocate.
103 fn from(expr
: P
<Expr
>) -> Self {
104 LhsExpr
::AlreadyParsed(expr
)
108 impl<'a
> Parser
<'a
> {
109 /// Parses an expression.
111 pub fn parse_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
112 self.current_closure
.take();
114 self.parse_expr_res(Restrictions
::empty(), None
)
117 /// Parses an expression, forcing tokens to be collected
118 pub fn parse_expr_force_collect(&mut self) -> PResult
<'a
, P
<Expr
>> {
119 self.collect_tokens_no_attrs(|this
| this
.parse_expr())
122 pub fn parse_anon_const_expr(&mut self) -> PResult
<'a
, AnonConst
> {
123 self.parse_expr().map(|value
| AnonConst { id: DUMMY_NODE_ID, value }
)
126 fn parse_expr_catch_underscore(&mut self) -> PResult
<'a
, P
<Expr
>> {
127 match self.parse_expr() {
128 Ok(expr
) => Ok(expr
),
129 Err(mut err
) => match self.token
.ident() {
130 Some((Ident { name: kw::Underscore, .. }
, false))
131 if self.may_recover() && self.look_ahead(1, |t
| t
== &token
::Comma
) =>
133 // Special-case handling of `foo(_, _, _)`
136 Ok(self.mk_expr(self.prev_token
.span
, ExprKind
::Err
))
143 /// Parses a sequence of expressions delimited by parentheses.
144 fn parse_paren_expr_seq(&mut self) -> PResult
<'a
, Vec
<P
<Expr
>>> {
145 self.parse_paren_comma_seq(|p
| p
.parse_expr_catch_underscore()).map(|(r
, _
)| r
)
148 /// Parses an expression, subject to the given restrictions.
150 pub(super) fn parse_expr_res(
153 already_parsed_attrs
: Option
<AttrWrapper
>,
154 ) -> PResult
<'a
, P
<Expr
>> {
155 self.with_res(r
, |this
| this
.parse_assoc_expr(already_parsed_attrs
))
158 /// Parses an associative expression.
160 /// This parses an expression accounting for associativity and precedence of the operators in
165 already_parsed_attrs
: Option
<AttrWrapper
>,
166 ) -> PResult
<'a
, P
<Expr
>> {
167 self.parse_assoc_expr_with(0, already_parsed_attrs
.into())
170 /// Parses an associative expression with operators of at least `min_prec` precedence.
171 pub(super) fn parse_assoc_expr_with(
175 ) -> PResult
<'a
, P
<Expr
>> {
176 let mut lhs
= if let LhsExpr
::AlreadyParsed(expr
) = lhs
{
179 let attrs
= match lhs
{
180 LhsExpr
::AttributesParsed(attrs
) => Some(attrs
),
183 if [token
::DotDot
, token
::DotDotDot
, token
::DotDotEq
].contains(&self.token
.kind
) {
184 return self.parse_prefix_range_expr(attrs
);
186 self.parse_prefix_expr(attrs
)?
189 let last_type_ascription_set
= self.last_type_ascription
.is_some();
191 if !self.should_continue_as_assoc_expr(&lhs
) {
192 self.last_type_ascription
= None
;
196 self.expected_tokens
.push(TokenType
::Operator
);
197 while let Some(op
) = self.check_assoc_op() {
198 // Adjust the span for interpolated LHS to point to the `$lhs` token
199 // and not to what it refers to.
200 let lhs_span
= match self.prev_token
.kind
{
201 TokenKind
::Interpolated(..) => self.prev_token
.span
,
205 let cur_op_span
= self.token
.span
;
206 let restrictions
= if op
.node
.is_assign_like() {
207 self.restrictions
& Restrictions
::NO_STRUCT_LITERAL
211 let prec
= op
.node
.precedence();
215 // Check for deprecated `...` syntax
216 if self.token
== token
::DotDotDot
&& op
.node
== AssocOp
::DotDotEq
{
217 self.err_dotdotdot_syntax(self.token
.span
);
220 if self.token
== token
::LArrow
{
221 self.err_larrow_operator(self.token
.span
);
225 if op
.node
.is_comparison() {
226 if let Some(expr
) = self.check_no_chained_comparison(&lhs
, &op
)?
{
231 // Look for JS' `===` and `!==` and recover
232 if (op
.node
== AssocOp
::Equal
|| op
.node
== AssocOp
::NotEqual
)
233 && self.token
.kind
== token
::Eq
234 && self.prev_token
.span
.hi() == self.token
.span
.lo()
236 let sp
= op
.span
.to(self.token
.span
);
237 let sugg
= match op
.node
{
238 AssocOp
::Equal
=> "==",
239 AssocOp
::NotEqual
=> "!=",
243 let invalid
= format
!("{}=", &sugg
);
244 self.sess
.emit_err(InvalidComparisonOperator
{
246 invalid
: invalid
.clone(),
247 sub
: InvalidComparisonOperatorSub
::Correctable
{
256 // Look for PHP's `<>` and recover
257 if op
.node
== AssocOp
::Less
258 && self.token
.kind
== token
::Gt
259 && self.prev_token
.span
.hi() == self.token
.span
.lo()
261 let sp
= op
.span
.to(self.token
.span
);
262 self.sess
.emit_err(InvalidComparisonOperator
{
264 invalid
: "<>".into(),
265 sub
: InvalidComparisonOperatorSub
::Correctable
{
267 invalid
: "<>".into(),
268 correct
: "!=".into(),
274 // Look for C++'s `<=>` and recover
275 if op
.node
== AssocOp
::LessEqual
276 && self.token
.kind
== token
::Gt
277 && self.prev_token
.span
.hi() == self.token
.span
.lo()
279 let sp
= op
.span
.to(self.token
.span
);
280 self.sess
.emit_err(InvalidComparisonOperator
{
282 invalid
: "<=>".into(),
283 sub
: InvalidComparisonOperatorSub
::Spaceship(sp
),
288 if self.prev_token
== token
::BinOp(token
::Plus
)
289 && self.token
== token
::BinOp(token
::Plus
)
290 && self.prev_token
.span
.between(self.token
.span
).is_empty()
292 let op_span
= self.prev_token
.span
.to(self.token
.span
);
293 // Eat the second `+`
295 lhs
= self.recover_from_postfix_increment(lhs
, op_span
)?
;
301 if op
== AssocOp
::As
{
302 lhs
= self.parse_assoc_op_cast(lhs
, lhs_span
, ExprKind
::Cast
)?
;
304 } else if op
== AssocOp
::Colon
{
305 lhs
= self.parse_assoc_op_ascribe(lhs
, lhs_span
)?
;
307 } else if op
== AssocOp
::DotDot
|| op
== AssocOp
::DotDotEq
{
308 // If we didn't have to handle `x..`/`x..=`, it would be pretty easy to
309 // generalise it to the Fixity::None code.
310 lhs
= self.parse_range_expr(prec
, lhs
, op
, cur_op_span
)?
;
314 let fixity
= op
.fixity();
315 let prec_adjustment
= match fixity
{
318 // We currently have no non-associative operators that are not handled above by
319 // the special cases. The code is here only for future convenience.
322 let rhs
= self.with_res(restrictions
- Restrictions
::STMT_EXPR
, |this
| {
323 this
.parse_assoc_expr_with(prec
+ prec_adjustment
, LhsExpr
::NotYetParsed
)
326 let span
= self.mk_expr_sp(&lhs
, lhs_span
, rhs
.span
);
339 | AssocOp
::ShiftRight
345 | AssocOp
::GreaterEqual
=> {
346 let ast_op
= op
.to_ast_binop().unwrap();
347 let binary
= self.mk_binary(source_map
::respan(cur_op_span
, ast_op
), lhs
, rhs
);
348 self.mk_expr(span
, binary
)
350 AssocOp
::Assign
=> self.mk_expr(span
, ExprKind
::Assign(lhs
, rhs
, cur_op_span
)),
351 AssocOp
::AssignOp(k
) => {
353 token
::Plus
=> BinOpKind
::Add
,
354 token
::Minus
=> BinOpKind
::Sub
,
355 token
::Star
=> BinOpKind
::Mul
,
356 token
::Slash
=> BinOpKind
::Div
,
357 token
::Percent
=> BinOpKind
::Rem
,
358 token
::Caret
=> BinOpKind
::BitXor
,
359 token
::And
=> BinOpKind
::BitAnd
,
360 token
::Or
=> BinOpKind
::BitOr
,
361 token
::Shl
=> BinOpKind
::Shl
,
362 token
::Shr
=> BinOpKind
::Shr
,
364 let aopexpr
= self.mk_assign_op(source_map
::respan(cur_op_span
, aop
), lhs
, rhs
);
365 self.mk_expr(span
, aopexpr
)
367 AssocOp
::As
| AssocOp
::Colon
| AssocOp
::DotDot
| AssocOp
::DotDotEq
=> {
368 self.span_bug(span
, "AssocOp should have been handled by special case")
372 if let Fixity
::None
= fixity
{
376 if last_type_ascription_set
{
377 self.last_type_ascription
= None
;
382 fn should_continue_as_assoc_expr(&mut self, lhs
: &Expr
) -> bool
{
383 match (self.expr_is_complete(lhs
), AssocOp
::from_token(&self.token
)) {
384 // Semi-statement forms are odd:
385 // See https://github.com/rust-lang/rust/issues/29071
386 (true, None
) => false,
387 (false, _
) => true, // Continue parsing the expression.
388 // An exhaustive check is done in the following block, but these are checked first
389 // because they *are* ambiguous but also reasonable looking incorrect syntax, so we
390 // want to keep their span info to improve diagnostics in these cases in a later stage.
391 (true, Some(AssocOp
::Multiply
)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
392 (true, Some(AssocOp
::Subtract
)) | // `{ 42 } -5`
393 (true, Some(AssocOp
::Add
)) | // `{ 42 } + 42` (unary plus)
394 (true, Some(AssocOp
::LAnd
)) | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
395 (true, Some(AssocOp
::LOr
)) | // `{ 42 } || 42` ("logical or" or closure)
396 (true, Some(AssocOp
::BitOr
)) // `{ 42 } | 42` or `{ 42 } |x| 42`
398 // These cases are ambiguous and can't be identified in the parser alone.
400 // Bitwise AND is left out because guessing intent is hard. We can make
401 // suggestions based on the assumption that double-refs are rarely intentional,
402 // and closures are distinct enough that they don't get mixed up with their
404 let sp
= self.sess
.source_map().start_point(self.token
.span
);
405 self.sess
.ambiguous_block_expr_parse
.borrow_mut().insert(sp
, lhs
.span
);
408 (true, Some(op
)) if !op
.can_continue_expr_unambiguously() => false,
410 self.error_found_expr_would_be_stmt(lhs
);
416 /// We've found an expression that would be parsed as a statement,
417 /// but the next token implies this should be parsed as an expression.
418 /// For example: `if let Some(x) = x { x } else { 0 } / 2`.
419 fn error_found_expr_would_be_stmt(&self, lhs
: &Expr
) {
420 self.sess
.emit_err(FoundExprWouldBeStmt
{
421 span
: self.token
.span
,
422 token
: self.token
.clone(),
423 suggestion
: ExprParenthesesNeeded
::surrounding(lhs
.span
),
427 /// Possibly translate the current token to an associative operator.
428 /// The method does not advance the current token.
430 /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
431 fn check_assoc_op(&self) -> Option
<Spanned
<AssocOp
>> {
432 let (op
, span
) = match (AssocOp
::from_token(&self.token
), self.token
.ident()) {
433 // When parsing const expressions, stop parsing when encountering `>`.
438 | AssocOp
::GreaterEqual
439 | AssocOp
::AssignOp(token
::BinOpToken
::Shr
),
442 ) if self.restrictions
.contains(Restrictions
::CONST_EXPR
) => {
445 (Some(op
), _
) => (op
, self.token
.span
),
446 (None
, Some((Ident { name: sym::and, span }
, false))) if self.may_recover() => {
447 self.sess
.emit_err(InvalidLogicalOperator
{
448 span
: self.token
.span
,
449 incorrect
: "and".into(),
450 sub
: InvalidLogicalOperatorSub
::Conjunction(self.token
.span
),
452 (AssocOp
::LAnd
, span
)
454 (None
, Some((Ident { name: sym::or, span }
, false))) if self.may_recover() => {
455 self.sess
.emit_err(InvalidLogicalOperator
{
456 span
: self.token
.span
,
457 incorrect
: "or".into(),
458 sub
: InvalidLogicalOperatorSub
::Disjunction(self.token
.span
),
464 Some(source_map
::respan(span
, op
))
467 /// Checks if this expression is a successfully parsed statement.
468 fn expr_is_complete(&self, e
: &Expr
) -> bool
{
469 self.restrictions
.contains(Restrictions
::STMT_EXPR
)
470 && !classify
::expr_requires_semi_to_be_stmt(e
)
473 /// Parses `x..y`, `x..=y`, and `x..`/`x..=`.
474 /// The other two variants are handled in `parse_prefix_range_expr` below.
481 ) -> PResult
<'a
, P
<Expr
>> {
482 let rhs
= if self.is_at_start_of_range_notation_rhs() {
483 Some(self.parse_assoc_expr_with(prec
+ 1, LhsExpr
::NotYetParsed
)?
)
487 let rhs_span
= rhs
.as_ref().map_or(cur_op_span
, |x
| x
.span
);
488 let span
= self.mk_expr_sp(&lhs
, lhs
.span
, rhs_span
);
490 if op
== AssocOp
::DotDot { RangeLimits::HalfOpen }
else { RangeLimits::Closed }
;
491 let range
= self.mk_range(Some(lhs
), rhs
, limits
);
492 Ok(self.mk_expr(span
, range
))
495 fn is_at_start_of_range_notation_rhs(&self) -> bool
{
496 if self.token
.can_begin_expr() {
497 // Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
498 if self.token
== token
::OpenDelim(Delimiter
::Brace
) {
499 return !self.restrictions
.contains(Restrictions
::NO_STRUCT_LITERAL
);
507 /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`.
508 fn parse_prefix_range_expr(&mut self, attrs
: Option
<AttrWrapper
>) -> PResult
<'a
, P
<Expr
>> {
509 // Check for deprecated `...` syntax.
510 if self.token
== token
::DotDotDot
{
511 self.err_dotdotdot_syntax(self.token
.span
);
515 [token
::DotDot
, token
::DotDotDot
, token
::DotDotEq
].contains(&self.token
.kind
),
516 "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq",
520 let limits
= match self.token
.kind
{
521 token
::DotDot
=> RangeLimits
::HalfOpen
,
522 _
=> RangeLimits
::Closed
,
524 let op
= AssocOp
::from_token(&self.token
);
525 // FIXME: `parse_prefix_range_expr` is called when the current
526 // token is `DotDot`, `DotDotDot`, or `DotDotEq`. If we haven't already
527 // parsed attributes, then trying to parse them here will always fail.
528 // We should figure out how we want attributes on range expressions to work.
529 let attrs
= self.parse_or_use_outer_attributes(attrs
)?
;
530 self.collect_tokens_for_expr(attrs
, |this
, attrs
| {
531 let lo
= this
.token
.span
;
533 let (span
, opt_end
) = if this
.is_at_start_of_range_notation_rhs() {
534 // RHS must be parsed with more associativity than the dots.
535 this
.parse_assoc_expr_with(op
.unwrap().precedence() + 1, LhsExpr
::NotYetParsed
)
536 .map(|x
| (lo
.to(x
.span
), Some(x
)))?
540 let range
= this
.mk_range(None
, opt_end
, limits
);
541 Ok(this
.mk_expr_with_attrs(span
, range
, attrs
))
545 /// Parses a prefix-unary-operator expr.
546 fn parse_prefix_expr(&mut self, attrs
: Option
<AttrWrapper
>) -> PResult
<'a
, P
<Expr
>> {
547 let attrs
= self.parse_or_use_outer_attributes(attrs
)?
;
548 let lo
= self.token
.span
;
550 macro_rules
! make_it
{
551 ($this
:ident
, $attrs
:expr
, |this
, _
| $body
:expr
) => {
552 $this
.collect_tokens_for_expr($attrs
, |$this
, attrs
| {
553 let (hi
, ex
) = $body?
;
554 Ok($this
.mk_expr_with_attrs(lo
.to(hi
), ex
, attrs
))
561 // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
562 match this
.token
.uninterpolate().kind
{
563 token
::Not
=> make_it
!(this
, attrs
, |this
, _
| this
.parse_unary_expr(lo
, UnOp
::Not
)), // `!expr`
564 token
::Tilde
=> make_it
!(this
, attrs
, |this
, _
| this
.recover_tilde_expr(lo
)), // `~expr`
565 token
::BinOp(token
::Minus
) => {
566 make_it
!(this
, attrs
, |this
, _
| this
.parse_unary_expr(lo
, UnOp
::Neg
))
568 token
::BinOp(token
::Star
) => {
569 make_it
!(this
, attrs
, |this
, _
| this
.parse_unary_expr(lo
, UnOp
::Deref
))
571 token
::BinOp(token
::And
) | token
::AndAnd
=> {
572 make_it
!(this
, attrs
, |this
, _
| this
.parse_borrow_expr(lo
))
574 token
::BinOp(token
::Plus
) if this
.look_ahead(1, |tok
| tok
.is_numeric_lit()) => {
576 LeadingPlusNotSupported { span: lo, remove_plus: None, add_parentheses: None }
;
578 // a block on the LHS might have been intended to be an expression instead
579 if let Some(sp
) = this
.sess
.ambiguous_block_expr_parse
.borrow().get(&lo
) {
580 err
.add_parentheses
= Some(ExprParenthesesNeeded
::surrounding(*sp
));
582 err
.remove_plus
= Some(lo
);
584 this
.sess
.emit_err(err
);
587 this
.parse_prefix_expr(None
)
589 // Recover from `++x`:
590 token
::BinOp(token
::Plus
)
591 if this
.look_ahead(1, |t
| *t
== token
::BinOp(token
::Plus
)) =>
593 let prev_is_semi
= this
.prev_token
== token
::Semi
;
594 let pre_span
= this
.token
.span
.to(this
.look_ahead(1, |t
| t
.span
));
599 let operand_expr
= this
.parse_dot_or_call_expr(Default
::default())?
;
600 this
.recover_from_prefix_increment(operand_expr
, pre_span
, prev_is_semi
)
602 token
::Ident(..) if this
.token
.is_keyword(kw
::Box
) => {
603 make_it
!(this
, attrs
, |this
, _
| this
.parse_box_expr(lo
))
605 token
::Ident(..) if this
.may_recover() && this
.is_mistaken_not_ident_negation() => {
606 make_it
!(this
, attrs
, |this
, _
| this
.recover_not_expr(lo
))
608 _
=> return this
.parse_dot_or_call_expr(Some(attrs
)),
612 fn parse_prefix_expr_common(&mut self, lo
: Span
) -> PResult
<'a
, (Span
, P
<Expr
>)> {
614 let expr
= self.parse_prefix_expr(None
);
615 let (span
, expr
) = self.interpolated_or_expr_span(expr
)?
;
616 Ok((lo
.to(span
), expr
))
619 fn parse_unary_expr(&mut self, lo
: Span
, op
: UnOp
) -> PResult
<'a
, (Span
, ExprKind
)> {
620 let (span
, expr
) = self.parse_prefix_expr_common(lo
)?
;
621 Ok((span
, self.mk_unary(op
, expr
)))
624 // Recover on `!` suggesting for bitwise negation instead.
625 fn recover_tilde_expr(&mut self, lo
: Span
) -> PResult
<'a
, (Span
, ExprKind
)> {
626 self.sess
.emit_err(TildeAsUnaryOperator(lo
));
628 self.parse_unary_expr(lo
, UnOp
::Not
)
631 /// Parse `box expr`.
632 fn parse_box_expr(&mut self, lo
: Span
) -> PResult
<'a
, (Span
, ExprKind
)> {
633 let (span
, expr
) = self.parse_prefix_expr_common(lo
)?
;
634 self.sess
.gated_spans
.gate(sym
::box_syntax
, span
);
635 Ok((span
, ExprKind
::Box(expr
)))
638 fn is_mistaken_not_ident_negation(&self) -> bool
{
639 let token_cannot_continue_expr
= |t
: &Token
| match t
.uninterpolate().kind
{
640 // These tokens can start an expression after `!`, but
641 // can't continue an expression after an ident
642 token
::Ident(name
, is_raw
) => token
::ident_can_begin_expr(name
, t
.span
, is_raw
),
643 token
::Literal(..) | token
::Pound
=> true,
644 _
=> t
.is_whole_expr(),
646 self.token
.is_ident_named(sym
::not
) && self.look_ahead(1, token_cannot_continue_expr
)
649 /// Recover on `not expr` in favor of `!expr`.
650 fn recover_not_expr(&mut self, lo
: Span
) -> PResult
<'a
, (Span
, ExprKind
)> {
652 let negated_token
= self.look_ahead(1, |t
| t
.clone());
654 let sub_diag
= if negated_token
.is_numeric_lit() {
655 NotAsNegationOperatorSub
::SuggestNotBitwise
656 } else if negated_token
.is_bool_lit() {
657 NotAsNegationOperatorSub
::SuggestNotLogical
659 NotAsNegationOperatorSub
::SuggestNotDefault
662 self.sess
.emit_err(NotAsNegationOperator
{
663 negated
: negated_token
.span
,
664 negated_desc
: super::token_descr(&negated_token
),
665 // Span the `not` plus trailing whitespace to avoid
666 // trailing whitespace after the `!` in our suggestion
668 self.sess
.source_map().span_until_non_whitespace(lo
.to(negated_token
.span
)),
673 self.parse_unary_expr(lo
, UnOp
::Not
)
676 /// Returns the span of expr, if it was not interpolated or the span of the interpolated token.
677 fn interpolated_or_expr_span(
679 expr
: PResult
<'a
, P
<Expr
>>,
680 ) -> PResult
<'a
, (Span
, P
<Expr
>)> {
683 match self.prev_token
.kind
{
684 TokenKind
::Interpolated(..) => self.prev_token
.span
,
692 fn parse_assoc_op_cast(
696 expr_kind
: fn(P
<Expr
>, P
<Ty
>) -> ExprKind
,
697 ) -> PResult
<'a
, P
<Expr
>> {
698 let mk_expr
= |this
: &mut Self, lhs
: P
<Expr
>, rhs
: P
<Ty
>| {
699 this
.mk_expr(this
.mk_expr_sp(&lhs
, lhs_span
, rhs
.span
), expr_kind(lhs
, rhs
))
702 // Save the state of the parser before parsing type normally, in case there is a
703 // LessThan comparison after this cast.
704 let parser_snapshot_before_type
= self.clone();
705 let cast_expr
= match self.parse_as_cast_ty() {
706 Ok(rhs
) => mk_expr(self, lhs
, rhs
),
708 if !self.may_recover() {
709 return Err(type_err
);
712 // Rewind to before attempting to parse the type with generics, to recover
713 // from situations like `x as usize < y` in which we first tried to parse
714 // `usize < y` as a type with generic arguments.
715 let parser_snapshot_after_type
= mem
::replace(self, parser_snapshot_before_type
);
717 // Check for typo of `'a: loop { break 'a }` with a missing `'`.
718 match (&lhs
.kind
, &self.token
.kind
) {
721 ExprKind
::Path(None
, ast
::Path { segments, .. }
),
722 TokenKind
::Ident(kw
::For
| kw
::Loop
| kw
::While
, false),
723 ) if segments
.len() == 1 => {
724 let snapshot
= self.create_snapshot_for_diagnostic();
726 ident
: Ident
::from_str_and_span(
727 &format
!("'{}", segments
[0].ident
),
728 segments
[0].ident
.span
,
731 match self.parse_labeled_expr(label
, false) {
734 self.sess
.emit_err(MalformedLoopLabel
{
735 span
: label
.ident
.span
,
736 correct_label
: label
.ident
,
742 self.restore_snapshot(snapshot
);
749 match self.parse_path(PathStyle
::Expr
) {
751 let span_after_type
= parser_snapshot_after_type
.token
.span
;
755 self.mk_ty(path
.span
, TyKind
::Path(None
, path
.clone())),
758 let args_span
= self.look_ahead(1, |t
| t
.span
).to(span_after_type
);
759 let suggestion
= ComparisonOrShiftInterpretedAsGenericSugg
{
760 left
: expr
.span
.shrink_to_lo(),
761 right
: expr
.span
.shrink_to_hi(),
764 match self.token
.kind
{
765 token
::Lt
=> self.sess
.emit_err(ComparisonInterpretedAsGeneric
{
766 comparison
: self.token
.span
,
771 token
::BinOp(token
::Shl
) => {
772 self.sess
.emit_err(ShiftInterpretedAsGeneric
{
773 shift
: self.token
.span
,
780 // We can end up here even without `<` being the next token, for
781 // example because `parse_ty_no_plus` returns `Err` on keywords,
782 // but `parse_path` returns `Ok` on them due to error recovery.
783 // Return original error and parser state.
784 *self = parser_snapshot_after_type
;
785 return Err(type_err
);
789 // Successfully parsed the type path leaving a `<` yet to parse.
792 // Keep `x as usize` as an expression in AST and continue parsing.
796 // Couldn't parse as a path, return original error and parser state.
798 *self = parser_snapshot_after_type
;
799 return Err(type_err
);
805 self.parse_and_disallow_postfix_after_cast(cast_expr
)
808 /// Parses a postfix operators such as `.`, `?`, or index (`[]`) after a cast,
809 /// then emits an error and returns the newly parsed tree.
810 /// The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`.
811 fn parse_and_disallow_postfix_after_cast(
814 ) -> PResult
<'a
, P
<Expr
>> {
815 let span
= cast_expr
.span
;
816 let (cast_kind
, maybe_ascription_span
) =
817 if let ExprKind
::Type(ascripted_expr
, _
) = &cast_expr
.kind
{
818 ("type ascription", Some(ascripted_expr
.span
.shrink_to_hi().with_hi(span
.hi())))
823 let with_postfix
= self.parse_dot_or_call_expr_with_(cast_expr
, span
)?
;
825 // Check if an illegal postfix operator has been added after the cast.
826 // If the resulting expression is not a cast, it is an illegal postfix operator.
827 if !matches
!(with_postfix
.kind
, ExprKind
::Cast(_
, _
) | ExprKind
::Type(_
, _
)) {
829 "{cast_kind} cannot be followed by {}",
830 match with_postfix
.kind
{
831 ExprKind
::Index(_
, _
) => "indexing",
832 ExprKind
::Try(_
) => "`?`",
833 ExprKind
::Field(_
, _
) => "a field access",
834 ExprKind
::MethodCall(_
) => "a method call",
835 ExprKind
::Call(_
, _
) => "a function call",
836 ExprKind
::Await(_
) => "`.await`",
837 ExprKind
::Err
=> return Ok(with_postfix
),
838 _
=> unreachable
!("parse_dot_or_call_expr_with_ shouldn't produce this"),
841 let mut err
= self.struct_span_err(span
, &msg
);
843 let suggest_parens
= |err
: &mut Diagnostic
| {
844 let suggestions
= vec
![
845 (span
.shrink_to_lo(), "(".to_string()),
846 (span
.shrink_to_hi(), ")".to_string()),
848 err
.multipart_suggestion(
849 "try surrounding the expression in parentheses",
851 Applicability
::MachineApplicable
,
855 // If type ascription is "likely an error", the user will already be getting a useful
856 // help message, and doesn't need a second.
857 if self.last_type_ascription
.map_or(false, |last_ascription
| last_ascription
.1) {
858 self.maybe_annotate_with_ascription(&mut err
, false);
859 } else if let Some(ascription_span
) = maybe_ascription_span
{
860 let is_nightly
= self.sess
.unstable_features
.is_nightly_build();
862 suggest_parens(&mut err
);
867 "{}remove the type ascription",
868 if is_nightly { "alternatively, " }
else { "" }
872 Applicability
::MaybeIncorrect
874 Applicability
::MachineApplicable
878 suggest_parens(&mut err
);
885 fn parse_assoc_op_ascribe(&mut self, lhs
: P
<Expr
>, lhs_span
: Span
) -> PResult
<'a
, P
<Expr
>> {
886 let maybe_path
= self.could_ascription_be_path(&lhs
.kind
);
887 self.last_type_ascription
= Some((self.prev_token
.span
, maybe_path
));
888 let lhs
= self.parse_assoc_op_cast(lhs
, lhs_span
, ExprKind
::Type
)?
;
889 self.sess
.gated_spans
.gate(sym
::type_ascription
, lhs
.span
);
893 /// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.
894 fn parse_borrow_expr(&mut self, lo
: Span
) -> PResult
<'a
, (Span
, ExprKind
)> {
896 let has_lifetime
= self.token
.is_lifetime() && self.look_ahead(1, |t
| t
!= &token
::Colon
);
897 let lifetime
= has_lifetime
.then(|| self.expect_lifetime()); // For recovery, see below.
898 let (borrow_kind
, mutbl
) = self.parse_borrow_modifiers(lo
);
899 let expr
= self.parse_prefix_expr(None
);
900 let (hi
, expr
) = self.interpolated_or_expr_span(expr
)?
;
901 let span
= lo
.to(hi
);
902 if let Some(lt
) = lifetime
{
903 self.error_remove_borrow_lifetime(span
, lt
.ident
.span
);
905 Ok((span
, ExprKind
::AddrOf(borrow_kind
, mutbl
, expr
)))
908 fn error_remove_borrow_lifetime(&self, span
: Span
, lt_span
: Span
) {
909 self.sess
.emit_err(LifetimeInBorrowExpression { span, lifetime_span: lt_span }
);
912 /// Parse `mut?` or `raw [ const | mut ]`.
913 fn parse_borrow_modifiers(&mut self, lo
: Span
) -> (ast
::BorrowKind
, ast
::Mutability
) {
914 if self.check_keyword(kw
::Raw
) && self.look_ahead(1, Token
::is_mutability
) {
915 // `raw [ const | mut ]`.
916 let found_raw
= self.eat_keyword(kw
::Raw
);
918 let mutability
= self.parse_const_or_mut().unwrap();
919 self.sess
.gated_spans
.gate(sym
::raw_ref_op
, lo
.to(self.prev_token
.span
));
920 (ast
::BorrowKind
::Raw
, mutability
)
923 (ast
::BorrowKind
::Ref
, self.parse_mutability())
927 /// Parses `a.b` or `a(13)` or `a[4]` or just `a`.
928 fn parse_dot_or_call_expr(&mut self, attrs
: Option
<AttrWrapper
>) -> PResult
<'a
, P
<Expr
>> {
929 let attrs
= self.parse_or_use_outer_attributes(attrs
)?
;
930 self.collect_tokens_for_expr(attrs
, |this
, attrs
| {
931 let base
= this
.parse_bottom_expr();
932 let (span
, base
) = this
.interpolated_or_expr_span(base
)?
;
933 this
.parse_dot_or_call_expr_with(base
, span
, attrs
)
937 pub(super) fn parse_dot_or_call_expr_with(
941 mut attrs
: ast
::AttrVec
,
942 ) -> PResult
<'a
, P
<Expr
>> {
943 // Stitch the list of outer attributes onto the return value.
944 // A little bit ugly, but the best way given the current code
946 let res
= self.parse_dot_or_call_expr_with_(e0
, lo
);
947 if attrs
.is_empty() {
951 expr
.map(|mut expr
| {
952 attrs
.extend(expr
.attrs
);
960 fn parse_dot_or_call_expr_with_(&mut self, mut e
: P
<Expr
>, lo
: Span
) -> PResult
<'a
, P
<Expr
>> {
962 let has_question
= if self.prev_token
.kind
== TokenKind
::Ident(kw
::Return
, false) {
963 // we are using noexpect here because we don't expect a `?` directly after a `return`
964 // which could be suggested otherwise
965 self.eat_noexpect(&token
::Question
)
967 self.eat(&token
::Question
)
971 e
= self.mk_expr(lo
.to(self.prev_token
.span
), ExprKind
::Try(e
));
974 let has_dot
= if self.prev_token
.kind
== TokenKind
::Ident(kw
::Return
, false) {
975 // we are using noexpect here because we don't expect a `.` directly after a `return`
976 // which could be suggested otherwise
977 self.eat_noexpect(&token
::Dot
)
979 self.eat(&token
::Dot
)
983 e
= self.parse_dot_suffix_expr(lo
, e
)?
;
986 if self.expr_is_complete(&e
) {
989 e
= match self.token
.kind
{
990 token
::OpenDelim(Delimiter
::Parenthesis
) => self.parse_fn_call_expr(lo
, e
),
991 token
::OpenDelim(Delimiter
::Bracket
) => self.parse_index_expr(lo
, e
)?
,
997 fn look_ahead_type_ascription_as_field(&mut self) -> bool
{
998 self.look_ahead(1, |t
| t
.is_ident())
999 && self.look_ahead(2, |t
| t
== &token
::Colon
)
1000 && self.look_ahead(3, |t
| t
.can_begin_expr())
1003 fn parse_dot_suffix_expr(&mut self, lo
: Span
, base
: P
<Expr
>) -> PResult
<'a
, P
<Expr
>> {
1004 match self.token
.uninterpolate().kind
{
1005 token
::Ident(..) => self.parse_dot_suffix(base
, lo
),
1006 token
::Literal(token
::Lit { kind: token::Integer, symbol, suffix }
) => {
1007 Ok(self.parse_tuple_field_access_expr(lo
, base
, symbol
, suffix
, None
))
1009 token
::Literal(token
::Lit { kind: token::Float, symbol, suffix }
) => {
1010 Ok(self.parse_tuple_field_access_expr_float(lo
, base
, symbol
, suffix
))
1013 self.error_unexpected_after_dot();
1019 fn error_unexpected_after_dot(&self) {
1020 // FIXME Could factor this out into non_fatal_unexpected or something.
1021 let actual
= pprust
::token_to_string(&self.token
);
1022 self.struct_span_err(self.token
.span
, &format
!("unexpected token: `{actual}`")).emit();
1025 // We need an identifier or integer, but the next token is a float.
1026 // Break the float into components to extract the identifier or integer.
1027 // FIXME: With current `TokenCursor` it's hard to break tokens into more than 2
1028 // parts unless those parts are processed immediately. `TokenCursor` should either
1029 // support pushing "future tokens" (would be also helpful to `break_and_eat`), or
1030 // we should break everything including floats into more basic proc-macro style
1031 // tokens in the lexer (probably preferable).
1032 fn parse_tuple_field_access_expr_float(
1037 suffix
: Option
<Symbol
>,
1040 enum FloatComponent
{
1044 use FloatComponent
::*;
1046 let float_str
= float
.as_str();
1047 let mut components
= Vec
::new();
1048 let mut ident_like
= String
::new();
1049 for c
in float_str
.chars() {
1050 if c
== '_'
|| c
.is_ascii_alphanumeric() {
1052 } else if matches
!(c
, '
.'
| '
+'
| '
-'
) {
1053 if !ident_like
.is_empty() {
1054 components
.push(IdentLike(mem
::take(&mut ident_like
)));
1056 components
.push(Punct(c
));
1058 panic
!("unexpected character in a float token: {:?}", c
)
1061 if !ident_like
.is_empty() {
1062 components
.push(IdentLike(ident_like
));
1065 // With proc macros the span can refer to anything, the source may be too short,
1066 // or too long, or non-ASCII. It only makes sense to break our span into components
1067 // if its underlying text is identical to our float literal.
1068 let span
= self.token
.span
;
1069 let can_take_span_apart
=
1070 || self.span_to_snippet(span
).as_deref() == Ok(float_str
).as_deref();
1072 match &*components
{
1075 self.parse_tuple_field_access_expr(lo
, base
, Symbol
::intern(&i
), suffix
, None
)
1078 [IdentLike(i
), Punct('
.'
)] => {
1079 let (ident_span
, dot_span
) = if can_take_span_apart() {
1080 let (span
, ident_len
) = (span
.data(), BytePos
::from_usize(i
.len()));
1081 let ident_span
= span
.with_hi(span
.lo
+ ident_len
);
1082 let dot_span
= span
.with_lo(span
.lo
+ ident_len
);
1083 (ident_span
, dot_span
)
1087 assert
!(suffix
.is_none());
1088 let symbol
= Symbol
::intern(&i
);
1089 self.token
= Token
::new(token
::Ident(symbol
, false), ident_span
);
1090 let next_token
= (Token
::new(token
::Dot
, dot_span
), self.token_spacing
);
1091 self.parse_tuple_field_access_expr(lo
, base
, symbol
, None
, Some(next_token
))
1094 [IdentLike(i1
), Punct('
.'
), IdentLike(i2
)] => {
1095 let (ident1_span
, dot_span
, ident2_span
) = if can_take_span_apart() {
1096 let (span
, ident1_len
) = (span
.data(), BytePos
::from_usize(i1
.len()));
1097 let ident1_span
= span
.with_hi(span
.lo
+ ident1_len
);
1099 .with_lo(span
.lo
+ ident1_len
)
1100 .with_hi(span
.lo
+ ident1_len
+ BytePos(1));
1101 let ident2_span
= self.token
.span
.with_lo(span
.lo
+ ident1_len
+ BytePos(1));
1102 (ident1_span
, dot_span
, ident2_span
)
1106 let symbol1
= Symbol
::intern(&i1
);
1107 self.token
= Token
::new(token
::Ident(symbol1
, false), ident1_span
);
1108 // This needs to be `Spacing::Alone` to prevent regressions.
1109 // See issue #76399 and PR #76285 for more details
1110 let next_token1
= (Token
::new(token
::Dot
, dot_span
), Spacing
::Alone
);
1112 self.parse_tuple_field_access_expr(lo
, base
, symbol1
, None
, Some(next_token1
));
1113 let symbol2
= Symbol
::intern(&i2
);
1114 let next_token2
= Token
::new(token
::Ident(symbol2
, false), ident2_span
);
1115 self.bump_with((next_token2
, self.token_spacing
)); // `.`
1116 self.parse_tuple_field_access_expr(lo
, base1
, symbol2
, suffix
, None
)
1118 // 1e+ | 1e- (recovered)
1119 [IdentLike(_
), Punct('
+'
| '
-'
)] |
1121 [IdentLike(_
), Punct('
+'
| '
-'
), IdentLike(_
)] |
1123 [IdentLike(_
), Punct('
.'
), IdentLike(_
), Punct('
+'
| '
-'
)] |
1125 [IdentLike(_
), Punct('
.'
), IdentLike(_
), Punct('
+'
| '
-'
), IdentLike(_
)] => {
1126 // See the FIXME about `TokenCursor` above.
1127 self.error_unexpected_after_dot();
1130 _
=> panic
!("unexpected components in a float token: {:?}", components
),
1134 fn parse_tuple_field_access_expr(
1139 suffix
: Option
<Symbol
>,
1140 next_token
: Option
<(Token
, Spacing
)>,
1143 Some(next_token
) => self.bump_with(next_token
),
1144 None
=> self.bump(),
1146 let span
= self.prev_token
.span
;
1147 let field
= ExprKind
::Field(base
, Ident
::new(field
, span
));
1148 if let Some(suffix
) = suffix
{
1149 self.expect_no_tuple_index_suffix(span
, suffix
);
1151 self.mk_expr(lo
.to(span
), field
)
1154 /// Parse a function call expression, `expr(...)`.
1155 fn parse_fn_call_expr(&mut self, lo
: Span
, fun
: P
<Expr
>) -> P
<Expr
> {
1156 let snapshot
= if self.token
.kind
== token
::OpenDelim(Delimiter
::Parenthesis
)
1157 && self.look_ahead_type_ascription_as_field()
1159 Some((self.create_snapshot_for_diagnostic(), fun
.kind
.clone()))
1163 let open_paren
= self.token
.span
;
1166 .parse_paren_expr_seq()
1167 .map(|args
| self.mk_expr(lo
.to(self.prev_token
.span
), self.mk_call(fun
, args
)));
1169 self.maybe_recover_struct_lit_bad_delims(lo
, open_paren
, &mut seq
, snapshot
)
1173 self.recover_seq_parse_error(Delimiter
::Parenthesis
, lo
, seq
)
1176 /// If we encounter a parser state that looks like the user has written a `struct` literal with
1177 /// parentheses instead of braces, recover the parser state and provide suggestions.
1178 #[instrument(skip(self, seq, snapshot), level = "trace")]
1179 fn maybe_recover_struct_lit_bad_delims(
1183 seq
: &mut PResult
<'a
, P
<Expr
>>,
1184 snapshot
: Option
<(SnapshotParser
<'a
>, ExprKind
)>,
1185 ) -> Option
<P
<Expr
>> {
1186 if !self.may_recover() {
1190 match (seq
.as_mut(), snapshot
) {
1191 (Err(err
), Some((mut snapshot
, ExprKind
::Path(None
, path
)))) => {
1192 snapshot
.bump(); // `(`
1193 match snapshot
.parse_struct_fields(path
.clone(), false, Delimiter
::Parenthesis
) {
1195 if snapshot
.eat(&token
::CloseDelim(Delimiter
::Parenthesis
)) =>
1197 // We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
1198 // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.
1199 self.restore_snapshot(snapshot
);
1200 let close_paren
= self.prev_token
.span
;
1201 let span
= lo
.to(self.prev_token
.span
);
1202 if !fields
.is_empty() {
1203 let mut replacement_err
= ParenthesesWithStructFields
{
1206 braces_for_struct
: BracesForStructLiteral
{
1208 second
: close_paren
,
1210 no_fields_for_fn
: NoFieldsForFnCall
{
1213 .map(|field
| field
.span
.until(field
.expr
.span
))
1217 .into_diagnostic(&self.sess
.span_diagnostic
);
1218 replacement_err
.emit();
1220 let old_err
= mem
::replace(err
, replacement_err
);
1225 return Some(self.mk_expr_err(span
));
1238 /// Parse an indexing expression `expr[...]`.
1239 fn parse_index_expr(&mut self, lo
: Span
, base
: P
<Expr
>) -> PResult
<'a
, P
<Expr
>> {
1240 let prev_span
= self.prev_token
.span
;
1241 let open_delim_span
= self.token
.span
;
1243 let index
= self.parse_expr()?
;
1244 self.suggest_missing_semicolon_before_array(prev_span
, open_delim_span
)?
;
1245 self.expect(&token
::CloseDelim(Delimiter
::Bracket
))?
;
1246 Ok(self.mk_expr(lo
.to(self.prev_token
.span
), self.mk_index(base
, index
)))
1249 /// Assuming we have just parsed `.`, continue parsing into an expression.
1250 fn parse_dot_suffix(&mut self, self_arg
: P
<Expr
>, lo
: Span
) -> PResult
<'a
, P
<Expr
>> {
1251 if self.token
.uninterpolated_span().rust_2018() && self.eat_keyword(kw
::Await
) {
1252 return Ok(self.mk_await_expr(self_arg
, lo
));
1255 let fn_span_lo
= self.token
.span
;
1256 let mut seg
= self.parse_path_segment(PathStyle
::Expr
, None
)?
;
1257 self.check_trailing_angle_brackets(&seg
, &[&token
::OpenDelim(Delimiter
::Parenthesis
)]);
1258 self.check_turbofish_missing_angle_brackets(&mut seg
);
1260 if self.check(&token
::OpenDelim(Delimiter
::Parenthesis
)) {
1261 // Method call `expr.f()`
1262 let args
= self.parse_paren_expr_seq()?
;
1263 let fn_span
= fn_span_lo
.to(self.prev_token
.span
);
1264 let span
= lo
.to(self.prev_token
.span
);
1267 ExprKind
::MethodCall(Box
::new(ast
::MethodCall
{
1275 // Field access `expr.f`
1276 if let Some(args
) = seg
.args
{
1277 self.sess
.emit_err(FieldExpressionWithGeneric(args
.span()));
1280 let span
= lo
.to(self.prev_token
.span
);
1281 Ok(self.mk_expr(span
, ExprKind
::Field(self_arg
, seg
.ident
)))
1285 /// At the bottom (top?) of the precedence hierarchy,
1286 /// Parses things like parenthesized exprs, macros, `return`, etc.
1288 /// N.B., this does not parse outer attributes, and is private because it only works
1289 /// correctly if called from `parse_dot_or_call_expr()`.
1290 fn parse_bottom_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
1291 maybe_recover_from_interpolated_ty_qpath
!(self, true);
1292 maybe_whole_expr
!(self);
1294 // Outer attributes are already parsed and will be
1295 // added to the return value after the fact.
1297 // Note: when adding new syntax here, don't forget to adjust `TokenKind::can_begin_expr()`.
1298 let lo
= self.token
.span
;
1299 if let token
::Literal(_
) = self.token
.kind
{
1300 // This match arm is a special-case of the `_` match arm below and
1301 // could be removed without changing functionality, but it's faster
1302 // to have it here, especially for programs with large constants.
1303 self.parse_lit_expr()
1304 } else if self.check(&token
::OpenDelim(Delimiter
::Parenthesis
)) {
1305 self.parse_tuple_parens_expr()
1306 } else if self.check(&token
::OpenDelim(Delimiter
::Brace
)) {
1307 self.parse_block_expr(None
, lo
, BlockCheckMode
::Default
)
1308 } else if self.check(&token
::BinOp(token
::Or
)) || self.check(&token
::OrOr
) {
1309 self.parse_closure_expr().map_err(|mut err
| {
1310 // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`
1311 // then suggest parens around the lhs.
1312 if let Some(sp
) = self.sess
.ambiguous_block_expr_parse
.borrow().get(&lo
) {
1313 err
.subdiagnostic(ExprParenthesesNeeded
::surrounding(*sp
));
1317 } else if self.check(&token
::OpenDelim(Delimiter
::Bracket
)) {
1318 self.parse_array_or_repeat_expr(Delimiter
::Bracket
)
1319 } else if self.check_path() {
1320 self.parse_path_start_expr()
1321 } else if self.check_keyword(kw
::Move
) || self.check_keyword(kw
::Static
) {
1322 self.parse_closure_expr()
1323 } else if self.eat_keyword(kw
::If
) {
1324 self.parse_if_expr()
1325 } else if self.check_keyword(kw
::For
) {
1326 if self.choose_generics_over_qpath(1) {
1327 self.parse_closure_expr()
1329 assert
!(self.eat_keyword(kw
::For
));
1330 self.parse_for_expr(None
, self.prev_token
.span
)
1332 } else if self.eat_keyword(kw
::While
) {
1333 self.parse_while_expr(None
, self.prev_token
.span
)
1334 } else if let Some(label
) = self.eat_label() {
1335 self.parse_labeled_expr(label
, true)
1336 } else if self.eat_keyword(kw
::Loop
) {
1337 let sp
= self.prev_token
.span
;
1338 self.parse_loop_expr(None
, self.prev_token
.span
).map_err(|mut err
| {
1339 err
.span_label(sp
, "while parsing this `loop` expression");
1342 } else if self.eat_keyword(kw
::Continue
) {
1343 let kind
= ExprKind
::Continue(self.eat_label());
1344 Ok(self.mk_expr(lo
.to(self.prev_token
.span
), kind
))
1345 } else if self.eat_keyword(kw
::Match
) {
1346 let match_sp
= self.prev_token
.span
;
1347 self.parse_match_expr().map_err(|mut err
| {
1348 err
.span_label(match_sp
, "while parsing this `match` expression");
1351 } else if self.eat_keyword(kw
::Unsafe
) {
1352 let sp
= self.prev_token
.span
;
1353 self.parse_block_expr(None
, lo
, BlockCheckMode
::Unsafe(ast
::UserProvided
)).map_err(
1355 err
.span_label(sp
, "while parsing this `unsafe` expression");
1359 } else if self.check_inline_const(0) {
1360 self.parse_const_block(lo
.to(self.token
.span
), false)
1361 } else if self.may_recover() && self.is_do_catch_block() {
1362 self.recover_do_catch()
1363 } else if self.is_try_block() {
1364 self.expect_keyword(kw
::Try
)?
;
1365 self.parse_try_block(lo
)
1366 } else if self.eat_keyword(kw
::Return
) {
1367 self.parse_return_expr()
1368 } else if self.eat_keyword(kw
::Break
) {
1369 self.parse_break_expr()
1370 } else if self.eat_keyword(kw
::Yield
) {
1371 self.parse_yield_expr()
1372 } else if self.is_do_yeet() {
1373 self.parse_yeet_expr()
1374 } else if self.check_keyword(kw
::Let
) {
1375 self.parse_let_expr()
1376 } else if self.eat_keyword(kw
::Underscore
) {
1377 Ok(self.mk_expr(self.prev_token
.span
, ExprKind
::Underscore
))
1378 } else if !self.unclosed_delims
.is_empty() && self.check(&token
::Semi
) {
1379 // Don't complain about bare semicolons after unclosed braces
1380 // recovery in order to keep the error count down. Fixing the
1381 // delimiters will possibly also fix the bare semicolon found in
1382 // expression context. For example, silence the following error:
1384 // error: expected expression, found `;`
1388 // | ^ expected expression
1390 Ok(self.mk_expr_err(self.token
.span
))
1391 } else if self.token
.uninterpolated_span().rust_2018() {
1392 // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly.
1393 if self.check_keyword(kw
::Async
) {
1394 if self.is_async_block() {
1395 // Check for `async {` and `async move {`.
1396 self.parse_async_block()
1398 self.parse_closure_expr()
1400 } else if self.eat_keyword(kw
::Await
) {
1401 self.recover_incorrect_await_syntax(lo
, self.prev_token
.span
)
1403 self.parse_lit_expr()
1406 self.parse_lit_expr()
1410 fn parse_lit_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
1411 let lo
= self.token
.span
;
1412 match self.parse_opt_token_lit() {
1413 Some((token_lit
, _
)) => {
1414 let expr
= self.mk_expr(lo
.to(self.prev_token
.span
), ExprKind
::Lit(token_lit
));
1415 self.maybe_recover_from_bad_qpath(expr
)
1417 None
=> self.try_macro_suggestion(),
1421 fn parse_tuple_parens_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
1422 let lo
= self.token
.span
;
1423 self.expect(&token
::OpenDelim(Delimiter
::Parenthesis
))?
;
1424 let (es
, trailing_comma
) = match self.parse_seq_to_end(
1425 &token
::CloseDelim(Delimiter
::Parenthesis
),
1426 SeqSep
::trailing_allowed(token
::Comma
),
1427 |p
| p
.parse_expr_catch_underscore(),
1431 return Ok(self.recover_seq_parse_error(Delimiter
::Parenthesis
, lo
, Err(err
)));
1434 let kind
= if es
.len() == 1 && !trailing_comma
{
1435 // `(e)` is parenthesized `e`.
1436 ExprKind
::Paren(es
.into_iter().next().unwrap())
1438 // `(e,)` is a tuple with only one field, `e`.
1441 let expr
= self.mk_expr(lo
.to(self.prev_token
.span
), kind
);
1442 self.maybe_recover_from_bad_qpath(expr
)
1445 fn parse_array_or_repeat_expr(&mut self, close_delim
: Delimiter
) -> PResult
<'a
, P
<Expr
>> {
1446 let lo
= self.token
.span
;
1447 self.bump(); // `[` or other open delim
1449 let close
= &token
::CloseDelim(close_delim
);
1450 let kind
= if self.eat(close
) {
1452 ExprKind
::Array(Vec
::new())
1455 let first_expr
= self.parse_expr()?
;
1456 if self.eat(&token
::Semi
) {
1457 // Repeating array syntax: `[ 0; 512 ]`
1458 let count
= self.parse_anon_const_expr()?
;
1459 self.expect(close
)?
;
1460 ExprKind
::Repeat(first_expr
, count
)
1461 } else if self.eat(&token
::Comma
) {
1462 // Vector with two or more elements.
1463 let sep
= SeqSep
::trailing_allowed(token
::Comma
);
1464 let (remaining_exprs
, _
) = self.parse_seq_to_end(close
, sep
, |p
| p
.parse_expr())?
;
1465 let mut exprs
= vec
![first_expr
];
1466 exprs
.extend(remaining_exprs
);
1467 ExprKind
::Array(exprs
)
1469 // Vector with one element
1470 self.expect(close
)?
;
1471 ExprKind
::Array(vec
![first_expr
])
1474 let expr
= self.mk_expr(lo
.to(self.prev_token
.span
), kind
);
1475 self.maybe_recover_from_bad_qpath(expr
)
1478 fn parse_path_start_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
1479 let (qself
, path
) = if self.eat_lt() {
1480 let (qself
, path
) = self.parse_qpath(PathStyle
::Expr
)?
;
1483 (None
, self.parse_path(PathStyle
::Expr
)?
)
1486 // `!`, as an operator, is prefix, so we know this isn't that.
1487 let (span
, kind
) = if self.eat(&token
::Not
) {
1488 // MACRO INVOCATION expression
1489 if qself
.is_some() {
1490 self.sess
.emit_err(MacroInvocationWithQualifiedPath(path
.span
));
1493 let mac
= P(MacCall
{
1495 args
: self.parse_delim_args()?
,
1496 prior_type_ascription
: self.last_type_ascription
,
1498 (lo
.to(self.prev_token
.span
), ExprKind
::MacCall(mac
))
1499 } else if self.check(&token
::OpenDelim(Delimiter
::Brace
)) &&
1500 let Some(expr
) = self.maybe_parse_struct_expr(&qself
, &path
) {
1501 if qself
.is_some() {
1502 self.sess
.gated_spans
.gate(sym
::more_qualified_paths
, path
.span
);
1506 (path
.span
, ExprKind
::Path(qself
, path
))
1509 let expr
= self.mk_expr(span
, kind
);
1510 self.maybe_recover_from_bad_qpath(expr
)
1513 /// Parse `'label: $expr`. The label is already parsed.
1514 fn parse_labeled_expr(
1517 mut consume_colon
: bool
,
1518 ) -> PResult
<'a
, P
<Expr
>> {
1519 let lo
= label_
.ident
.span
;
1520 let label
= Some(label_
);
1521 let ate_colon
= self.eat(&token
::Colon
);
1522 let expr
= if self.eat_keyword(kw
::While
) {
1523 self.parse_while_expr(label
, lo
)
1524 } else if self.eat_keyword(kw
::For
) {
1525 self.parse_for_expr(label
, lo
)
1526 } else if self.eat_keyword(kw
::Loop
) {
1527 self.parse_loop_expr(label
, lo
)
1528 } else if self.check_noexpect(&token
::OpenDelim(Delimiter
::Brace
))
1529 || self.token
.is_whole_block()
1531 self.parse_block_expr(label
, lo
, BlockCheckMode
::Default
)
1532 } else if !ate_colon
1533 && self.may_recover()
1534 && (matches
!(self.token
.kind
, token
::CloseDelim(_
) | token
::Comma
)
1535 || self.token
.is_op())
1537 let lit
= self.recover_unclosed_char(label_
.ident
, |self_
| {
1538 self_
.sess
.create_err(UnexpectedTokenAfterLabel
{
1539 span
: self_
.token
.span
,
1541 enclose_in_block
: None
,
1544 consume_colon
= false;
1545 Ok(self.mk_expr(lo
, ExprKind
::Lit(lit
.token_lit
)))
1546 } else if !ate_colon
1547 && (self.check_noexpect(&TokenKind
::Comma
) || self.check_noexpect(&TokenKind
::Gt
))
1549 // We're probably inside of a `Path<'a>` that needs a turbofish
1550 self.sess
.emit_err(UnexpectedTokenAfterLabel
{
1551 span
: self.token
.span
,
1553 enclose_in_block
: None
,
1555 consume_colon
= false;
1556 Ok(self.mk_expr_err(lo
))
1558 let mut err
= UnexpectedTokenAfterLabel
{
1559 span
: self.token
.span
,
1561 enclose_in_block
: None
,
1564 // Continue as an expression in an effort to recover on `'label: non_block_expr`.
1565 let expr
= self.parse_expr().map(|expr
| {
1566 let span
= expr
.span
;
1568 let found_labeled_breaks
= {
1569 struct FindLabeledBreaksVisitor(bool
);
1571 impl<'ast
> Visitor
<'ast
> for FindLabeledBreaksVisitor
{
1572 fn visit_expr_post(&mut self, ex
: &'ast Expr
) {
1573 if let ExprKind
::Break(Some(_label
), _
) = ex
.kind
{
1579 let mut vis
= FindLabeledBreaksVisitor(false);
1580 vis
.visit_expr(&expr
);
1584 // Suggestion involves adding a (as of time of writing this, unstable) labeled block.
1586 // If there are no breaks that may use this label, suggest removing the label and
1587 // recover to the unmodified expression.
1588 if !found_labeled_breaks
{
1589 err
.remove_label
= Some(lo
.until(span
));
1594 err
.enclose_in_block
= Some(UnexpectedTokenAfterLabelSugg
{
1595 left
: span
.shrink_to_lo(),
1596 right
: span
.shrink_to_hi(),
1599 // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`.
1600 let stmt
= self.mk_stmt(span
, StmtKind
::Expr(expr
));
1601 let blk
= self.mk_block(vec
![stmt
], BlockCheckMode
::Default
, span
);
1602 self.mk_expr(span
, ExprKind
::Block(blk
, label
))
1605 self.sess
.emit_err(err
);
1609 if !ate_colon
&& consume_colon
{
1610 self.sess
.emit_err(RequireColonAfterLabeledExpression
{
1613 label_end
: lo
.shrink_to_hi(),
1620 /// Emit an error when a char is parsed as a lifetime because of a missing quote
1621 pub(super) fn recover_unclosed_char(
1624 err
: impl FnOnce(&Self) -> DiagnosticBuilder
<'a
, ErrorGuaranteed
>,
1625 ) -> ast
::MetaItemLit
{
1626 if let Some(mut diag
) =
1627 self.sess
.span_diagnostic
.steal_diagnostic(lifetime
.span
, StashKey
::LifetimeIsChar
)
1629 diag
.span_suggestion_verbose(
1630 lifetime
.span
.shrink_to_hi(),
1631 "add `'` to close the char literal",
1633 Applicability
::MaybeIncorrect
,
1638 .span_suggestion_verbose(
1639 lifetime
.span
.shrink_to_hi(),
1640 "add `'` to close the char literal",
1642 Applicability
::MaybeIncorrect
,
1646 let name
= lifetime
.without_first_quote().name
;
1648 token_lit
: token
::Lit
::new(token
::LitKind
::Char
, name
, None
),
1649 kind
: ast
::LitKind
::Char(name
.as_str().chars().next().unwrap_or('_'
)),
1650 span
: lifetime
.span
,
1654 /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
1655 fn recover_do_catch(&mut self) -> PResult
<'a
, P
<Expr
>> {
1656 let lo
= self.token
.span
;
1658 self.bump(); // `do`
1659 self.bump(); // `catch`
1661 let span
= lo
.to(self.prev_token
.span
);
1662 self.sess
.emit_err(DoCatchSyntaxRemoved { span }
);
1664 self.parse_try_block(lo
)
1667 /// Parse an expression if the token can begin one.
1668 fn parse_expr_opt(&mut self) -> PResult
<'a
, Option
<P
<Expr
>>> {
1669 Ok(if self.token
.can_begin_expr() { Some(self.parse_expr()?) }
else { None }
)
1672 /// Parse `"return" expr?`.
1673 fn parse_return_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
1674 let lo
= self.prev_token
.span
;
1675 let kind
= ExprKind
::Ret(self.parse_expr_opt()?
);
1676 let expr
= self.mk_expr(lo
.to(self.prev_token
.span
), kind
);
1677 self.maybe_recover_from_bad_qpath(expr
)
1680 /// Parse `"do" "yeet" expr?`.
1681 fn parse_yeet_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
1682 let lo
= self.token
.span
;
1684 self.bump(); // `do`
1685 self.bump(); // `yeet`
1687 let kind
= ExprKind
::Yeet(self.parse_expr_opt()?
);
1689 let span
= lo
.to(self.prev_token
.span
);
1690 self.sess
.gated_spans
.gate(sym
::yeet_expr
, span
);
1691 let expr
= self.mk_expr(span
, kind
);
1692 self.maybe_recover_from_bad_qpath(expr
)
1695 /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
1696 /// If the label is followed immediately by a `:` token, the label and `:` are
1697 /// parsed as part of the expression (i.e. a labeled loop). The language team has
1698 /// decided in #87026 to require parentheses as a visual aid to avoid confusion if
1699 /// the break expression of an unlabeled break is a labeled loop (as in
1700 /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value
1701 /// expression only gets a warning for compatibility reasons; and a labeled break
1702 /// with a labeled loop does not even get a warning because there is no ambiguity.
1703 fn parse_break_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
1704 let lo
= self.prev_token
.span
;
1705 let mut label
= self.eat_label();
1706 let kind
= if label
.is_some() && self.token
== token
::Colon
{
1707 // The value expression can be a labeled loop, see issue #86948, e.g.:
1708 // `loop { break 'label: loop { break 'label 42; }; }`
1709 let lexpr
= self.parse_labeled_expr(label
.take().unwrap(), true)?
;
1710 self.sess
.emit_err(LabeledLoopInBreak
{
1712 sub
: WrapExpressionInParentheses
{
1713 left
: lexpr
.span
.shrink_to_lo(),
1714 right
: lexpr
.span
.shrink_to_hi(),
1718 } else if self.token
!= token
::OpenDelim(Delimiter
::Brace
)
1719 || !self.restrictions
.contains(Restrictions
::NO_STRUCT_LITERAL
)
1721 let expr
= self.parse_expr_opt()?
;
1722 if let Some(expr
) = &expr
{
1726 ExprKind
::While(_
, _
, None
)
1727 | ExprKind
::ForLoop(_
, _
, _
, None
)
1728 | ExprKind
::Loop(_
, None
, _
)
1729 | ExprKind
::Block(_
, None
)
1732 self.sess
.buffer_lint_with_diagnostic(
1733 BREAK_WITH_LABEL_AND_LOOP
,
1736 "this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression",
1737 BuiltinLintDiagnostics
::BreakWithLabelAndLoop(expr
.span
),
1745 let expr
= self.mk_expr(lo
.to(self.prev_token
.span
), ExprKind
::Break(label
, kind
));
1746 self.maybe_recover_from_bad_qpath(expr
)
1749 /// Parse `"yield" expr?`.
1750 fn parse_yield_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
1751 let lo
= self.prev_token
.span
;
1752 let kind
= ExprKind
::Yield(self.parse_expr_opt()?
);
1753 let span
= lo
.to(self.prev_token
.span
);
1754 self.sess
.gated_spans
.gate(sym
::generators
, span
);
1755 let expr
= self.mk_expr(span
, kind
);
1756 self.maybe_recover_from_bad_qpath(expr
)
1759 /// Returns a string literal if the next token is a string literal.
1760 /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
1761 /// and returns `None` if the next token is not literal at all.
1762 pub fn parse_str_lit(&mut self) -> Result
<ast
::StrLit
, Option
<MetaItemLit
>> {
1763 match self.parse_opt_meta_item_lit() {
1764 Some(lit
) => match lit
.kind
{
1765 ast
::LitKind
::Str(symbol_unescaped
, style
) => Ok(ast
::StrLit
{
1767 symbol
: lit
.token_lit
.symbol
,
1768 suffix
: lit
.token_lit
.suffix
,
1772 _
=> Err(Some(lit
)),
1778 fn handle_missing_lit(&mut self) -> PResult
<'a
, MetaItemLit
> {
1779 if let token
::Interpolated(inner
) = &self.token
.kind
{
1780 let expr
= match inner
.as_ref() {
1781 token
::NtExpr(expr
) => Some(expr
),
1782 token
::NtLiteral(expr
) => Some(expr
),
1785 if let Some(expr
) = expr
{
1786 if matches
!(expr
.kind
, ExprKind
::Err
) {
1787 let mut err
= InvalidInterpolatedExpression { span: self.token.span }
1788 .into_diagnostic(&self.sess
.span_diagnostic
);
1789 err
.downgrade_to_delayed_bug();
1794 let token
= self.token
.clone();
1795 let err
= |self_
: &Self| {
1796 let msg
= format
!("unexpected token: {}", super::token_descr(&token
));
1797 self_
.struct_span_err(token
.span
, &msg
)
1799 // On an error path, eagerly consider a lifetime to be an unclosed character lit
1800 if self.token
.is_lifetime() {
1801 let lt
= self.expect_lifetime();
1802 Ok(self.recover_unclosed_char(lt
.ident
, err
))
1808 pub(super) fn parse_token_lit(&mut self) -> PResult
<'a
, (token
::Lit
, Span
)> {
1809 self.parse_opt_token_lit()
1811 .or_else(|()| self.handle_missing_lit().map(|lit
| (lit
.token_lit
, lit
.span
)))
1814 pub(super) fn parse_meta_item_lit(&mut self) -> PResult
<'a
, MetaItemLit
> {
1815 self.parse_opt_meta_item_lit().ok_or(()).or_else(|()| self.handle_missing_lit())
1818 fn recover_after_dot(&mut self) -> Option
<Token
> {
1819 let mut recovered
= None
;
1820 if self.token
== token
::Dot
{
1821 // Attempt to recover `.4` as `0.4`. We don't currently have any syntax where
1822 // dot would follow an optional literal, so we do this unconditionally.
1823 recovered
= self.look_ahead(1, |next_token
| {
1824 if let token
::Literal(token
::Lit { kind: token::Integer, symbol, suffix }
) =
1827 if self.token
.span
.hi() == next_token
.span
.lo() {
1828 let s
= String
::from("0.") + symbol
.as_str();
1829 let kind
= TokenKind
::lit(token
::Float
, Symbol
::intern(&s
), suffix
);
1830 return Some(Token
::new(kind
, self.token
.span
.to(next_token
.span
)));
1835 if let Some(token
) = &recovered
{
1837 self.sess
.emit_err(FloatLiteralRequiresIntegerPart
{
1839 correct
: pprust
::token_to_string(token
).into_owned(),
1847 /// Matches `lit = true | false | token_lit`.
1848 /// Returns `None` if the next token is not a literal.
1849 pub(super) fn parse_opt_token_lit(&mut self) -> Option
<(token
::Lit
, Span
)> {
1850 let recovered
= self.recover_after_dot();
1851 let token
= recovered
.as_ref().unwrap_or(&self.token
);
1852 let span
= token
.span
;
1853 token
::Lit
::from_token(token
).map(|token_lit
| {
1859 /// Matches `lit = true | false | token_lit`.
1860 /// Returns `None` if the next token is not a literal.
1861 pub(super) fn parse_opt_meta_item_lit(&mut self) -> Option
<MetaItemLit
> {
1862 let recovered
= self.recover_after_dot();
1863 let token
= recovered
.as_ref().unwrap_or(&self.token
);
1864 match token
::Lit
::from_token(token
) {
1865 Some(token_lit
) => {
1866 match MetaItemLit
::from_token_lit(token_lit
, token
.span
) {
1872 let span
= token
.span
;
1873 let token
::Literal(lit
) = token
.kind
else {
1877 report_lit_error(&self.sess
, err
, lit
, span
);
1878 // Pack possible quotes and prefixes from the original literal into
1879 // the error literal's symbol so they can be pretty-printed faithfully.
1880 let suffixless_lit
= token
::Lit
::new(lit
.kind
, lit
.symbol
, None
);
1881 let symbol
= Symbol
::intern(&suffixless_lit
.to_string());
1882 let lit
= token
::Lit
::new(token
::Err
, symbol
, lit
.suffix
);
1884 MetaItemLit
::from_token_lit(lit
, span
)
1885 .unwrap_or_else(|_
| unreachable
!()),
1894 pub(super) fn expect_no_tuple_index_suffix(&self, span
: Span
, suffix
: Symbol
) {
1895 if [sym
::i32, sym
::u32, sym
::isize, sym
::usize].contains(&suffix
) {
1896 // #59553: warn instead of reject out of hand to allow the fix to percolate
1897 // through the ecosystem when people fix their macros
1898 self.sess
.emit_warning(InvalidLiteralSuffixOnTupleIndex
{
1901 exception
: Some(()),
1904 self.sess
.emit_err(InvalidLiteralSuffixOnTupleIndex { span, suffix, exception: None }
);
1908 /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
1909 /// Keep this in sync with `Token::can_begin_literal_maybe_minus`.
1910 pub fn parse_literal_maybe_minus(&mut self) -> PResult
<'a
, P
<Expr
>> {
1911 maybe_whole_expr
!(self);
1913 let lo
= self.token
.span
;
1914 let minus_present
= self.eat(&token
::BinOp(token
::Minus
));
1915 let (token_lit
, span
) = self.parse_token_lit()?
;
1916 let expr
= self.mk_expr(span
, ExprKind
::Lit(token_lit
));
1919 Ok(self.mk_expr(lo
.to(self.prev_token
.span
), self.mk_unary(UnOp
::Neg
, expr
)))
1925 fn is_array_like_block(&mut self) -> bool
{
1926 self.look_ahead(1, |t
| matches
!(t
.kind
, TokenKind
::Ident(..) | TokenKind
::Literal(_
)))
1927 && self.look_ahead(2, |t
| t
== &token
::Comma
)
1928 && self.look_ahead(3, |t
| t
.can_begin_expr())
1931 /// Emits a suggestion if it looks like the user meant an array but
1932 /// accidentally used braces, causing the code to be interpreted as a block
1934 fn maybe_suggest_brackets_instead_of_braces(&mut self, lo
: Span
) -> Option
<P
<Expr
>> {
1935 let mut snapshot
= self.create_snapshot_for_diagnostic();
1936 match snapshot
.parse_array_or_repeat_expr(Delimiter
::Brace
) {
1938 self.sess
.emit_err(ArrayBracketsInsteadOfSpaces
{
1940 sub
: ArrayBracketsInsteadOfSpacesSugg
{
1942 right
: snapshot
.prev_token
.span
,
1946 self.restore_snapshot(snapshot
);
1947 Some(self.mk_expr_err(arr
.span
))
1956 fn suggest_missing_semicolon_before_array(
1959 open_delim_span
: Span
,
1960 ) -> PResult
<'a
, ()> {
1961 if !self.may_recover() {
1965 if self.token
.kind
== token
::Comma
{
1966 if !self.sess
.source_map().is_multiline(prev_span
.until(self.token
.span
)) {
1969 let mut snapshot
= self.create_snapshot_for_diagnostic();
1971 match snapshot
.parse_seq_to_before_end(
1972 &token
::CloseDelim(Delimiter
::Bracket
),
1973 SeqSep
::trailing_allowed(token
::Comma
),
1977 // When the close delim is `)`, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
1978 // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`.
1979 // This is because the `token.kind` of the close delim is treated as the same as
1980 // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
1981 // Therefore, `token.kind` should not be compared here.
1983 .span_to_snippet(snapshot
.token
.span
)
1984 .map_or(false, |snippet
| snippet
== "]") =>
1986 return Err(MissingSemicolonBeforeArray
{
1987 open_delim
: open_delim_span
,
1988 semicolon
: prev_span
.shrink_to_hi(),
1989 }.into_diagnostic(&self.sess
.span_diagnostic
));
1992 Err(err
) => err
.cancel(),
1998 /// Parses a block or unsafe block.
1999 pub(super) fn parse_block_expr(
2001 opt_label
: Option
<Label
>,
2003 blk_mode
: BlockCheckMode
,
2004 ) -> PResult
<'a
, P
<Expr
>> {
2005 if self.may_recover() && self.is_array_like_block() {
2006 if let Some(arr
) = self.maybe_suggest_brackets_instead_of_braces(lo
) {
2011 if self.token
.is_whole_block() {
2012 self.sess
.emit_err(InvalidBlockMacroSegment
{
2013 span
: self.token
.span
,
2014 context
: lo
.to(self.token
.span
),
2018 let (attrs
, blk
) = self.parse_block_common(lo
, blk_mode
)?
;
2019 Ok(self.mk_expr_with_attrs(blk
.span
, ExprKind
::Block(blk
, opt_label
), attrs
))
2022 /// Parse a block which takes no attributes and has no label
2023 fn parse_simple_block(&mut self) -> PResult
<'a
, P
<Expr
>> {
2024 let blk
= self.parse_block()?
;
2025 Ok(self.mk_expr(blk
.span
, ExprKind
::Block(blk
, None
)))
2028 /// Parses a closure expression (e.g., `move |args| expr`).
2029 fn parse_closure_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
2030 let lo
= self.token
.span
;
2032 let binder
= if self.check_keyword(kw
::For
) {
2033 let lo
= self.token
.span
;
2034 let lifetime_defs
= self.parse_late_bound_lifetime_defs()?
;
2035 let span
= lo
.to(self.prev_token
.span
);
2037 self.sess
.gated_spans
.gate(sym
::closure_lifetime_binder
, span
);
2039 ClosureBinder
::For { span, generic_params: P::from_vec(lifetime_defs) }
2041 ClosureBinder
::NotPresent
2045 if self.eat_keyword(kw
::Static
) { Movability::Static }
else { Movability::Movable }
;
2047 let asyncness
= if self.token
.uninterpolated_span().rust_2018() {
2048 self.parse_asyncness(Case
::Sensitive
)
2053 let capture_clause
= self.parse_capture_clause()?
;
2054 let (fn_decl
, fn_arg_span
) = self.parse_fn_block_decl()?
;
2055 let decl_hi
= self.prev_token
.span
;
2056 let mut body
= match fn_decl
.output
{
2057 FnRetTy
::Default(_
) => {
2058 let restrictions
= self.restrictions
- Restrictions
::STMT_EXPR
;
2059 self.parse_expr_res(restrictions
, None
)?
2062 // If an explicit return type is given, require a block to appear (RFC 968).
2063 let body_lo
= self.token
.span
;
2064 self.parse_block_expr(None
, body_lo
, BlockCheckMode
::Default
)?
2068 if let Async
::Yes { span, .. }
= asyncness
{
2069 // Feature-gate `async ||` closures.
2070 self.sess
.gated_spans
.gate(sym
::async_closure
, span
);
2073 if self.token
.kind
== TokenKind
::Semi
2074 && matches
!(self.token_cursor
.frame
.delim_sp
, Some((Delimiter
::Parenthesis
, _
)))
2075 && self.may_recover()
2077 // It is likely that the closure body is a block but where the
2078 // braces have been removed. We will recover and eat the next
2079 // statements later in the parsing process.
2080 body
= self.mk_expr_err(body
.span
);
2083 let body_span
= body
.span
;
2085 let closure
= self.mk_expr(
2087 ExprKind
::Closure(Box
::new(ast
::Closure
{
2094 fn_decl_span
: lo
.to(decl_hi
),
2099 // Disable recovery for closure body
2101 ClosureSpans { whole_closure: closure.span, closing_pipe: decl_hi, body: body_span }
;
2102 self.current_closure
= Some(spans
);
2107 /// Parses an optional `move` prefix to a closure-like construct.
2108 fn parse_capture_clause(&mut self) -> PResult
<'a
, CaptureBy
> {
2109 if self.eat_keyword(kw
::Move
) {
2110 // Check for `move async` and recover
2111 if self.check_keyword(kw
::Async
) {
2112 let move_async_span
= self.token
.span
.with_lo(self.prev_token
.span
.data().lo
);
2113 Err(AsyncMoveOrderIncorrect { span: move_async_span }
2114 .into_diagnostic(&self.sess
.span_diagnostic
))
2116 Ok(CaptureBy
::Value
)
2123 /// Parses the `|arg, arg|` header of a closure.
2124 fn parse_fn_block_decl(&mut self) -> PResult
<'a
, (P
<FnDecl
>, Span
)> {
2125 let arg_start
= self.token
.span
.lo();
2127 let inputs
= if self.eat(&token
::OrOr
) {
2130 self.expect(&token
::BinOp(token
::Or
))?
;
2132 .parse_seq_to_before_tokens(
2133 &[&token
::BinOp(token
::Or
), &token
::OrOr
],
2134 SeqSep
::trailing_allowed(token
::Comma
),
2135 TokenExpectType
::NoExpect
,
2136 |p
| p
.parse_fn_block_param(),
2142 let arg_span
= self.prev_token
.span
.with_lo(arg_start
);
2144 self.parse_ret_ty(AllowPlus
::Yes
, RecoverQPath
::Yes
, RecoverReturnSign
::Yes
)?
;
2146 Ok((P(FnDecl { inputs, output }
), arg_span
))
2149 /// Parses a parameter in a closure header (e.g., `|arg, arg|`).
2150 fn parse_fn_block_param(&mut self) -> PResult
<'a
, Param
> {
2151 let lo
= self.token
.span
;
2152 let attrs
= self.parse_outer_attributes()?
;
2153 self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
2154 let pat
= this
.parse_pat_no_top_alt(PARAM_EXPECTED
)?
;
2155 let ty
= if this
.eat(&token
::Colon
) {
2158 this
.mk_ty(this
.prev_token
.span
, TyKind
::Infer
)
2166 span
: lo
.to(this
.prev_token
.span
),
2168 is_placeholder
: false,
2170 TrailingToken
::MaybeComma
,
2175 /// Parses an `if` expression (`if` token already eaten).
2176 fn parse_if_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
2177 let lo
= self.prev_token
.span
;
2178 let cond
= self.parse_cond_expr()?
;
2179 self.parse_if_after_cond(lo
, cond
)
2182 fn parse_if_after_cond(&mut self, lo
: Span
, mut cond
: P
<Expr
>) -> PResult
<'a
, P
<Expr
>> {
2183 let cond_span
= cond
.span
;
2184 // Tries to interpret `cond` as either a missing expression if it's a block,
2185 // or as an unfinished expression if it's a binop and the RHS is a block.
2186 // We could probably add more recoveries here too...
2187 let mut recover_block_from_condition
= |this
: &mut Self| {
2188 let block
= match &mut cond
.kind
{
2189 ExprKind
::Binary(Spanned { span: binop_span, .. }
, _
, right
)
2190 if let ExprKind
::Block(_
, None
) = right
.kind
=> {
2191 self.sess
.emit_err(IfExpressionMissingThenBlock
{
2193 sub
: IfExpressionMissingThenBlockSub
::UnfinishedCondition(
2194 cond_span
.shrink_to_lo().to(*binop_span
)
2197 std
::mem
::replace(right
, this
.mk_expr_err(binop_span
.shrink_to_hi()))
2199 ExprKind
::Block(_
, None
) => {
2200 self.sess
.emit_err(IfExpressionMissingCondition
{
2201 if_span
: lo
.shrink_to_hi(),
2202 block_span
: self.sess
.source_map().start_point(cond_span
),
2204 std
::mem
::replace(&mut cond
, this
.mk_expr_err(cond_span
.shrink_to_hi()))
2210 if let ExprKind
::Block(block
, _
) = &block
.kind
{
2217 let thn
= if self.token
.is_keyword(kw
::Else
) {
2218 if let Some(block
) = recover_block_from_condition(self) {
2221 self.sess
.emit_err(IfExpressionMissingThenBlock
{
2223 sub
: IfExpressionMissingThenBlockSub
::AddThenBlock(cond_span
.shrink_to_hi()),
2225 self.mk_block_err(cond_span
.shrink_to_hi())
2228 let attrs
= self.parse_outer_attributes()?
; // For recovery.
2229 let block
= if self.check(&token
::OpenDelim(Delimiter
::Brace
)) {
2232 if let Some(block
) = recover_block_from_condition(self) {
2235 self.error_on_extra_if(&cond
)?
;
2236 // Parse block, which will always fail, but we can add a nice note to the error
2237 self.parse_block().map_err(|mut err
| {
2240 "the `if` expression is missing a block after this condition",
2246 self.error_on_if_block_attrs(lo
, false, block
.span
, attrs
);
2249 let els
= if self.eat_keyword(kw
::Else
) { Some(self.parse_else_expr()?) }
else { None }
;
2250 Ok(self.mk_expr(lo
.to(self.prev_token
.span
), ExprKind
::If(cond
, thn
, els
)))
2253 /// Parses the condition of a `if` or `while` expression.
2254 fn parse_cond_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
2256 self.parse_expr_res(Restrictions
::NO_STRUCT_LITERAL
| Restrictions
::ALLOW_LET
, None
)?
;
2258 if let ExprKind
::Let(..) = cond
.kind
{
2259 // Remove the last feature gating of a `let` expression since it's stable.
2260 self.sess
.gated_spans
.ungate_last(sym
::let_chains
, cond
.span
);
2266 /// Parses a `let $pat = $expr` pseudo-expression.
2267 fn parse_let_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
2268 // This is a *approximate* heuristic that detects if `let` chains are
2269 // being parsed in the right position. It's approximate because it
2270 // doesn't deny all invalid `let` expressions, just completely wrong usages.
2271 let not_in_chain
= !matches
!(
2272 self.prev_token
.kind
,
2273 TokenKind
::AndAnd
| TokenKind
::Ident(kw
::If
, _
) | TokenKind
::Ident(kw
::While
, _
)
2275 if !self.restrictions
.contains(Restrictions
::ALLOW_LET
) || not_in_chain
{
2276 self.sess
.emit_err(ExpectedExpressionFoundLet { span: self.token.span }
);
2279 self.bump(); // Eat `let` token
2280 let lo
= self.prev_token
.span
;
2281 let pat
= self.parse_pat_allow_top_alt(
2285 CommaRecoveryMode
::LikelyTuple
,
2287 if self.token
== token
::EqEq
{
2288 self.sess
.emit_err(ExpectedEqForLetExpr
{
2289 span
: self.token
.span
,
2290 sugg_span
: self.token
.span
,
2294 self.expect(&token
::Eq
)?
;
2296 let expr
= self.with_res(self.restrictions
| Restrictions
::NO_STRUCT_LITERAL
, |this
| {
2297 this
.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None
.into())
2299 let span
= lo
.to(expr
.span
);
2300 self.sess
.gated_spans
.gate(sym
::let_chains
, span
);
2301 Ok(self.mk_expr(span
, ExprKind
::Let(pat
, expr
, span
)))
2304 /// Parses an `else { ... }` expression (`else` token already eaten).
2305 fn parse_else_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
2306 let else_span
= self.prev_token
.span
; // `else`
2307 let attrs
= self.parse_outer_attributes()?
; // For recovery.
2308 let expr
= if self.eat_keyword(kw
::If
) {
2309 self.parse_if_expr()?
2310 } else if self.check(&TokenKind
::OpenDelim(Delimiter
::Brace
)) {
2311 self.parse_simple_block()?
2313 let snapshot
= self.create_snapshot_for_diagnostic();
2314 let first_tok
= super::token_descr(&self.token
);
2315 let first_tok_span
= self.token
.span
;
2316 match self.parse_expr() {
2318 // If it's not a free-standing expression, and is followed by a block,
2319 // then it's very likely the condition to an `else if`.
2320 if self.check(&TokenKind
::OpenDelim(Delimiter
::Brace
))
2321 && classify
::expr_requires_semi_to_be_stmt(&cond
) =>
2323 self.sess
.emit_err(ExpectedElseBlock
{
2327 condition_start
: cond
.span
.shrink_to_lo(),
2329 self.parse_if_after_cond(cond
.span
.shrink_to_lo(), cond
)?
2333 self.restore_snapshot(snapshot
);
2334 self.parse_simple_block()?
2337 self.restore_snapshot(snapshot
);
2338 self.parse_simple_block()?
2342 self.error_on_if_block_attrs(else_span
, true, expr
.span
, attrs
);
2346 fn error_on_if_block_attrs(
2353 if attrs
.is_empty() {
2357 let attrs
: &[ast
::Attribute
] = &attrs
.take_for_recovery(self.sess
);
2358 let (attributes
, last
) = match attrs
{
2360 [x0 @ xn
] | [x0
, .., xn
] => (x0
.span
.to(xn
.span
), xn
.span
),
2362 let ctx
= if is_ctx_else { "else" }
else { "if" }
;
2363 self.sess
.emit_err(OuterAttributeNotAllowedOnIfElse
{
2367 ctx
: ctx
.to_string(),
2372 fn error_on_extra_if(&mut self, cond
: &P
<Expr
>) -> PResult
<'a
, ()> {
2373 if let ExprKind
::Binary(Spanned { span: binop_span, node: binop}
, _
, right
) = &cond
.kind
&&
2374 let BinOpKind
::And
= binop
&&
2375 let ExprKind
::If(cond
, ..) = &right
.kind
{
2376 Err(self.sess
.create_err(UnexpectedIfWithIf(binop_span
.shrink_to_hi().to(cond
.span
.shrink_to_lo()))))
2382 /// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
2383 fn parse_for_expr(&mut self, opt_label
: Option
<Label
>, lo
: Span
) -> PResult
<'a
, P
<Expr
>> {
2384 // Record whether we are about to parse `for (`.
2385 // This is used below for recovery in case of `for ( $stuff ) $block`
2386 // in which case we will suggest `for $stuff $block`.
2387 let begin_paren
= match self.token
.kind
{
2388 token
::OpenDelim(Delimiter
::Parenthesis
) => Some(self.token
.span
),
2392 let pat
= self.parse_pat_allow_top_alt(
2396 CommaRecoveryMode
::LikelyTuple
,
2398 if !self.eat_keyword(kw
::In
) {
2399 self.error_missing_in_for_loop();
2401 self.check_for_for_in_in_typo(self.prev_token
.span
);
2402 let expr
= self.parse_expr_res(Restrictions
::NO_STRUCT_LITERAL
, None
)?
;
2404 let pat
= self.recover_parens_around_for_head(pat
, begin_paren
);
2406 let (attrs
, loop_block
) = self.parse_inner_attrs_and_block()?
;
2408 let kind
= ExprKind
::ForLoop(pat
, expr
, loop_block
, opt_label
);
2409 Ok(self.mk_expr_with_attrs(lo
.to(self.prev_token
.span
), kind
, attrs
))
2412 fn error_missing_in_for_loop(&mut self) {
2413 let (span
, sub
): (_
, fn(_
) -> _
) = if self.token
.is_ident_named(sym
::of
) {
2414 // Possibly using JS syntax (#75311).
2415 let span
= self.token
.span
;
2417 (span
, MissingInInForLoopSub
::InNotOf
)
2419 (self.prev_token
.span
.between(self.token
.span
), MissingInInForLoopSub
::AddIn
)
2422 self.sess
.emit_err(MissingInInForLoop { span, sub: sub(span) }
);
2425 /// Parses a `while` or `while let` expression (`while` token already eaten).
2426 fn parse_while_expr(&mut self, opt_label
: Option
<Label
>, lo
: Span
) -> PResult
<'a
, P
<Expr
>> {
2427 let cond
= self.parse_cond_expr().map_err(|mut err
| {
2428 err
.span_label(lo
, "while parsing the condition of this `while` expression");
2431 let (attrs
, body
) = self.parse_inner_attrs_and_block().map_err(|mut err
| {
2432 err
.span_label(lo
, "while parsing the body of this `while` expression");
2433 err
.span_label(cond
.span
, "this `while` condition successfully parsed");
2436 Ok(self.mk_expr_with_attrs(
2437 lo
.to(self.prev_token
.span
),
2438 ExprKind
::While(cond
, body
, opt_label
),
2443 /// Parses `loop { ... }` (`loop` token already eaten).
2444 fn parse_loop_expr(&mut self, opt_label
: Option
<Label
>, lo
: Span
) -> PResult
<'a
, P
<Expr
>> {
2445 let loop_span
= self.prev_token
.span
;
2446 let (attrs
, body
) = self.parse_inner_attrs_and_block()?
;
2447 Ok(self.mk_expr_with_attrs(
2448 lo
.to(self.prev_token
.span
),
2449 ExprKind
::Loop(body
, opt_label
, loop_span
),
2454 pub(crate) fn eat_label(&mut self) -> Option
<Label
> {
2455 self.token
.lifetime().map(|ident
| {
2461 /// Parses a `match ... { ... }` expression (`match` token already eaten).
2462 fn parse_match_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
2463 let match_span
= self.prev_token
.span
;
2464 let lo
= self.prev_token
.span
;
2465 let scrutinee
= self.parse_expr_res(Restrictions
::NO_STRUCT_LITERAL
, None
)?
;
2466 if let Err(mut e
) = self.expect(&token
::OpenDelim(Delimiter
::Brace
)) {
2467 if self.token
== token
::Semi
{
2468 e
.span_suggestion_short(
2470 "try removing this `match`",
2472 Applicability
::MaybeIncorrect
, // speculative
2475 if self.maybe_recover_unexpected_block_label() {
2482 let attrs
= self.parse_inner_attributes()?
;
2484 let mut arms
: Vec
<Arm
> = Vec
::new();
2485 while self.token
!= token
::CloseDelim(Delimiter
::Brace
) {
2486 match self.parse_arm() {
2487 Ok(arm
) => arms
.push(arm
),
2489 // Recover by skipping to the end of the block.
2491 self.recover_stmt();
2492 let span
= lo
.to(self.token
.span
);
2493 if self.token
== token
::CloseDelim(Delimiter
::Brace
) {
2496 return Ok(self.mk_expr_with_attrs(
2498 ExprKind
::Match(scrutinee
, arms
),
2504 let hi
= self.token
.span
;
2506 Ok(self.mk_expr_with_attrs(lo
.to(hi
), ExprKind
::Match(scrutinee
, arms
), attrs
))
2509 /// Attempt to recover from match arm body with statements and no surrounding braces.
2510 fn parse_arm_body_missing_braces(
2512 first_expr
: &P
<Expr
>,
2514 ) -> Option
<P
<Expr
>> {
2515 if self.token
.kind
!= token
::Semi
{
2518 let start_snapshot
= self.create_snapshot_for_diagnostic();
2519 let semi_sp
= self.token
.span
;
2522 vec
![self.mk_stmt(first_expr
.span
, ast
::StmtKind
::Expr(first_expr
.clone()))];
2523 let err
= |this
: &Parser
<'_
>, stmts
: Vec
<ast
::Stmt
>| {
2524 let span
= stmts
[0].span
.to(stmts
[stmts
.len() - 1].span
);
2526 this
.sess
.emit_err(MatchArmBodyWithoutBraces
{
2529 num_statements
: stmts
.len(),
2530 sub
: if stmts
.len() > 1 {
2531 MatchArmBodyWithoutBracesSugg
::AddBraces
{
2532 left
: span
.shrink_to_lo(),
2533 right
: span
.shrink_to_hi(),
2536 MatchArmBodyWithoutBracesSugg
::UseComma { semicolon: semi_sp }
2539 this
.mk_expr_err(span
)
2541 // We might have either a `,` -> `;` typo, or a block without braces. We need
2542 // a more subtle parsing strategy.
2544 if self.token
.kind
== token
::CloseDelim(Delimiter
::Brace
) {
2545 // We have reached the closing brace of the `match` expression.
2546 return Some(err(self, stmts
));
2548 if self.token
.kind
== token
::Comma
{
2549 self.restore_snapshot(start_snapshot
);
2552 let pre_pat_snapshot
= self.create_snapshot_for_diagnostic();
2553 match self.parse_pat_no_top_alt(None
) {
2555 if self.token
.kind
== token
::FatArrow
{
2557 self.restore_snapshot(pre_pat_snapshot
);
2558 return Some(err(self, stmts
));
2566 self.restore_snapshot(pre_pat_snapshot
);
2567 match self.parse_stmt_without_recovery(true, ForceCollect
::No
) {
2568 // Consume statements for as long as possible.
2573 self.restore_snapshot(start_snapshot
);
2576 // We couldn't parse either yet another statement missing it's
2577 // enclosing block nor the next arm's pattern or closing brace.
2580 self.restore_snapshot(start_snapshot
);
2588 pub(super) fn parse_arm(&mut self) -> PResult
<'a
, Arm
> {
2589 // Used to check the `let_chains` and `if_let_guard` features mostly by scanning
2591 fn check_let_expr(expr
: &Expr
) -> (bool
, bool
) {
2593 ExprKind
::Binary(BinOp { node: BinOpKind::And, .. }
, lhs
, rhs
) => {
2594 let lhs_rslt
= check_let_expr(lhs
);
2595 let rhs_rslt
= check_let_expr(rhs
);
2596 (lhs_rslt
.0 || rhs_rslt
.0, false)
2598 ExprKind
::Let(..) => (true, true),
2602 let attrs
= self.parse_outer_attributes()?
;
2603 self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
2604 let lo
= this
.token
.span
;
2605 let pat
= this
.parse_pat_allow_top_alt(
2609 CommaRecoveryMode
::EitherTupleOrPipe
,
2611 let guard
= if this
.eat_keyword(kw
::If
) {
2612 let if_span
= this
.prev_token
.span
;
2613 let cond
= this
.parse_expr_res(Restrictions
::ALLOW_LET
, None
)?
;
2614 let (has_let_expr
, does_not_have_bin_op
) = check_let_expr(&cond
);
2616 if does_not_have_bin_op
{
2617 // Remove the last feature gating of a `let` expression since it's stable.
2618 this
.sess
.gated_spans
.ungate_last(sym
::let_chains
, cond
.span
);
2620 let span
= if_span
.to(cond
.span
);
2621 this
.sess
.gated_spans
.gate(sym
::if_let_guard
, span
);
2627 let arrow_span
= this
.token
.span
;
2628 if let Err(mut err
) = this
.expect(&token
::FatArrow
) {
2629 // We might have a `=>` -> `=` or `->` typo (issue #89396).
2630 if TokenKind
::FatArrow
2632 .map_or(false, |similar_tokens
| similar_tokens
.contains(&this
.token
.kind
))
2634 err
.span_suggestion(
2636 "try using a fat arrow here",
2638 Applicability
::MaybeIncorrect
,
2646 let arm_start_span
= this
.token
.span
;
2648 let expr
= this
.parse_expr_res(Restrictions
::STMT_EXPR
, None
).map_err(|mut err
| {
2649 err
.span_label(arrow_span
, "while parsing the `match` arm starting here");
2653 let require_comma
= classify
::expr_requires_semi_to_be_stmt(&expr
)
2654 && this
.token
!= token
::CloseDelim(Delimiter
::Brace
);
2656 let hi
= this
.prev_token
.span
;
2659 let sm
= this
.sess
.source_map();
2660 if let Some(body
) = this
.parse_arm_body_missing_braces(&expr
, arrow_span
) {
2661 let span
= body
.span
;
2670 is_placeholder
: false,
2672 TrailingToken
::None
,
2675 this
.expect_one_of(&[token
::Comma
], &[token
::CloseDelim(Delimiter
::Brace
)])
2676 .or_else(|mut err
| {
2677 if this
.token
== token
::FatArrow
{
2678 if let Ok(expr_lines
) = sm
.span_to_lines(expr
.span
)
2679 && let Ok(arm_start_lines
) = sm
.span_to_lines(arm_start_span
)
2680 && arm_start_lines
.lines
[0].end_col
== expr_lines
.lines
[0].end_col
2681 && expr_lines
.lines
.len() == 2
2683 // We check whether there's any trailing code in the parse span,
2684 // if there isn't, we very likely have the following:
2687 // | -- - missing comma
2691 // | - ^^ self.token.span
2693 // | parsed until here as `"y" & X`
2694 err
.span_suggestion_short(
2695 arm_start_span
.shrink_to_hi(),
2696 "missing a comma here to end this `match` arm",
2698 Applicability
::MachineApplicable
,
2703 // FIXME(compiler-errors): We could also recover `; PAT =>` here
2705 // Try to parse a following `PAT =>`, if successful
2706 // then we should recover.
2707 let mut snapshot
= this
.create_snapshot_for_diagnostic();
2708 let pattern_follows
= snapshot
2709 .parse_pat_allow_top_alt(
2713 CommaRecoveryMode
::EitherTupleOrPipe
,
2715 .map_err(|err
| err
.cancel())
2717 if pattern_follows
&& snapshot
.check(&TokenKind
::FatArrow
) {
2719 this
.sess
.emit_err(MissingCommaAfterMatchArm
{
2720 span
: hi
.shrink_to_hi(),
2725 err
.span_label(arrow_span
, "while parsing the `match` arm starting here");
2729 this
.eat(&token
::Comma
);
2740 is_placeholder
: false,
2742 TrailingToken
::None
,
2747 /// Parses a `try {...}` expression (`try` token already eaten).
2748 fn parse_try_block(&mut self, span_lo
: Span
) -> PResult
<'a
, P
<Expr
>> {
2749 let (attrs
, body
) = self.parse_inner_attrs_and_block()?
;
2750 if self.eat_keyword(kw
::Catch
) {
2751 Err(CatchAfterTry { span: self.prev_token.span }
2752 .into_diagnostic(&self.sess
.span_diagnostic
))
2754 let span
= span_lo
.to(body
.span
);
2755 self.sess
.gated_spans
.gate(sym
::try_blocks
, span
);
2756 Ok(self.mk_expr_with_attrs(span
, ExprKind
::TryBlock(body
), attrs
))
2760 fn is_do_catch_block(&self) -> bool
{
2761 self.token
.is_keyword(kw
::Do
)
2762 && self.is_keyword_ahead(1, &[kw
::Catch
])
2763 && self.look_ahead(2, |t
| *t
== token
::OpenDelim(Delimiter
::Brace
))
2764 && !self.restrictions
.contains(Restrictions
::NO_STRUCT_LITERAL
)
2767 fn is_do_yeet(&self) -> bool
{
2768 self.token
.is_keyword(kw
::Do
) && self.is_keyword_ahead(1, &[kw
::Yeet
])
2771 fn is_try_block(&self) -> bool
{
2772 self.token
.is_keyword(kw
::Try
)
2773 && self.look_ahead(1, |t
| *t
== token
::OpenDelim(Delimiter
::Brace
))
2774 && self.token
.uninterpolated_span().rust_2018()
2777 /// Parses an `async move? {...}` expression.
2778 fn parse_async_block(&mut self) -> PResult
<'a
, P
<Expr
>> {
2779 let lo
= self.token
.span
;
2780 self.expect_keyword(kw
::Async
)?
;
2781 let capture_clause
= self.parse_capture_clause()?
;
2782 let (attrs
, body
) = self.parse_inner_attrs_and_block()?
;
2783 let kind
= ExprKind
::Async(capture_clause
, DUMMY_NODE_ID
, body
);
2784 Ok(self.mk_expr_with_attrs(lo
.to(self.prev_token
.span
), kind
, attrs
))
2787 fn is_async_block(&self) -> bool
{
2788 self.token
.is_keyword(kw
::Async
)
2791 self.is_keyword_ahead(1, &[kw
::Move
])
2792 && self.look_ahead(2, |t
| *t
== token
::OpenDelim(Delimiter
::Brace
))
2795 self.look_ahead(1, |t
| *t
== token
::OpenDelim(Delimiter
::Brace
))
2799 fn is_certainly_not_a_block(&self) -> bool
{
2800 self.look_ahead(1, |t
| t
.is_ident())
2802 // `{ ident, ` cannot start a block.
2803 self.look_ahead(2, |t
| t
== &token
::Comma
)
2804 || self.look_ahead(2, |t
| t
== &token
::Colon
)
2806 // `{ ident: token, ` cannot start a block.
2807 self.look_ahead(4, |t
| t
== &token
::Comma
) ||
2808 // `{ ident: ` cannot start a block unless it's a type ascription `ident: Type`.
2809 self.look_ahead(3, |t
| !t
.can_begin_type())
2814 fn maybe_parse_struct_expr(
2816 qself
: &Option
<P
<ast
::QSelf
>>,
2818 ) -> Option
<PResult
<'a
, P
<Expr
>>> {
2819 let struct_allowed
= !self.restrictions
.contains(Restrictions
::NO_STRUCT_LITERAL
);
2820 if struct_allowed
|| self.is_certainly_not_a_block() {
2821 if let Err(err
) = self.expect(&token
::OpenDelim(Delimiter
::Brace
)) {
2822 return Some(Err(err
));
2824 let expr
= self.parse_struct_expr(qself
.clone(), path
.clone(), true);
2825 if let (Ok(expr
), false) = (&expr
, struct_allowed
) {
2826 // This is a struct literal, but we don't can't accept them here.
2827 self.sess
.emit_err(StructLiteralNotAllowedHere
{
2829 sub
: StructLiteralNotAllowedHereSugg
{
2830 left
: path
.span
.shrink_to_lo(),
2831 right
: expr
.span
.shrink_to_hi(),
2840 pub(super) fn parse_struct_fields(
2844 close_delim
: Delimiter
,
2845 ) -> PResult
<'a
, (Vec
<ExprField
>, ast
::StructRest
, bool
)> {
2846 let mut fields
= Vec
::new();
2847 let mut base
= ast
::StructRest
::None
;
2848 let mut recover_async
= false;
2850 let mut async_block_err
= |e
: &mut Diagnostic
, span
: Span
| {
2851 recover_async
= true;
2852 e
.span_label(span
, "`async` blocks are only allowed in Rust 2018 or later");
2853 e
.help_use_latest_edition();
2856 while self.token
!= token
::CloseDelim(close_delim
) {
2857 if self.eat(&token
::DotDot
) || self.recover_struct_field_dots(close_delim
) {
2858 let exp_span
= self.prev_token
.span
;
2859 // We permit `.. }` on the left-hand side of a destructuring assignment.
2860 if self.check(&token
::CloseDelim(close_delim
)) {
2861 base
= ast
::StructRest
::Rest(self.prev_token
.span
.shrink_to_hi());
2864 match self.parse_expr() {
2865 Ok(e
) => base
= ast
::StructRest
::Base(e
),
2866 Err(mut e
) if recover
=> {
2868 self.recover_stmt();
2870 Err(e
) => return Err(e
),
2872 self.recover_struct_comma_after_dotdot(exp_span
);
2876 let recovery_field
= self.find_struct_error_after_field_looking_code();
2877 let parsed_field
= match self.parse_expr_field() {
2880 if pth
== kw
::Async
{
2881 async_block_err(&mut e
, pth
.span
);
2883 e
.span_label(pth
.span
, "while parsing this struct");
2887 // If the next token is a comma, then try to parse
2888 // what comes next as additional fields, rather than
2889 // bailing out until next `}`.
2890 if self.token
!= token
::Comma
{
2891 self.recover_stmt_(SemiColonMode
::Comma
, BlockMode
::Ignore
);
2892 if self.token
!= token
::Comma
{
2900 let is_shorthand
= parsed_field
.as_ref().map_or(false, |f
| f
.is_shorthand
);
2901 // A shorthand field can be turned into a full field with `:`.
2902 // We should point this out.
2903 self.check_or_expected(!is_shorthand
, TokenType
::Token(token
::Colon
));
2905 match self.expect_one_of(&[token
::Comma
], &[token
::CloseDelim(close_delim
)]) {
2907 if let Some(f
) = parsed_field
.or(recovery_field
) {
2908 // Only include the field if there's no parse error for the field name.
2913 if pth
== kw
::Async
{
2914 async_block_err(&mut e
, pth
.span
);
2916 e
.span_label(pth
.span
, "while parsing this struct");
2917 if let Some(f
) = recovery_field
{
2920 self.prev_token
.span
.shrink_to_hi(),
2921 "try adding a comma",
2923 Applicability
::MachineApplicable
,
2925 } else if is_shorthand
2926 && (AssocOp
::from_token(&self.token
).is_some()
2927 || matches
!(&self.token
.kind
, token
::OpenDelim(_
))
2928 || self.token
.kind
== token
::Dot
)
2930 // Looks like they tried to write a shorthand, complex expression.
2931 let ident
= parsed_field
.expect("is_shorthand implies Some").ident
;
2933 ident
.span
.shrink_to_lo(),
2934 "try naming a field",
2935 &format
!("{ident}: "),
2936 Applicability
::HasPlaceholders
,
2944 self.recover_stmt_(SemiColonMode
::Comma
, BlockMode
::Ignore
);
2945 self.eat(&token
::Comma
);
2949 Ok((fields
, base
, recover_async
))
2952 /// Precondition: already parsed the '{'.
2953 pub(super) fn parse_struct_expr(
2955 qself
: Option
<P
<ast
::QSelf
>>,
2958 ) -> PResult
<'a
, P
<Expr
>> {
2960 let (fields
, base
, recover_async
) =
2961 self.parse_struct_fields(pth
.clone(), recover
, Delimiter
::Brace
)?
;
2962 let span
= lo
.to(self.token
.span
);
2963 self.expect(&token
::CloseDelim(Delimiter
::Brace
))?
;
2964 let expr
= if recover_async
{
2967 ExprKind
::Struct(P(ast
::StructExpr { qself, path: pth, fields, rest: base }
))
2969 Ok(self.mk_expr(span
, expr
))
2972 /// Use in case of error after field-looking code: `S { foo: () with a }`.
2973 fn find_struct_error_after_field_looking_code(&self) -> Option
<ExprField
> {
2974 match self.token
.ident() {
2975 Some((ident
, is_raw
))
2976 if (is_raw
|| !ident
.is_reserved())
2977 && self.look_ahead(1, |t
| *t
== token
::Colon
) =>
2979 Some(ast
::ExprField
{
2981 span
: self.token
.span
,
2982 expr
: self.mk_expr_err(self.token
.span
),
2983 is_shorthand
: false,
2984 attrs
: AttrVec
::new(),
2986 is_placeholder
: false,
2993 fn recover_struct_comma_after_dotdot(&mut self, span
: Span
) {
2994 if self.token
!= token
::Comma
{
2997 self.sess
.emit_err(CommaAfterBaseStruct
{
2998 span
: span
.to(self.prev_token
.span
),
2999 comma
: self.token
.span
,
3001 self.recover_stmt();
3004 fn recover_struct_field_dots(&mut self, close_delim
: Delimiter
) -> bool
{
3005 if !self.look_ahead(1, |t
| *t
== token
::CloseDelim(close_delim
))
3006 && self.eat(&token
::DotDotDot
)
3008 // recover from typo of `...`, suggest `..`
3009 let span
= self.prev_token
.span
;
3010 self.sess
.emit_err(MissingDotDot { token_span: span, sugg_span: span }
);
3016 /// Parses `ident (COLON expr)?`.
3017 fn parse_expr_field(&mut self) -> PResult
<'a
, ExprField
> {
3018 let attrs
= self.parse_outer_attributes()?
;
3019 self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
3020 let lo
= this
.token
.span
;
3022 // Check if a colon exists one ahead. This means we're parsing a fieldname.
3023 let is_shorthand
= !this
.look_ahead(1, |t
| t
== &token
::Colon
|| t
== &token
::Eq
);
3024 let (ident
, expr
) = if is_shorthand
{
3025 // Mimic `x: x` for the `x` field shorthand.
3026 let ident
= this
.parse_ident_common(false)?
;
3027 let path
= ast
::Path
::from_ident(ident
);
3028 (ident
, this
.mk_expr(ident
.span
, ExprKind
::Path(None
, path
)))
3030 let ident
= this
.parse_field_name()?
;
3031 this
.error_on_eq_field_init(ident
);
3033 (ident
, this
.parse_expr()?
)
3039 span
: lo
.to(expr
.span
),
3044 is_placeholder
: false,
3046 TrailingToken
::MaybeComma
,
3051 /// Check for `=`. This means the source incorrectly attempts to
3052 /// initialize a field with an eq rather than a colon.
3053 fn error_on_eq_field_init(&self, field_name
: Ident
) {
3054 if self.token
!= token
::Eq
{
3058 self.sess
.emit_err(EqFieldInit
{
3059 span
: self.token
.span
,
3060 eq
: field_name
.span
.shrink_to_hi().to(self.token
.span
),
3064 fn err_dotdotdot_syntax(&self, span
: Span
) {
3065 self.sess
.emit_err(DotDotDot { span }
);
3068 fn err_larrow_operator(&self, span
: Span
) {
3069 self.sess
.emit_err(LeftArrowOperator { span }
);
3072 fn mk_assign_op(&self, binop
: BinOp
, lhs
: P
<Expr
>, rhs
: P
<Expr
>) -> ExprKind
{
3073 ExprKind
::AssignOp(binop
, lhs
, rhs
)
3078 start
: Option
<P
<Expr
>>,
3079 end
: Option
<P
<Expr
>>,
3080 limits
: RangeLimits
,
3082 if end
.is_none() && limits
== RangeLimits
::Closed
{
3083 self.inclusive_range_with_incorrect_end(self.prev_token
.span
);
3086 ExprKind
::Range(start
, end
, limits
)
3090 fn mk_unary(&self, unop
: UnOp
, expr
: P
<Expr
>) -> ExprKind
{
3091 ExprKind
::Unary(unop
, expr
)
3094 fn mk_binary(&self, binop
: BinOp
, lhs
: P
<Expr
>, rhs
: P
<Expr
>) -> ExprKind
{
3095 ExprKind
::Binary(binop
, lhs
, rhs
)
3098 fn mk_index(&self, expr
: P
<Expr
>, idx
: P
<Expr
>) -> ExprKind
{
3099 ExprKind
::Index(expr
, idx
)
3102 fn mk_call(&self, f
: P
<Expr
>, args
: Vec
<P
<Expr
>>) -> ExprKind
{
3103 ExprKind
::Call(f
, args
)
3106 fn mk_await_expr(&mut self, self_arg
: P
<Expr
>, lo
: Span
) -> P
<Expr
> {
3107 let span
= lo
.to(self.prev_token
.span
);
3108 let await_expr
= self.mk_expr(span
, ExprKind
::Await(self_arg
));
3109 self.recover_from_await_method_call();
3113 pub(crate) fn mk_expr_with_attrs(&self, span
: Span
, kind
: ExprKind
, attrs
: AttrVec
) -> P
<Expr
> {
3114 P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None }
)
3117 pub(crate) fn mk_expr(&self, span
: Span
, kind
: ExprKind
) -> P
<Expr
> {
3118 P(Expr { kind, span, attrs: AttrVec::new(), id: DUMMY_NODE_ID, tokens: None }
)
3121 pub(super) fn mk_expr_err(&self, span
: Span
) -> P
<Expr
> {
3122 self.mk_expr(span
, ExprKind
::Err
)
3125 /// Create expression span ensuring the span of the parent node
3126 /// is larger than the span of lhs and rhs, including the attributes.
3127 fn mk_expr_sp(&self, lhs
: &P
<Expr
>, lhs_span
: Span
, rhs_span
: Span
) -> Span
{
3130 .find(|a
| a
.style
== AttrStyle
::Outer
)
3131 .map_or(lhs_span
, |a
| a
.span
)
3135 fn collect_tokens_for_expr(
3138 f
: impl FnOnce(&mut Self, ast
::AttrVec
) -> PResult
<'a
, P
<Expr
>>,
3139 ) -> PResult
<'a
, P
<Expr
>> {
3140 self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
3141 let res
= f(this
, attrs
)?
;
3142 let trailing
= if this
.restrictions
.contains(Restrictions
::STMT_EXPR
)
3143 && this
.token
.kind
== token
::Semi
3146 } else if this
.token
.kind
== token
::Gt
{
3149 // FIXME - pass this through from the place where we know
3150 // we need a comma, rather than assuming that `#[attr] expr,`
3151 // always captures a trailing comma
3152 TrailingToken
::MaybeComma