rustc_parse/parser/
expr.rs

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

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

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


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy