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