rustc_parse/parser/
expr.rs

1// ignore-tidy-filelength
2
3use core::mem;
4use core::ops::{Bound, ControlFlow};
5
6use ast::mut_visit::{self, MutVisitor};
7use ast::token::IdentIsRaw;
8use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered};
9use rustc_ast::ptr::P;
10use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, Token, TokenKind};
11use rustc_ast::tokenstream::TokenTree;
12use rustc_ast::util::case::Case;
13use rustc_ast::util::classify;
14use rustc_ast::util::parser::{AssocOp, ExprPrecedence, Fixity, prec_let_scrutinee_needs_par};
15use rustc_ast::visit::{Visitor, walk_expr};
16use rustc_ast::{
17    self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind,
18    BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl,
19    FnRetTy, Label, MacCall, MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind,
20    UnOp, UnsafeBinderCastKind, YieldKind,
21};
22use rustc_data_structures::stack::ensure_sufficient_stack;
23use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
24use rustc_literal_escaper::unescape_char;
25use rustc_macros::Subdiagnostic;
26use rustc_session::errors::{ExprParenthesesNeeded, report_lit_error};
27use rustc_session::lint::BuiltinLintDiag;
28use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
29use rustc_span::edition::Edition;
30use rustc_span::source_map::{self, Spanned};
31use rustc_span::{BytePos, ErrorGuaranteed, Ident, Pos, Span, Symbol, kw, sym};
32use thin_vec::{ThinVec, thin_vec};
33use tracing::instrument;
34
35use super::diagnostics::SnapshotParser;
36use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
37use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
38use super::{
39    AttrWrapper, BlockMode, ClosureSpans, ExpTokenPair, ForceCollect, Parser, PathStyle,
40    Restrictions, SemiColonMode, SeqSep, TokenType, Trailing, UsePreAttrPos,
41};
42use crate::{errors, exp, maybe_recover_from_interpolated_ty_qpath};
43
44#[derive(Debug)]
45pub(super) enum DestructuredFloat {
46    /// 1e2
47    Single(Symbol, Span),
48    /// 1.
49    TrailingDot(Symbol, Span, Span),
50    /// 1.2 | 1.2e3
51    MiddleDot(Symbol, Span, Span, Symbol, Span),
52    /// Invalid
53    Error,
54}
55
56impl<'a> Parser<'a> {
57    /// Parses an expression.
58    #[inline]
59    pub fn parse_expr(&mut self) -> PResult<'a, P<Expr>> {
60        self.current_closure.take();
61
62        let attrs = self.parse_outer_attributes()?;
63        self.parse_expr_res(Restrictions::empty(), attrs).map(|res| res.0)
64    }
65
66    /// Parses an expression, forcing tokens to be collected.
67    pub fn parse_expr_force_collect(&mut self) -> PResult<'a, P<Expr>> {
68        self.current_closure.take();
69
70        // If the expression is associative (e.g. `1 + 2`), then any preceding
71        // outer attribute actually belongs to the first inner sub-expression.
72        // In which case we must use the pre-attr pos to include the attribute
73        // in the collected tokens for the outer expression.
74        let pre_attr_pos = self.collect_pos();
75        let attrs = self.parse_outer_attributes()?;
76        self.collect_tokens(
77            Some(pre_attr_pos),
78            AttrWrapper::empty(),
79            ForceCollect::Yes,
80            |this, _empty_attrs| {
81                let (expr, is_assoc) = this.parse_expr_res(Restrictions::empty(), attrs)?;
82                let use_pre_attr_pos =
83                    if is_assoc { UsePreAttrPos::Yes } else { UsePreAttrPos::No };
84                Ok((expr, Trailing::No, use_pre_attr_pos))
85            },
86        )
87    }
88
89    pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> {
90        self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value })
91    }
92
93    fn parse_expr_catch_underscore(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>> {
94        let attrs = self.parse_outer_attributes()?;
95        match self.parse_expr_res(restrictions, attrs) {
96            Ok((expr, _)) => Ok(expr),
97            Err(err) => match self.token.ident() {
98                Some((Ident { name: kw::Underscore, .. }, IdentIsRaw::No))
99                    if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) =>
100                {
101                    // Special-case handling of `foo(_, _, _)`
102                    let guar = err.emit();
103                    self.bump();
104                    Ok(self.mk_expr(self.prev_token.span, ExprKind::Err(guar)))
105                }
106                _ => Err(err),
107            },
108        }
109    }
110
111    /// Parses a sequence of expressions delimited by parentheses.
112    fn parse_expr_paren_seq(&mut self) -> PResult<'a, ThinVec<P<Expr>>> {
113        self.parse_paren_comma_seq(|p| p.parse_expr_catch_underscore(Restrictions::empty()))
114            .map(|(r, _)| r)
115    }
116
117    /// Parses an expression, subject to the given restrictions.
118    #[inline]
119    pub(super) fn parse_expr_res(
120        &mut self,
121        r: Restrictions,
122        attrs: AttrWrapper,
123    ) -> PResult<'a, (P<Expr>, bool)> {
124        self.with_res(r, |this| this.parse_expr_assoc_with(Bound::Unbounded, attrs))
125    }
126
127    /// Parses an associative expression with operators of at least `min_prec` precedence.
128    /// The `bool` in the return value indicates if it was an assoc expr, i.e. with an operator
129    /// followed by a subexpression (e.g. `1 + 2`).
130    pub(super) fn parse_expr_assoc_with(
131        &mut self,
132        min_prec: Bound<ExprPrecedence>,
133        attrs: AttrWrapper,
134    ) -> PResult<'a, (P<Expr>, bool)> {
135        let lhs = if self.token.is_range_separator() {
136            return self.parse_expr_prefix_range(attrs).map(|res| (res, false));
137        } else {
138            self.parse_expr_prefix(attrs)?
139        };
140        self.parse_expr_assoc_rest_with(min_prec, false, lhs)
141    }
142
143    /// Parses the rest of an associative expression (i.e. the part after the lhs) with operators
144    /// of at least `min_prec` precedence. The `bool` in the return value indicates if something
145    /// was actually parsed.
146    pub(super) fn parse_expr_assoc_rest_with(
147        &mut self,
148        min_prec: Bound<ExprPrecedence>,
149        starts_stmt: bool,
150        mut lhs: P<Expr>,
151    ) -> PResult<'a, (P<Expr>, bool)> {
152        let mut parsed_something = false;
153        if !self.should_continue_as_assoc_expr(&lhs) {
154            return Ok((lhs, parsed_something));
155        }
156
157        self.expected_token_types.insert(TokenType::Operator);
158        while let Some(op) = self.check_assoc_op() {
159            let lhs_span = self.interpolated_or_expr_span(&lhs);
160            let cur_op_span = self.token.span;
161            let restrictions = if op.node.is_assign_like() {
162                self.restrictions & Restrictions::NO_STRUCT_LITERAL
163            } else {
164                self.restrictions
165            };
166            let prec = op.node.precedence();
167            if match min_prec {
168                Bound::Included(min_prec) => prec < min_prec,
169                Bound::Excluded(min_prec) => prec <= min_prec,
170                Bound::Unbounded => false,
171            } {
172                break;
173            }
174            // Check for deprecated `...` syntax
175            if self.token == token::DotDotDot && op.node == AssocOp::Range(RangeLimits::Closed) {
176                self.err_dotdotdot_syntax(self.token.span);
177            }
178
179            if self.token == token::LArrow {
180                self.err_larrow_operator(self.token.span);
181            }
182
183            parsed_something = true;
184            self.bump();
185            if op.node.is_comparison() {
186                if let Some(expr) = self.check_no_chained_comparison(&lhs, &op)? {
187                    return Ok((expr, parsed_something));
188                }
189            }
190
191            // Look for JS' `===` and `!==` and recover
192            if let AssocOp::Binary(bop @ BinOpKind::Eq | bop @ BinOpKind::Ne) = op.node
193                && self.token == token::Eq
194                && self.prev_token.span.hi() == self.token.span.lo()
195            {
196                let sp = op.span.to(self.token.span);
197                let sugg = bop.as_str().into();
198                let invalid = format!("{sugg}=");
199                self.dcx().emit_err(errors::InvalidComparisonOperator {
200                    span: sp,
201                    invalid: invalid.clone(),
202                    sub: errors::InvalidComparisonOperatorSub::Correctable {
203                        span: sp,
204                        invalid,
205                        correct: sugg,
206                    },
207                });
208                self.bump();
209            }
210
211            // Look for PHP's `<>` and recover
212            if op.node == AssocOp::Binary(BinOpKind::Lt)
213                && self.token == token::Gt
214                && self.prev_token.span.hi() == self.token.span.lo()
215            {
216                let sp = op.span.to(self.token.span);
217                self.dcx().emit_err(errors::InvalidComparisonOperator {
218                    span: sp,
219                    invalid: "<>".into(),
220                    sub: errors::InvalidComparisonOperatorSub::Correctable {
221                        span: sp,
222                        invalid: "<>".into(),
223                        correct: "!=".into(),
224                    },
225                });
226                self.bump();
227            }
228
229            // Look for C++'s `<=>` and recover
230            if op.node == AssocOp::Binary(BinOpKind::Le)
231                && self.token == token::Gt
232                && self.prev_token.span.hi() == self.token.span.lo()
233            {
234                let sp = op.span.to(self.token.span);
235                self.dcx().emit_err(errors::InvalidComparisonOperator {
236                    span: sp,
237                    invalid: "<=>".into(),
238                    sub: errors::InvalidComparisonOperatorSub::Spaceship(sp),
239                });
240                self.bump();
241            }
242
243            if self.prev_token == token::Plus
244                && self.token == token::Plus
245                && self.prev_token.span.between(self.token.span).is_empty()
246            {
247                let op_span = self.prev_token.span.to(self.token.span);
248                // Eat the second `+`
249                self.bump();
250                lhs = self.recover_from_postfix_increment(lhs, op_span, starts_stmt)?;
251                continue;
252            }
253
254            if self.prev_token == token::Minus
255                && self.token == token::Minus
256                && self.prev_token.span.between(self.token.span).is_empty()
257                && !self.look_ahead(1, |tok| tok.can_begin_expr())
258            {
259                let op_span = self.prev_token.span.to(self.token.span);
260                // Eat the second `-`
261                self.bump();
262                lhs = self.recover_from_postfix_decrement(lhs, op_span, starts_stmt)?;
263                continue;
264            }
265
266            let op = op.node;
267            // Special cases:
268            if op == AssocOp::Cast {
269                lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?;
270                continue;
271            } else if let AssocOp::Range(limits) = op {
272                // If we didn't have to handle `x..`/`x..=`, it would be pretty easy to
273                // generalise it to the Fixity::None code.
274                lhs = self.parse_expr_range(prec, lhs, limits, cur_op_span)?;
275                break;
276            }
277
278            let min_prec = match op.fixity() {
279                Fixity::Right => Bound::Included(prec),
280                Fixity::Left | Fixity::None => Bound::Excluded(prec),
281            };
282            let (rhs, _) = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
283                let attrs = this.parse_outer_attributes()?;
284                this.parse_expr_assoc_with(min_prec, attrs)
285            })?;
286
287            let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span);
288            lhs = match op {
289                AssocOp::Binary(ast_op) => {
290                    let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs);
291                    self.mk_expr(span, binary)
292                }
293                AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span)),
294                AssocOp::AssignOp(aop) => {
295                    let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs);
296                    self.mk_expr(span, aopexpr)
297                }
298                AssocOp::Cast | AssocOp::Range(_) => {
299                    self.dcx().span_bug(span, "AssocOp should have been handled by special case")
300                }
301            };
302        }
303
304        Ok((lhs, parsed_something))
305    }
306
307    fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
308        match (self.expr_is_complete(lhs), AssocOp::from_token(&self.token)) {
309            // Semi-statement forms are odd:
310            // See https://github.com/rust-lang/rust/issues/29071
311            (true, None) => false,
312            (false, _) => true, // Continue parsing the expression.
313            // An exhaustive check is done in the following block, but these are checked first
314            // because they *are* ambiguous but also reasonable looking incorrect syntax, so we
315            // want to keep their span info to improve diagnostics in these cases in a later stage.
316            (true, Some(AssocOp::Binary(
317                BinOpKind::Mul | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
318                BinOpKind::Sub | // `{ 42 } -5`
319                BinOpKind::Add | // `{ 42 } + 42` (unary plus)
320                BinOpKind::And | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
321                BinOpKind::Or | // `{ 42 } || 42` ("logical or" or closure)
322                BinOpKind::BitOr // `{ 42 } | 42` or `{ 42 } |x| 42`
323            ))) => {
324                // These cases are ambiguous and can't be identified in the parser alone.
325                //
326                // Bitwise AND is left out because guessing intent is hard. We can make
327                // suggestions based on the assumption that double-refs are rarely intentional,
328                // and closures are distinct enough that they don't get mixed up with their
329                // return value.
330                let sp = self.psess.source_map().start_point(self.token.span);
331                self.psess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
332                false
333            }
334            (true, Some(op)) if !op.can_continue_expr_unambiguously() => false,
335            (true, Some(_)) => {
336                self.error_found_expr_would_be_stmt(lhs);
337                true
338            }
339        }
340    }
341
342    /// We've found an expression that would be parsed as a statement,
343    /// but the next token implies this should be parsed as an expression.
344    /// For example: `if let Some(x) = x { x } else { 0 } / 2`.
345    fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {
346        self.dcx().emit_err(errors::FoundExprWouldBeStmt {
347            span: self.token.span,
348            token: self.token,
349            suggestion: ExprParenthesesNeeded::surrounding(lhs.span),
350        });
351    }
352
353    /// Possibly translate the current token to an associative operator.
354    /// The method does not advance the current token.
355    ///
356    /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
357    pub(super) fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
358        let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) {
359            // When parsing const expressions, stop parsing when encountering `>`.
360            (
361                Some(
362                    AssocOp::Binary(BinOpKind::Shr | BinOpKind::Gt | BinOpKind::Ge)
363                    | AssocOp::AssignOp(AssignOpKind::ShrAssign),
364                ),
365                _,
366            ) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
367                return None;
368            }
369            // When recovering patterns as expressions, stop parsing when encountering an
370            // assignment `=`, an alternative `|`, or a range `..`.
371            (
372                Some(
373                    AssocOp::Assign
374                    | AssocOp::AssignOp(_)
375                    | AssocOp::Binary(BinOpKind::BitOr)
376                    | AssocOp::Range(_),
377                ),
378                _,
379            ) if self.restrictions.contains(Restrictions::IS_PAT) => {
380                return None;
381            }
382            (Some(op), _) => (op, self.token.span),
383            (None, Some((Ident { name: sym::and, span }, IdentIsRaw::No)))
384                if self.may_recover() =>
385            {
386                self.dcx().emit_err(errors::InvalidLogicalOperator {
387                    span: self.token.span,
388                    incorrect: "and".into(),
389                    sub: errors::InvalidLogicalOperatorSub::Conjunction(self.token.span),
390                });
391                (AssocOp::Binary(BinOpKind::And), span)
392            }
393            (None, Some((Ident { name: sym::or, span }, IdentIsRaw::No))) if self.may_recover() => {
394                self.dcx().emit_err(errors::InvalidLogicalOperator {
395                    span: self.token.span,
396                    incorrect: "or".into(),
397                    sub: errors::InvalidLogicalOperatorSub::Disjunction(self.token.span),
398                });
399                (AssocOp::Binary(BinOpKind::Or), span)
400            }
401            _ => return None,
402        };
403        Some(source_map::respan(span, op))
404    }
405
406    /// Checks if this expression is a successfully parsed statement.
407    fn expr_is_complete(&self, e: &Expr) -> bool {
408        self.restrictions.contains(Restrictions::STMT_EXPR) && classify::expr_is_complete(e)
409    }
410
411    /// Parses `x..y`, `x..=y`, and `x..`/`x..=`.
412    /// The other two variants are handled in `parse_prefix_range_expr` below.
413    fn parse_expr_range(
414        &mut self,
415        prec: ExprPrecedence,
416        lhs: P<Expr>,
417        limits: RangeLimits,
418        cur_op_span: Span,
419    ) -> PResult<'a, P<Expr>> {
420        let rhs = if self.is_at_start_of_range_notation_rhs() {
421            let maybe_lt = self.token;
422            let attrs = self.parse_outer_attributes()?;
423            Some(
424                self.parse_expr_assoc_with(Bound::Excluded(prec), attrs)
425                    .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?
426                    .0,
427            )
428        } else {
429            None
430        };
431        let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);
432        let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span);
433        let range = self.mk_range(Some(lhs), rhs, limits);
434        Ok(self.mk_expr(span, range))
435    }
436
437    fn is_at_start_of_range_notation_rhs(&self) -> bool {
438        if self.token.can_begin_expr() {
439            // Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
440            if self.token == token::OpenBrace {
441                return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
442            }
443            true
444        } else {
445            false
446        }
447    }
448
449    /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`.
450    fn parse_expr_prefix_range(&mut self, attrs: AttrWrapper) -> PResult<'a, P<Expr>> {
451        if !attrs.is_empty() {
452            let err = errors::DotDotRangeAttribute { span: self.token.span };
453            self.dcx().emit_err(err);
454        }
455
456        // Check for deprecated `...` syntax.
457        if self.token == token::DotDotDot {
458            self.err_dotdotdot_syntax(self.token.span);
459        }
460
461        debug_assert!(
462            self.token.is_range_separator(),
463            "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq",
464            self.token
465        );
466
467        let limits = match self.token.kind {
468            token::DotDot => RangeLimits::HalfOpen,
469            _ => RangeLimits::Closed,
470        };
471        let op = AssocOp::from_token(&self.token);
472        let attrs = self.parse_outer_attributes()?;
473        self.collect_tokens_for_expr(attrs, |this, attrs| {
474            let lo = this.token.span;
475            let maybe_lt = this.look_ahead(1, |t| t.clone());
476            this.bump();
477            let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {
478                // RHS must be parsed with more associativity than the dots.
479                let attrs = this.parse_outer_attributes()?;
480                this.parse_expr_assoc_with(Bound::Excluded(op.unwrap().precedence()), attrs)
481                    .map(|(x, _)| (lo.to(x.span), Some(x)))
482                    .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
483            } else {
484                (lo, None)
485            };
486            let range = this.mk_range(None, opt_end, limits);
487            Ok(this.mk_expr_with_attrs(span, range, attrs))
488        })
489    }
490
491    /// Parses a prefix-unary-operator expr.
492    fn parse_expr_prefix(&mut self, attrs: AttrWrapper) -> PResult<'a, P<Expr>> {
493        let lo = self.token.span;
494
495        macro_rules! make_it {
496            ($this:ident, $attrs:expr, |this, _| $body:expr) => {
497                $this.collect_tokens_for_expr($attrs, |$this, attrs| {
498                    let (hi, ex) = $body?;
499                    Ok($this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
500                })
501            };
502        }
503
504        let this = self;
505
506        // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
507        match this.token.uninterpolate().kind {
508            // `!expr`
509            token::Bang => make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Not)),
510            // `~expr`
511            token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)),
512            // `-expr`
513            token::Minus => {
514                make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Neg))
515            }
516            // `*expr`
517            token::Star => {
518                make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Deref))
519            }
520            // `&expr` and `&&expr`
521            token::And | token::AndAnd => {
522                make_it!(this, attrs, |this, _| this.parse_expr_borrow(lo))
523            }
524            // `+lit`
525            token::Plus if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
526                let mut err = errors::LeadingPlusNotSupported {
527                    span: lo,
528                    remove_plus: None,
529                    add_parentheses: None,
530                };
531
532                // a block on the LHS might have been intended to be an expression instead
533                if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) {
534                    err.add_parentheses = Some(ExprParenthesesNeeded::surrounding(*sp));
535                } else {
536                    err.remove_plus = Some(lo);
537                }
538                this.dcx().emit_err(err);
539
540                this.bump();
541                let attrs = this.parse_outer_attributes()?;
542                this.parse_expr_prefix(attrs)
543            }
544            // Recover from `++x`:
545            token::Plus if this.look_ahead(1, |t| *t == token::Plus) => {
546                let starts_stmt =
547                    this.prev_token == token::Semi || this.prev_token == token::CloseBrace;
548                let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span));
549                // Eat both `+`s.
550                this.bump();
551                this.bump();
552
553                let operand_expr = this.parse_expr_dot_or_call(attrs)?;
554                this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt)
555            }
556            token::Ident(..) if this.token.is_keyword(kw::Box) => {
557                make_it!(this, attrs, |this, _| this.parse_expr_box(lo))
558            }
559            token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => {
560                make_it!(this, attrs, |this, _| this.recover_not_expr(lo))
561            }
562            _ => return this.parse_expr_dot_or_call(attrs),
563        }
564    }
565
566    fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, P<Expr>)> {
567        self.bump();
568        let attrs = self.parse_outer_attributes()?;
569        let expr = if self.token.is_range_separator() {
570            self.parse_expr_prefix_range(attrs)
571        } else {
572            self.parse_expr_prefix(attrs)
573        }?;
574        let span = self.interpolated_or_expr_span(&expr);
575        Ok((lo.to(span), expr))
576    }
577
578    fn parse_expr_unary(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> {
579        let (span, expr) = self.parse_expr_prefix_common(lo)?;
580        Ok((span, self.mk_unary(op, expr)))
581    }
582
583    /// Recover on `~expr` in favor of `!expr`.
584    fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
585        self.dcx().emit_err(errors::TildeAsUnaryOperator(lo));
586
587        self.parse_expr_unary(lo, UnOp::Not)
588    }
589
590    /// Parse `box expr` - this syntax has been removed, but we still parse this
591    /// for now to provide a more useful error
592    fn parse_expr_box(&mut self, box_kw: Span) -> PResult<'a, (Span, ExprKind)> {
593        let (span, expr) = self.parse_expr_prefix_common(box_kw)?;
594        // Make a multipart suggestion instead of `span_to_snippet` in case source isn't available
595        let box_kw_and_lo = box_kw.until(self.interpolated_or_expr_span(&expr));
596        let hi = span.shrink_to_hi();
597        let sugg = errors::AddBoxNew { box_kw_and_lo, hi };
598        let guar = self.dcx().emit_err(errors::BoxSyntaxRemoved { span, sugg });
599        Ok((span, ExprKind::Err(guar)))
600    }
601
602    fn is_mistaken_not_ident_negation(&self) -> bool {
603        let token_cannot_continue_expr = |t: &Token| match t.uninterpolate().kind {
604            // These tokens can start an expression after `!`, but
605            // can't continue an expression after an ident
606            token::Ident(name, is_raw) => token::ident_can_begin_expr(name, t.span, is_raw),
607            token::Literal(..) | token::Pound => true,
608            _ => t.is_metavar_expr(),
609        };
610        self.token.is_ident_named(sym::not) && self.look_ahead(1, token_cannot_continue_expr)
611    }
612
613    /// Recover on `not expr` in favor of `!expr`.
614    fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
615        let negated_token = self.look_ahead(1, |t| *t);
616
617        let sub_diag = if negated_token.is_numeric_lit() {
618            errors::NotAsNegationOperatorSub::SuggestNotBitwise
619        } else if negated_token.is_bool_lit() {
620            errors::NotAsNegationOperatorSub::SuggestNotLogical
621        } else {
622            errors::NotAsNegationOperatorSub::SuggestNotDefault
623        };
624
625        self.dcx().emit_err(errors::NotAsNegationOperator {
626            negated: negated_token.span,
627            negated_desc: super::token_descr(&negated_token),
628            // Span the `not` plus trailing whitespace to avoid
629            // trailing whitespace after the `!` in our suggestion
630            sub: sub_diag(
631                self.psess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),
632            ),
633        });
634
635        self.parse_expr_unary(lo, UnOp::Not)
636    }
637
638    /// Returns the span of expr if it was not interpolated, or the span of the interpolated token.
639    fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
640        match self.prev_token.kind {
641            token::NtIdent(..) | token::NtLifetime(..) => self.prev_token.span,
642            token::CloseInvisible(InvisibleOrigin::MetaVar(_)) => {
643                // `expr.span` is the interpolated span, because invisible open
644                // and close delims both get marked with the same span, one
645                // that covers the entire thing between them. (See
646                // `rustc_expand::mbe::transcribe::transcribe`.)
647                self.prev_token.span
648            }
649            _ => expr.span,
650        }
651    }
652
653    fn parse_assoc_op_cast(
654        &mut self,
655        lhs: P<Expr>,
656        lhs_span: Span,
657        expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
658    ) -> PResult<'a, P<Expr>> {
659        let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| {
660            this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, rhs.span), expr_kind(lhs, rhs))
661        };
662
663        // Save the state of the parser before parsing type normally, in case there is a
664        // LessThan comparison after this cast.
665        let parser_snapshot_before_type = self.clone();
666        let cast_expr = match self.parse_as_cast_ty() {
667            Ok(rhs) => mk_expr(self, lhs, rhs),
668            Err(type_err) => {
669                if !self.may_recover() {
670                    return Err(type_err);
671                }
672
673                // Rewind to before attempting to parse the type with generics, to recover
674                // from situations like `x as usize < y` in which we first tried to parse
675                // `usize < y` as a type with generic arguments.
676                let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
677
678                // Check for typo of `'a: loop { break 'a }` with a missing `'`.
679                match (&lhs.kind, &self.token.kind) {
680                    (
681                        // `foo: `
682                        ExprKind::Path(None, ast::Path { segments, .. }),
683                        token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No),
684                    ) if let [segment] = segments.as_slice() => {
685                        let snapshot = self.create_snapshot_for_diagnostic();
686                        let label = Label {
687                            ident: Ident::from_str_and_span(
688                                &format!("'{}", segment.ident),
689                                segment.ident.span,
690                            ),
691                        };
692                        match self.parse_expr_labeled(label, false) {
693                            Ok(expr) => {
694                                type_err.cancel();
695                                self.dcx().emit_err(errors::MalformedLoopLabel {
696                                    span: label.ident.span,
697                                    suggestion: label.ident.span.shrink_to_lo(),
698                                });
699                                return Ok(expr);
700                            }
701                            Err(err) => {
702                                err.cancel();
703                                self.restore_snapshot(snapshot);
704                            }
705                        }
706                    }
707                    _ => {}
708                }
709
710                match self.parse_path(PathStyle::Expr) {
711                    Ok(path) => {
712                        let span_after_type = parser_snapshot_after_type.token.span;
713                        let expr = mk_expr(
714                            self,
715                            lhs,
716                            self.mk_ty(path.span, TyKind::Path(None, path.clone())),
717                        );
718
719                        let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);
720                        let suggestion = errors::ComparisonOrShiftInterpretedAsGenericSugg {
721                            left: expr.span.shrink_to_lo(),
722                            right: expr.span.shrink_to_hi(),
723                        };
724
725                        match self.token.kind {
726                            token::Lt => {
727                                self.dcx().emit_err(errors::ComparisonInterpretedAsGeneric {
728                                    comparison: self.token.span,
729                                    r#type: path,
730                                    args: args_span,
731                                    suggestion,
732                                })
733                            }
734                            token::Shl => self.dcx().emit_err(errors::ShiftInterpretedAsGeneric {
735                                shift: self.token.span,
736                                r#type: path,
737                                args: args_span,
738                                suggestion,
739                            }),
740                            _ => {
741                                // We can end up here even without `<` being the next token, for
742                                // example because `parse_ty_no_plus` returns `Err` on keywords,
743                                // but `parse_path` returns `Ok` on them due to error recovery.
744                                // Return original error and parser state.
745                                *self = parser_snapshot_after_type;
746                                return Err(type_err);
747                            }
748                        };
749
750                        // Successfully parsed the type path leaving a `<` yet to parse.
751                        type_err.cancel();
752
753                        // Keep `x as usize` as an expression in AST and continue parsing.
754                        expr
755                    }
756                    Err(path_err) => {
757                        // Couldn't parse as a path, return original error and parser state.
758                        path_err.cancel();
759                        *self = parser_snapshot_after_type;
760                        return Err(type_err);
761                    }
762                }
763            }
764        };
765
766        // Try to parse a postfix operator such as `.`, `?`, or index (`[]`)
767        // after a cast. If one is present, emit an error then return a valid
768        // parse tree; For something like `&x as T[0]` will be as if it was
769        // written `((&x) as T)[0]`.
770
771        let span = cast_expr.span;
772
773        let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?;
774
775        // Check if an illegal postfix operator has been added after the cast.
776        // If the resulting expression is not a cast, it is an illegal postfix operator.
777        if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) {
778            let msg = format!(
779                "cast cannot be followed by {}",
780                match with_postfix.kind {
781                    ExprKind::Index(..) => "indexing",
782                    ExprKind::Try(_) => "`?`",
783                    ExprKind::Field(_, _) => "a field access",
784                    ExprKind::MethodCall(_) => "a method call",
785                    ExprKind::Call(_, _) => "a function call",
786                    ExprKind::Await(_, _) => "`.await`",
787                    ExprKind::Use(_, _) => "`.use`",
788                    ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
789                    ExprKind::Err(_) => return Ok(with_postfix),
790                    _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
791                }
792            );
793            let mut err = self.dcx().struct_span_err(span, msg);
794
795            let suggest_parens = |err: &mut Diag<'_>| {
796                let suggestions = vec![
797                    (span.shrink_to_lo(), "(".to_string()),
798                    (span.shrink_to_hi(), ")".to_string()),
799                ];
800                err.multipart_suggestion(
801                    "try surrounding the expression in parentheses",
802                    suggestions,
803                    Applicability::MachineApplicable,
804                );
805            };
806
807            suggest_parens(&mut err);
808
809            err.emit();
810        };
811        Ok(with_postfix)
812    }
813
814    /// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.
815    fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
816        self.expect_and()?;
817        let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon);
818        let lifetime = has_lifetime.then(|| self.expect_lifetime()); // For recovery, see below.
819        let (borrow_kind, mutbl) = self.parse_borrow_modifiers();
820        let attrs = self.parse_outer_attributes()?;
821        let expr = if self.token.is_range_separator() {
822            self.parse_expr_prefix_range(attrs)
823        } else {
824            self.parse_expr_prefix(attrs)
825        }?;
826        let hi = self.interpolated_or_expr_span(&expr);
827        let span = lo.to(hi);
828        if let Some(lt) = lifetime {
829            self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));
830        }
831
832        // Add expected tokens if we parsed `&raw` as an expression.
833        // This will make sure we see "expected `const`, `mut`", and
834        // guides recovery in case we write `&raw expr`.
835        if borrow_kind == ast::BorrowKind::Ref
836            && mutbl == ast::Mutability::Not
837            && matches!(&expr.kind, ExprKind::Path(None, p) if *p == kw::Raw)
838        {
839            self.expected_token_types.insert(TokenType::KwMut);
840            self.expected_token_types.insert(TokenType::KwConst);
841        }
842
843        Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
844    }
845
846    fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
847        self.dcx().emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span });
848    }
849
850    /// Parse `mut?` or `[ raw | pin ] [ const | mut ]`.
851    fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {
852        if self.check_keyword(exp!(Raw)) && self.look_ahead(1, Token::is_mutability) {
853            // `raw [ const | mut ]`.
854            let found_raw = self.eat_keyword(exp!(Raw));
855            assert!(found_raw);
856            let mutability = self.parse_const_or_mut().unwrap();
857            (ast::BorrowKind::Raw, mutability)
858        } else if let Some((ast::Pinnedness::Pinned, mutbl)) = self.parse_pin_and_mut() {
859            // `pin [ const | mut ]`.
860            // `pin` has been gated in `self.parse_pin_and_mut()` so we don't
861            // need to gate it here.
862            (ast::BorrowKind::Pin, mutbl)
863        } else {
864            // `mut?`
865            (ast::BorrowKind::Ref, self.parse_mutability())
866        }
867    }
868
869    /// Parses `a.b` or `a(13)` or `a[4]` or just `a`.
870    fn parse_expr_dot_or_call(&mut self, attrs: AttrWrapper) -> PResult<'a, P<Expr>> {
871        self.collect_tokens_for_expr(attrs, |this, attrs| {
872            let base = this.parse_expr_bottom()?;
873            let span = this.interpolated_or_expr_span(&base);
874            this.parse_expr_dot_or_call_with(attrs, base, span)
875        })
876    }
877
878    pub(super) fn parse_expr_dot_or_call_with(
879        &mut self,
880        mut attrs: ast::AttrVec,
881        mut e: P<Expr>,
882        lo: Span,
883    ) -> PResult<'a, P<Expr>> {
884        let mut res = ensure_sufficient_stack(|| {
885            loop {
886                let has_question =
887                    if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
888                        // We are using noexpect here because we don't expect a `?` directly after
889                        // a `return` which could be suggested otherwise.
890                        self.eat_noexpect(&token::Question)
891                    } else {
892                        self.eat(exp!(Question))
893                    };
894                if has_question {
895                    // `expr?`
896                    e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
897                    continue;
898                }
899                let has_dot = if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
900                    // We are using noexpect here because we don't expect a `.` directly after
901                    // a `return` which could be suggested otherwise.
902                    self.eat_noexpect(&token::Dot)
903                } else if self.token == TokenKind::RArrow && self.may_recover() {
904                    // Recovery for `expr->suffix`.
905                    self.bump();
906                    let span = self.prev_token.span;
907                    self.dcx().emit_err(errors::ExprRArrowCall { span });
908                    true
909                } else {
910                    self.eat(exp!(Dot))
911                };
912                if has_dot {
913                    // expr.f
914                    e = self.parse_dot_suffix_expr(lo, e)?;
915                    continue;
916                }
917                if self.expr_is_complete(&e) {
918                    return Ok(e);
919                }
920                e = match self.token.kind {
921                    token::OpenParen => self.parse_expr_fn_call(lo, e),
922                    token::OpenBracket => self.parse_expr_index(lo, e)?,
923                    _ => return Ok(e),
924                }
925            }
926        });
927
928        // Stitch the list of outer attributes onto the return value. A little
929        // bit ugly, but the best way given the current code structure.
930        if !attrs.is_empty()
931            && let Ok(expr) = &mut res
932        {
933            mem::swap(&mut expr.attrs, &mut attrs);
934            expr.attrs.extend(attrs)
935        }
936        res
937    }
938
939    pub(super) fn parse_dot_suffix_expr(
940        &mut self,
941        lo: Span,
942        base: P<Expr>,
943    ) -> PResult<'a, P<Expr>> {
944        // At this point we've consumed something like `expr.` and `self.token` holds the token
945        // after the dot.
946        match self.token.uninterpolate().kind {
947            token::Ident(..) => self.parse_dot_suffix(base, lo),
948            token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {
949                let ident_span = self.token.span;
950                self.bump();
951                Ok(self.mk_expr_tuple_field_access(lo, ident_span, base, symbol, suffix))
952            }
953            token::Literal(token::Lit { kind: token::Float, symbol, suffix }) => {
954                Ok(match self.break_up_float(symbol, self.token.span) {
955                    // 1e2
956                    DestructuredFloat::Single(sym, _sp) => {
957                        // `foo.1e2`: a single complete dot access, fully consumed. We end up with
958                        // the `1e2` token in `self.prev_token` and the following token in
959                        // `self.token`.
960                        let ident_span = self.token.span;
961                        self.bump();
962                        self.mk_expr_tuple_field_access(lo, ident_span, base, sym, suffix)
963                    }
964                    // 1.
965                    DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {
966                        // `foo.1.`: a single complete dot access and the start of another.
967                        // We end up with the `sym` (`1`) token in `self.prev_token` and a dot in
968                        // `self.token`.
969                        assert!(suffix.is_none());
970                        self.token = Token::new(token::Ident(sym, IdentIsRaw::No), ident_span);
971                        self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));
972                        self.mk_expr_tuple_field_access(lo, ident_span, base, sym, None)
973                    }
974                    // 1.2 | 1.2e3
975                    DestructuredFloat::MiddleDot(
976                        sym1,
977                        ident1_span,
978                        _dot_span,
979                        sym2,
980                        ident2_span,
981                    ) => {
982                        // `foo.1.2` (or `foo.1.2e3`): two complete dot accesses. We end up with
983                        // the `sym2` (`2` or `2e3`) token in `self.prev_token` and the following
984                        // token in `self.token`.
985                        let next_token2 =
986                            Token::new(token::Ident(sym2, IdentIsRaw::No), ident2_span);
987                        self.bump_with((next_token2, self.token_spacing));
988                        self.bump();
989                        let base1 =
990                            self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None);
991                        self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix)
992                    }
993                    DestructuredFloat::Error => base,
994                })
995            }
996            _ => {
997                self.error_unexpected_after_dot();
998                Ok(base)
999            }
1000        }
1001    }
1002
1003    fn error_unexpected_after_dot(&self) {
1004        let actual = super::token_descr(&self.token);
1005        let span = self.token.span;
1006        let sm = self.psess.source_map();
1007        let (span, actual) = match (&self.token.kind, self.subparser_name) {
1008            (token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => {
1009                (span.shrink_to_hi(), format!("`{}`", snippet))
1010            }
1011            (token::CloseInvisible(InvisibleOrigin::MetaVar(_)), _) => {
1012                // No need to report an error. This case will only occur when parsing a pasted
1013                // metavariable, and we should have emitted an error when parsing the macro call in
1014                // the first place. E.g. in this code:
1015                // ```
1016                // macro_rules! m { ($e:expr) => { $e }; }
1017                //
1018                // fn main() {
1019                //     let f = 1;
1020                //     m!(f.);
1021                // }
1022                // ```
1023                // we'll get an error "unexpected token: `)` when parsing the `m!(f.)`, so we don't
1024                // want to issue a second error when parsing the expansion `«f.»` (where `«`/`»`
1025                // represent the invisible delimiters).
1026                self.dcx().span_delayed_bug(span, "bad dot expr in metavariable");
1027                return;
1028            }
1029            _ => (span, actual),
1030        };
1031        self.dcx().emit_err(errors::UnexpectedTokenAfterDot { span, actual });
1032    }
1033
1034    /// We need an identifier or integer, but the next token is a float.
1035    /// Break the float into components to extract the identifier or integer.
1036    ///
1037    /// See also [`TokenKind::break_two_token_op`] which does similar splitting of `>>` into `>`.
1038    //
1039    // FIXME: With current `TokenCursor` it's hard to break tokens into more than 2
1040    //  parts unless those parts are processed immediately. `TokenCursor` should either
1041    //  support pushing "future tokens" (would be also helpful to `break_and_eat`), or
1042    //  we should break everything including floats into more basic proc-macro style
1043    //  tokens in the lexer (probably preferable).
1044    pub(super) fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat {
1045        #[derive(Debug)]
1046        enum FloatComponent {
1047            IdentLike(String),
1048            Punct(char),
1049        }
1050        use FloatComponent::*;
1051
1052        let float_str = float.as_str();
1053        let mut components = Vec::new();
1054        let mut ident_like = String::new();
1055        for c in float_str.chars() {
1056            if c == '_' || c.is_ascii_alphanumeric() {
1057                ident_like.push(c);
1058            } else if matches!(c, '.' | '+' | '-') {
1059                if !ident_like.is_empty() {
1060                    components.push(IdentLike(mem::take(&mut ident_like)));
1061                }
1062                components.push(Punct(c));
1063            } else {
1064                panic!("unexpected character in a float token: {c:?}")
1065            }
1066        }
1067        if !ident_like.is_empty() {
1068            components.push(IdentLike(ident_like));
1069        }
1070
1071        // With proc macros the span can refer to anything, the source may be too short,
1072        // or too long, or non-ASCII. It only makes sense to break our span into components
1073        // if its underlying text is identical to our float literal.
1074        let can_take_span_apart =
1075            || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref();
1076
1077        match &*components {
1078            // 1e2
1079            [IdentLike(i)] => {
1080                DestructuredFloat::Single(Symbol::intern(i), span)
1081            }
1082            // 1.
1083            [IdentLike(left), Punct('.')] => {
1084                let (left_span, dot_span) = if can_take_span_apart() {
1085                    let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
1086                    let dot_span = span.with_lo(left_span.hi());
1087                    (left_span, dot_span)
1088                } else {
1089                    (span, span)
1090                };
1091                let left = Symbol::intern(left);
1092                DestructuredFloat::TrailingDot(left, left_span, dot_span)
1093            }
1094            // 1.2 | 1.2e3
1095            [IdentLike(left), Punct('.'), IdentLike(right)] => {
1096                let (left_span, dot_span, right_span) = if can_take_span_apart() {
1097                    let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
1098                    let dot_span = span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1));
1099                    let right_span = span.with_lo(dot_span.hi());
1100                    (left_span, dot_span, right_span)
1101                } else {
1102                    (span, span, span)
1103                };
1104                let left = Symbol::intern(left);
1105                let right = Symbol::intern(right);
1106                DestructuredFloat::MiddleDot(left, left_span, dot_span, right, right_span)
1107            }
1108            // 1e+ | 1e- (recovered)
1109            [IdentLike(_), Punct('+' | '-')] |
1110            // 1e+2 | 1e-2
1111            [IdentLike(_), Punct('+' | '-'), IdentLike(_)] |
1112            // 1.2e+ | 1.2e-
1113            [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-')] |
1114            // 1.2e+3 | 1.2e-3
1115            [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {
1116                // See the FIXME about `TokenCursor` above.
1117                self.error_unexpected_after_dot();
1118                DestructuredFloat::Error
1119            }
1120            _ => panic!("unexpected components in a float token: {components:?}"),
1121        }
1122    }
1123
1124    /// Parse the field access used in offset_of, matched by `$(e:expr)+`.
1125    /// Currently returns a list of idents. However, it should be possible in
1126    /// future to also do array indices, which might be arbitrary expressions.
1127    fn parse_floating_field_access(&mut self) -> PResult<'a, Vec<Ident>> {
1128        let mut fields = Vec::new();
1129        let mut trailing_dot = None;
1130
1131        loop {
1132            // This is expected to use a metavariable $(args:expr)+, but the builtin syntax
1133            // could be called directly. Calling `parse_expr` allows this function to only
1134            // consider `Expr`s.
1135            let expr = self.parse_expr()?;
1136            let mut current = &expr;
1137            let start_idx = fields.len();
1138            loop {
1139                match current.kind {
1140                    ExprKind::Field(ref left, right) => {
1141                        // Field access is read right-to-left.
1142                        fields.insert(start_idx, right);
1143                        trailing_dot = None;
1144                        current = left;
1145                    }
1146                    // Parse this both to give helpful error messages and to
1147                    // verify it can be done with this parser setup.
1148                    ExprKind::Index(ref left, ref _right, span) => {
1149                        self.dcx().emit_err(errors::ArrayIndexInOffsetOf(span));
1150                        current = left;
1151                    }
1152                    ExprKind::Lit(token::Lit {
1153                        kind: token::Float | token::Integer,
1154                        symbol,
1155                        suffix,
1156                    }) => {
1157                        if let Some(suffix) = suffix {
1158                            self.expect_no_tuple_index_suffix(current.span, suffix);
1159                        }
1160                        match self.break_up_float(symbol, current.span) {
1161                            // 1e2
1162                            DestructuredFloat::Single(sym, sp) => {
1163                                trailing_dot = None;
1164                                fields.insert(start_idx, Ident::new(sym, sp));
1165                            }
1166                            // 1.
1167                            DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {
1168                                assert!(suffix.is_none());
1169                                trailing_dot = Some(dot_span);
1170                                fields.insert(start_idx, Ident::new(sym, sym_span));
1171                            }
1172                            // 1.2 | 1.2e3
1173                            DestructuredFloat::MiddleDot(
1174                                symbol1,
1175                                span1,
1176                                _dot_span,
1177                                symbol2,
1178                                span2,
1179                            ) => {
1180                                trailing_dot = None;
1181                                fields.insert(start_idx, Ident::new(symbol2, span2));
1182                                fields.insert(start_idx, Ident::new(symbol1, span1));
1183                            }
1184                            DestructuredFloat::Error => {
1185                                trailing_dot = None;
1186                                fields.insert(start_idx, Ident::new(symbol, self.prev_token.span));
1187                            }
1188                        }
1189                        break;
1190                    }
1191                    ExprKind::Path(None, Path { ref segments, .. }) => {
1192                        match &segments[..] {
1193                            [PathSegment { ident, args: None, .. }] => {
1194                                trailing_dot = None;
1195                                fields.insert(start_idx, *ident)
1196                            }
1197                            _ => {
1198                                self.dcx().emit_err(errors::InvalidOffsetOf(current.span));
1199                                break;
1200                            }
1201                        }
1202                        break;
1203                    }
1204                    _ => {
1205                        self.dcx().emit_err(errors::InvalidOffsetOf(current.span));
1206                        break;
1207                    }
1208                }
1209            }
1210
1211            if self.token.kind.close_delim().is_some() || self.token.kind == token::Comma {
1212                break;
1213            } else if trailing_dot.is_none() {
1214                // This loop should only repeat if there is a trailing dot.
1215                self.dcx().emit_err(errors::InvalidOffsetOf(self.token.span));
1216                break;
1217            }
1218        }
1219        if let Some(dot) = trailing_dot {
1220            self.dcx().emit_err(errors::InvalidOffsetOf(dot));
1221        }
1222        Ok(fields.into_iter().collect())
1223    }
1224
1225    fn mk_expr_tuple_field_access(
1226        &self,
1227        lo: Span,
1228        ident_span: Span,
1229        base: P<Expr>,
1230        field: Symbol,
1231        suffix: Option<Symbol>,
1232    ) -> P<Expr> {
1233        if let Some(suffix) = suffix {
1234            self.expect_no_tuple_index_suffix(ident_span, suffix);
1235        }
1236        self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span)))
1237    }
1238
1239    /// Parse a function call expression, `expr(...)`.
1240    fn parse_expr_fn_call(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> {
1241        let snapshot = if self.token == token::OpenParen {
1242            Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))
1243        } else {
1244            None
1245        };
1246        let open_paren = self.token.span;
1247
1248        let seq = self
1249            .parse_expr_paren_seq()
1250            .map(|args| self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args)));
1251        match self.maybe_recover_struct_lit_bad_delims(lo, open_paren, seq, snapshot) {
1252            Ok(expr) => expr,
1253            Err(err) => self.recover_seq_parse_error(exp!(OpenParen), exp!(CloseParen), lo, err),
1254        }
1255    }
1256
1257    /// If we encounter a parser state that looks like the user has written a `struct` literal with
1258    /// parentheses instead of braces, recover the parser state and provide suggestions.
1259    #[instrument(skip(self, seq, snapshot), level = "trace")]
1260    fn maybe_recover_struct_lit_bad_delims(
1261        &mut self,
1262        lo: Span,
1263        open_paren: Span,
1264        seq: PResult<'a, P<Expr>>,
1265        snapshot: Option<(SnapshotParser<'a>, ExprKind)>,
1266    ) -> PResult<'a, P<Expr>> {
1267        match (self.may_recover(), seq, snapshot) {
1268            (true, Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
1269                snapshot.bump(); // `(`
1270                match snapshot.parse_struct_fields(path.clone(), false, exp!(CloseParen)) {
1271                    Ok((fields, ..)) if snapshot.eat(exp!(CloseParen)) => {
1272                        // We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
1273                        // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.
1274                        self.restore_snapshot(snapshot);
1275                        let close_paren = self.prev_token.span;
1276                        let span = lo.to(close_paren);
1277                        // filter shorthand fields
1278                        let fields: Vec<_> =
1279                            fields.into_iter().filter(|field| !field.is_shorthand).collect();
1280
1281                        let guar = if !fields.is_empty() &&
1282                            // `token.kind` should not be compared here.
1283                            // This is because the `snapshot.token.kind` is treated as the same as
1284                            // that of the open delim in `TokenTreesReader::parse_token_tree`, even
1285                            // if they are different.
1286                            self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")")
1287                        {
1288                            err.cancel();
1289                            self.dcx()
1290                                .create_err(errors::ParenthesesWithStructFields {
1291                                    span,
1292                                    r#type: path,
1293                                    braces_for_struct: errors::BracesForStructLiteral {
1294                                        first: open_paren,
1295                                        second: close_paren,
1296                                    },
1297                                    no_fields_for_fn: errors::NoFieldsForFnCall {
1298                                        fields: fields
1299                                            .into_iter()
1300                                            .map(|field| field.span.until(field.expr.span))
1301                                            .collect(),
1302                                    },
1303                                })
1304                                .emit()
1305                        } else {
1306                            err.emit()
1307                        };
1308                        Ok(self.mk_expr_err(span, guar))
1309                    }
1310                    Ok(_) => Err(err),
1311                    Err(err2) => {
1312                        err2.cancel();
1313                        Err(err)
1314                    }
1315                }
1316            }
1317            (_, seq, _) => seq,
1318        }
1319    }
1320
1321    /// Parse an indexing expression `expr[...]`.
1322    fn parse_expr_index(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
1323        let prev_span = self.prev_token.span;
1324        let open_delim_span = self.token.span;
1325        self.bump(); // `[`
1326        let index = self.parse_expr()?;
1327        self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?;
1328        self.expect(exp!(CloseBracket))?;
1329        Ok(self.mk_expr(
1330            lo.to(self.prev_token.span),
1331            self.mk_index(base, index, open_delim_span.to(self.prev_token.span)),
1332        ))
1333    }
1334
1335    /// Assuming we have just parsed `.`, continue parsing into an expression.
1336    fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
1337        if self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Await)) {
1338            return Ok(self.mk_await_expr(self_arg, lo));
1339        }
1340
1341        if self.eat_keyword(exp!(Use)) {
1342            let use_span = self.prev_token.span;
1343            self.psess.gated_spans.gate(sym::ergonomic_clones, use_span);
1344            return Ok(self.mk_use_expr(self_arg, lo));
1345        }
1346
1347        // Post-fix match
1348        if self.eat_keyword(exp!(Match)) {
1349            let match_span = self.prev_token.span;
1350            self.psess.gated_spans.gate(sym::postfix_match, match_span);
1351            return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);
1352        }
1353
1354        // Parse a postfix `yield`.
1355        if self.eat_keyword(exp!(Yield)) {
1356            let yield_span = self.prev_token.span;
1357            self.psess.gated_spans.gate(sym::yield_expr, yield_span);
1358            return Ok(
1359                self.mk_expr(lo.to(yield_span), ExprKind::Yield(YieldKind::Postfix(self_arg)))
1360            );
1361        }
1362
1363        let fn_span_lo = self.token.span;
1364        let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
1365        self.check_trailing_angle_brackets(&seg, &[exp!(OpenParen)]);
1366        self.check_turbofish_missing_angle_brackets(&mut seg);
1367
1368        if self.check(exp!(OpenParen)) {
1369            // Method call `expr.f()`
1370            let args = self.parse_expr_paren_seq()?;
1371            let fn_span = fn_span_lo.to(self.prev_token.span);
1372            let span = lo.to(self.prev_token.span);
1373            Ok(self.mk_expr(
1374                span,
1375                ExprKind::MethodCall(Box::new(ast::MethodCall {
1376                    seg,
1377                    receiver: self_arg,
1378                    args,
1379                    span: fn_span,
1380                })),
1381            ))
1382        } else {
1383            // Field access `expr.f`
1384            let span = lo.to(self.prev_token.span);
1385            if let Some(args) = seg.args {
1386                // See `StashKey::GenericInFieldExpr` for more info on why we stash this.
1387                self.dcx()
1388                    .create_err(errors::FieldExpressionWithGeneric(args.span()))
1389                    .stash(seg.ident.span, StashKey::GenericInFieldExpr);
1390            }
1391
1392            Ok(self.mk_expr(span, ExprKind::Field(self_arg, seg.ident)))
1393        }
1394    }
1395
1396    /// At the bottom (top?) of the precedence hierarchy,
1397    /// Parses things like parenthesized exprs, macros, `return`, etc.
1398    ///
1399    /// N.B., this does not parse outer attributes, and is private because it only works
1400    /// correctly if called from `parse_expr_dot_or_call`.
1401    fn parse_expr_bottom(&mut self) -> PResult<'a, P<Expr>> {
1402        maybe_recover_from_interpolated_ty_qpath!(self, true);
1403
1404        let span = self.token.span;
1405        if let Some(expr) = self.eat_metavar_seq_with_matcher(
1406            |mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }),
1407            |this| {
1408                // Force collection (as opposed to just `parse_expr`) is required to avoid the
1409                // attribute duplication seen in #138478.
1410                let expr = this.parse_expr_force_collect();
1411                // FIXME(nnethercote) Sometimes with expressions we get a trailing comma, possibly
1412                // related to the FIXME in `collect_tokens_for_expr`. Examples are the multi-line
1413                // `assert_eq!` calls involving arguments annotated with `#[rustfmt::skip]` in
1414                // `compiler/rustc_index/src/bit_set/tests.rs`.
1415                if this.token.kind == token::Comma {
1416                    this.bump();
1417                }
1418                expr
1419            },
1420        ) {
1421            return Ok(expr);
1422        } else if let Some(lit) =
1423            self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
1424        {
1425            return Ok(lit);
1426        } else if let Some(block) =
1427            self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block())
1428        {
1429            return Ok(self.mk_expr(span, ExprKind::Block(block, None)));
1430        } else if let Some(path) =
1431            self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type))
1432        {
1433            return Ok(self.mk_expr(span, ExprKind::Path(None, path)));
1434        }
1435
1436        // Outer attributes are already parsed and will be
1437        // added to the return value after the fact.
1438
1439        let restrictions = self.restrictions;
1440        self.with_res(restrictions - Restrictions::ALLOW_LET, |this| {
1441            // Note: adding new syntax here? Don't forget to adjust `TokenKind::can_begin_expr()`.
1442            let lo = this.token.span;
1443            if let token::Literal(_) = this.token.kind {
1444                // This match arm is a special-case of the `_` match arm below and
1445                // could be removed without changing functionality, but it's faster
1446                // to have it here, especially for programs with large constants.
1447                this.parse_expr_lit()
1448            } else if this.check(exp!(OpenParen)) {
1449                this.parse_expr_tuple_parens(restrictions)
1450            } else if this.check(exp!(OpenBrace)) {
1451                this.parse_expr_block(None, lo, BlockCheckMode::Default)
1452            } else if this.check(exp!(Or)) || this.check(exp!(OrOr)) {
1453                this.parse_expr_closure().map_err(|mut err| {
1454                    // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`
1455                    // then suggest parens around the lhs.
1456                    if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) {
1457                        err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
1458                    }
1459                    err
1460                })
1461            } else if this.check(exp!(OpenBracket)) {
1462                this.parse_expr_array_or_repeat(exp!(CloseBracket))
1463            } else if this.is_builtin() {
1464                this.parse_expr_builtin()
1465            } else if this.check_path() {
1466                this.parse_expr_path_start()
1467            } else if this.check_keyword(exp!(Move))
1468                || this.check_keyword(exp!(Use))
1469                || this.check_keyword(exp!(Static))
1470                || this.check_const_closure()
1471            {
1472                this.parse_expr_closure()
1473            } else if this.eat_keyword(exp!(If)) {
1474                this.parse_expr_if()
1475            } else if this.check_keyword(exp!(For)) {
1476                if this.choose_generics_over_qpath(1) {
1477                    this.parse_expr_closure()
1478                } else {
1479                    assert!(this.eat_keyword(exp!(For)));
1480                    this.parse_expr_for(None, lo)
1481                }
1482            } else if this.eat_keyword(exp!(While)) {
1483                this.parse_expr_while(None, lo)
1484            } else if let Some(label) = this.eat_label() {
1485                this.parse_expr_labeled(label, true)
1486            } else if this.eat_keyword(exp!(Loop)) {
1487                this.parse_expr_loop(None, lo).map_err(|mut err| {
1488                    err.span_label(lo, "while parsing this `loop` expression");
1489                    err
1490                })
1491            } else if this.eat_keyword(exp!(Match)) {
1492                this.parse_expr_match().map_err(|mut err| {
1493                    err.span_label(lo, "while parsing this `match` expression");
1494                    err
1495                })
1496            } else if this.eat_keyword(exp!(Unsafe)) {
1497                this.parse_expr_block(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err(
1498                    |mut err| {
1499                        err.span_label(lo, "while parsing this `unsafe` expression");
1500                        err
1501                    },
1502                )
1503            } else if this.check_inline_const(0) {
1504                this.parse_const_block(lo, false)
1505            } else if this.may_recover() && this.is_do_catch_block() {
1506                this.recover_do_catch()
1507            } else if this.is_try_block() {
1508                this.expect_keyword(exp!(Try))?;
1509                this.parse_try_block(lo)
1510            } else if this.eat_keyword(exp!(Return)) {
1511                this.parse_expr_return()
1512            } else if this.eat_keyword(exp!(Continue)) {
1513                this.parse_expr_continue(lo)
1514            } else if this.eat_keyword(exp!(Break)) {
1515                this.parse_expr_break()
1516            } else if this.eat_keyword(exp!(Yield)) {
1517                this.parse_expr_yield()
1518            } else if this.is_do_yeet() {
1519                this.parse_expr_yeet()
1520            } else if this.eat_keyword(exp!(Become)) {
1521                this.parse_expr_become()
1522            } else if this.check_keyword(exp!(Let)) {
1523                this.parse_expr_let(restrictions)
1524            } else if this.eat_keyword(exp!(Underscore)) {
1525                Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))
1526            } else if this.token_uninterpolated_span().at_least_rust_2018() {
1527                // `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
1528                let at_async = this.check_keyword(exp!(Async));
1529                // check for `gen {}` and `gen move {}`
1530                // or `async gen {}` and `async gen move {}`
1531                // FIXME: (async) gen closures aren't yet parsed.
1532                // FIXME(gen_blocks): Parse `gen async` and suggest swap
1533                if this.token_uninterpolated_span().at_least_rust_2024()
1534                    && this.is_gen_block(kw::Gen, at_async as usize)
1535                {
1536                    this.parse_gen_block()
1537                // Check for `async {` and `async move {`,
1538                } else if this.is_gen_block(kw::Async, 0) {
1539                    this.parse_gen_block()
1540                } else if at_async {
1541                    this.parse_expr_closure()
1542                } else if this.eat_keyword_noexpect(kw::Await) {
1543                    this.recover_incorrect_await_syntax(lo)
1544                } else {
1545                    this.parse_expr_lit()
1546                }
1547            } else {
1548                this.parse_expr_lit()
1549            }
1550        })
1551    }
1552
1553    fn parse_expr_lit(&mut self) -> PResult<'a, P<Expr>> {
1554        let lo = self.token.span;
1555        match self.parse_opt_token_lit() {
1556            Some((token_lit, _)) => {
1557                let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(token_lit));
1558                self.maybe_recover_from_bad_qpath(expr)
1559            }
1560            None => self.try_macro_suggestion(),
1561        }
1562    }
1563
1564    fn parse_expr_tuple_parens(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>> {
1565        let lo = self.token.span;
1566        self.expect(exp!(OpenParen))?;
1567        let (es, trailing_comma) = match self.parse_seq_to_end(
1568            exp!(CloseParen),
1569            SeqSep::trailing_allowed(exp!(Comma)),
1570            |p| p.parse_expr_catch_underscore(restrictions.intersection(Restrictions::ALLOW_LET)),
1571        ) {
1572            Ok(x) => x,
1573            Err(err) => {
1574                return Ok(self.recover_seq_parse_error(
1575                    exp!(OpenParen),
1576                    exp!(CloseParen),
1577                    lo,
1578                    err,
1579                ));
1580            }
1581        };
1582        let kind = if es.len() == 1 && matches!(trailing_comma, Trailing::No) {
1583            // `(e)` is parenthesized `e`.
1584            ExprKind::Paren(es.into_iter().next().unwrap())
1585        } else {
1586            // `(e,)` is a tuple with only one field, `e`.
1587            ExprKind::Tup(es)
1588        };
1589        let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1590        self.maybe_recover_from_bad_qpath(expr)
1591    }
1592
1593    fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair<'_>) -> PResult<'a, P<Expr>> {
1594        let lo = self.token.span;
1595        self.bump(); // `[` or other open delim
1596
1597        let kind = if self.eat(close) {
1598            // Empty vector
1599            ExprKind::Array(ThinVec::new())
1600        } else {
1601            // Non-empty vector
1602            let first_expr = self.parse_expr()?;
1603            if self.eat(exp!(Semi)) {
1604                // Repeating array syntax: `[ 0; 512 ]`
1605                let count = self.parse_expr_anon_const()?;
1606                self.expect(close)?;
1607                ExprKind::Repeat(first_expr, count)
1608            } else if self.eat(exp!(Comma)) {
1609                // Vector with two or more elements.
1610                let sep = SeqSep::trailing_allowed(exp!(Comma));
1611                let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
1612                exprs.insert(0, first_expr);
1613                ExprKind::Array(exprs)
1614            } else {
1615                // Vector with one element
1616                self.expect(close)?;
1617                ExprKind::Array(thin_vec![first_expr])
1618            }
1619        };
1620        let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1621        self.maybe_recover_from_bad_qpath(expr)
1622    }
1623
1624    fn parse_expr_path_start(&mut self) -> PResult<'a, P<Expr>> {
1625        let maybe_eq_tok = self.prev_token;
1626        let (qself, path) = if self.eat_lt() {
1627            let lt_span = self.prev_token.span;
1628            let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {
1629                // Suggests using '<=' if there is an error parsing qpath when the previous token
1630                // is an '=' token. Only emits suggestion if the '<' token and '=' token are
1631                // directly adjacent (i.e. '=<')
1632                if maybe_eq_tok == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
1633                    let eq_lt = maybe_eq_tok.span.to(lt_span);
1634                    err.span_suggestion(eq_lt, "did you mean", "<=", Applicability::Unspecified);
1635                }
1636                err
1637            })?;
1638            (Some(qself), path)
1639        } else {
1640            (None, self.parse_path(PathStyle::Expr)?)
1641        };
1642
1643        // `!`, as an operator, is prefix, so we know this isn't that.
1644        let (span, kind) = if self.eat(exp!(Bang)) {
1645            // MACRO INVOCATION expression
1646            if qself.is_some() {
1647                self.dcx().emit_err(errors::MacroInvocationWithQualifiedPath(path.span));
1648            }
1649            let lo = path.span;
1650            let mac = P(MacCall { path, args: self.parse_delim_args()? });
1651            (lo.to(self.prev_token.span), ExprKind::MacCall(mac))
1652        } else if self.check(exp!(OpenBrace))
1653            && let Some(expr) = self.maybe_parse_struct_expr(&qself, &path)
1654        {
1655            if qself.is_some() {
1656                self.psess.gated_spans.gate(sym::more_qualified_paths, path.span);
1657            }
1658            return expr;
1659        } else {
1660            (path.span, ExprKind::Path(qself, path))
1661        };
1662
1663        let expr = self.mk_expr(span, kind);
1664        self.maybe_recover_from_bad_qpath(expr)
1665    }
1666
1667    /// Parse `'label: $expr`. The label is already parsed.
1668    pub(super) fn parse_expr_labeled(
1669        &mut self,
1670        label_: Label,
1671        mut consume_colon: bool,
1672    ) -> PResult<'a, P<Expr>> {
1673        let lo = label_.ident.span;
1674        let label = Some(label_);
1675        let ate_colon = self.eat(exp!(Colon));
1676        let tok_sp = self.token.span;
1677        let expr = if self.eat_keyword(exp!(While)) {
1678            self.parse_expr_while(label, lo)
1679        } else if self.eat_keyword(exp!(For)) {
1680            self.parse_expr_for(label, lo)
1681        } else if self.eat_keyword(exp!(Loop)) {
1682            self.parse_expr_loop(label, lo)
1683        } else if self.check_noexpect(&token::OpenBrace) || self.token.is_metavar_block() {
1684            self.parse_expr_block(label, lo, BlockCheckMode::Default)
1685        } else if !ate_colon
1686            && self.may_recover()
1687            && (self.token.kind.close_delim().is_some() || self.token.is_punct())
1688            && could_be_unclosed_char_literal(label_.ident)
1689        {
1690            let (lit, _) =
1691                self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| {
1692                    self_.dcx().create_err(errors::UnexpectedTokenAfterLabel {
1693                        span: self_.token.span,
1694                        remove_label: None,
1695                        enclose_in_block: None,
1696                    })
1697                });
1698            consume_colon = false;
1699            Ok(self.mk_expr(lo, ExprKind::Lit(lit)))
1700        } else if !ate_colon
1701            && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
1702        {
1703            // We're probably inside of a `Path<'a>` that needs a turbofish
1704            let guar = self.dcx().emit_err(errors::UnexpectedTokenAfterLabel {
1705                span: self.token.span,
1706                remove_label: None,
1707                enclose_in_block: None,
1708            });
1709            consume_colon = false;
1710            Ok(self.mk_expr_err(lo, guar))
1711        } else {
1712            let mut err = errors::UnexpectedTokenAfterLabel {
1713                span: self.token.span,
1714                remove_label: None,
1715                enclose_in_block: None,
1716            };
1717
1718            // Continue as an expression in an effort to recover on `'label: non_block_expr`.
1719            let expr = self.parse_expr().map(|expr| {
1720                let span = expr.span;
1721
1722                let found_labeled_breaks = {
1723                    struct FindLabeledBreaksVisitor;
1724
1725                    impl<'ast> Visitor<'ast> for FindLabeledBreaksVisitor {
1726                        type Result = ControlFlow<()>;
1727                        fn visit_expr(&mut self, ex: &'ast Expr) -> ControlFlow<()> {
1728                            if let ExprKind::Break(Some(_label), _) = ex.kind {
1729                                ControlFlow::Break(())
1730                            } else {
1731                                walk_expr(self, ex)
1732                            }
1733                        }
1734                    }
1735
1736                    FindLabeledBreaksVisitor.visit_expr(&expr).is_break()
1737                };
1738
1739                // Suggestion involves adding a labeled block.
1740                //
1741                // If there are no breaks that may use this label, suggest removing the label and
1742                // recover to the unmodified expression.
1743                if !found_labeled_breaks {
1744                    err.remove_label = Some(lo.until(span));
1745
1746                    return expr;
1747                }
1748
1749                err.enclose_in_block = Some(errors::UnexpectedTokenAfterLabelSugg {
1750                    left: span.shrink_to_lo(),
1751                    right: span.shrink_to_hi(),
1752                });
1753
1754                // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`.
1755                let stmt = self.mk_stmt(span, StmtKind::Expr(expr));
1756                let blk = self.mk_block(thin_vec![stmt], BlockCheckMode::Default, span);
1757                self.mk_expr(span, ExprKind::Block(blk, label))
1758            });
1759
1760            self.dcx().emit_err(err);
1761            expr
1762        }?;
1763
1764        if !ate_colon && consume_colon {
1765            self.dcx().emit_err(errors::RequireColonAfterLabeledExpression {
1766                span: expr.span,
1767                label: lo,
1768                label_end: lo.between(tok_sp),
1769            });
1770        }
1771
1772        Ok(expr)
1773    }
1774
1775    /// Emit an error when a char is parsed as a lifetime or label because of a missing quote.
1776    pub(super) fn recover_unclosed_char<L>(
1777        &self,
1778        ident: Ident,
1779        mk_lit_char: impl FnOnce(Symbol, Span) -> L,
1780        err: impl FnOnce(&Self) -> Diag<'a>,
1781    ) -> L {
1782        assert!(could_be_unclosed_char_literal(ident));
1783        self.dcx()
1784            .try_steal_modify_and_emit_err(ident.span, StashKey::LifetimeIsChar, |err| {
1785                err.span_suggestion_verbose(
1786                    ident.span.shrink_to_hi(),
1787                    "add `'` to close the char literal",
1788                    "'",
1789                    Applicability::MaybeIncorrect,
1790                );
1791            })
1792            .unwrap_or_else(|| {
1793                err(self)
1794                    .with_span_suggestion_verbose(
1795                        ident.span.shrink_to_hi(),
1796                        "add `'` to close the char literal",
1797                        "'",
1798                        Applicability::MaybeIncorrect,
1799                    )
1800                    .emit()
1801            });
1802        let name = ident.without_first_quote().name;
1803        mk_lit_char(name, ident.span)
1804    }
1805
1806    /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
1807    fn recover_do_catch(&mut self) -> PResult<'a, P<Expr>> {
1808        let lo = self.token.span;
1809
1810        self.bump(); // `do`
1811        self.bump(); // `catch`
1812
1813        let span = lo.to(self.prev_token.span);
1814        self.dcx().emit_err(errors::DoCatchSyntaxRemoved { span });
1815
1816        self.parse_try_block(lo)
1817    }
1818
1819    /// Parse an expression if the token can begin one.
1820    fn parse_expr_opt(&mut self) -> PResult<'a, Option<P<Expr>>> {
1821        Ok(if self.token.can_begin_expr() { Some(self.parse_expr()?) } else { None })
1822    }
1823
1824    /// Parse `"return" expr?`.
1825    fn parse_expr_return(&mut self) -> PResult<'a, P<Expr>> {
1826        let lo = self.prev_token.span;
1827        let kind = ExprKind::Ret(self.parse_expr_opt()?);
1828        let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1829        self.maybe_recover_from_bad_qpath(expr)
1830    }
1831
1832    /// Parse `"do" "yeet" expr?`.
1833    fn parse_expr_yeet(&mut self) -> PResult<'a, P<Expr>> {
1834        let lo = self.token.span;
1835
1836        self.bump(); // `do`
1837        self.bump(); // `yeet`
1838
1839        let kind = ExprKind::Yeet(self.parse_expr_opt()?);
1840
1841        let span = lo.to(self.prev_token.span);
1842        self.psess.gated_spans.gate(sym::yeet_expr, span);
1843        let expr = self.mk_expr(span, kind);
1844        self.maybe_recover_from_bad_qpath(expr)
1845    }
1846
1847    /// Parse `"become" expr`, with `"become"` token already eaten.
1848    fn parse_expr_become(&mut self) -> PResult<'a, P<Expr>> {
1849        let lo = self.prev_token.span;
1850        let kind = ExprKind::Become(self.parse_expr()?);
1851        let span = lo.to(self.prev_token.span);
1852        self.psess.gated_spans.gate(sym::explicit_tail_calls, span);
1853        let expr = self.mk_expr(span, kind);
1854        self.maybe_recover_from_bad_qpath(expr)
1855    }
1856
1857    /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
1858    /// If the label is followed immediately by a `:` token, the label and `:` are
1859    /// parsed as part of the expression (i.e. a labeled loop). The language team has
1860    /// decided in #87026 to require parentheses as a visual aid to avoid confusion if
1861    /// the break expression of an unlabeled break is a labeled loop (as in
1862    /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value
1863    /// expression only gets a warning for compatibility reasons; and a labeled break
1864    /// with a labeled loop does not even get a warning because there is no ambiguity.
1865    fn parse_expr_break(&mut self) -> PResult<'a, P<Expr>> {
1866        let lo = self.prev_token.span;
1867        let mut label = self.eat_label();
1868        let kind = if self.token == token::Colon
1869            && let Some(label) = label.take()
1870        {
1871            // The value expression can be a labeled loop, see issue #86948, e.g.:
1872            // `loop { break 'label: loop { break 'label 42; }; }`
1873            let lexpr = self.parse_expr_labeled(label, true)?;
1874            self.dcx().emit_err(errors::LabeledLoopInBreak {
1875                span: lexpr.span,
1876                sub: errors::WrapInParentheses::Expression {
1877                    left: lexpr.span.shrink_to_lo(),
1878                    right: lexpr.span.shrink_to_hi(),
1879                },
1880            });
1881            Some(lexpr)
1882        } else if self.token != token::OpenBrace
1883            || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
1884        {
1885            let mut expr = self.parse_expr_opt()?;
1886            if let Some(expr) = &mut expr {
1887                if label.is_some()
1888                    && match &expr.kind {
1889                        ExprKind::While(_, _, None)
1890                        | ExprKind::ForLoop { label: None, .. }
1891                        | ExprKind::Loop(_, None, _) => true,
1892                        ExprKind::Block(block, None) => {
1893                            matches!(block.rules, BlockCheckMode::Default)
1894                        }
1895                        _ => false,
1896                    }
1897                {
1898                    self.psess.buffer_lint(
1899                        BREAK_WITH_LABEL_AND_LOOP,
1900                        lo.to(expr.span),
1901                        ast::CRATE_NODE_ID,
1902                        BuiltinLintDiag::BreakWithLabelAndLoop(expr.span),
1903                    );
1904                }
1905
1906                // Recover `break label aaaaa`
1907                if self.may_recover()
1908                    && let ExprKind::Path(None, p) = &expr.kind
1909                    && let [segment] = &*p.segments
1910                    && let &ast::PathSegment { ident, args: None, .. } = segment
1911                    && let Some(next) = self.parse_expr_opt()?
1912                {
1913                    label = Some(self.recover_ident_into_label(ident));
1914                    *expr = next;
1915                }
1916            }
1917
1918            expr
1919        } else {
1920            None
1921        };
1922        let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind));
1923        self.maybe_recover_from_bad_qpath(expr)
1924    }
1925
1926    /// Parse `"continue" label?`.
1927    fn parse_expr_continue(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
1928        let mut label = self.eat_label();
1929
1930        // Recover `continue label` -> `continue 'label`
1931        if self.may_recover()
1932            && label.is_none()
1933            && let Some((ident, _)) = self.token.ident()
1934        {
1935            self.bump();
1936            label = Some(self.recover_ident_into_label(ident));
1937        }
1938
1939        let kind = ExprKind::Continue(label);
1940        Ok(self.mk_expr(lo.to(self.prev_token.span), kind))
1941    }
1942
1943    /// Parse `"yield" expr?`.
1944    fn parse_expr_yield(&mut self) -> PResult<'a, P<Expr>> {
1945        let lo = self.prev_token.span;
1946        let kind = ExprKind::Yield(YieldKind::Prefix(self.parse_expr_opt()?));
1947        let span = lo.to(self.prev_token.span);
1948        self.psess.gated_spans.gate(sym::yield_expr, span);
1949        let expr = self.mk_expr(span, kind);
1950        self.maybe_recover_from_bad_qpath(expr)
1951    }
1952
1953    /// Parse `builtin # ident(args,*)`.
1954    fn parse_expr_builtin(&mut self) -> PResult<'a, P<Expr>> {
1955        self.parse_builtin(|this, lo, ident| {
1956            Ok(match ident.name {
1957                sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
1958                sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
1959                sym::wrap_binder => {
1960                    Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?)
1961                }
1962                sym::unwrap_binder => {
1963                    Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?)
1964                }
1965                _ => None,
1966            })
1967        })
1968    }
1969
1970    pub(crate) fn parse_builtin<T>(
1971        &mut self,
1972        parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option<T>>,
1973    ) -> PResult<'a, T> {
1974        let lo = self.token.span;
1975
1976        self.bump(); // `builtin`
1977        self.bump(); // `#`
1978
1979        let Some((ident, IdentIsRaw::No)) = self.token.ident() else {
1980            let err = self.dcx().create_err(errors::ExpectedBuiltinIdent { span: self.token.span });
1981            return Err(err);
1982        };
1983        self.psess.gated_spans.gate(sym::builtin_syntax, ident.span);
1984        self.bump();
1985
1986        self.expect(exp!(OpenParen))?;
1987        let ret = if let Some(res) = parse(self, lo, ident)? {
1988            Ok(res)
1989        } else {
1990            let err = self.dcx().create_err(errors::UnknownBuiltinConstruct {
1991                span: lo.to(ident.span),
1992                name: ident,
1993            });
1994            return Err(err);
1995        };
1996        self.expect(exp!(CloseParen))?;
1997
1998        ret
1999    }
2000
2001    /// Built-in macro for `offset_of!` expressions.
2002    pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
2003        let container = self.parse_ty()?;
2004        self.expect(exp!(Comma))?;
2005
2006        let fields = self.parse_floating_field_access()?;
2007        let trailing_comma = self.eat_noexpect(&TokenKind::Comma);
2008
2009        if let Err(mut e) = self.expect_one_of(&[], &[exp!(CloseParen)]) {
2010            if trailing_comma {
2011                e.note("unexpected third argument to offset_of");
2012            } else {
2013                e.note("offset_of expects dot-separated field and variant names");
2014            }
2015            e.emit();
2016        }
2017
2018        // Eat tokens until the macro call ends.
2019        if self.may_recover() {
2020            while !self.token.kind.is_close_delim_or_eof() {
2021                self.bump();
2022            }
2023        }
2024
2025        let span = lo.to(self.token.span);
2026        Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields)))
2027    }
2028
2029    /// Built-in macro for type ascription expressions.
2030    pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
2031        let expr = self.parse_expr()?;
2032        self.expect(exp!(Comma))?;
2033        let ty = self.parse_ty()?;
2034        let span = lo.to(self.token.span);
2035        Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
2036    }
2037
2038    pub(crate) fn parse_expr_unsafe_binder_cast(
2039        &mut self,
2040        lo: Span,
2041        kind: UnsafeBinderCastKind,
2042    ) -> PResult<'a, P<Expr>> {
2043        let expr = self.parse_expr()?;
2044        let ty = if self.eat(exp!(Comma)) { Some(self.parse_ty()?) } else { None };
2045        let span = lo.to(self.token.span);
2046        Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty)))
2047    }
2048
2049    /// Returns a string literal if the next token is a string literal.
2050    /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
2051    /// and returns `None` if the next token is not literal at all.
2052    pub fn parse_str_lit(&mut self) -> Result<ast::StrLit, Option<MetaItemLit>> {
2053        match self.parse_opt_meta_item_lit() {
2054            Some(lit) => match lit.kind {
2055                ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit {
2056                    style,
2057                    symbol: lit.symbol,
2058                    suffix: lit.suffix,
2059                    span: lit.span,
2060                    symbol_unescaped,
2061                }),
2062                _ => Err(Some(lit)),
2063            },
2064            None => Err(None),
2065        }
2066    }
2067
2068    pub(crate) fn mk_token_lit_char(name: Symbol, span: Span) -> (token::Lit, Span) {
2069        (token::Lit { symbol: name, suffix: None, kind: token::Char }, span)
2070    }
2071
2072    fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {
2073        ast::MetaItemLit {
2074            symbol: name,
2075            suffix: None,
2076            kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')),
2077            span,
2078        }
2079    }
2080
2081    fn handle_missing_lit<L>(
2082        &mut self,
2083        mk_lit_char: impl FnOnce(Symbol, Span) -> L,
2084    ) -> PResult<'a, L> {
2085        let token = self.token;
2086        let err = |self_: &Self| {
2087            let msg = format!("unexpected token: {}", super::token_descr(&token));
2088            self_.dcx().struct_span_err(token.span, msg)
2089        };
2090        // On an error path, eagerly consider a lifetime to be an unclosed character lit, if that
2091        // makes sense.
2092        if let Some((ident, IdentIsRaw::No)) = self.token.lifetime()
2093            && could_be_unclosed_char_literal(ident)
2094        {
2095            let lt = self.expect_lifetime();
2096            Ok(self.recover_unclosed_char(lt.ident, mk_lit_char, err))
2097        } else {
2098            Err(err(self))
2099        }
2100    }
2101
2102    pub(super) fn parse_token_lit(&mut self) -> PResult<'a, (token::Lit, Span)> {
2103        self.parse_opt_token_lit()
2104            .ok_or(())
2105            .or_else(|()| self.handle_missing_lit(Parser::mk_token_lit_char))
2106    }
2107
2108    pub(super) fn parse_meta_item_lit(&mut self) -> PResult<'a, MetaItemLit> {
2109        self.parse_opt_meta_item_lit()
2110            .ok_or(())
2111            .or_else(|()| self.handle_missing_lit(Parser::mk_meta_item_lit_char))
2112    }
2113
2114    fn recover_after_dot(&mut self) {
2115        if self.token == token::Dot {
2116            // Attempt to recover `.4` as `0.4`. We don't currently have any syntax where
2117            // dot would follow an optional literal, so we do this unconditionally.
2118            let recovered = self.look_ahead(1, |next_token| {
2119                // If it's an integer that looks like a float, then recover as such.
2120                //
2121                // We will never encounter the exponent part of a floating
2122                // point literal here, since there's no use of the exponent
2123                // syntax that also constitutes a valid integer, so we need
2124                // not check for that.
2125                if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) =
2126                    next_token.kind
2127                    && suffix.is_none_or(|s| s == sym::f32 || s == sym::f64)
2128                    && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_')
2129                    && self.token.span.hi() == next_token.span.lo()
2130                {
2131                    let s = String::from("0.") + symbol.as_str();
2132                    let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
2133                    Some(Token::new(kind, self.token.span.to(next_token.span)))
2134                } else {
2135                    None
2136                }
2137            });
2138            if let Some(recovered) = recovered {
2139                self.dcx().emit_err(errors::FloatLiteralRequiresIntegerPart {
2140                    span: recovered.span,
2141                    suggestion: recovered.span.shrink_to_lo(),
2142                });
2143                self.bump();
2144                self.token = recovered;
2145            }
2146        }
2147    }
2148
2149    /// Keep this in sync with `Token::can_begin_literal_maybe_minus` and
2150    /// `Lit::from_token` (excluding unary negation).
2151    fn eat_token_lit(&mut self) -> Option<token::Lit> {
2152        let check_expr = |expr: P<Expr>| {
2153            if let ast::ExprKind::Lit(token_lit) = expr.kind {
2154                Some(token_lit)
2155            } else if let ast::ExprKind::Unary(UnOp::Neg, inner) = &expr.kind
2156                && let ast::Expr { kind: ast::ExprKind::Lit(_), .. } = **inner
2157            {
2158                None
2159            } else {
2160                panic!("unexpected reparsed expr/literal: {:?}", expr.kind);
2161            }
2162        };
2163        match self.token.uninterpolate().kind {
2164            token::Ident(name, IdentIsRaw::No) if name.is_bool_lit() => {
2165                self.bump();
2166                Some(token::Lit::new(token::Bool, name, None))
2167            }
2168            token::Literal(token_lit) => {
2169                self.bump();
2170                Some(token_lit)
2171            }
2172            token::OpenInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Literal)) => {
2173                let lit = self
2174                    .eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
2175                    .expect("metavar seq literal");
2176                check_expr(lit)
2177            }
2178            token::OpenInvisible(InvisibleOrigin::MetaVar(
2179                mv_kind @ MetaVarKind::Expr { can_begin_literal_maybe_minus: true, .. },
2180            )) => {
2181                let expr = self
2182                    .eat_metavar_seq(mv_kind, |this| this.parse_expr())
2183                    .expect("metavar seq expr");
2184                check_expr(expr)
2185            }
2186            _ => None,
2187        }
2188    }
2189
2190    /// Matches `lit = true | false | token_lit`.
2191    /// Returns `None` if the next token is not a literal.
2192    fn parse_opt_token_lit(&mut self) -> Option<(token::Lit, Span)> {
2193        self.recover_after_dot();
2194        let span = self.token.span;
2195        self.eat_token_lit().map(|token_lit| (token_lit, span))
2196    }
2197
2198    /// Matches `lit = true | false | token_lit`.
2199    /// Returns `None` if the next token is not a literal.
2200    fn parse_opt_meta_item_lit(&mut self) -> Option<MetaItemLit> {
2201        self.recover_after_dot();
2202        let span = self.token.span;
2203        let uninterpolated_span = self.token_uninterpolated_span();
2204        self.eat_token_lit().map(|token_lit| {
2205            match MetaItemLit::from_token_lit(token_lit, span) {
2206                Ok(lit) => lit,
2207                Err(err) => {
2208                    let guar = report_lit_error(&self.psess, err, token_lit, uninterpolated_span);
2209                    // Pack possible quotes and prefixes from the original literal into
2210                    // the error literal's symbol so they can be pretty-printed faithfully.
2211                    let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None);
2212                    let symbol = Symbol::intern(&suffixless_lit.to_string());
2213                    let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix);
2214                    MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap()
2215                }
2216            }
2217        })
2218    }
2219
2220    pub(super) fn expect_no_tuple_index_suffix(&self, span: Span, suffix: Symbol) {
2221        if [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suffix) {
2222            // #59553: warn instead of reject out of hand to allow the fix to percolate
2223            // through the ecosystem when people fix their macros
2224            self.dcx().emit_warn(errors::InvalidLiteralSuffixOnTupleIndex {
2225                span,
2226                suffix,
2227                exception: true,
2228            });
2229        } else {
2230            self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex {
2231                span,
2232                suffix,
2233                exception: false,
2234            });
2235        }
2236    }
2237
2238    /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
2239    /// Keep this in sync with `Token::can_begin_literal_maybe_minus`.
2240    pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
2241        if let Some(expr) = self.eat_metavar_seq_with_matcher(
2242            |mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }),
2243            |this| {
2244                // FIXME(nnethercote) The `expr` case should only match if
2245                // `e` is an `ExprKind::Lit` or an `ExprKind::Unary` containing
2246                // an `UnOp::Neg` and an `ExprKind::Lit`, like how
2247                // `can_begin_literal_maybe_minus` works. But this method has
2248                // been over-accepting for a long time, and to make that change
2249                // here requires also changing some `parse_literal_maybe_minus`
2250                // call sites to accept additional expression kinds. E.g.
2251                // `ExprKind::Path` must be accepted when parsing range
2252                // patterns. That requires some care. So for now, we continue
2253                // being less strict here than we should be.
2254                this.parse_expr()
2255            },
2256        ) {
2257            return Ok(expr);
2258        } else if let Some(lit) =
2259            self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
2260        {
2261            return Ok(lit);
2262        }
2263
2264        let lo = self.token.span;
2265        let minus_present = self.eat(exp!(Minus));
2266        let (token_lit, span) = self.parse_token_lit()?;
2267        let expr = self.mk_expr(span, ExprKind::Lit(token_lit));
2268
2269        if minus_present {
2270            Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_unary(UnOp::Neg, expr)))
2271        } else {
2272            Ok(expr)
2273        }
2274    }
2275
2276    fn is_array_like_block(&mut self) -> bool {
2277        self.token.kind == TokenKind::OpenBrace
2278            && self
2279                .look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_)))
2280            && self.look_ahead(2, |t| t == &token::Comma)
2281            && self.look_ahead(3, |t| t.can_begin_expr())
2282    }
2283
2284    /// Emits a suggestion if it looks like the user meant an array but
2285    /// accidentally used braces, causing the code to be interpreted as a block
2286    /// expression.
2287    fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option<P<Expr>> {
2288        let mut snapshot = self.create_snapshot_for_diagnostic();
2289        match snapshot.parse_expr_array_or_repeat(exp!(CloseBrace)) {
2290            Ok(arr) => {
2291                let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfBraces {
2292                    span: arr.span,
2293                    sub: errors::ArrayBracketsInsteadOfBracesSugg {
2294                        left: lo,
2295                        right: snapshot.prev_token.span,
2296                    },
2297                });
2298
2299                self.restore_snapshot(snapshot);
2300                Some(self.mk_expr_err(arr.span, guar))
2301            }
2302            Err(e) => {
2303                e.cancel();
2304                None
2305            }
2306        }
2307    }
2308
2309    fn suggest_missing_semicolon_before_array(
2310        &self,
2311        prev_span: Span,
2312        open_delim_span: Span,
2313    ) -> PResult<'a, ()> {
2314        if !self.may_recover() {
2315            return Ok(());
2316        }
2317
2318        if self.token == token::Comma {
2319            if !self.psess.source_map().is_multiline(prev_span.until(self.token.span)) {
2320                return Ok(());
2321            }
2322            let mut snapshot = self.create_snapshot_for_diagnostic();
2323            snapshot.bump();
2324            match snapshot.parse_seq_to_before_end(
2325                exp!(CloseBracket),
2326                SeqSep::trailing_allowed(exp!(Comma)),
2327                |p| p.parse_expr(),
2328            ) {
2329                Ok(_)
2330                    // When the close delim is `)`, `token.kind` is expected to be `token::CloseParen`,
2331                    // but the actual `token.kind` is `token::CloseBracket`.
2332                    // This is because the `token.kind` of the close delim is treated as the same as
2333                    // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
2334                    // Therefore, `token.kind` should not be compared here.
2335                    if snapshot
2336                        .span_to_snippet(snapshot.token.span)
2337                        .is_ok_and(|snippet| snippet == "]") =>
2338                {
2339                    return Err(self.dcx().create_err(errors::MissingSemicolonBeforeArray {
2340                        open_delim: open_delim_span,
2341                        semicolon: prev_span.shrink_to_hi(),
2342                    }));
2343                }
2344                Ok(_) => (),
2345                Err(err) => err.cancel(),
2346            }
2347        }
2348        Ok(())
2349    }
2350
2351    /// Parses a block or unsafe block.
2352    pub(super) fn parse_expr_block(
2353        &mut self,
2354        opt_label: Option<Label>,
2355        lo: Span,
2356        blk_mode: BlockCheckMode,
2357    ) -> PResult<'a, P<Expr>> {
2358        if self.may_recover() && self.is_array_like_block() {
2359            if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo) {
2360                return Ok(arr);
2361            }
2362        }
2363
2364        if self.token.is_metavar_block() {
2365            self.dcx().emit_err(errors::InvalidBlockMacroSegment {
2366                span: self.token.span,
2367                context: lo.to(self.token.span),
2368                wrap: errors::WrapInExplicitBlock {
2369                    lo: self.token.span.shrink_to_lo(),
2370                    hi: self.token.span.shrink_to_hi(),
2371                },
2372            });
2373        }
2374
2375        let (attrs, blk) = self.parse_block_common(lo, blk_mode, None)?;
2376        Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs))
2377    }
2378
2379    /// Parse a block which takes no attributes and has no label
2380    fn parse_simple_block(&mut self) -> PResult<'a, P<Expr>> {
2381        let blk = self.parse_block()?;
2382        Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None)))
2383    }
2384
2385    /// Parses a closure expression (e.g., `move |args| expr`).
2386    fn parse_expr_closure(&mut self) -> PResult<'a, P<Expr>> {
2387        let lo = self.token.span;
2388
2389        let before = self.prev_token;
2390        let binder = if self.check_keyword(exp!(For)) {
2391            let lo = self.token.span;
2392            let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
2393            let span = lo.to(self.prev_token.span);
2394
2395            self.psess.gated_spans.gate(sym::closure_lifetime_binder, span);
2396
2397            ClosureBinder::For { span, generic_params: lifetime_defs }
2398        } else {
2399            ClosureBinder::NotPresent
2400        };
2401
2402        let constness = self.parse_closure_constness();
2403
2404        let movability =
2405            if self.eat_keyword(exp!(Static)) { Movability::Static } else { Movability::Movable };
2406
2407        let coroutine_kind = if self.token_uninterpolated_span().at_least_rust_2018() {
2408            self.parse_coroutine_kind(Case::Sensitive)
2409        } else {
2410            None
2411        };
2412
2413        if let ClosureBinder::NotPresent = binder
2414            && coroutine_kind.is_some()
2415        {
2416            // coroutine closures and generators can have the same qualifiers, so we might end up
2417            // in here if there is a missing `|` but also no `{`. Adjust the expectations in that case.
2418            self.expected_token_types.insert(TokenType::OpenBrace);
2419        }
2420
2421        let capture_clause = self.parse_capture_clause()?;
2422        let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
2423        let decl_hi = self.prev_token.span;
2424        let mut body = match &fn_decl.output {
2425            // No return type.
2426            FnRetTy::Default(_) => {
2427                let restrictions =
2428                    self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
2429                let prev = self.prev_token;
2430                let token = self.token;
2431                let attrs = self.parse_outer_attributes()?;
2432                match self.parse_expr_res(restrictions, attrs) {
2433                    Ok((expr, _)) => expr,
2434                    Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?,
2435                }
2436            }
2437            // Explicit return type (`->`) needs block `-> T { }`.
2438            FnRetTy::Ty(ty) => self.parse_closure_block_body(ty.span)?,
2439        };
2440
2441        match coroutine_kind {
2442            Some(CoroutineKind::Async { .. }) => {}
2443            Some(CoroutineKind::Gen { span, .. }) | Some(CoroutineKind::AsyncGen { span, .. }) => {
2444                // Feature-gate `gen ||` and `async gen ||` closures.
2445                // FIXME(gen_blocks): This perhaps should be a different gate.
2446                self.psess.gated_spans.gate(sym::gen_blocks, span);
2447            }
2448            None => {}
2449        }
2450
2451        if self.token == TokenKind::Semi
2452            && let Some(last) = self.token_cursor.stack.last()
2453            && let Some(TokenTree::Delimited(_, _, Delimiter::Parenthesis, _)) = last.curr()
2454            && self.may_recover()
2455        {
2456            // It is likely that the closure body is a block but where the
2457            // braces have been removed. We will recover and eat the next
2458            // statements later in the parsing process.
2459            body = self.mk_expr_err(
2460                body.span,
2461                self.dcx().span_delayed_bug(body.span, "recovered a closure body as a block"),
2462            );
2463        }
2464
2465        let body_span = body.span;
2466
2467        let closure = self.mk_expr(
2468            lo.to(body.span),
2469            ExprKind::Closure(Box::new(ast::Closure {
2470                binder,
2471                capture_clause,
2472                constness,
2473                coroutine_kind,
2474                movability,
2475                fn_decl,
2476                body,
2477                fn_decl_span: lo.to(decl_hi),
2478                fn_arg_span,
2479            })),
2480        );
2481
2482        // Disable recovery for closure body
2483        let spans =
2484            ClosureSpans { whole_closure: closure.span, closing_pipe: decl_hi, body: body_span };
2485        self.current_closure = Some(spans);
2486
2487        Ok(closure)
2488    }
2489
2490    /// If an explicit return type is given, require a block to appear (RFC 968).
2491    fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, P<Expr>> {
2492        if self.may_recover()
2493            && self.token.can_begin_expr()
2494            && self.token.kind != TokenKind::OpenBrace
2495            && !self.token.is_metavar_block()
2496        {
2497            let snapshot = self.create_snapshot_for_diagnostic();
2498            let restrictions =
2499                self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
2500            let tok = self.token.clone();
2501            match self.parse_expr_res(restrictions, AttrWrapper::empty()) {
2502                Ok((expr, _)) => {
2503                    let descr = super::token_descr(&tok);
2504                    let mut diag = self
2505                        .dcx()
2506                        .struct_span_err(tok.span, format!("expected `{{`, found {descr}"));
2507                    diag.span_label(
2508                        ret_span,
2509                        "explicit return type requires closure body to be enclosed in braces",
2510                    );
2511                    diag.multipart_suggestion_verbose(
2512                        "wrap the expression in curly braces",
2513                        vec![
2514                            (expr.span.shrink_to_lo(), "{ ".to_string()),
2515                            (expr.span.shrink_to_hi(), " }".to_string()),
2516                        ],
2517                        Applicability::MachineApplicable,
2518                    );
2519                    diag.emit();
2520                    return Ok(expr);
2521                }
2522                Err(diag) => {
2523                    diag.cancel();
2524                    self.restore_snapshot(snapshot);
2525                }
2526            }
2527        }
2528
2529        let body_lo = self.token.span;
2530        self.parse_expr_block(None, body_lo, BlockCheckMode::Default)
2531    }
2532
2533    /// Parses an optional `move` or `use` prefix to a closure-like construct.
2534    fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
2535        if self.eat_keyword(exp!(Move)) {
2536            let move_kw_span = self.prev_token.span;
2537            // Check for `move async` and recover
2538            if self.check_keyword(exp!(Async)) {
2539                let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
2540                Err(self
2541                    .dcx()
2542                    .create_err(errors::AsyncMoveOrderIncorrect { span: move_async_span }))
2543            } else {
2544                Ok(CaptureBy::Value { move_kw: move_kw_span })
2545            }
2546        } else if self.eat_keyword(exp!(Use)) {
2547            let use_kw_span = self.prev_token.span;
2548            self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span);
2549            // Check for `use async` and recover
2550            if self.check_keyword(exp!(Async)) {
2551                let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
2552                Err(self.dcx().create_err(errors::AsyncUseOrderIncorrect { span: use_async_span }))
2553            } else {
2554                Ok(CaptureBy::Use { use_kw: use_kw_span })
2555            }
2556        } else {
2557            Ok(CaptureBy::Ref)
2558        }
2559    }
2560
2561    /// Parses the `|arg, arg|` header of a closure.
2562    fn parse_fn_block_decl(&mut self) -> PResult<'a, (P<FnDecl>, Span)> {
2563        let arg_start = self.token.span.lo();
2564
2565        let inputs = if self.eat(exp!(OrOr)) {
2566            ThinVec::new()
2567        } else {
2568            self.expect(exp!(Or))?;
2569            let args = self
2570                .parse_seq_to_before_tokens(
2571                    &[exp!(Or)],
2572                    &[&token::OrOr],
2573                    SeqSep::trailing_allowed(exp!(Comma)),
2574                    |p| p.parse_fn_block_param(),
2575                )?
2576                .0;
2577            self.expect_or()?;
2578            args
2579        };
2580        let arg_span = self.prev_token.span.with_lo(arg_start);
2581        let output =
2582            self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?;
2583
2584        Ok((P(FnDecl { inputs, output }), arg_span))
2585    }
2586
2587    /// Parses a parameter in a closure header (e.g., `|arg, arg|`).
2588    fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
2589        let lo = self.token.span;
2590        let attrs = self.parse_outer_attributes()?;
2591        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
2592            let pat = this.parse_pat_no_top_alt(Some(Expected::ParameterName), None)?;
2593            let ty = if this.eat(exp!(Colon)) {
2594                this.parse_ty()?
2595            } else {
2596                this.mk_ty(pat.span, TyKind::Infer)
2597            };
2598
2599            Ok((
2600                Param {
2601                    attrs,
2602                    ty,
2603                    pat,
2604                    span: lo.to(this.prev_token.span),
2605                    id: DUMMY_NODE_ID,
2606                    is_placeholder: false,
2607                },
2608                Trailing::from(this.token == token::Comma),
2609                UsePreAttrPos::No,
2610            ))
2611        })
2612    }
2613
2614    /// Parses an `if` expression (`if` token already eaten).
2615    fn parse_expr_if(&mut self) -> PResult<'a, P<Expr>> {
2616        let lo = self.prev_token.span;
2617        // Scoping code checks the top level edition of the `if`; let's match it here.
2618        // The `CondChecker` also checks the edition of the `let` itself, just to make sure.
2619        let let_chains_policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
2620        let cond = self.parse_expr_cond(let_chains_policy)?;
2621        self.parse_if_after_cond(lo, cond)
2622    }
2623
2624    fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<Expr>> {
2625        let cond_span = cond.span;
2626        // Tries to interpret `cond` as either a missing expression if it's a block,
2627        // or as an unfinished expression if it's a binop and the RHS is a block.
2628        // We could probably add more recoveries here too...
2629        let mut recover_block_from_condition = |this: &mut Self| {
2630            let block = match &mut cond.kind {
2631                ExprKind::Binary(Spanned { span: binop_span, .. }, _, right)
2632                    if let ExprKind::Block(_, None) = right.kind =>
2633                {
2634                    let guar = this.dcx().emit_err(errors::IfExpressionMissingThenBlock {
2635                        if_span: lo,
2636                        missing_then_block_sub:
2637                            errors::IfExpressionMissingThenBlockSub::UnfinishedCondition(
2638                                cond_span.shrink_to_lo().to(*binop_span),
2639                            ),
2640                        let_else_sub: None,
2641                    });
2642                    std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi(), guar))
2643                }
2644                ExprKind::Block(_, None) => {
2645                    let guar = this.dcx().emit_err(errors::IfExpressionMissingCondition {
2646                        if_span: lo.with_neighbor(cond.span).shrink_to_hi(),
2647                        block_span: self.psess.source_map().start_point(cond_span),
2648                    });
2649                    std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi(), guar))
2650                }
2651                _ => {
2652                    return None;
2653                }
2654            };
2655            if let ExprKind::Block(block, _) = &block.kind {
2656                Some(block.clone())
2657            } else {
2658                unreachable!()
2659            }
2660        };
2661        // Parse then block
2662        let thn = if self.token.is_keyword(kw::Else) {
2663            if let Some(block) = recover_block_from_condition(self) {
2664                block
2665            } else {
2666                let let_else_sub = matches!(cond.kind, ExprKind::Let(..))
2667                    .then(|| errors::IfExpressionLetSomeSub { if_span: lo.until(cond_span) });
2668
2669                let guar = self.dcx().emit_err(errors::IfExpressionMissingThenBlock {
2670                    if_span: lo,
2671                    missing_then_block_sub: errors::IfExpressionMissingThenBlockSub::AddThenBlock(
2672                        cond_span.shrink_to_hi(),
2673                    ),
2674                    let_else_sub,
2675                });
2676                self.mk_block_err(cond_span.shrink_to_hi(), guar)
2677            }
2678        } else {
2679            let attrs = self.parse_outer_attributes()?; // For recovery.
2680            let maybe_fatarrow = self.token;
2681            let block = if self.check(exp!(OpenBrace)) {
2682                self.parse_block()?
2683            } else if let Some(block) = recover_block_from_condition(self) {
2684                block
2685            } else {
2686                self.error_on_extra_if(&cond)?;
2687                // Parse block, which will always fail, but we can add a nice note to the error
2688                self.parse_block().map_err(|mut err| {
2689                        if self.prev_token == token::Semi
2690                            && self.token == token::AndAnd
2691                            && let maybe_let = self.look_ahead(1, |t| t.clone())
2692                            && maybe_let.is_keyword(kw::Let)
2693                        {
2694                            err.span_suggestion(
2695                                self.prev_token.span,
2696                                "consider removing this semicolon to parse the `let` as part of the same chain",
2697                                "",
2698                                Applicability::MachineApplicable,
2699                            ).span_note(
2700                                self.token.span.to(maybe_let.span),
2701                                "you likely meant to continue parsing the let-chain starting here",
2702                            );
2703                        } else {
2704                            // Look for usages of '=>' where '>=' might be intended
2705                            if maybe_fatarrow == token::FatArrow {
2706                                err.span_suggestion(
2707                                    maybe_fatarrow.span,
2708                                    "you might have meant to write a \"greater than or equal to\" comparison",
2709                                    ">=",
2710                                    Applicability::MaybeIncorrect,
2711                                );
2712                            }
2713                            err.span_note(
2714                                cond_span,
2715                                "the `if` expression is missing a block after this condition",
2716                            );
2717                        }
2718                        err
2719                    })?
2720            };
2721            self.error_on_if_block_attrs(lo, false, block.span, attrs);
2722            block
2723        };
2724        let els = if self.eat_keyword(exp!(Else)) { Some(self.parse_expr_else()?) } else { None };
2725        Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
2726    }
2727
2728    /// Parses the condition of a `if` or `while` expression.
2729    ///
2730    /// The specified `edition` in `let_chains_policy` should be that of the whole `if` construct,
2731    /// i.e. the same span we use to later decide whether the drop behaviour should be that of
2732    /// edition `..=2021` or that of `2024..`.
2733    // Public because it is used in rustfmt forks such as https://github.com/tucant/rustfmt/blob/30c83df9e1db10007bdd16dafce8a86b404329b2/src/parse/macros/html.rs#L57 for custom if expressions.
2734    pub fn parse_expr_cond(&mut self, let_chains_policy: LetChainsPolicy) -> PResult<'a, P<Expr>> {
2735        let attrs = self.parse_outer_attributes()?;
2736        let (mut cond, _) =
2737            self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?;
2738
2739        CondChecker::new(self, let_chains_policy).visit_expr(&mut cond);
2740
2741        Ok(cond)
2742    }
2743
2744    /// Parses a `let $pat = $expr` pseudo-expression.
2745    fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>> {
2746        let recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
2747            let err = errors::ExpectedExpressionFoundLet {
2748                span: self.token.span,
2749                reason: ForbiddenLetReason::OtherForbidden,
2750                missing_let: None,
2751                comparison: None,
2752            };
2753            if self.prev_token == token::Or {
2754                // This was part of a closure, the that part of the parser recover.
2755                return Err(self.dcx().create_err(err));
2756            } else {
2757                Recovered::Yes(self.dcx().emit_err(err))
2758            }
2759        } else {
2760            Recovered::No
2761        };
2762        self.bump(); // Eat `let` token
2763        let lo = self.prev_token.span;
2764        let pat = self.parse_pat_no_top_guard(
2765            None,
2766            RecoverComma::Yes,
2767            RecoverColon::Yes,
2768            CommaRecoveryMode::LikelyTuple,
2769        )?;
2770        if self.token == token::EqEq {
2771            self.dcx().emit_err(errors::ExpectedEqForLetExpr {
2772                span: self.token.span,
2773                sugg_span: self.token.span,
2774            });
2775            self.bump();
2776        } else {
2777            self.expect(exp!(Eq))?;
2778        }
2779        let attrs = self.parse_outer_attributes()?;
2780        let (expr, _) =
2781            self.parse_expr_assoc_with(Bound::Excluded(prec_let_scrutinee_needs_par()), attrs)?;
2782        let span = lo.to(expr.span);
2783        Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span, recovered)))
2784    }
2785
2786    /// Parses an `else { ... }` expression (`else` token already eaten).
2787    fn parse_expr_else(&mut self) -> PResult<'a, P<Expr>> {
2788        let else_span = self.prev_token.span; // `else`
2789        let attrs = self.parse_outer_attributes()?; // For recovery.
2790        let expr = if self.eat_keyword(exp!(If)) {
2791            ensure_sufficient_stack(|| self.parse_expr_if())?
2792        } else if self.check(exp!(OpenBrace)) {
2793            self.parse_simple_block()?
2794        } else {
2795            let snapshot = self.create_snapshot_for_diagnostic();
2796            let first_tok = super::token_descr(&self.token);
2797            let first_tok_span = self.token.span;
2798            match self.parse_expr() {
2799                Ok(cond)
2800                // Try to guess the difference between a "condition-like" vs
2801                // "statement-like" expression.
2802                //
2803                // We are seeing the following code, in which $cond is neither
2804                // ExprKind::Block nor ExprKind::If (the 2 cases wherein this
2805                // would be valid syntax).
2806                //
2807                //     if ... {
2808                //     } else $cond
2809                //
2810                // If $cond is "condition-like" such as ExprKind::Binary, we
2811                // want to suggest inserting `if`.
2812                //
2813                //     if ... {
2814                //     } else if a == b {
2815                //            ^^
2816                //     }
2817                //
2818                // We account for macro calls that were meant as conditions as well.
2819                //
2820                //     if ... {
2821                //     } else if macro! { foo bar } {
2822                //            ^^
2823                //     }
2824                //
2825                // If $cond is "statement-like" such as ExprKind::While then we
2826                // want to suggest wrapping in braces.
2827                //
2828                //     if ... {
2829                //     } else {
2830                //            ^
2831                //         while true {}
2832                //     }
2833                //     ^
2834                    if self.check(exp!(OpenBrace))
2835                        && (classify::expr_requires_semi_to_be_stmt(&cond)
2836                            || matches!(cond.kind, ExprKind::MacCall(..)))
2837                    =>
2838                {
2839                    self.dcx().emit_err(errors::ExpectedElseBlock {
2840                        first_tok_span,
2841                        first_tok,
2842                        else_span,
2843                        condition_start: cond.span.shrink_to_lo(),
2844                    });
2845                    self.parse_if_after_cond(cond.span.shrink_to_lo(), cond)?
2846                }
2847                Err(e) => {
2848                    e.cancel();
2849                    self.restore_snapshot(snapshot);
2850                    self.parse_simple_block()?
2851                },
2852                Ok(_) => {
2853                    self.restore_snapshot(snapshot);
2854                    self.parse_simple_block()?
2855                },
2856            }
2857        };
2858        self.error_on_if_block_attrs(else_span, true, expr.span, attrs);
2859        Ok(expr)
2860    }
2861
2862    fn error_on_if_block_attrs(
2863        &self,
2864        ctx_span: Span,
2865        is_ctx_else: bool,
2866        branch_span: Span,
2867        attrs: AttrWrapper,
2868    ) {
2869        if !attrs.is_empty()
2870            && let [x0 @ xn] | [x0, .., xn] = &*attrs.take_for_recovery(self.psess)
2871        {
2872            let attributes = x0.span.until(branch_span);
2873            let last = xn.span;
2874            let ctx = if is_ctx_else { "else" } else { "if" };
2875            self.dcx().emit_err(errors::OuterAttributeNotAllowedOnIfElse {
2876                last,
2877                branch_span,
2878                ctx_span,
2879                ctx: ctx.to_string(),
2880                attributes,
2881            });
2882        }
2883    }
2884
2885    fn error_on_extra_if(&mut self, cond: &P<Expr>) -> PResult<'a, ()> {
2886        if let ExprKind::Binary(Spanned { span: binop_span, node: binop }, _, right) = &cond.kind
2887            && let BinOpKind::And = binop
2888            && let ExprKind::If(cond, ..) = &right.kind
2889        {
2890            Err(self.dcx().create_err(errors::UnexpectedIfWithIf(
2891                binop_span.shrink_to_hi().to(cond.span.shrink_to_lo()),
2892            )))
2893        } else {
2894            Ok(())
2895        }
2896    }
2897
2898    fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> {
2899        let begin_paren = if self.token == token::OpenParen {
2900            // Record whether we are about to parse `for (`.
2901            // This is used below for recovery in case of `for ( $stuff ) $block`
2902            // in which case we will suggest `for $stuff $block`.
2903            let start_span = self.token.span;
2904            let left = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
2905            Some((start_span, left))
2906        } else {
2907            None
2908        };
2909        // Try to parse the pattern `for ($PAT) in $EXPR`.
2910        let pat = match (
2911            self.parse_pat_allow_top_guard(
2912                None,
2913                RecoverComma::Yes,
2914                RecoverColon::Yes,
2915                CommaRecoveryMode::LikelyTuple,
2916            ),
2917            begin_paren,
2918        ) {
2919            (Ok(pat), _) => pat, // Happy path.
2920            (Err(err), Some((start_span, left))) if self.eat_keyword(exp!(In)) => {
2921                // We know for sure we have seen `for ($SOMETHING in`. In the happy path this would
2922                // happen right before the return of this method.
2923                let attrs = self.parse_outer_attributes()?;
2924                let (expr, _) = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs) {
2925                    Ok(expr) => expr,
2926                    Err(expr_err) => {
2927                        // We don't know what followed the `in`, so cancel and bubble up the
2928                        // original error.
2929                        expr_err.cancel();
2930                        return Err(err);
2931                    }
2932                };
2933                return if self.token == token::CloseParen {
2934                    // We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the
2935                    // parser state and emit a targeted suggestion.
2936                    let span = vec![start_span, self.token.span];
2937                    let right = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
2938                    self.bump(); // )
2939                    err.cancel();
2940                    self.dcx().emit_err(errors::ParenthesesInForHead {
2941                        span,
2942                        // With e.g. `for (x) in y)` this would replace `(x) in y)`
2943                        // with `x) in y)` which is syntactically invalid.
2944                        // However, this is prevented before we get here.
2945                        sugg: errors::ParenthesesInForHeadSugg { left, right },
2946                    });
2947                    Ok((self.mk_pat(start_span.to(right), ast::PatKind::Wild), expr))
2948                } else {
2949                    Err(err) // Some other error, bubble up.
2950                };
2951            }
2952            (Err(err), _) => return Err(err), // Some other error, bubble up.
2953        };
2954        if !self.eat_keyword(exp!(In)) {
2955            self.error_missing_in_for_loop();
2956        }
2957        self.check_for_for_in_in_typo(self.prev_token.span);
2958        let attrs = self.parse_outer_attributes()?;
2959        let (expr, _) = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs)?;
2960        Ok((pat, expr))
2961    }
2962
2963    /// Parses `for await? <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
2964    fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
2965        let is_await =
2966            self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Await));
2967
2968        if is_await {
2969            self.psess.gated_spans.gate(sym::async_for_loop, self.prev_token.span);
2970        }
2971
2972        let kind = if is_await { ForLoopKind::ForAwait } else { ForLoopKind::For };
2973
2974        let (pat, expr) = self.parse_for_head()?;
2975        // Recover from missing expression in `for` loop
2976        if matches!(expr.kind, ExprKind::Block(..))
2977            && self.token.kind != token::OpenBrace
2978            && self.may_recover()
2979        {
2980            let guar = self
2981                .dcx()
2982                .emit_err(errors::MissingExpressionInForLoop { span: expr.span.shrink_to_lo() });
2983            let err_expr = self.mk_expr(expr.span, ExprKind::Err(guar));
2984            let block = self.mk_block(thin_vec![], BlockCheckMode::Default, self.prev_token.span);
2985            return Ok(self.mk_expr(
2986                lo.to(self.prev_token.span),
2987                ExprKind::ForLoop { pat, iter: err_expr, body: block, label: opt_label, kind },
2988            ));
2989        }
2990
2991        let (attrs, loop_block) = self.parse_inner_attrs_and_block(
2992            // Only suggest moving erroneous block label to the loop header
2993            // if there is not already a label there
2994            opt_label.is_none().then_some(lo),
2995        )?;
2996
2997        let kind = ExprKind::ForLoop { pat, iter: expr, body: loop_block, label: opt_label, kind };
2998
2999        self.recover_loop_else("for", lo)?;
3000
3001        Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
3002    }
3003
3004    /// Recovers from an `else` clause after a loop (`for...else`, `while...else`)
3005    fn recover_loop_else(&mut self, loop_kind: &'static str, loop_kw: Span) -> PResult<'a, ()> {
3006        if self.token.is_keyword(kw::Else) && self.may_recover() {
3007            let else_span = self.token.span;
3008            self.bump();
3009            let else_clause = self.parse_expr_else()?;
3010            self.dcx().emit_err(errors::LoopElseNotSupported {
3011                span: else_span.to(else_clause.span),
3012                loop_kind,
3013                loop_kw,
3014            });
3015        }
3016        Ok(())
3017    }
3018
3019    fn error_missing_in_for_loop(&mut self) {
3020        let (span, sub): (_, fn(_) -> _) = if self.token.is_ident_named(sym::of) {
3021            // Possibly using JS syntax (#75311).
3022            let span = self.token.span;
3023            self.bump();
3024            (span, errors::MissingInInForLoopSub::InNotOf)
3025        } else {
3026            (self.prev_token.span.between(self.token.span), errors::MissingInInForLoopSub::AddIn)
3027        };
3028
3029        self.dcx().emit_err(errors::MissingInInForLoop { span, sub: sub(span) });
3030    }
3031
3032    /// Parses a `while` or `while let` expression (`while` token already eaten).
3033    fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
3034        let policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
3035        let cond = self.parse_expr_cond(policy).map_err(|mut err| {
3036            err.span_label(lo, "while parsing the condition of this `while` expression");
3037            err
3038        })?;
3039        let (attrs, body) = self
3040            .parse_inner_attrs_and_block(
3041                // Only suggest moving erroneous block label to the loop header
3042                // if there is not already a label there
3043                opt_label.is_none().then_some(lo),
3044            )
3045            .map_err(|mut err| {
3046                err.span_label(lo, "while parsing the body of this `while` expression");
3047                err.span_label(cond.span, "this `while` condition successfully parsed");
3048                err
3049            })?;
3050
3051        self.recover_loop_else("while", lo)?;
3052
3053        Ok(self.mk_expr_with_attrs(
3054            lo.to(self.prev_token.span),
3055            ExprKind::While(cond, body, opt_label),
3056            attrs,
3057        ))
3058    }
3059
3060    /// Parses `loop { ... }` (`loop` token already eaten).
3061    fn parse_expr_loop(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
3062        let loop_span = self.prev_token.span;
3063        let (attrs, body) = self.parse_inner_attrs_and_block(
3064            // Only suggest moving erroneous block label to the loop header
3065            // if there is not already a label there
3066            opt_label.is_none().then_some(lo),
3067        )?;
3068        self.recover_loop_else("loop", lo)?;
3069        Ok(self.mk_expr_with_attrs(
3070            lo.to(self.prev_token.span),
3071            ExprKind::Loop(body, opt_label, loop_span),
3072            attrs,
3073        ))
3074    }
3075
3076    pub(crate) fn eat_label(&mut self) -> Option<Label> {
3077        if let Some((ident, is_raw)) = self.token.lifetime() {
3078            // Disallow `'fn`, but with a better error message than `expect_lifetime`.
3079            if matches!(is_raw, IdentIsRaw::No) && ident.without_first_quote().is_reserved() {
3080                self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
3081            }
3082
3083            self.bump();
3084            Some(Label { ident })
3085        } else {
3086            None
3087        }
3088    }
3089
3090    /// Parses a `match ... { ... }` expression (`match` token already eaten).
3091    fn parse_expr_match(&mut self) -> PResult<'a, P<Expr>> {
3092        let match_span = self.prev_token.span;
3093        let attrs = self.parse_outer_attributes()?;
3094        let (scrutinee, _) = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs)?;
3095
3096        self.parse_match_block(match_span, match_span, scrutinee, MatchKind::Prefix)
3097    }
3098
3099    /// Parses the block of a `match expr { ... }` or a `expr.match { ... }`
3100    /// expression. This is after the match token and scrutinee are eaten
3101    fn parse_match_block(
3102        &mut self,
3103        lo: Span,
3104        match_span: Span,
3105        scrutinee: P<Expr>,
3106        match_kind: MatchKind,
3107    ) -> PResult<'a, P<Expr>> {
3108        if let Err(mut e) = self.expect(exp!(OpenBrace)) {
3109            if self.token == token::Semi {
3110                e.span_suggestion_short(
3111                    match_span,
3112                    "try removing this `match`",
3113                    "",
3114                    Applicability::MaybeIncorrect, // speculative
3115                );
3116            }
3117            if self.maybe_recover_unexpected_block_label(None) {
3118                e.cancel();
3119                self.bump();
3120            } else {
3121                return Err(e);
3122            }
3123        }
3124        let attrs = self.parse_inner_attributes()?;
3125
3126        let mut arms = ThinVec::new();
3127        while self.token != token::CloseBrace {
3128            match self.parse_arm() {
3129                Ok(arm) => arms.push(arm),
3130                Err(e) => {
3131                    // Recover by skipping to the end of the block.
3132                    let guar = e.emit();
3133                    self.recover_stmt();
3134                    let span = lo.to(self.token.span);
3135                    if self.token == token::CloseBrace {
3136                        self.bump();
3137                    }
3138                    // Always push at least one arm to make the match non-empty
3139                    arms.push(Arm {
3140                        attrs: Default::default(),
3141                        pat: self.mk_pat(span, ast::PatKind::Err(guar)),
3142                        guard: None,
3143                        body: Some(self.mk_expr_err(span, guar)),
3144                        span,
3145                        id: DUMMY_NODE_ID,
3146                        is_placeholder: false,
3147                    });
3148                    return Ok(self.mk_expr_with_attrs(
3149                        span,
3150                        ExprKind::Match(scrutinee, arms, match_kind),
3151                        attrs,
3152                    ));
3153                }
3154            }
3155        }
3156        let hi = self.token.span;
3157        self.bump();
3158        Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms, match_kind), attrs))
3159    }
3160
3161    /// Attempt to recover from match arm body with statements and no surrounding braces.
3162    fn parse_arm_body_missing_braces(
3163        &mut self,
3164        first_expr: &P<Expr>,
3165        arrow_span: Span,
3166    ) -> Option<(Span, ErrorGuaranteed)> {
3167        if self.token != token::Semi {
3168            return None;
3169        }
3170        let start_snapshot = self.create_snapshot_for_diagnostic();
3171        let semi_sp = self.token.span;
3172        self.bump(); // `;`
3173        let mut stmts =
3174            vec![self.mk_stmt(first_expr.span, ast::StmtKind::Expr(first_expr.clone()))];
3175        let err = |this: &Parser<'_>, stmts: Vec<ast::Stmt>| {
3176            let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
3177
3178            let guar = this.dcx().emit_err(errors::MatchArmBodyWithoutBraces {
3179                statements: span,
3180                arrow: arrow_span,
3181                num_statements: stmts.len(),
3182                sub: if stmts.len() > 1 {
3183                    errors::MatchArmBodyWithoutBracesSugg::AddBraces {
3184                        left: span.shrink_to_lo(),
3185                        right: span.shrink_to_hi(),
3186                    }
3187                } else {
3188                    errors::MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp }
3189                },
3190            });
3191            (span, guar)
3192        };
3193        // We might have either a `,` -> `;` typo, or a block without braces. We need
3194        // a more subtle parsing strategy.
3195        loop {
3196            if self.token == token::CloseBrace {
3197                // We have reached the closing brace of the `match` expression.
3198                return Some(err(self, stmts));
3199            }
3200            if self.token == token::Comma {
3201                self.restore_snapshot(start_snapshot);
3202                return None;
3203            }
3204            let pre_pat_snapshot = self.create_snapshot_for_diagnostic();
3205            match self.parse_pat_no_top_alt(None, None) {
3206                Ok(_pat) => {
3207                    if self.token == token::FatArrow {
3208                        // Reached arm end.
3209                        self.restore_snapshot(pre_pat_snapshot);
3210                        return Some(err(self, stmts));
3211                    }
3212                }
3213                Err(err) => {
3214                    err.cancel();
3215                }
3216            }
3217
3218            self.restore_snapshot(pre_pat_snapshot);
3219            match self.parse_stmt_without_recovery(true, ForceCollect::No, false) {
3220                // Consume statements for as long as possible.
3221                Ok(Some(stmt)) => {
3222                    stmts.push(stmt);
3223                }
3224                Ok(None) => {
3225                    self.restore_snapshot(start_snapshot);
3226                    break;
3227                }
3228                // We couldn't parse either yet another statement missing it's
3229                // enclosing block nor the next arm's pattern or closing brace.
3230                Err(stmt_err) => {
3231                    stmt_err.cancel();
3232                    self.restore_snapshot(start_snapshot);
3233                    break;
3234                }
3235            }
3236        }
3237        None
3238    }
3239
3240    pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
3241        let attrs = self.parse_outer_attributes()?;
3242        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
3243            let lo = this.token.span;
3244            let (pat, guard) = this.parse_match_arm_pat_and_guard()?;
3245
3246            let span_before_body = this.prev_token.span;
3247            let arm_body;
3248            let is_fat_arrow = this.check(exp!(FatArrow));
3249            let is_almost_fat_arrow =
3250                TokenKind::FatArrow.similar_tokens().contains(&this.token.kind);
3251
3252            // this avoids the compiler saying that a `,` or `}` was expected even though
3253            // the pattern isn't a never pattern (and thus an arm body is required)
3254            let armless = (!is_fat_arrow && !is_almost_fat_arrow && pat.could_be_never_pattern())
3255                || matches!(this.token.kind, token::Comma | token::CloseBrace);
3256
3257            let mut result = if armless {
3258                // A pattern without a body, allowed for never patterns.
3259                arm_body = None;
3260                let span = lo.to(this.prev_token.span);
3261                this.expect_one_of(&[exp!(Comma)], &[exp!(CloseBrace)]).map(|x| {
3262                    // Don't gate twice
3263                    if !pat.contains_never_pattern() {
3264                        this.psess.gated_spans.gate(sym::never_patterns, span);
3265                    }
3266                    x
3267                })
3268            } else {
3269                if let Err(mut err) = this.expect(exp!(FatArrow)) {
3270                    // We might have a `=>` -> `=` or `->` typo (issue #89396).
3271                    if is_almost_fat_arrow {
3272                        err.span_suggestion(
3273                            this.token.span,
3274                            "use a fat arrow to start a match arm",
3275                            "=>",
3276                            Applicability::MachineApplicable,
3277                        );
3278                        if matches!(
3279                            (&this.prev_token.kind, &this.token.kind),
3280                            (token::DotDotEq, token::Gt)
3281                        ) {
3282                            // `error_inclusive_range_match_arrow` handles cases like `0..=> {}`,
3283                            // so we suppress the error here
3284                            err.delay_as_bug();
3285                        } else {
3286                            err.emit();
3287                        }
3288                        this.bump();
3289                    } else {
3290                        return Err(err);
3291                    }
3292                }
3293                let arrow_span = this.prev_token.span;
3294                let arm_start_span = this.token.span;
3295
3296                let attrs = this.parse_outer_attributes()?;
3297                let (expr, _) =
3298                    this.parse_expr_res(Restrictions::STMT_EXPR, attrs).map_err(|mut err| {
3299                        err.span_label(arrow_span, "while parsing the `match` arm starting here");
3300                        err
3301                    })?;
3302
3303                let require_comma =
3304                    !classify::expr_is_complete(&expr) && this.token != token::CloseBrace;
3305
3306                if !require_comma {
3307                    arm_body = Some(expr);
3308                    // Eat a comma if it exists, though.
3309                    let _ = this.eat(exp!(Comma));
3310                    Ok(Recovered::No)
3311                } else if let Some((span, guar)) =
3312                    this.parse_arm_body_missing_braces(&expr, arrow_span)
3313                {
3314                    let body = this.mk_expr_err(span, guar);
3315                    arm_body = Some(body);
3316                    Ok(Recovered::Yes(guar))
3317                } else {
3318                    let expr_span = expr.span;
3319                    arm_body = Some(expr);
3320                    this.expect_one_of(&[exp!(Comma)], &[exp!(CloseBrace)]).map_err(|mut err| {
3321                        if this.token == token::FatArrow {
3322                            let sm = this.psess.source_map();
3323                            if let Ok(expr_lines) = sm.span_to_lines(expr_span)
3324                                && let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
3325                                && expr_lines.lines.len() == 2
3326                            {
3327                                if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col {
3328                                    // We check whether there's any trailing code in the parse span,
3329                                    // if there isn't, we very likely have the following:
3330                                    //
3331                                    // X |     &Y => "y"
3332                                    //   |        --    - missing comma
3333                                    //   |        |
3334                                    //   |        arrow_span
3335                                    // X |     &X => "x"
3336                                    //   |      - ^^ self.token.span
3337                                    //   |      |
3338                                    //   |      parsed until here as `"y" & X`
3339                                    err.span_suggestion_short(
3340                                        arm_start_span.shrink_to_hi(),
3341                                        "missing a comma here to end this `match` arm",
3342                                        ",",
3343                                        Applicability::MachineApplicable,
3344                                    );
3345                                } else if arm_start_lines.lines[0].end_col + rustc_span::CharPos(1)
3346                                    == expr_lines.lines[0].end_col
3347                                {
3348                                    // similar to the above, but we may typo a `.` or `/` at the end of the line
3349                                    let comma_span = arm_start_span
3350                                        .shrink_to_hi()
3351                                        .with_hi(arm_start_span.hi() + rustc_span::BytePos(1));
3352                                    if let Ok(res) = sm.span_to_snippet(comma_span)
3353                                        && (res == "." || res == "/")
3354                                    {
3355                                        err.span_suggestion_short(
3356                                            comma_span,
3357                                            "you might have meant to write a `,` to end this `match` arm",
3358                                            ",",
3359                                            Applicability::MachineApplicable,
3360                                        );
3361                                    }
3362                                }
3363                            }
3364                        } else {
3365                            err.span_label(
3366                                arrow_span,
3367                                "while parsing the `match` arm starting here",
3368                            );
3369                        }
3370                        err
3371                    })
3372                }
3373            };
3374
3375            let hi_span = arm_body.as_ref().map_or(span_before_body, |body| body.span);
3376            let arm_span = lo.to(hi_span);
3377
3378            // We want to recover:
3379            // X |     Some(_) => foo()
3380            //   |                     - missing comma
3381            // X |     None => "x"
3382            //   |     ^^^^ self.token.span
3383            // as well as:
3384            // X |     Some(!)
3385            //   |            - missing comma
3386            // X |     None => "x"
3387            //   |     ^^^^ self.token.span
3388            // But we musn't recover
3389            // X |     pat[0] => {}
3390            //   |        ^ self.token.span
3391            let recover_missing_comma = arm_body.is_some() || pat.could_be_never_pattern();
3392            if recover_missing_comma {
3393                result = result.or_else(|err| {
3394                    // FIXME(compiler-errors): We could also recover `; PAT =>` here
3395
3396                    // Try to parse a following `PAT =>`, if successful
3397                    // then we should recover.
3398                    let mut snapshot = this.create_snapshot_for_diagnostic();
3399                    let pattern_follows = snapshot
3400                        .parse_pat_no_top_guard(
3401                            None,
3402                            RecoverComma::Yes,
3403                            RecoverColon::Yes,
3404                            CommaRecoveryMode::EitherTupleOrPipe,
3405                        )
3406                        .map_err(|err| err.cancel())
3407                        .is_ok();
3408                    if pattern_follows && snapshot.check(exp!(FatArrow)) {
3409                        err.cancel();
3410                        let guar = this.dcx().emit_err(errors::MissingCommaAfterMatchArm {
3411                            span: arm_span.shrink_to_hi(),
3412                        });
3413                        return Ok(Recovered::Yes(guar));
3414                    }
3415                    Err(err)
3416                });
3417            }
3418            result?;
3419
3420            Ok((
3421                ast::Arm {
3422                    attrs,
3423                    pat,
3424                    guard,
3425                    body: arm_body,
3426                    span: arm_span,
3427                    id: DUMMY_NODE_ID,
3428                    is_placeholder: false,
3429                },
3430                Trailing::No,
3431                UsePreAttrPos::No,
3432            ))
3433        })
3434    }
3435
3436    fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<P<Expr>>> {
3437        // Used to check the `if_let_guard` feature mostly by scanning
3438        // `&&` tokens.
3439        fn has_let_expr(expr: &Expr) -> bool {
3440            match &expr.kind {
3441                ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, lhs, rhs) => {
3442                    let lhs_rslt = has_let_expr(lhs);
3443                    let rhs_rslt = has_let_expr(rhs);
3444                    lhs_rslt || rhs_rslt
3445                }
3446                ExprKind::Let(..) => true,
3447                _ => false,
3448            }
3449        }
3450        if !self.eat_keyword(exp!(If)) {
3451            // No match arm guard present.
3452            return Ok(None);
3453        }
3454
3455        let if_span = self.prev_token.span;
3456        let mut cond = self.parse_match_guard_condition()?;
3457
3458        CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
3459
3460        if has_let_expr(&cond) {
3461            let span = if_span.to(cond.span);
3462            self.psess.gated_spans.gate(sym::if_let_guard, span);
3463        }
3464        Ok(Some(cond))
3465    }
3466
3467    fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Expr>>)> {
3468        if self.token == token::OpenParen {
3469            let left = self.token.span;
3470            let pat = self.parse_pat_no_top_guard(
3471                None,
3472                RecoverComma::Yes,
3473                RecoverColon::Yes,
3474                CommaRecoveryMode::EitherTupleOrPipe,
3475            )?;
3476            if let ast::PatKind::Paren(subpat) = &pat.kind
3477                && let ast::PatKind::Guard(..) = &subpat.kind
3478            {
3479                // Detect and recover from `($pat if $cond) => $arm`.
3480                // FIXME(guard_patterns): convert this to a normal guard instead
3481                let span = pat.span;
3482                let ast::PatKind::Paren(subpat) = pat.kind else { unreachable!() };
3483                let ast::PatKind::Guard(_, mut cond) = subpat.kind else { unreachable!() };
3484                self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
3485                CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
3486                let right = self.prev_token.span;
3487                self.dcx().emit_err(errors::ParenthesesInMatchPat {
3488                    span: vec![left, right],
3489                    sugg: errors::ParenthesesInMatchPatSugg { left, right },
3490                });
3491                Ok((self.mk_pat(span, ast::PatKind::Wild), Some(cond)))
3492            } else {
3493                Ok((pat, self.parse_match_arm_guard()?))
3494            }
3495        } else {
3496            // Regular parser flow:
3497            let pat = self.parse_pat_no_top_guard(
3498                None,
3499                RecoverComma::Yes,
3500                RecoverColon::Yes,
3501                CommaRecoveryMode::EitherTupleOrPipe,
3502            )?;
3503            Ok((pat, self.parse_match_arm_guard()?))
3504        }
3505    }
3506
3507    fn parse_match_guard_condition(&mut self) -> PResult<'a, P<Expr>> {
3508        let attrs = self.parse_outer_attributes()?;
3509        match self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs) {
3510            Ok((expr, _)) => Ok(expr),
3511            Err(mut err) => {
3512                if self.prev_token == token::OpenBrace {
3513                    let sugg_sp = self.prev_token.span.shrink_to_lo();
3514                    // Consume everything within the braces, let's avoid further parse
3515                    // errors.
3516                    self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
3517                    let msg = "you might have meant to start a match arm after the match guard";
3518                    if self.eat(exp!(CloseBrace)) {
3519                        let applicability = if self.token != token::FatArrow {
3520                            // We have high confidence that we indeed didn't have a struct
3521                            // literal in the match guard, but rather we had some operation
3522                            // that ended in a path, immediately followed by a block that was
3523                            // meant to be the match arm.
3524                            Applicability::MachineApplicable
3525                        } else {
3526                            Applicability::MaybeIncorrect
3527                        };
3528                        err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
3529                    }
3530                }
3531                Err(err)
3532            }
3533        }
3534    }
3535
3536    pub(crate) fn is_builtin(&self) -> bool {
3537        self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
3538    }
3539
3540    /// Parses a `try {...}` expression (`try` token already eaten).
3541    fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
3542        let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3543        if self.eat_keyword(exp!(Catch)) {
3544            Err(self.dcx().create_err(errors::CatchAfterTry { span: self.prev_token.span }))
3545        } else {
3546            let span = span_lo.to(body.span);
3547            self.psess.gated_spans.gate(sym::try_blocks, span);
3548            Ok(self.mk_expr_with_attrs(span, ExprKind::TryBlock(body), attrs))
3549        }
3550    }
3551
3552    fn is_do_catch_block(&self) -> bool {
3553        self.token.is_keyword(kw::Do)
3554            && self.is_keyword_ahead(1, &[kw::Catch])
3555            && self.look_ahead(2, |t| *t == token::OpenBrace || t.is_metavar_block())
3556            && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3557    }
3558
3559    fn is_do_yeet(&self) -> bool {
3560        self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Yeet])
3561    }
3562
3563    fn is_try_block(&self) -> bool {
3564        self.token.is_keyword(kw::Try)
3565            && self.look_ahead(1, |t| *t == token::OpenBrace || t.is_metavar_block())
3566            && self.token_uninterpolated_span().at_least_rust_2018()
3567    }
3568
3569    /// Parses an `async move? {...}` or `gen move? {...}` expression.
3570    fn parse_gen_block(&mut self) -> PResult<'a, P<Expr>> {
3571        let lo = self.token.span;
3572        let kind = if self.eat_keyword(exp!(Async)) {
3573            if self.eat_keyword(exp!(Gen)) { GenBlockKind::AsyncGen } else { GenBlockKind::Async }
3574        } else {
3575            assert!(self.eat_keyword(exp!(Gen)));
3576            GenBlockKind::Gen
3577        };
3578        match kind {
3579            GenBlockKind::Async => {
3580                // `async` blocks are stable
3581            }
3582            GenBlockKind::Gen | GenBlockKind::AsyncGen => {
3583                self.psess.gated_spans.gate(sym::gen_blocks, lo.to(self.prev_token.span));
3584            }
3585        }
3586        let capture_clause = self.parse_capture_clause()?;
3587        let decl_span = lo.to(self.prev_token.span);
3588        let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3589        let kind = ExprKind::Gen(capture_clause, body, kind, decl_span);
3590        Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
3591    }
3592
3593    fn is_gen_block(&self, kw: Symbol, lookahead: usize) -> bool {
3594        self.is_keyword_ahead(lookahead, &[kw])
3595            && ((
3596                // `async move {`
3597                self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
3598                    && self.look_ahead(lookahead + 2, |t| {
3599                        *t == token::OpenBrace || t.is_metavar_block()
3600                    })
3601            ) || (
3602                // `async {`
3603                self.look_ahead(lookahead + 1, |t| *t == token::OpenBrace || t.is_metavar_block())
3604            ))
3605    }
3606
3607    pub(super) fn is_async_gen_block(&self) -> bool {
3608        self.token.is_keyword(kw::Async) && self.is_gen_block(kw::Gen, 1)
3609    }
3610
3611    fn is_certainly_not_a_block(&self) -> bool {
3612        // `{ ident, ` and `{ ident: ` cannot start a block.
3613        self.look_ahead(1, |t| t.is_ident())
3614            && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon)
3615    }
3616
3617    fn maybe_parse_struct_expr(
3618        &mut self,
3619        qself: &Option<P<ast::QSelf>>,
3620        path: &ast::Path,
3621    ) -> Option<PResult<'a, P<Expr>>> {
3622        let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
3623        if struct_allowed || self.is_certainly_not_a_block() {
3624            if let Err(err) = self.expect(exp!(OpenBrace)) {
3625                return Some(Err(err));
3626            }
3627            let expr = self.parse_expr_struct(qself.clone(), path.clone(), true);
3628            if let (Ok(expr), false) = (&expr, struct_allowed) {
3629                // This is a struct literal, but we don't can't accept them here.
3630                self.dcx().emit_err(errors::StructLiteralNotAllowedHere {
3631                    span: expr.span,
3632                    sub: errors::StructLiteralNotAllowedHereSugg {
3633                        left: path.span.shrink_to_lo(),
3634                        right: expr.span.shrink_to_hi(),
3635                    },
3636                });
3637            }
3638            return Some(expr);
3639        }
3640        None
3641    }
3642
3643    pub(super) fn parse_struct_fields(
3644        &mut self,
3645        pth: ast::Path,
3646        recover: bool,
3647        close: ExpTokenPair<'_>,
3648    ) -> PResult<
3649        'a,
3650        (
3651            ThinVec<ExprField>,
3652            ast::StructRest,
3653            Option<ErrorGuaranteed>, /* async blocks are forbidden in Rust 2015 */
3654        ),
3655    > {
3656        let mut fields = ThinVec::new();
3657        let mut base = ast::StructRest::None;
3658        let mut recovered_async = None;
3659        let in_if_guard = self.restrictions.contains(Restrictions::IN_IF_GUARD);
3660
3661        let async_block_err = |e: &mut Diag<'_>, span: Span| {
3662            errors::AsyncBlockIn2015 { span }.add_to_diag(e);
3663            errors::HelpUseLatestEdition::new().add_to_diag(e);
3664        };
3665
3666        while self.token != *close.tok {
3667            if self.eat(exp!(DotDot)) || self.recover_struct_field_dots(close.tok) {
3668                let exp_span = self.prev_token.span;
3669                // We permit `.. }` on the left-hand side of a destructuring assignment.
3670                if self.check(close) {
3671                    base = ast::StructRest::Rest(self.prev_token.span);
3672                    break;
3673                }
3674                match self.parse_expr() {
3675                    Ok(e) => base = ast::StructRest::Base(e),
3676                    Err(e) if recover => {
3677                        e.emit();
3678                        self.recover_stmt();
3679                    }
3680                    Err(e) => return Err(e),
3681                }
3682                self.recover_struct_comma_after_dotdot(exp_span);
3683                break;
3684            }
3685
3686            // Peek the field's ident before parsing its expr in order to emit better diagnostics.
3687            let peek = self
3688                .token
3689                .ident()
3690                .filter(|(ident, is_raw)| {
3691                    (!ident.is_reserved() || matches!(is_raw, IdentIsRaw::Yes))
3692                        && self.look_ahead(1, |tok| *tok == token::Colon)
3693                })
3694                .map(|(ident, _)| ident);
3695
3696            // We still want a field even if its expr didn't parse.
3697            let field_ident = |this: &Self, guar: ErrorGuaranteed| {
3698                peek.map(|ident| {
3699                    let span = ident.span;
3700                    ExprField {
3701                        ident,
3702                        span,
3703                        expr: this.mk_expr_err(span, guar),
3704                        is_shorthand: false,
3705                        attrs: AttrVec::new(),
3706                        id: DUMMY_NODE_ID,
3707                        is_placeholder: false,
3708                    }
3709                })
3710            };
3711
3712            let parsed_field = match self.parse_expr_field() {
3713                Ok(f) => Ok(f),
3714                Err(mut e) => {
3715                    if pth == kw::Async {
3716                        async_block_err(&mut e, pth.span);
3717                    } else {
3718                        e.span_label(pth.span, "while parsing this struct");
3719                    }
3720
3721                    if let Some((ident, _)) = self.token.ident()
3722                        && !self.token.is_reserved_ident()
3723                        && self.look_ahead(1, |t| {
3724                            AssocOp::from_token(t).is_some()
3725                                || matches!(
3726                                    t.kind,
3727                                    token::OpenParen | token::OpenBracket | token::OpenBrace
3728                                )
3729                                || *t == token::Dot
3730                        })
3731                    {
3732                        // Looks like they tried to write a shorthand, complex expression,
3733                        // E.g.: `n + m`, `f(a)`, `a[i]`, `S { x: 3 }`, or `x.y`.
3734                        e.span_suggestion_verbose(
3735                            self.token.span.shrink_to_lo(),
3736                            "try naming a field",
3737                            &format!("{ident}: ",),
3738                            Applicability::MaybeIncorrect,
3739                        );
3740                    }
3741                    if in_if_guard && close.token_type == TokenType::CloseBrace {
3742                        return Err(e);
3743                    }
3744
3745                    if !recover {
3746                        return Err(e);
3747                    }
3748
3749                    let guar = e.emit();
3750                    if pth == kw::Async {
3751                        recovered_async = Some(guar);
3752                    }
3753
3754                    // If the next token is a comma, then try to parse
3755                    // what comes next as additional fields, rather than
3756                    // bailing out until next `}`.
3757                    if self.token != token::Comma {
3758                        self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
3759                        if self.token != token::Comma {
3760                            break;
3761                        }
3762                    }
3763
3764                    Err(guar)
3765                }
3766            };
3767
3768            let is_shorthand = parsed_field.as_ref().is_ok_and(|f| f.is_shorthand);
3769            // A shorthand field can be turned into a full field with `:`.
3770            // We should point this out.
3771            self.check_or_expected(!is_shorthand, TokenType::Colon);
3772
3773            match self.expect_one_of(&[exp!(Comma)], &[close]) {
3774                Ok(_) => {
3775                    if let Ok(f) = parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar))
3776                    {
3777                        // Only include the field if there's no parse error for the field name.
3778                        fields.push(f);
3779                    }
3780                }
3781                Err(mut e) => {
3782                    if pth == kw::Async {
3783                        async_block_err(&mut e, pth.span);
3784                    } else {
3785                        e.span_label(pth.span, "while parsing this struct");
3786                        if peek.is_some() {
3787                            e.span_suggestion(
3788                                self.prev_token.span.shrink_to_hi(),
3789                                "try adding a comma",
3790                                ",",
3791                                Applicability::MachineApplicable,
3792                            );
3793                        }
3794                    }
3795                    if !recover {
3796                        return Err(e);
3797                    }
3798                    let guar = e.emit();
3799                    if pth == kw::Async {
3800                        recovered_async = Some(guar);
3801                    } else if let Some(f) = field_ident(self, guar) {
3802                        fields.push(f);
3803                    }
3804                    self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
3805                    let _ = self.eat(exp!(Comma));
3806                }
3807            }
3808        }
3809        Ok((fields, base, recovered_async))
3810    }
3811
3812    /// Precondition: already parsed the '{'.
3813    pub(super) fn parse_expr_struct(
3814        &mut self,
3815        qself: Option<P<ast::QSelf>>,
3816        pth: ast::Path,
3817        recover: bool,
3818    ) -> PResult<'a, P<Expr>> {
3819        let lo = pth.span;
3820        let (fields, base, recovered_async) =
3821            self.parse_struct_fields(pth.clone(), recover, exp!(CloseBrace))?;
3822        let span = lo.to(self.token.span);
3823        self.expect(exp!(CloseBrace))?;
3824        let expr = if let Some(guar) = recovered_async {
3825            ExprKind::Err(guar)
3826        } else {
3827            ExprKind::Struct(P(ast::StructExpr { qself, path: pth, fields, rest: base }))
3828        };
3829        Ok(self.mk_expr(span, expr))
3830    }
3831
3832    fn recover_struct_comma_after_dotdot(&mut self, span: Span) {
3833        if self.token != token::Comma {
3834            return;
3835        }
3836        self.dcx().emit_err(errors::CommaAfterBaseStruct {
3837            span: span.to(self.prev_token.span),
3838            comma: self.token.span,
3839        });
3840        self.recover_stmt();
3841    }
3842
3843    fn recover_struct_field_dots(&mut self, close: &TokenKind) -> bool {
3844        if !self.look_ahead(1, |t| t == close) && self.eat(exp!(DotDotDot)) {
3845            // recover from typo of `...`, suggest `..`
3846            let span = self.prev_token.span;
3847            self.dcx().emit_err(errors::MissingDotDot { token_span: span, sugg_span: span });
3848            return true;
3849        }
3850        false
3851    }
3852
3853    /// Converts an ident into 'label and emits an "expected a label, found an identifier" error.
3854    fn recover_ident_into_label(&mut self, ident: Ident) -> Label {
3855        // Convert `label` -> `'label`,
3856        // so that nameres doesn't complain about non-existing label
3857        let label = format!("'{}", ident.name);
3858        let ident = Ident::new(Symbol::intern(&label), ident.span);
3859
3860        self.dcx().emit_err(errors::ExpectedLabelFoundIdent {
3861            span: ident.span,
3862            start: ident.span.shrink_to_lo(),
3863        });
3864
3865        Label { ident }
3866    }
3867
3868    /// Parses `ident (COLON expr)?`.
3869    fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
3870        let attrs = self.parse_outer_attributes()?;
3871        self.recover_vcs_conflict_marker();
3872        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
3873            let lo = this.token.span;
3874
3875            // Check if a colon exists one ahead. This means we're parsing a fieldname.
3876            let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq);
3877            // Proactively check whether parsing the field will be incorrect.
3878            let is_wrong = this.token.is_non_reserved_ident()
3879                && !this.look_ahead(1, |t| {
3880                    t == &token::Colon
3881                        || t == &token::Eq
3882                        || t == &token::Comma
3883                        || t == &token::CloseBrace
3884                        || t == &token::CloseParen
3885                });
3886            if is_wrong {
3887                return Err(this.dcx().create_err(errors::ExpectedStructField {
3888                    span: this.look_ahead(1, |t| t.span),
3889                    ident_span: this.token.span,
3890                    token: this.look_ahead(1, |t| *t),
3891                }));
3892            }
3893            let (ident, expr) = if is_shorthand {
3894                // Mimic `x: x` for the `x` field shorthand.
3895                let ident = this.parse_ident_common(false)?;
3896                let path = ast::Path::from_ident(ident);
3897                (ident, this.mk_expr(ident.span, ExprKind::Path(None, path)))
3898            } else {
3899                let ident = this.parse_field_name()?;
3900                this.error_on_eq_field_init(ident);
3901                this.bump(); // `:`
3902                (ident, this.parse_expr()?)
3903            };
3904
3905            Ok((
3906                ast::ExprField {
3907                    ident,
3908                    span: lo.to(expr.span),
3909                    expr,
3910                    is_shorthand,
3911                    attrs,
3912                    id: DUMMY_NODE_ID,
3913                    is_placeholder: false,
3914                },
3915                Trailing::from(this.token == token::Comma),
3916                UsePreAttrPos::No,
3917            ))
3918        })
3919    }
3920
3921    /// Check for `=`. This means the source incorrectly attempts to
3922    /// initialize a field with an eq rather than a colon.
3923    fn error_on_eq_field_init(&self, field_name: Ident) {
3924        if self.token != token::Eq {
3925            return;
3926        }
3927
3928        self.dcx().emit_err(errors::EqFieldInit {
3929            span: self.token.span,
3930            eq: field_name.span.shrink_to_hi().to(self.token.span),
3931        });
3932    }
3933
3934    fn err_dotdotdot_syntax(&self, span: Span) {
3935        self.dcx().emit_err(errors::DotDotDot { span });
3936    }
3937
3938    fn err_larrow_operator(&self, span: Span) {
3939        self.dcx().emit_err(errors::LeftArrowOperator { span });
3940    }
3941
3942    fn mk_assign_op(&self, assign_op: AssignOp, lhs: P<Expr>, rhs: P<Expr>) -> ExprKind {
3943        ExprKind::AssignOp(assign_op, lhs, rhs)
3944    }
3945
3946    fn mk_range(
3947        &mut self,
3948        start: Option<P<Expr>>,
3949        end: Option<P<Expr>>,
3950        limits: RangeLimits,
3951    ) -> ExprKind {
3952        if end.is_none() && limits == RangeLimits::Closed {
3953            let guar = self.inclusive_range_with_incorrect_end();
3954            ExprKind::Err(guar)
3955        } else {
3956            ExprKind::Range(start, end, limits)
3957        }
3958    }
3959
3960    fn mk_unary(&self, unop: UnOp, expr: P<Expr>) -> ExprKind {
3961        ExprKind::Unary(unop, expr)
3962    }
3963
3964    fn mk_binary(&self, binop: BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ExprKind {
3965        ExprKind::Binary(binop, lhs, rhs)
3966    }
3967
3968    fn mk_index(&self, expr: P<Expr>, idx: P<Expr>, brackets_span: Span) -> ExprKind {
3969        ExprKind::Index(expr, idx, brackets_span)
3970    }
3971
3972    fn mk_call(&self, f: P<Expr>, args: ThinVec<P<Expr>>) -> ExprKind {
3973        ExprKind::Call(f, args)
3974    }
3975
3976    fn mk_await_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> {
3977        let span = lo.to(self.prev_token.span);
3978        let await_expr = self.mk_expr(span, ExprKind::Await(self_arg, self.prev_token.span));
3979        self.recover_from_await_method_call();
3980        await_expr
3981    }
3982
3983    fn mk_use_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> {
3984        let span = lo.to(self.prev_token.span);
3985        let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span));
3986        self.recover_from_use();
3987        use_expr
3988    }
3989
3990    pub(crate) fn mk_expr_with_attrs(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P<Expr> {
3991        P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
3992    }
3993
3994    pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind) -> P<Expr> {
3995        self.mk_expr_with_attrs(span, kind, AttrVec::new())
3996    }
3997
3998    pub(super) fn mk_expr_err(&self, span: Span, guar: ErrorGuaranteed) -> P<Expr> {
3999        self.mk_expr(span, ExprKind::Err(guar))
4000    }
4001
4002    /// Create expression span ensuring the span of the parent node
4003    /// is larger than the span of lhs and rhs, including the attributes.
4004    fn mk_expr_sp(&self, lhs: &P<Expr>, lhs_span: Span, rhs_span: Span) -> Span {
4005        lhs.attrs
4006            .iter()
4007            .find(|a| a.style == AttrStyle::Outer)
4008            .map_or(lhs_span, |a| a.span)
4009            .to(rhs_span)
4010    }
4011
4012    fn collect_tokens_for_expr(
4013        &mut self,
4014        attrs: AttrWrapper,
4015        f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, P<Expr>>,
4016    ) -> PResult<'a, P<Expr>> {
4017        self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
4018            let res = f(this, attrs)?;
4019            let trailing = Trailing::from(
4020                this.restrictions.contains(Restrictions::STMT_EXPR)
4021                     && this.token == token::Semi
4022                // FIXME: pass an additional condition through from the place
4023                // where we know we need a comma, rather than assuming that
4024                // `#[attr] expr,` always captures a trailing comma.
4025                || this.token == token::Comma,
4026            );
4027            Ok((res, trailing, UsePreAttrPos::No))
4028        })
4029    }
4030}
4031
4032/// Could this lifetime/label be an unclosed char literal? For example, `'a`
4033/// could be, but `'abc` could not.
4034pub(crate) fn could_be_unclosed_char_literal(ident: Ident) -> bool {
4035    ident.name.as_str().starts_with('\'')
4036        && unescape_char(ident.without_first_quote().name.as_str()).is_ok()
4037}
4038
4039/// Used to forbid `let` expressions in certain syntactic locations.
4040#[derive(Clone, Copy, Subdiagnostic)]
4041pub(crate) enum ForbiddenLetReason {
4042    /// `let` is not valid and the source environment is not important
4043    OtherForbidden,
4044    /// A let chain with the `||` operator
4045    #[note(parse_not_supported_or)]
4046    NotSupportedOr(#[primary_span] Span),
4047    /// A let chain with invalid parentheses
4048    ///
4049    /// For example, `let 1 = 1 && (expr && expr)` is allowed
4050    /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
4051    #[note(parse_not_supported_parentheses)]
4052    NotSupportedParentheses(#[primary_span] Span),
4053}
4054
4055/// Whether let chains are allowed on all editions, or it's edition dependent (allowed only on
4056/// 2024 and later). In case of edition dependence, specify the currently present edition.
4057pub enum LetChainsPolicy {
4058    AlwaysAllowed,
4059    EditionDependent { current_edition: Edition },
4060}
4061
4062/// Visitor to check for invalid use of `ExprKind::Let` that can't
4063/// easily be caught in parsing. For example:
4064///
4065/// ```rust,ignore (example)
4066/// // Only know that the let isn't allowed once the `||` token is reached
4067/// if let Some(x) = y || true {}
4068/// // Only know that the let isn't allowed once the second `=` token is reached.
4069/// if let Some(x) = y && z = 1 {}
4070/// ```
4071struct CondChecker<'a> {
4072    parser: &'a Parser<'a>,
4073    let_chains_policy: LetChainsPolicy,
4074    depth: u32,
4075    forbid_let_reason: Option<ForbiddenLetReason>,
4076    missing_let: Option<errors::MaybeMissingLet>,
4077    comparison: Option<errors::MaybeComparison>,
4078}
4079
4080impl<'a> CondChecker<'a> {
4081    fn new(parser: &'a Parser<'a>, let_chains_policy: LetChainsPolicy) -> Self {
4082        CondChecker {
4083            parser,
4084            forbid_let_reason: None,
4085            missing_let: None,
4086            comparison: None,
4087            let_chains_policy,
4088            depth: 0,
4089        }
4090    }
4091}
4092
4093impl MutVisitor for CondChecker<'_> {
4094    fn visit_expr(&mut self, e: &mut Expr) {
4095        self.depth += 1;
4096        use ForbiddenLetReason::*;
4097
4098        let span = e.span;
4099        match e.kind {
4100            ExprKind::Let(_, _, _, ref mut recovered @ Recovered::No) => {
4101                if let Some(reason) = self.forbid_let_reason {
4102                    let error = match reason {
4103                        NotSupportedOr(or_span) => {
4104                            self.parser.dcx().emit_err(errors::OrInLetChain { span: or_span })
4105                        }
4106                        _ => self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet {
4107                            span,
4108                            reason,
4109                            missing_let: self.missing_let,
4110                            comparison: self.comparison,
4111                        }),
4112                    };
4113                    *recovered = Recovered::Yes(error);
4114                } else if self.depth > 1 {
4115                    // Top level `let` is always allowed; only gate chains
4116                    match self.let_chains_policy {
4117                        LetChainsPolicy::AlwaysAllowed => (),
4118                        LetChainsPolicy::EditionDependent { current_edition } => {
4119                            if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
4120                                self.parser.dcx().emit_err(errors::LetChainPre2024 { span });
4121                            }
4122                        }
4123                    }
4124                }
4125            }
4126            ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
4127                mut_visit::walk_expr(self, e);
4128            }
4129            ExprKind::Binary(Spanned { node: BinOpKind::Or, span: or_span }, _, _)
4130                if let None | Some(NotSupportedOr(_)) = self.forbid_let_reason =>
4131            {
4132                let forbid_let_reason = self.forbid_let_reason;
4133                self.forbid_let_reason = Some(NotSupportedOr(or_span));
4134                mut_visit::walk_expr(self, e);
4135                self.forbid_let_reason = forbid_let_reason;
4136            }
4137            ExprKind::Paren(ref inner)
4138                if let None | Some(NotSupportedParentheses(_)) = self.forbid_let_reason =>
4139            {
4140                let forbid_let_reason = self.forbid_let_reason;
4141                self.forbid_let_reason = Some(NotSupportedParentheses(inner.span));
4142                mut_visit::walk_expr(self, e);
4143                self.forbid_let_reason = forbid_let_reason;
4144            }
4145            ExprKind::Assign(ref lhs, _, span) => {
4146                let forbid_let_reason = self.forbid_let_reason;
4147                self.forbid_let_reason = Some(OtherForbidden);
4148                let missing_let = self.missing_let;
4149                if let ExprKind::Binary(_, _, rhs) = &lhs.kind
4150                    && let ExprKind::Path(_, _)
4151                    | ExprKind::Struct(_)
4152                    | ExprKind::Call(_, _)
4153                    | ExprKind::Array(_) = rhs.kind
4154                {
4155                    self.missing_let =
4156                        Some(errors::MaybeMissingLet { span: rhs.span.shrink_to_lo() });
4157                }
4158                let comparison = self.comparison;
4159                self.comparison = Some(errors::MaybeComparison { span: span.shrink_to_hi() });
4160                mut_visit::walk_expr(self, e);
4161                self.forbid_let_reason = forbid_let_reason;
4162                self.missing_let = missing_let;
4163                self.comparison = comparison;
4164            }
4165            ExprKind::Unary(_, _)
4166            | ExprKind::Await(_, _)
4167            | ExprKind::Use(_, _)
4168            | ExprKind::AssignOp(_, _, _)
4169            | ExprKind::Range(_, _, _)
4170            | ExprKind::Try(_)
4171            | ExprKind::AddrOf(_, _, _)
4172            | ExprKind::Binary(_, _, _)
4173            | ExprKind::Field(_, _)
4174            | ExprKind::Index(_, _, _)
4175            | ExprKind::Call(_, _)
4176            | ExprKind::MethodCall(_)
4177            | ExprKind::Tup(_)
4178            | ExprKind::Paren(_) => {
4179                let forbid_let_reason = self.forbid_let_reason;
4180                self.forbid_let_reason = Some(OtherForbidden);
4181                mut_visit::walk_expr(self, e);
4182                self.forbid_let_reason = forbid_let_reason;
4183            }
4184            ExprKind::Cast(ref mut op, _)
4185            | ExprKind::Type(ref mut op, _)
4186            | ExprKind::UnsafeBinderCast(_, ref mut op, _) => {
4187                let forbid_let_reason = self.forbid_let_reason;
4188                self.forbid_let_reason = Some(OtherForbidden);
4189                self.visit_expr(op);
4190                self.forbid_let_reason = forbid_let_reason;
4191            }
4192            ExprKind::Let(_, _, _, Recovered::Yes(_))
4193            | ExprKind::Array(_)
4194            | ExprKind::ConstBlock(_)
4195            | ExprKind::Lit(_)
4196            | ExprKind::If(_, _, _)
4197            | ExprKind::While(_, _, _)
4198            | ExprKind::ForLoop { .. }
4199            | ExprKind::Loop(_, _, _)
4200            | ExprKind::Match(_, _, _)
4201            | ExprKind::Closure(_)
4202            | ExprKind::Block(_, _)
4203            | ExprKind::Gen(_, _, _, _)
4204            | ExprKind::TryBlock(_)
4205            | ExprKind::Underscore
4206            | ExprKind::Path(_, _)
4207            | ExprKind::Break(_, _)
4208            | ExprKind::Continue(_)
4209            | ExprKind::Ret(_)
4210            | ExprKind::InlineAsm(_)
4211            | ExprKind::OffsetOf(_, _)
4212            | ExprKind::MacCall(_)
4213            | ExprKind::Struct(_)
4214            | ExprKind::Repeat(_, _)
4215            | ExprKind::Yield(_)
4216            | ExprKind::Yeet(_)
4217            | ExprKind::Become(_)
4218            | ExprKind::IncludedBytes(_)
4219            | ExprKind::FormatArgs(_)
4220            | ExprKind::Err(_)
4221            | ExprKind::Dummy => {
4222                // These would forbid any let expressions they contain already.
4223            }
4224        }
4225        self.depth -= 1;
4226    }
4227}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy