rustc_parse/parser/
expr.rs

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