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