rustc_parse/parser/
diagnostics.rs

1use std::mem::take;
2use std::ops::{Deref, DerefMut};
3
4use ast::token::IdentIsRaw;
5use rustc_ast as ast;
6use rustc_ast::ptr::P;
7use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind};
8use rustc_ast::util::parser::AssocOp;
9use rustc_ast::{
10    AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
11    BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind,
12    Path, PathSegment, QSelf, Recovered, Ty, TyKind,
13};
14use rustc_ast_pretty::pprust;
15use rustc_data_structures::fx::FxHashSet;
16use rustc_errors::{
17    Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, PResult, Subdiagnostic, Suggestions,
18    pluralize,
19};
20use rustc_session::errors::ExprParenthesesNeeded;
21use rustc_span::edit_distance::find_best_match_for_name;
22use rustc_span::source_map::Spanned;
23use rustc_span::symbol::used_keywords;
24use rustc_span::{BytePos, DUMMY_SP, Ident, Span, SpanSnippetError, Symbol, kw, sym};
25use thin_vec::{ThinVec, thin_vec};
26use tracing::{debug, trace};
27
28use super::pat::Expected;
29use super::{
30    BlockMode, CommaRecoveryMode, ExpTokenPair, Parser, PathStyle, Restrictions, SemiColonMode,
31    SeqSep, TokenType,
32};
33use crate::errors::{
34    AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType,
35    AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi,
36    ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
37    ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything,
38    DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
39    GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
40    HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
41    IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody,
42    QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
43    StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma,
44    TernaryOperator, TernaryOperatorSuggestion, UnexpectedConstInGenericParam,
45    UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets,
46    UseEqInstead, WrapType,
47};
48use crate::parser::attr::InnerAttrPolicy;
49use crate::{exp, fluent_generated as fluent};
50
51/// Creates a placeholder argument.
52pub(super) fn dummy_arg(ident: Ident, guar: ErrorGuaranteed) -> Param {
53    let pat = P(Pat {
54        id: ast::DUMMY_NODE_ID,
55        kind: PatKind::Ident(BindingMode::NONE, ident, None),
56        span: ident.span,
57        tokens: None,
58    });
59    let ty = Ty { kind: TyKind::Err(guar), span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None };
60    Param {
61        attrs: AttrVec::default(),
62        id: ast::DUMMY_NODE_ID,
63        pat,
64        span: ident.span,
65        ty: P(ty),
66        is_placeholder: false,
67    }
68}
69
70pub(super) trait RecoverQPath: Sized + 'static {
71    const PATH_STYLE: PathStyle = PathStyle::Expr;
72    fn to_ty(&self) -> Option<P<Ty>>;
73    fn recovered(qself: Option<P<QSelf>>, path: ast::Path) -> Self;
74}
75
76impl RecoverQPath for Ty {
77    const PATH_STYLE: PathStyle = PathStyle::Type;
78    fn to_ty(&self) -> Option<P<Ty>> {
79        Some(P(self.clone()))
80    }
81    fn recovered(qself: Option<P<QSelf>>, path: ast::Path) -> Self {
82        Self {
83            span: path.span,
84            kind: TyKind::Path(qself, path),
85            id: ast::DUMMY_NODE_ID,
86            tokens: None,
87        }
88    }
89}
90
91impl RecoverQPath for Pat {
92    const PATH_STYLE: PathStyle = PathStyle::Pat;
93    fn to_ty(&self) -> Option<P<Ty>> {
94        self.to_ty()
95    }
96    fn recovered(qself: Option<P<QSelf>>, path: ast::Path) -> Self {
97        Self {
98            span: path.span,
99            kind: PatKind::Path(qself, path),
100            id: ast::DUMMY_NODE_ID,
101            tokens: None,
102        }
103    }
104}
105
106impl RecoverQPath for Expr {
107    fn to_ty(&self) -> Option<P<Ty>> {
108        self.to_ty()
109    }
110    fn recovered(qself: Option<P<QSelf>>, path: ast::Path) -> Self {
111        Self {
112            span: path.span,
113            kind: ExprKind::Path(qself, path),
114            attrs: AttrVec::new(),
115            id: ast::DUMMY_NODE_ID,
116            tokens: None,
117        }
118    }
119}
120
121/// Control whether the closing delimiter should be consumed when calling `Parser::consume_block`.
122pub(crate) enum ConsumeClosingDelim {
123    Yes,
124    No,
125}
126
127#[derive(Clone, Copy)]
128pub enum AttemptLocalParseRecovery {
129    Yes,
130    No,
131}
132
133impl AttemptLocalParseRecovery {
134    pub(super) fn yes(&self) -> bool {
135        match self {
136            AttemptLocalParseRecovery::Yes => true,
137            AttemptLocalParseRecovery::No => false,
138        }
139    }
140
141    pub(super) fn no(&self) -> bool {
142        match self {
143            AttemptLocalParseRecovery::Yes => false,
144            AttemptLocalParseRecovery::No => true,
145        }
146    }
147}
148
149/// Information for emitting suggestions and recovering from
150/// C-style `i++`, `--i`, etc.
151#[derive(Debug, Copy, Clone)]
152struct IncDecRecovery {
153    /// Is this increment/decrement its own statement?
154    standalone: IsStandalone,
155    /// Is this an increment or decrement?
156    op: IncOrDec,
157    /// Is this pre- or postfix?
158    fixity: UnaryFixity,
159}
160
161/// Is an increment or decrement expression its own statement?
162#[derive(Debug, Copy, Clone)]
163enum IsStandalone {
164    /// It's standalone, i.e., its own statement.
165    Standalone,
166    /// It's a subexpression, i.e., *not* standalone.
167    Subexpr,
168}
169
170#[derive(Debug, Copy, Clone, PartialEq, Eq)]
171enum IncOrDec {
172    Inc,
173    Dec,
174}
175
176#[derive(Debug, Copy, Clone, PartialEq, Eq)]
177enum UnaryFixity {
178    Pre,
179    Post,
180}
181
182impl IncOrDec {
183    fn chr(&self) -> char {
184        match self {
185            Self::Inc => '+',
186            Self::Dec => '-',
187        }
188    }
189
190    fn name(&self) -> &'static str {
191        match self {
192            Self::Inc => "increment",
193            Self::Dec => "decrement",
194        }
195    }
196}
197
198impl std::fmt::Display for UnaryFixity {
199    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200        match self {
201            Self::Pre => write!(f, "prefix"),
202            Self::Post => write!(f, "postfix"),
203        }
204    }
205}
206
207#[derive(Debug, rustc_macros::Subdiagnostic)]
208#[suggestion(
209    parse_misspelled_kw,
210    applicability = "machine-applicable",
211    code = "{similar_kw}",
212    style = "verbose"
213)]
214struct MisspelledKw {
215    similar_kw: String,
216    #[primary_span]
217    span: Span,
218    is_incorrect_case: bool,
219}
220
221/// Checks if the given `lookup` identifier is similar to any keyword symbol in `candidates`.
222fn find_similar_kw(lookup: Ident, candidates: &[Symbol]) -> Option<MisspelledKw> {
223    let lowercase = lookup.name.as_str().to_lowercase();
224    let lowercase_sym = Symbol::intern(&lowercase);
225    if candidates.contains(&lowercase_sym) {
226        Some(MisspelledKw { similar_kw: lowercase, span: lookup.span, is_incorrect_case: true })
227    } else if let Some(similar_sym) = find_best_match_for_name(candidates, lookup.name, None) {
228        Some(MisspelledKw {
229            similar_kw: similar_sym.to_string(),
230            span: lookup.span,
231            is_incorrect_case: false,
232        })
233    } else {
234        None
235    }
236}
237
238struct MultiSugg {
239    msg: String,
240    patches: Vec<(Span, String)>,
241    applicability: Applicability,
242}
243
244impl MultiSugg {
245    fn emit(self, err: &mut Diag<'_>) {
246        err.multipart_suggestion(self.msg, self.patches, self.applicability);
247    }
248
249    fn emit_verbose(self, err: &mut Diag<'_>) {
250        err.multipart_suggestion_verbose(self.msg, self.patches, self.applicability);
251    }
252}
253
254/// SnapshotParser is used to create a snapshot of the parser
255/// without causing duplicate errors being emitted when the `Parser`
256/// is dropped.
257pub struct SnapshotParser<'a> {
258    parser: Parser<'a>,
259}
260
261impl<'a> Deref for SnapshotParser<'a> {
262    type Target = Parser<'a>;
263
264    fn deref(&self) -> &Self::Target {
265        &self.parser
266    }
267}
268
269impl<'a> DerefMut for SnapshotParser<'a> {
270    fn deref_mut(&mut self) -> &mut Self::Target {
271        &mut self.parser
272    }
273}
274
275impl<'a> Parser<'a> {
276    pub fn dcx(&self) -> DiagCtxtHandle<'a> {
277        self.psess.dcx()
278    }
279
280    /// Replace `self` with `snapshot.parser`.
281    pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
282        *self = snapshot.parser;
283    }
284
285    /// Create a snapshot of the `Parser`.
286    pub fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> {
287        let snapshot = self.clone();
288        SnapshotParser { parser: snapshot }
289    }
290
291    pub(super) fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> {
292        self.psess.source_map().span_to_snippet(span)
293    }
294
295    /// Emits an error with suggestions if an identifier was expected but not found.
296    ///
297    /// Returns a possibly recovered identifier.
298    pub(super) fn expected_ident_found(
299        &mut self,
300        recover: bool,
301    ) -> PResult<'a, (Ident, IdentIsRaw)> {
302        let valid_follow = &[
303            TokenKind::Eq,
304            TokenKind::Colon,
305            TokenKind::Comma,
306            TokenKind::Semi,
307            TokenKind::PathSep,
308            TokenKind::OpenBrace,
309            TokenKind::OpenParen,
310            TokenKind::CloseBrace,
311            TokenKind::CloseParen,
312        ];
313        if let TokenKind::DocComment(..) = self.prev_token.kind
314            && valid_follow.contains(&self.token.kind)
315        {
316            let err = self.dcx().create_err(DocCommentDoesNotDocumentAnything {
317                span: self.prev_token.span,
318                missing_comma: None,
319            });
320            return Err(err);
321        }
322
323        let mut recovered_ident = None;
324        // we take this here so that the correct original token is retained in
325        // the diagnostic, regardless of eager recovery.
326        let bad_token = self.token;
327
328        // suggest prepending a keyword in identifier position with `r#`
329        let suggest_raw = if let Some((ident, IdentIsRaw::No)) = self.token.ident()
330            && ident.is_raw_guess()
331            && self.look_ahead(1, |t| valid_follow.contains(&t.kind))
332        {
333            recovered_ident = Some((ident, IdentIsRaw::Yes));
334
335            // `Symbol::to_string()` is different from `Symbol::into_diag_arg()`,
336            // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#`
337            let ident_name = ident.name.to_string();
338
339            Some(SuggEscapeIdentifier { span: ident.span.shrink_to_lo(), ident_name })
340        } else {
341            None
342        };
343
344        let suggest_remove_comma =
345            if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
346                if recover {
347                    self.bump();
348                    recovered_ident = self.ident_or_err(false).ok();
349                };
350
351                Some(SuggRemoveComma { span: bad_token.span })
352            } else {
353                None
354            };
355
356        let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, valid_portion)| {
357            let (invalid, valid) = self.token.span.split_at(len as u32);
358
359            recovered_ident = Some((Ident::new(valid_portion, valid), IdentIsRaw::No));
360
361            HelpIdentifierStartsWithNumber { num_span: invalid }
362        });
363
364        let err = ExpectedIdentifier {
365            span: bad_token.span,
366            token: bad_token,
367            suggest_raw,
368            suggest_remove_comma,
369            help_cannot_start_number,
370        };
371        let mut err = self.dcx().create_err(err);
372
373        // if the token we have is a `<`
374        // it *might* be a misplaced generic
375        // FIXME: could we recover with this?
376        if self.token == token::Lt {
377            // all keywords that could have generic applied
378            let valid_prev_keywords =
379                [kw::Fn, kw::Type, kw::Struct, kw::Enum, kw::Union, kw::Trait];
380
381            // If we've expected an identifier,
382            // and the current token is a '<'
383            // if the previous token is a valid keyword
384            // that might use a generic, then suggest a correct
385            // generic placement (later on)
386            let maybe_keyword = self.prev_token;
387            if valid_prev_keywords.into_iter().any(|x| maybe_keyword.is_keyword(x)) {
388                // if we have a valid keyword, attempt to parse generics
389                // also obtain the keywords symbol
390                match self.parse_generics() {
391                    Ok(generic) => {
392                        if let TokenKind::Ident(symbol, _) = maybe_keyword.kind {
393                            let ident_name = symbol;
394                            // at this point, we've found something like
395                            // `fn <T>id`
396                            // and current token should be Ident with the item name (i.e. the function name)
397                            // if there is a `<` after the fn name, then don't show a suggestion, show help
398
399                            if !self.look_ahead(1, |t| *t == token::Lt)
400                                && let Ok(snippet) =
401                                    self.psess.source_map().span_to_snippet(generic.span)
402                            {
403                                err.multipart_suggestion_verbose(
404                                        format!("place the generic parameter name after the {ident_name} name"),
405                                        vec![
406                                            (self.token.span.shrink_to_hi(), snippet),
407                                            (generic.span, String::new())
408                                        ],
409                                        Applicability::MaybeIncorrect,
410                                    );
411                            } else {
412                                err.help(format!(
413                                    "place the generic parameter name after the {ident_name} name"
414                                ));
415                            }
416                        }
417                    }
418                    Err(err) => {
419                        // if there's an error parsing the generics,
420                        // then don't do a misplaced generics suggestion
421                        // and emit the expected ident error instead;
422                        err.cancel();
423                    }
424                }
425            }
426        }
427
428        if let Some(recovered_ident) = recovered_ident
429            && recover
430        {
431            err.emit();
432            Ok(recovered_ident)
433        } else {
434            Err(err)
435        }
436    }
437
438    pub(super) fn expected_ident_found_err(&mut self) -> Diag<'a> {
439        self.expected_ident_found(false).unwrap_err()
440    }
441
442    /// Checks if the current token is a integer or float literal and looks like
443    /// it could be a invalid identifier with digits at the start.
444    ///
445    /// Returns the number of characters (bytes) composing the invalid portion
446    /// of the identifier and the valid portion of the identifier.
447    pub(super) fn is_lit_bad_ident(&mut self) -> Option<(usize, Symbol)> {
448        // ensure that the integer literal is followed by a *invalid*
449        // suffix: this is how we know that it is a identifier with an
450        // invalid beginning.
451        if let token::Literal(Lit {
452            kind: token::LitKind::Integer | token::LitKind::Float,
453            symbol,
454            suffix: Some(suffix), // no suffix makes it a valid literal
455        }) = self.token.kind
456            && rustc_ast::MetaItemLit::from_token(&self.token).is_none()
457        {
458            Some((symbol.as_str().len(), suffix))
459        } else {
460            None
461        }
462    }
463
464    pub(super) fn expected_one_of_not_found(
465        &mut self,
466        edible: &[ExpTokenPair<'_>],
467        inedible: &[ExpTokenPair<'_>],
468    ) -> PResult<'a, ErrorGuaranteed> {
469        debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
470        fn tokens_to_string(tokens: &[TokenType]) -> String {
471            let mut i = tokens.iter();
472            // This might be a sign we need a connect method on `Iterator`.
473            let b = i.next().map_or_else(String::new, |t| t.to_string());
474            i.enumerate().fold(b, |mut b, (i, a)| {
475                if tokens.len() > 2 && i == tokens.len() - 2 {
476                    b.push_str(", or ");
477                } else if tokens.len() == 2 && i == tokens.len() - 2 {
478                    b.push_str(" or ");
479                } else {
480                    b.push_str(", ");
481                }
482                b.push_str(&a.to_string());
483                b
484            })
485        }
486
487        for exp in edible.iter().chain(inedible.iter()) {
488            self.expected_token_types.insert(exp.token_type);
489        }
490        let mut expected: Vec<_> = self.expected_token_types.iter().collect();
491        expected.sort_by_cached_key(|x| x.to_string());
492        expected.dedup();
493
494        let sm = self.psess.source_map();
495
496        // Special-case "expected `;`" errors.
497        if expected.contains(&TokenType::Semi) {
498            // If the user is trying to write a ternary expression, recover it and
499            // return an Err to prevent a cascade of irrelevant diagnostics.
500            if self.prev_token == token::Question
501                && let Err(e) = self.maybe_recover_from_ternary_operator(None)
502            {
503                return Err(e);
504            }
505
506            if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP {
507                // Likely inside a macro, can't provide meaningful suggestions.
508            } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) {
509                // The current token is in the same line as the prior token, not recoverable.
510            } else if [token::Comma, token::Colon].contains(&self.token.kind)
511                && self.prev_token == token::CloseParen
512            {
513                // Likely typo: The current token is on a new line and is expected to be
514                // `.`, `;`, `?`, or an operator after a close delimiter token.
515                //
516                // let a = std::process::Command::new("echo")
517                //         .arg("1")
518                //         ,arg("2")
519                //         ^
520                // https://github.com/rust-lang/rust/issues/72253
521            } else if self.look_ahead(1, |t| {
522                t == &token::CloseBrace || t.can_begin_expr() && *t != token::Colon
523            }) && [token::Comma, token::Colon].contains(&self.token.kind)
524            {
525                // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is
526                // either `,` or `:`, and the next token could either start a new statement or is a
527                // block close. For example:
528                //
529                //   let x = 32:
530                //   let y = 42;
531                let guar = self.dcx().emit_err(ExpectedSemi {
532                    span: self.token.span,
533                    token: self.token,
534                    unexpected_token_label: None,
535                    sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span),
536                });
537                self.bump();
538                return Ok(guar);
539            } else if self.look_ahead(0, |t| {
540                t == &token::CloseBrace
541                    || ((t.can_begin_expr() || t.can_begin_item())
542                        && t != &token::Semi
543                        && t != &token::Pound)
544                    // Avoid triggering with too many trailing `#` in raw string.
545                    || (sm.is_multiline(
546                        self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()),
547                    ) && t == &token::Pound)
548            }) && !expected.contains(&TokenType::Comma)
549            {
550                // Missing semicolon typo. This is triggered if the next token could either start a
551                // new statement or is a block close. For example:
552                //
553                //   let x = 32
554                //   let y = 42;
555                let span = self.prev_token.span.shrink_to_hi();
556                let guar = self.dcx().emit_err(ExpectedSemi {
557                    span,
558                    token: self.token,
559                    unexpected_token_label: Some(self.token.span),
560                    sugg: ExpectedSemiSugg::AddSemi(span),
561                });
562                return Ok(guar);
563            }
564        }
565
566        if self.token == TokenKind::EqEq
567            && self.prev_token.is_ident()
568            && expected.contains(&TokenType::Eq)
569        {
570            // Likely typo: `=` → `==` in let expr or enum item
571            return Err(self.dcx().create_err(UseEqInstead { span: self.token.span }));
572        }
573
574        if (self.token.is_keyword(kw::Move) || self.token.is_keyword(kw::Use))
575            && self.prev_token.is_keyword(kw::Async)
576        {
577            // The 2015 edition is in use because parsing of `async move` or `async use` has failed.
578            let span = self.prev_token.span.to(self.token.span);
579            if self.token.is_keyword(kw::Move) {
580                return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span }));
581            } else {
582                // kw::Use
583                return Err(self.dcx().create_err(AsyncUseBlockIn2015 { span }));
584            }
585        }
586
587        let expect = tokens_to_string(&expected);
588        let actual = super::token_descr(&self.token);
589        let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
590            let fmt = format!("expected one of {expect}, found {actual}");
591            let short_expect = if expected.len() > 6 {
592                format!("{} possible tokens", expected.len())
593            } else {
594                expect
595            };
596            (fmt, (self.prev_token.span.shrink_to_hi(), format!("expected one of {short_expect}")))
597        } else if expected.is_empty() {
598            (
599                format!("unexpected token: {actual}"),
600                (self.prev_token.span, "unexpected token after this".to_string()),
601            )
602        } else {
603            (
604                format!("expected {expect}, found {actual}"),
605                (self.prev_token.span.shrink_to_hi(), format!("expected {expect}")),
606            )
607        };
608        self.last_unexpected_token_span = Some(self.token.span);
609        // FIXME: translation requires list formatting (for `expect`)
610        let mut err = self.dcx().struct_span_err(self.token.span, msg_exp);
611
612        self.label_expected_raw_ref(&mut err);
613
614        // Look for usages of '=>' where '>=' was probably intended
615        if self.token == token::FatArrow
616            && expected.iter().any(|tok| matches!(tok, TokenType::Operator | TokenType::Le))
617            && !expected.iter().any(|tok| matches!(tok, TokenType::FatArrow | TokenType::Comma))
618        {
619            err.span_suggestion(
620                self.token.span,
621                "you might have meant to write a \"greater than or equal to\" comparison",
622                ">=",
623                Applicability::MaybeIncorrect,
624            );
625        }
626
627        if let TokenKind::Ident(symbol, _) = &self.prev_token.kind {
628            if ["def", "fun", "func", "function"].contains(&symbol.as_str()) {
629                err.span_suggestion_short(
630                    self.prev_token.span,
631                    format!("write `fn` instead of `{symbol}` to declare a function"),
632                    "fn",
633                    Applicability::MachineApplicable,
634                );
635            }
636        }
637
638        if let TokenKind::Ident(prev, _) = &self.prev_token.kind
639            && let TokenKind::Ident(cur, _) = &self.token.kind
640        {
641            let concat = Symbol::intern(&format!("{prev}{cur}"));
642            let ident = Ident::new(concat, DUMMY_SP);
643            if ident.is_used_keyword() || ident.is_reserved() || ident.is_raw_guess() {
644                let concat_span = self.prev_token.span.to(self.token.span);
645                err.span_suggestion_verbose(
646                    concat_span,
647                    format!("consider removing the space to spell keyword `{concat}`"),
648                    concat,
649                    Applicability::MachineApplicable,
650                );
651            }
652        }
653
654        // Try to detect an intended c-string literal while using a pre-2021 edition. The heuristic
655        // here is to identify a cooked, uninterpolated `c` id immediately followed by a string, or
656        // a cooked, uninterpolated `cr` id immediately followed by a string or a `#`, in an edition
657        // where c-string literals are not allowed. There is the very slight possibility of a false
658        // positive for a `cr#` that wasn't intended to start a c-string literal, but identifying
659        // that in the parser requires unbounded lookahead, so we only add a hint to the existing
660        // error rather than replacing it entirely.
661        if ((self.prev_token == TokenKind::Ident(sym::c, IdentIsRaw::No)
662            && matches!(&self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. })))
663            || (self.prev_token == TokenKind::Ident(sym::cr, IdentIsRaw::No)
664                && matches!(
665                    &self.token.kind,
666                    TokenKind::Literal(token::Lit { kind: token::Str, .. }) | token::Pound
667                )))
668            && self.prev_token.span.hi() == self.token.span.lo()
669            && !self.token.span.at_least_rust_2021()
670        {
671            err.note("you may be trying to write a c-string literal");
672            err.note("c-string literals require Rust 2021 or later");
673            err.subdiagnostic(HelpUseLatestEdition::new());
674        }
675
676        // `pub` may be used for an item or `pub(crate)`
677        if self.prev_token.is_ident_named(sym::public)
678            && (self.token.can_begin_item() || self.token == TokenKind::OpenParen)
679        {
680            err.span_suggestion_short(
681                self.prev_token.span,
682                "write `pub` instead of `public` to make the item public",
683                "pub",
684                Applicability::MachineApplicable,
685            );
686        }
687
688        if let token::DocComment(kind, style, _) = self.token.kind {
689            // We have something like `expr //!val` where the user likely meant `expr // !val`
690            let pos = self.token.span.lo() + BytePos(2);
691            let span = self.token.span.with_lo(pos).with_hi(pos);
692            err.span_suggestion_verbose(
693                span,
694                format!(
695                    "add a space before {} to write a regular comment",
696                    match (kind, style) {
697                        (token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`",
698                        (token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`",
699                        (token::CommentKind::Line, ast::AttrStyle::Outer) => "the last `/`",
700                        (token::CommentKind::Block, ast::AttrStyle::Outer) => "the last `*`",
701                    },
702                ),
703                " ".to_string(),
704                Applicability::MachineApplicable,
705            );
706        }
707
708        let sp = if self.token == token::Eof {
709            // This is EOF; don't want to point at the following char, but rather the last token.
710            self.prev_token.span
711        } else {
712            label_sp
713        };
714
715        if self.check_too_many_raw_str_terminators(&mut err) {
716            if expected.contains(&TokenType::Semi) && self.eat(exp!(Semi)) {
717                let guar = err.emit();
718                return Ok(guar);
719            } else {
720                return Err(err);
721            }
722        }
723
724        if self.prev_token.span == DUMMY_SP {
725            // Account for macro context where the previous span might not be
726            // available to avoid incorrect output (#54841).
727            err.span_label(self.token.span, label_exp);
728        } else if !sm.is_multiline(self.token.span.shrink_to_hi().until(sp.shrink_to_lo())) {
729            // When the spans are in the same line, it means that the only content between
730            // them is whitespace, point at the found token in that case:
731            //
732            // X |     () => { syntax error };
733            //   |                    ^^^^^ expected one of 8 possible tokens here
734            //
735            // instead of having:
736            //
737            // X |     () => { syntax error };
738            //   |                   -^^^^^ unexpected token
739            //   |                   |
740            //   |                   expected one of 8 possible tokens here
741            err.span_label(self.token.span, label_exp);
742        } else {
743            err.span_label(sp, label_exp);
744            err.span_label(self.token.span, "unexpected token");
745        }
746
747        // Check for misspelled keywords if there are no suggestions added to the diagnostic.
748        if matches!(&err.suggestions, Suggestions::Enabled(list) if list.is_empty()) {
749            self.check_for_misspelled_kw(&mut err, &expected);
750        }
751        Err(err)
752    }
753
754    /// Adds a label when `&raw EXPR` was written instead of `&raw const EXPR`/`&raw mut EXPR`.
755    ///
756    /// Given that not all parser diagnostics flow through `expected_one_of_not_found`, this
757    /// label may need added to other diagnostics emission paths as needed.
758    pub(super) fn label_expected_raw_ref(&mut self, err: &mut Diag<'_>) {
759        if self.prev_token.is_keyword(kw::Raw)
760            && self.expected_token_types.contains(TokenType::KwMut)
761            && self.expected_token_types.contains(TokenType::KwConst)
762            && self.token.can_begin_expr()
763        {
764            err.span_suggestions(
765                self.prev_token.span.shrink_to_hi(),
766                "`&raw` must be followed by `const` or `mut` to be a raw reference expression",
767                [" const".to_string(), " mut".to_string()],
768                Applicability::MaybeIncorrect,
769            );
770        }
771    }
772
773    /// Checks if the current token or the previous token are misspelled keywords
774    /// and adds a helpful suggestion.
775    fn check_for_misspelled_kw(&self, err: &mut Diag<'_>, expected: &[TokenType]) {
776        let Some((curr_ident, _)) = self.token.ident() else {
777            return;
778        };
779        let expected_token_types: &[TokenType] =
780            expected.len().checked_sub(10).map_or(&expected, |index| &expected[index..]);
781        let expected_keywords: Vec<Symbol> =
782            expected_token_types.iter().filter_map(|token| token.is_keyword()).collect();
783
784        // When there are a few keywords in the last ten elements of `self.expected_token_types`
785        // and the current token is an identifier, it's probably a misspelled keyword. This handles
786        // code like `async Move {}`, misspelled `if` in match guard, misspelled `else` in
787        // `if`-`else` and misspelled `where` in a where clause.
788        if !expected_keywords.is_empty()
789            && !curr_ident.is_used_keyword()
790            && let Some(misspelled_kw) = find_similar_kw(curr_ident, &expected_keywords)
791        {
792            err.subdiagnostic(misspelled_kw);
793            // We don't want other suggestions to be added as they are most likely meaningless
794            // when there is a misspelled keyword.
795            err.seal_suggestions();
796        } else if let Some((prev_ident, _)) = self.prev_token.ident()
797            && !prev_ident.is_used_keyword()
798        {
799            // We generate a list of all keywords at runtime rather than at compile time
800            // so that it gets generated only when the diagnostic needs it.
801            // Also, it is unlikely that this list is generated multiple times because the
802            // parser halts after execution hits this path.
803            let all_keywords = used_keywords(|| prev_ident.span.edition());
804
805            // Otherwise, check the previous token with all the keywords as possible candidates.
806            // This handles code like `Struct Human;` and `While a < b {}`.
807            // We check the previous token only when the current token is an identifier to avoid
808            // false positives like suggesting keyword `for` for `extern crate foo {}`.
809            if let Some(misspelled_kw) = find_similar_kw(prev_ident, &all_keywords) {
810                err.subdiagnostic(misspelled_kw);
811                // We don't want other suggestions to be added as they are most likely meaningless
812                // when there is a misspelled keyword.
813                err.seal_suggestions();
814            }
815        }
816    }
817
818    /// The user has written `#[attr] expr` which is unsupported. (#106020)
819    pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) -> ErrorGuaranteed {
820        // Missing semicolon typo error.
821        let span = self.prev_token.span.shrink_to_hi();
822        let mut err = self.dcx().create_err(ExpectedSemi {
823            span,
824            token: self.token,
825            unexpected_token_label: Some(self.token.span),
826            sugg: ExpectedSemiSugg::AddSemi(span),
827        });
828        let attr_span = match &expr.attrs[..] {
829            [] => unreachable!(),
830            [only] => only.span,
831            [first, rest @ ..] => {
832                for attr in rest {
833                    err.span_label(attr.span, "");
834                }
835                first.span
836            }
837        };
838        err.span_label(
839            attr_span,
840            format!(
841                "only `;` terminated statements or tail expressions are allowed after {}",
842                if expr.attrs.len() == 1 { "this attribute" } else { "these attributes" },
843            ),
844        );
845        if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) {
846            // We have
847            // #[attr]
848            // expr
849            // #[not_attr]
850            // other_expr
851            err.span_label(span, "expected `;` here");
852            err.multipart_suggestion(
853                "alternatively, consider surrounding the expression with a block",
854                vec![
855                    (expr.span.shrink_to_lo(), "{ ".to_string()),
856                    (expr.span.shrink_to_hi(), " }".to_string()),
857                ],
858                Applicability::MachineApplicable,
859            );
860
861            // Special handling for `#[cfg(...)]` chains
862            let mut snapshot = self.create_snapshot_for_diagnostic();
863            if let [attr] = &expr.attrs[..]
864                && let ast::AttrKind::Normal(attr_kind) = &attr.kind
865                && let [segment] = &attr_kind.item.path.segments[..]
866                && segment.ident.name == sym::cfg
867                && let Some(args_span) = attr_kind.item.args.span()
868                && let next_attr = match snapshot.parse_attribute(InnerAttrPolicy::Forbidden(None))
869                {
870                    Ok(next_attr) => next_attr,
871                    Err(inner_err) => {
872                        inner_err.cancel();
873                        return err.emit();
874                    }
875                }
876                && let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind
877                && let Some(next_attr_args_span) = next_attr_kind.item.args.span()
878                && let [next_segment] = &next_attr_kind.item.path.segments[..]
879                && segment.ident.name == sym::cfg
880            {
881                let next_expr = match snapshot.parse_expr() {
882                    Ok(next_expr) => next_expr,
883                    Err(inner_err) => {
884                        inner_err.cancel();
885                        return err.emit();
886                    }
887                };
888                // We have for sure
889                // #[cfg(..)]
890                // expr
891                // #[cfg(..)]
892                // other_expr
893                // So we suggest using `if cfg!(..) { expr } else if cfg!(..) { other_expr }`.
894                let margin = self.psess.source_map().span_to_margin(next_expr.span).unwrap_or(0);
895                let sugg = vec![
896                    (attr.span.with_hi(segment.span().hi()), "if cfg!".to_string()),
897                    (args_span.shrink_to_hi().with_hi(attr.span.hi()), " {".to_string()),
898                    (expr.span.shrink_to_lo(), "    ".to_string()),
899                    (
900                        next_attr.span.with_hi(next_segment.span().hi()),
901                        "} else if cfg!".to_string(),
902                    ),
903                    (
904                        next_attr_args_span.shrink_to_hi().with_hi(next_attr.span.hi()),
905                        " {".to_string(),
906                    ),
907                    (next_expr.span.shrink_to_lo(), "    ".to_string()),
908                    (next_expr.span.shrink_to_hi(), format!("\n{}}}", " ".repeat(margin))),
909                ];
910                err.multipart_suggestion(
911                    "it seems like you are trying to provide different expressions depending on \
912                     `cfg`, consider using `if cfg!(..)`",
913                    sugg,
914                    Applicability::MachineApplicable,
915                );
916            }
917        }
918
919        err.emit()
920    }
921
922    fn check_too_many_raw_str_terminators(&mut self, err: &mut Diag<'_>) -> bool {
923        let sm = self.psess.source_map();
924        match (&self.prev_token.kind, &self.token.kind) {
925            (
926                TokenKind::Literal(Lit {
927                    kind: LitKind::StrRaw(n_hashes) | LitKind::ByteStrRaw(n_hashes),
928                    ..
929                }),
930                TokenKind::Pound,
931            ) if !sm.is_multiline(
932                self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()),
933            ) =>
934            {
935                let n_hashes: u8 = *n_hashes;
936                err.primary_message("too many `#` when terminating raw string");
937                let str_span = self.prev_token.span;
938                let mut span = self.token.span;
939                let mut count = 0;
940                while self.token == TokenKind::Pound
941                    && !sm.is_multiline(span.shrink_to_hi().until(self.token.span.shrink_to_lo()))
942                {
943                    span = span.with_hi(self.token.span.hi());
944                    self.bump();
945                    count += 1;
946                }
947                err.span(span);
948                err.span_suggestion(
949                    span,
950                    format!("remove the extra `#`{}", pluralize!(count)),
951                    "",
952                    Applicability::MachineApplicable,
953                );
954                err.span_label(
955                    str_span,
956                    format!("this raw string started with {n_hashes} `#`{}", pluralize!(n_hashes)),
957                );
958                true
959            }
960            _ => false,
961        }
962    }
963
964    pub(super) fn maybe_suggest_struct_literal(
965        &mut self,
966        lo: Span,
967        s: BlockCheckMode,
968        maybe_struct_name: token::Token,
969    ) -> Option<PResult<'a, P<Block>>> {
970        if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) {
971            // We might be having a struct literal where people forgot to include the path:
972            // fn foo() -> Foo {
973            //     field: value,
974            // }
975            debug!(?maybe_struct_name, ?self.token);
976            let mut snapshot = self.create_snapshot_for_diagnostic();
977            let path = Path {
978                segments: ThinVec::new(),
979                span: self.prev_token.span.shrink_to_lo(),
980                tokens: None,
981            };
982            let struct_expr = snapshot.parse_expr_struct(None, path, false);
983            let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No);
984            return Some(match (struct_expr, block_tail) {
985                (Ok(expr), Err(err)) => {
986                    // We have encountered the following:
987                    // fn foo() -> Foo {
988                    //     field: value,
989                    // }
990                    // Suggest:
991                    // fn foo() -> Foo { Path {
992                    //     field: value,
993                    // } }
994                    err.cancel();
995                    self.restore_snapshot(snapshot);
996                    let guar = self.dcx().emit_err(StructLiteralBodyWithoutPath {
997                        span: expr.span,
998                        sugg: StructLiteralBodyWithoutPathSugg {
999                            before: expr.span.shrink_to_lo(),
1000                            after: expr.span.shrink_to_hi(),
1001                        },
1002                    });
1003                    Ok(self.mk_block(
1004                        thin_vec![self.mk_stmt_err(expr.span, guar)],
1005                        s,
1006                        lo.to(self.prev_token.span),
1007                    ))
1008                }
1009                (Err(err), Ok(tail)) => {
1010                    // We have a block tail that contains a somehow valid expr.
1011                    err.cancel();
1012                    Ok(tail)
1013                }
1014                (Err(snapshot_err), Err(err)) => {
1015                    // We don't know what went wrong, emit the normal error.
1016                    snapshot_err.cancel();
1017                    self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);
1018                    Err(err)
1019                }
1020                (Ok(_), Ok(tail)) => Ok(tail),
1021            });
1022        }
1023        None
1024    }
1025
1026    pub(super) fn recover_closure_body(
1027        &mut self,
1028        mut err: Diag<'a>,
1029        before: token::Token,
1030        prev: token::Token,
1031        token: token::Token,
1032        lo: Span,
1033        decl_hi: Span,
1034    ) -> PResult<'a, P<Expr>> {
1035        err.span_label(lo.to(decl_hi), "while parsing the body of this closure");
1036        let guar = match before.kind {
1037            token::OpenBrace if token.kind != token::OpenBrace => {
1038                // `{ || () }` should have been `|| { () }`
1039                err.multipart_suggestion(
1040                    "you might have meant to open the body of the closure, instead of enclosing \
1041                     the closure in a block",
1042                    vec![
1043                        (before.span, String::new()),
1044                        (prev.span.shrink_to_hi(), " {".to_string()),
1045                    ],
1046                    Applicability::MaybeIncorrect,
1047                );
1048                let guar = err.emit();
1049                self.eat_to_tokens(&[exp!(CloseBrace)]);
1050                guar
1051            }
1052            token::OpenParen if token.kind != token::OpenBrace => {
1053                // We are within a function call or tuple, we can emit the error
1054                // and recover.
1055                self.eat_to_tokens(&[exp!(CloseParen), exp!(Comma)]);
1056
1057                err.multipart_suggestion_verbose(
1058                    "you might have meant to open the body of the closure",
1059                    vec![
1060                        (prev.span.shrink_to_hi(), " {".to_string()),
1061                        (self.token.span.shrink_to_lo(), "}".to_string()),
1062                    ],
1063                    Applicability::MaybeIncorrect,
1064                );
1065                err.emit()
1066            }
1067            _ if token.kind != token::OpenBrace => {
1068                // We don't have a heuristic to correctly identify where the block
1069                // should be closed.
1070                err.multipart_suggestion_verbose(
1071                    "you might have meant to open the body of the closure",
1072                    vec![(prev.span.shrink_to_hi(), " {".to_string())],
1073                    Applicability::HasPlaceholders,
1074                );
1075                return Err(err);
1076            }
1077            _ => return Err(err),
1078        };
1079        Ok(self.mk_expr_err(lo.to(self.token.span), guar))
1080    }
1081
1082    /// Eats and discards tokens until one of `closes` is encountered. Respects token trees,
1083    /// passes through any errors encountered. Used for error recovery.
1084    pub(super) fn eat_to_tokens(&mut self, closes: &[ExpTokenPair<'_>]) {
1085        if let Err(err) = self
1086            .parse_seq_to_before_tokens(closes, &[], SeqSep::none(), |p| Ok(p.parse_token_tree()))
1087        {
1088            err.cancel();
1089        }
1090    }
1091
1092    /// This function checks if there are trailing angle brackets and produces
1093    /// a diagnostic to suggest removing them.
1094    ///
1095    /// ```ignore (diagnostic)
1096    /// let _ = [1, 2, 3].into_iter().collect::<Vec<usize>>>>();
1097    ///                                                    ^^ help: remove extra angle brackets
1098    /// ```
1099    ///
1100    /// If `true` is returned, then trailing brackets were recovered, tokens were consumed
1101    /// up until one of the tokens in 'end' was encountered, and an error was emitted.
1102    pub(super) fn check_trailing_angle_brackets(
1103        &mut self,
1104        segment: &PathSegment,
1105        end: &[ExpTokenPair<'_>],
1106    ) -> Option<ErrorGuaranteed> {
1107        if !self.may_recover() {
1108            return None;
1109        }
1110
1111        // This function is intended to be invoked after parsing a path segment where there are two
1112        // cases:
1113        //
1114        // 1. A specific token is expected after the path segment.
1115        //    eg. `x.foo(`, `x.foo::<u32>(` (parenthesis - method call),
1116        //        `Foo::`, or `Foo::<Bar>::` (mod sep - continued path).
1117        // 2. No specific token is expected after the path segment.
1118        //    eg. `x.foo` (field access)
1119        //
1120        // This function is called after parsing `.foo` and before parsing the token `end` (if
1121        // present). This includes any angle bracket arguments, such as `.foo::<u32>` or
1122        // `Foo::<Bar>`.
1123
1124        // We only care about trailing angle brackets if we previously parsed angle bracket
1125        // arguments. This helps stop us incorrectly suggesting that extra angle brackets be
1126        // removed in this case:
1127        //
1128        // `x.foo >> (3)` (where `x.foo` is a `u32` for example)
1129        //
1130        // This case is particularly tricky as we won't notice it just looking at the tokens -
1131        // it will appear the same (in terms of upcoming tokens) as below (since the `::<u32>` will
1132        // have already been parsed):
1133        //
1134        // `x.foo::<u32>>>(3)`
1135        let parsed_angle_bracket_args =
1136            segment.args.as_ref().is_some_and(|args| args.is_angle_bracketed());
1137
1138        debug!(
1139            "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}",
1140            parsed_angle_bracket_args,
1141        );
1142        if !parsed_angle_bracket_args {
1143            return None;
1144        }
1145
1146        // Keep the span at the start so we can highlight the sequence of `>` characters to be
1147        // removed.
1148        let lo = self.token.span;
1149
1150        // We need to look-ahead to see if we have `>` characters without moving the cursor forward
1151        // (since we might have the field access case and the characters we're eating are
1152        // actual operators and not trailing characters - ie `x.foo >> 3`).
1153        let mut position = 0;
1154
1155        // We can encounter `>` or `>>` tokens in any order, so we need to keep track of how
1156        // many of each (so we can correctly pluralize our error messages) and continue to
1157        // advance.
1158        let mut number_of_shr = 0;
1159        let mut number_of_gt = 0;
1160        while self.look_ahead(position, |t| {
1161            trace!("check_trailing_angle_brackets: t={:?}", t);
1162            if *t == token::Shr {
1163                number_of_shr += 1;
1164                true
1165            } else if *t == token::Gt {
1166                number_of_gt += 1;
1167                true
1168            } else {
1169                false
1170            }
1171        }) {
1172            position += 1;
1173        }
1174
1175        // If we didn't find any trailing `>` characters, then we have nothing to error about.
1176        debug!(
1177            "check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?}",
1178            number_of_gt, number_of_shr,
1179        );
1180        if number_of_gt < 1 && number_of_shr < 1 {
1181            return None;
1182        }
1183
1184        // Finally, double check that we have our end token as otherwise this is the
1185        // second case.
1186        if self.look_ahead(position, |t| {
1187            trace!("check_trailing_angle_brackets: t={:?}", t);
1188            end.iter().any(|exp| exp.tok == &t.kind)
1189        }) {
1190            // Eat from where we started until the end token so that parsing can continue
1191            // as if we didn't have those extra angle brackets.
1192            self.eat_to_tokens(end);
1193            let span = lo.to(self.prev_token.span);
1194
1195            let num_extra_brackets = number_of_gt + number_of_shr * 2;
1196            return Some(self.dcx().emit_err(UnmatchedAngleBrackets { span, num_extra_brackets }));
1197        }
1198        None
1199    }
1200
1201    /// Check if a method call with an intended turbofish has been written without surrounding
1202    /// angle brackets.
1203    pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut PathSegment) {
1204        if !self.may_recover() {
1205            return;
1206        }
1207
1208        if self.token == token::PathSep && segment.args.is_none() {
1209            let snapshot = self.create_snapshot_for_diagnostic();
1210            self.bump();
1211            let lo = self.token.span;
1212            match self.parse_angle_args(None) {
1213                Ok(args) => {
1214                    let span = lo.to(self.prev_token.span);
1215                    // Detect trailing `>` like in `x.collect::Vec<_>>()`.
1216                    let mut trailing_span = self.prev_token.span.shrink_to_hi();
1217                    while self.token == token::Shr || self.token == token::Gt {
1218                        trailing_span = trailing_span.to(self.token.span);
1219                        self.bump();
1220                    }
1221                    if self.token == token::OpenParen {
1222                        // Recover from bad turbofish: `foo.collect::Vec<_>()`.
1223                        segment.args = Some(AngleBracketedArgs { args, span }.into());
1224
1225                        self.dcx().emit_err(GenericParamsWithoutAngleBrackets {
1226                            span,
1227                            sugg: GenericParamsWithoutAngleBracketsSugg {
1228                                left: span.shrink_to_lo(),
1229                                right: trailing_span,
1230                            },
1231                        });
1232                    } else {
1233                        // This doesn't look like an invalid turbofish, can't recover parse state.
1234                        self.restore_snapshot(snapshot);
1235                    }
1236                }
1237                Err(err) => {
1238                    // We couldn't parse generic parameters, unlikely to be a turbofish. Rely on
1239                    // generic parse error instead.
1240                    err.cancel();
1241                    self.restore_snapshot(snapshot);
1242                }
1243            }
1244        }
1245    }
1246
1247    /// When writing a turbofish with multiple type parameters missing the leading `::`, we will
1248    /// encounter a parse error when encountering the first `,`.
1249    pub(super) fn check_mistyped_turbofish_with_multiple_type_params(
1250        &mut self,
1251        mut e: Diag<'a>,
1252        expr: &mut P<Expr>,
1253    ) -> PResult<'a, ErrorGuaranteed> {
1254        if let ExprKind::Binary(binop, _, _) = &expr.kind
1255            && let ast::BinOpKind::Lt = binop.node
1256            && self.eat(exp!(Comma))
1257        {
1258            let x = self.parse_seq_to_before_end(
1259                exp!(Gt),
1260                SeqSep::trailing_allowed(exp!(Comma)),
1261                |p| match p.parse_generic_arg(None)? {
1262                    Some(arg) => Ok(arg),
1263                    // If we didn't eat a generic arg, then we should error.
1264                    None => p.unexpected_any(),
1265                },
1266            );
1267            match x {
1268                Ok((_, _, Recovered::No)) => {
1269                    if self.eat(exp!(Gt)) {
1270                        // We made sense of it. Improve the error message.
1271                        e.span_suggestion_verbose(
1272                            binop.span.shrink_to_lo(),
1273                            fluent::parse_sugg_turbofish_syntax,
1274                            "::",
1275                            Applicability::MaybeIncorrect,
1276                        );
1277                        match self.parse_expr() {
1278                            Ok(_) => {
1279                                // The subsequent expression is valid. Mark
1280                                // `expr` as erroneous and emit `e` now, but
1281                                // return `Ok` so parsing can continue.
1282                                let guar = e.emit();
1283                                *expr = self.mk_expr_err(expr.span.to(self.prev_token.span), guar);
1284                                return Ok(guar);
1285                            }
1286                            Err(err) => {
1287                                err.cancel();
1288                            }
1289                        }
1290                    }
1291                }
1292                Ok((_, _, Recovered::Yes(_))) => {}
1293                Err(err) => {
1294                    err.cancel();
1295                }
1296            }
1297        }
1298        Err(e)
1299    }
1300
1301    /// Suggest add the missing `let` before the identifier in stmt
1302    /// `a: Ty = 1` -> `let a: Ty = 1`
1303    pub(super) fn suggest_add_missing_let_for_stmt(&mut self, err: &mut Diag<'a>) {
1304        if self.token == token::Colon {
1305            let prev_span = self.prev_token.span.shrink_to_lo();
1306            let snapshot = self.create_snapshot_for_diagnostic();
1307            self.bump();
1308            match self.parse_ty() {
1309                Ok(_) => {
1310                    if self.token == token::Eq {
1311                        let sugg = SuggAddMissingLetStmt { span: prev_span };
1312                        sugg.add_to_diag(err);
1313                    }
1314                }
1315                Err(e) => {
1316                    e.cancel();
1317                }
1318            }
1319            self.restore_snapshot(snapshot);
1320        }
1321    }
1322
1323    /// Check to see if a pair of chained operators looks like an attempt at chained comparison,
1324    /// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
1325    /// parenthesising the leftmost comparison. The return value indicates if recovery happened.
1326    fn attempt_chained_comparison_suggestion(
1327        &mut self,
1328        err: &mut ComparisonOperatorsCannotBeChained,
1329        inner_op: &Expr,
1330        outer_op: &Spanned<AssocOp>,
1331    ) -> bool {
1332        if let ExprKind::Binary(op, l1, r1) = &inner_op.kind {
1333            if let ExprKind::Field(_, ident) = l1.kind
1334                && !ident.is_numeric()
1335                && !matches!(r1.kind, ExprKind::Lit(_))
1336            {
1337                // The parser has encountered `foo.bar<baz`, the likelihood of the turbofish
1338                // suggestion being the only one to apply is high.
1339                return false;
1340            }
1341            return match (op.node, &outer_op.node) {
1342                // `x == y == z`
1343                (BinOpKind::Eq, AssocOp::Binary(BinOpKind::Eq)) |
1344                // `x < y < z` and friends.
1345                (BinOpKind::Lt, AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le)) |
1346                (BinOpKind::Le, AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le)) |
1347                // `x > y > z` and friends.
1348                (BinOpKind::Gt, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) |
1349                (BinOpKind::Ge, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) => {
1350                    let expr_to_str = |e: &Expr| {
1351                        self.span_to_snippet(e.span)
1352                            .unwrap_or_else(|_| pprust::expr_to_string(e))
1353                    };
1354                    err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::SplitComparison {
1355                        span: inner_op.span.shrink_to_hi(),
1356                        middle_term: expr_to_str(r1),
1357                    });
1358                    false // Keep the current parse behavior, where the AST is `(x < y) < z`.
1359                }
1360                // `x == y < z`
1361                (
1362                    BinOpKind::Eq,
1363                    AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge)
1364                ) => {
1365                    // Consume `z`/outer-op-rhs.
1366                    let snapshot = self.create_snapshot_for_diagnostic();
1367                    match self.parse_expr() {
1368                        Ok(r2) => {
1369                            // We are sure that outer-op-rhs could be consumed, the suggestion is
1370                            // likely correct.
1371                            err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize {
1372                                left: r1.span.shrink_to_lo(),
1373                                right: r2.span.shrink_to_hi(),
1374                            });
1375                            true
1376                        }
1377                        Err(expr_err) => {
1378                            expr_err.cancel();
1379                            self.restore_snapshot(snapshot);
1380                            true
1381                        }
1382                    }
1383                }
1384                // `x > y == z`
1385                (
1386                    BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge,
1387                    AssocOp::Binary(BinOpKind::Eq)
1388                ) => {
1389                    let snapshot = self.create_snapshot_for_diagnostic();
1390                    // At this point it is always valid to enclose the lhs in parentheses, no
1391                    // further checks are necessary.
1392                    match self.parse_expr() {
1393                        Ok(_) => {
1394                            err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize {
1395                                left: l1.span.shrink_to_lo(),
1396                                right: r1.span.shrink_to_hi(),
1397                            });
1398                            true
1399                        }
1400                        Err(expr_err) => {
1401                            expr_err.cancel();
1402                            self.restore_snapshot(snapshot);
1403                            false
1404                        }
1405                    }
1406                }
1407                _ => false
1408            };
1409        }
1410        false
1411    }
1412
1413    /// Produces an error if comparison operators are chained (RFC #558).
1414    /// We only need to check the LHS, not the RHS, because all comparison ops have same
1415    /// precedence (see `fn precedence`) and are left-associative (see `fn fixity`).
1416    ///
1417    /// This can also be hit if someone incorrectly writes `foo<bar>()` when they should have used
1418    /// the turbofish (`foo::<bar>()`) syntax. We attempt some heuristic recovery if that is the
1419    /// case.
1420    ///
1421    /// Keep in mind that given that `outer_op.is_comparison()` holds and comparison ops are left
1422    /// associative we can infer that we have:
1423    ///
1424    /// ```text
1425    ///           outer_op
1426    ///           /   \
1427    ///     inner_op   r2
1428    ///        /  \
1429    ///      l1    r1
1430    /// ```
1431    pub(super) fn check_no_chained_comparison(
1432        &mut self,
1433        inner_op: &Expr,
1434        outer_op: &Spanned<AssocOp>,
1435    ) -> PResult<'a, Option<P<Expr>>> {
1436        debug_assert!(
1437            outer_op.node.is_comparison(),
1438            "check_no_chained_comparison: {:?} is not comparison",
1439            outer_op.node,
1440        );
1441
1442        let mk_err_expr =
1443            |this: &Self, span, guar| Ok(Some(this.mk_expr(span, ExprKind::Err(guar))));
1444
1445        match &inner_op.kind {
1446            ExprKind::Binary(op, l1, r1) if op.node.is_comparison() => {
1447                let mut err = ComparisonOperatorsCannotBeChained {
1448                    span: vec![op.span, self.prev_token.span],
1449                    suggest_turbofish: None,
1450                    help_turbofish: false,
1451                    chaining_sugg: None,
1452                };
1453
1454                // Include `<` to provide this recommendation even in a case like
1455                // `Foo<Bar<Baz<Qux, ()>>>`
1456                if op.node == BinOpKind::Lt && outer_op.node == AssocOp::Binary(BinOpKind::Lt)
1457                    || outer_op.node == AssocOp::Binary(BinOpKind::Gt)
1458                {
1459                    if outer_op.node == AssocOp::Binary(BinOpKind::Lt) {
1460                        let snapshot = self.create_snapshot_for_diagnostic();
1461                        self.bump();
1462                        // So far we have parsed `foo<bar<`, consume the rest of the type args.
1463                        let modifiers = [(token::Lt, 1), (token::Gt, -1), (token::Shr, -2)];
1464                        self.consume_tts(1, &modifiers);
1465
1466                        if !matches!(self.token.kind, token::OpenParen | token::PathSep) {
1467                            // We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the
1468                            // parser and bail out.
1469                            self.restore_snapshot(snapshot);
1470                        }
1471                    }
1472                    return if self.token == token::PathSep {
1473                        // We have some certainty that this was a bad turbofish at this point.
1474                        // `foo< bar >::`
1475                        if let ExprKind::Binary(o, ..) = inner_op.kind
1476                            && o.node == BinOpKind::Lt
1477                        {
1478                            err.suggest_turbofish = Some(op.span.shrink_to_lo());
1479                        } else {
1480                            err.help_turbofish = true;
1481                        }
1482
1483                        let snapshot = self.create_snapshot_for_diagnostic();
1484                        self.bump(); // `::`
1485
1486                        // Consume the rest of the likely `foo<bar>::new()` or return at `foo<bar>`.
1487                        match self.parse_expr() {
1488                            Ok(_) => {
1489                                // 99% certain that the suggestion is correct, continue parsing.
1490                                let guar = self.dcx().emit_err(err);
1491                                // FIXME: actually check that the two expressions in the binop are
1492                                // paths and resynthesize new fn call expression instead of using
1493                                // `ExprKind::Err` placeholder.
1494                                mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar)
1495                            }
1496                            Err(expr_err) => {
1497                                expr_err.cancel();
1498                                // Not entirely sure now, but we bubble the error up with the
1499                                // suggestion.
1500                                self.restore_snapshot(snapshot);
1501                                Err(self.dcx().create_err(err))
1502                            }
1503                        }
1504                    } else if self.token == token::OpenParen {
1505                        // We have high certainty that this was a bad turbofish at this point.
1506                        // `foo< bar >(`
1507                        if let ExprKind::Binary(o, ..) = inner_op.kind
1508                            && o.node == BinOpKind::Lt
1509                        {
1510                            err.suggest_turbofish = Some(op.span.shrink_to_lo());
1511                        } else {
1512                            err.help_turbofish = true;
1513                        }
1514                        // Consume the fn call arguments.
1515                        match self.consume_fn_args() {
1516                            Err(()) => Err(self.dcx().create_err(err)),
1517                            Ok(()) => {
1518                                let guar = self.dcx().emit_err(err);
1519                                // FIXME: actually check that the two expressions in the binop are
1520                                // paths and resynthesize new fn call expression instead of using
1521                                // `ExprKind::Err` placeholder.
1522                                mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar)
1523                            }
1524                        }
1525                    } else {
1526                        if !matches!(l1.kind, ExprKind::Lit(_))
1527                            && !matches!(r1.kind, ExprKind::Lit(_))
1528                        {
1529                            // All we know is that this is `foo < bar >` and *nothing* else. Try to
1530                            // be helpful, but don't attempt to recover.
1531                            err.help_turbofish = true;
1532                        }
1533
1534                        // If it looks like a genuine attempt to chain operators (as opposed to a
1535                        // misformatted turbofish, for instance), suggest a correct form.
1536                        let recovered = self
1537                            .attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
1538                        if recovered {
1539                            let guar = self.dcx().emit_err(err);
1540                            mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar)
1541                        } else {
1542                            // These cases cause too many knock-down errors, bail out (#61329).
1543                            Err(self.dcx().create_err(err))
1544                        }
1545                    };
1546                }
1547                let recovered =
1548                    self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
1549                let guar = self.dcx().emit_err(err);
1550                if recovered {
1551                    return mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar);
1552                }
1553            }
1554            _ => {}
1555        }
1556        Ok(None)
1557    }
1558
1559    fn consume_fn_args(&mut self) -> Result<(), ()> {
1560        let snapshot = self.create_snapshot_for_diagnostic();
1561        self.bump(); // `(`
1562
1563        // Consume the fn call arguments.
1564        let modifiers = [(token::OpenParen, 1), (token::CloseParen, -1)];
1565        self.consume_tts(1, &modifiers);
1566
1567        if self.token == token::Eof {
1568            // Not entirely sure that what we consumed were fn arguments, rollback.
1569            self.restore_snapshot(snapshot);
1570            Err(())
1571        } else {
1572            // 99% certain that the suggestion is correct, continue parsing.
1573            Ok(())
1574        }
1575    }
1576
1577    pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) {
1578        if impl_dyn_multi {
1579            self.dcx().emit_err(AmbiguousPlus {
1580                span: ty.span,
1581                suggestion: AddParen { lo: ty.span.shrink_to_lo(), hi: ty.span.shrink_to_hi() },
1582            });
1583        }
1584    }
1585
1586    /// Swift lets users write `Ty?` to mean `Option<Ty>`. Parse the construct and recover from it.
1587    pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P<Ty>) -> P<Ty> {
1588        if self.token == token::Question {
1589            self.bump();
1590            let guar = self.dcx().emit_err(QuestionMarkInType {
1591                span: self.prev_token.span,
1592                sugg: QuestionMarkInTypeSugg {
1593                    left: ty.span.shrink_to_lo(),
1594                    right: self.prev_token.span,
1595                },
1596            });
1597            self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err(guar))
1598        } else {
1599            ty
1600        }
1601    }
1602
1603    /// Rust has no ternary operator (`cond ? then : else`). Parse it and try
1604    /// to recover from it if `then` and `else` are valid expressions. Returns
1605    /// an err if this appears to be a ternary expression.
1606    /// If we have the span of the condition, we can provide a better error span
1607    /// and code suggestion.
1608    pub(super) fn maybe_recover_from_ternary_operator(
1609        &mut self,
1610        cond: Option<Span>,
1611    ) -> PResult<'a, ()> {
1612        if self.prev_token != token::Question {
1613            return PResult::Ok(());
1614        }
1615
1616        let question = self.prev_token.span;
1617        let lo = cond.unwrap_or(question).lo();
1618        let snapshot = self.create_snapshot_for_diagnostic();
1619
1620        if match self.parse_expr() {
1621            Ok(_) => true,
1622            Err(err) => {
1623                err.cancel();
1624                // The colon can sometimes be mistaken for type
1625                // ascription. Catch when this happens and continue.
1626                self.token == token::Colon
1627            }
1628        } {
1629            if self.eat_noexpect(&token::Colon) {
1630                let colon = self.prev_token.span;
1631                match self.parse_expr() {
1632                    Ok(expr) => {
1633                        let sugg = cond.map(|cond| TernaryOperatorSuggestion {
1634                            before_cond: cond.shrink_to_lo(),
1635                            question,
1636                            colon,
1637                            end: expr.span.shrink_to_hi(),
1638                        });
1639                        return Err(self.dcx().create_err(TernaryOperator {
1640                            span: self.prev_token.span.with_lo(lo),
1641                            sugg,
1642                            no_sugg: sugg.is_none(),
1643                        }));
1644                    }
1645                    Err(err) => {
1646                        err.cancel();
1647                    }
1648                };
1649            }
1650        }
1651        self.restore_snapshot(snapshot);
1652        Ok(())
1653    }
1654
1655    pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> {
1656        // Do not add `+` to expected tokens.
1657        if !self.token.is_like_plus() {
1658            return Ok(());
1659        }
1660
1661        self.bump(); // `+`
1662        let _bounds = self.parse_generic_bounds()?;
1663        let sub = match &ty.kind {
1664            TyKind::Ref(_lifetime, mut_ty) => {
1665                let lo = mut_ty.ty.span.shrink_to_lo();
1666                let hi = self.prev_token.span.shrink_to_hi();
1667                BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } }
1668            }
1669            TyKind::Ptr(..) | TyKind::BareFn(..) => {
1670                BadTypePlusSub::ForgotParen { span: ty.span.to(self.prev_token.span) }
1671            }
1672            _ => BadTypePlusSub::ExpectPath { span: ty.span },
1673        };
1674
1675        self.dcx().emit_err(BadTypePlus { span: ty.span, sub });
1676
1677        Ok(())
1678    }
1679
1680    pub(super) fn recover_from_prefix_increment(
1681        &mut self,
1682        operand_expr: P<Expr>,
1683        op_span: Span,
1684        start_stmt: bool,
1685    ) -> PResult<'a, P<Expr>> {
1686        let standalone = if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr };
1687        let kind = IncDecRecovery { standalone, op: IncOrDec::Inc, fixity: UnaryFixity::Pre };
1688        self.recover_from_inc_dec(operand_expr, kind, op_span)
1689    }
1690
1691    pub(super) fn recover_from_postfix_increment(
1692        &mut self,
1693        operand_expr: P<Expr>,
1694        op_span: Span,
1695        start_stmt: bool,
1696    ) -> PResult<'a, P<Expr>> {
1697        let kind = IncDecRecovery {
1698            standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr },
1699            op: IncOrDec::Inc,
1700            fixity: UnaryFixity::Post,
1701        };
1702        self.recover_from_inc_dec(operand_expr, kind, op_span)
1703    }
1704
1705    pub(super) fn recover_from_postfix_decrement(
1706        &mut self,
1707        operand_expr: P<Expr>,
1708        op_span: Span,
1709        start_stmt: bool,
1710    ) -> PResult<'a, P<Expr>> {
1711        let kind = IncDecRecovery {
1712            standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr },
1713            op: IncOrDec::Dec,
1714            fixity: UnaryFixity::Post,
1715        };
1716        self.recover_from_inc_dec(operand_expr, kind, op_span)
1717    }
1718
1719    fn recover_from_inc_dec(
1720        &mut self,
1721        base: P<Expr>,
1722        kind: IncDecRecovery,
1723        op_span: Span,
1724    ) -> PResult<'a, P<Expr>> {
1725        let mut err = self.dcx().struct_span_err(
1726            op_span,
1727            format!("Rust has no {} {} operator", kind.fixity, kind.op.name()),
1728        );
1729        err.span_label(op_span, format!("not a valid {} operator", kind.fixity));
1730
1731        let help_base_case = |mut err: Diag<'_, _>, base| {
1732            err.help(format!("use `{}= 1` instead", kind.op.chr()));
1733            err.emit();
1734            Ok(base)
1735        };
1736
1737        // (pre, post)
1738        let spans = match kind.fixity {
1739            UnaryFixity::Pre => (op_span, base.span.shrink_to_hi()),
1740            UnaryFixity::Post => (base.span.shrink_to_lo(), op_span),
1741        };
1742
1743        match kind.standalone {
1744            IsStandalone::Standalone => {
1745                self.inc_dec_standalone_suggest(kind, spans).emit_verbose(&mut err)
1746            }
1747            IsStandalone::Subexpr => {
1748                let Ok(base_src) = self.span_to_snippet(base.span) else {
1749                    return help_base_case(err, base);
1750                };
1751                match kind.fixity {
1752                    UnaryFixity::Pre => {
1753                        self.prefix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
1754                    }
1755                    UnaryFixity::Post => {
1756                        // won't suggest since we can not handle the precedences
1757                        // for example: `a + b++` has been parsed (a + b)++ and we can not suggest here
1758                        if !matches!(base.kind, ExprKind::Binary(_, _, _)) {
1759                            self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
1760                        }
1761                    }
1762                }
1763            }
1764        }
1765        Err(err)
1766    }
1767
1768    fn prefix_inc_dec_suggest(
1769        &mut self,
1770        base_src: String,
1771        kind: IncDecRecovery,
1772        (pre_span, post_span): (Span, Span),
1773    ) -> MultiSugg {
1774        MultiSugg {
1775            msg: format!("use `{}= 1` instead", kind.op.chr()),
1776            patches: vec![
1777                (pre_span, "{ ".to_string()),
1778                (post_span, format!(" {}= 1; {} }}", kind.op.chr(), base_src)),
1779            ],
1780            applicability: Applicability::MachineApplicable,
1781        }
1782    }
1783
1784    fn postfix_inc_dec_suggest(
1785        &mut self,
1786        base_src: String,
1787        kind: IncDecRecovery,
1788        (pre_span, post_span): (Span, Span),
1789    ) -> MultiSugg {
1790        let tmp_var = if base_src.trim() == "tmp" { "tmp_" } else { "tmp" };
1791        MultiSugg {
1792            msg: format!("use `{}= 1` instead", kind.op.chr()),
1793            patches: vec![
1794                (pre_span, format!("{{ let {tmp_var} = ")),
1795                (post_span, format!("; {} {}= 1; {} }}", base_src, kind.op.chr(), tmp_var)),
1796            ],
1797            applicability: Applicability::HasPlaceholders,
1798        }
1799    }
1800
1801    fn inc_dec_standalone_suggest(
1802        &mut self,
1803        kind: IncDecRecovery,
1804        (pre_span, post_span): (Span, Span),
1805    ) -> MultiSugg {
1806        let mut patches = Vec::new();
1807
1808        if !pre_span.is_empty() {
1809            patches.push((pre_span, String::new()));
1810        }
1811
1812        patches.push((post_span, format!(" {}= 1", kind.op.chr())));
1813        MultiSugg {
1814            msg: format!("use `{}= 1` instead", kind.op.chr()),
1815            patches,
1816            applicability: Applicability::MachineApplicable,
1817        }
1818    }
1819
1820    /// Tries to recover from associated item paths like `[T]::AssocItem` / `(T, U)::AssocItem`.
1821    /// Attempts to convert the base expression/pattern/type into a type, parses the `::AssocItem`
1822    /// tail, and combines them into a `<Ty>::AssocItem` expression/pattern/type.
1823    pub(super) fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
1824        &mut self,
1825        base: P<T>,
1826    ) -> PResult<'a, P<T>> {
1827        if !self.may_recover() {
1828            return Ok(base);
1829        }
1830
1831        // Do not add `::` to expected tokens.
1832        if self.token == token::PathSep {
1833            if let Some(ty) = base.to_ty() {
1834                return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
1835            }
1836        }
1837        Ok(base)
1838    }
1839
1840    /// Given an already parsed `Ty`, parses the `::AssocItem` tail and
1841    /// combines them into a `<Ty>::AssocItem` expression/pattern/type.
1842    pub(super) fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
1843        &mut self,
1844        ty_span: Span,
1845        ty: P<Ty>,
1846    ) -> PResult<'a, P<T>> {
1847        self.expect(exp!(PathSep))?;
1848
1849        let mut path = ast::Path { segments: ThinVec::new(), span: DUMMY_SP, tokens: None };
1850        self.parse_path_segments(&mut path.segments, T::PATH_STYLE, None)?;
1851        path.span = ty_span.to(self.prev_token.span);
1852
1853        self.dcx().emit_err(BadQPathStage2 {
1854            span: ty_span,
1855            wrap: WrapType { lo: ty_span.shrink_to_lo(), hi: ty_span.shrink_to_hi() },
1856        });
1857
1858        let path_span = ty_span.shrink_to_hi(); // Use an empty path since `position == 0`.
1859        Ok(P(T::recovered(Some(P(QSelf { ty, path_span, position: 0 })), path)))
1860    }
1861
1862    /// This function gets called in places where a semicolon is NOT expected and if there's a
1863    /// semicolon it emits the appropriate error and returns true.
1864    pub fn maybe_consume_incorrect_semicolon(&mut self, previous_item: Option<&Item>) -> bool {
1865        if self.token != TokenKind::Semi {
1866            return false;
1867        }
1868
1869        // Check previous item to add it to the diagnostic, for example to say
1870        // `enum declarations are not followed by a semicolon`
1871        let err = match previous_item {
1872            Some(previous_item) => {
1873                let name = match previous_item.kind {
1874                    // Say "braced struct" because tuple-structs and
1875                    // braceless-empty-struct declarations do take a semicolon.
1876                    ItemKind::Struct(..) => "braced struct",
1877                    _ => previous_item.kind.descr(),
1878                };
1879                IncorrectSemicolon { span: self.token.span, name, show_help: true }
1880            }
1881            None => IncorrectSemicolon { span: self.token.span, name: "", show_help: false },
1882        };
1883        self.dcx().emit_err(err);
1884
1885        self.bump();
1886        true
1887    }
1888
1889    /// Creates a `Diag` for an unexpected token `t` and tries to recover if it is a
1890    /// closing delimiter.
1891    pub(super) fn unexpected_try_recover(&mut self, t: &TokenKind) -> PResult<'a, Recovered> {
1892        let token_str = pprust::token_kind_to_string(t);
1893        let this_token_str = super::token_descr(&self.token);
1894        let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) {
1895            // Point at the end of the macro call when reaching end of macro arguments.
1896            (token::Eof, Some(_)) => {
1897                let sp = self.prev_token.span.shrink_to_hi();
1898                (sp, sp)
1899            }
1900            // We don't want to point at the following span after DUMMY_SP.
1901            // This happens when the parser finds an empty TokenStream.
1902            _ if self.prev_token.span == DUMMY_SP => (self.token.span, self.token.span),
1903            // EOF, don't want to point at the following char, but rather the last token.
1904            (token::Eof, None) => (self.prev_token.span, self.token.span),
1905            _ => (self.prev_token.span.shrink_to_hi(), self.token.span),
1906        };
1907        let msg = format!(
1908            "expected `{}`, found {}",
1909            token_str,
1910            match (&self.token.kind, self.subparser_name) {
1911                (token::Eof, Some(origin)) => format!("end of {origin}"),
1912                _ => this_token_str,
1913            },
1914        );
1915        let mut err = self.dcx().struct_span_err(sp, msg);
1916        let label_exp = format!("expected `{token_str}`");
1917        let sm = self.psess.source_map();
1918        if !sm.is_multiline(prev_sp.until(sp)) {
1919            // When the spans are in the same line, it means that the only content
1920            // between them is whitespace, point only at the found token.
1921            err.span_label(sp, label_exp);
1922        } else {
1923            err.span_label(prev_sp, label_exp);
1924            err.span_label(sp, "unexpected token");
1925        }
1926        Err(err)
1927    }
1928
1929    pub(super) fn expect_semi(&mut self) -> PResult<'a, ()> {
1930        if self.eat(exp!(Semi)) || self.recover_colon_as_semi() {
1931            return Ok(());
1932        }
1933        self.expect(exp!(Semi)).map(drop) // Error unconditionally
1934    }
1935
1936    pub(super) fn recover_colon_as_semi(&mut self) -> bool {
1937        let line_idx = |span: Span| {
1938            self.psess
1939                .source_map()
1940                .span_to_lines(span)
1941                .ok()
1942                .and_then(|lines| Some(lines.lines.get(0)?.line_index))
1943        };
1944
1945        if self.may_recover()
1946            && self.token == token::Colon
1947            && self.look_ahead(1, |next| line_idx(self.token.span) < line_idx(next.span))
1948        {
1949            self.dcx().emit_err(ColonAsSemi { span: self.token.span });
1950            self.bump();
1951            return true;
1952        }
1953
1954        false
1955    }
1956
1957    /// Consumes alternative await syntaxes like `await!(<expr>)`, `await <expr>`,
1958    /// `await? <expr>`, `await(<expr>)`, and `await { <expr> }`.
1959    pub(super) fn recover_incorrect_await_syntax(
1960        &mut self,
1961        await_sp: Span,
1962    ) -> PResult<'a, P<Expr>> {
1963        let (hi, expr, is_question) = if self.token == token::Bang {
1964            // Handle `await!(<expr>)`.
1965            self.recover_await_macro()?
1966        } else {
1967            self.recover_await_prefix(await_sp)?
1968        };
1969        let (sp, guar) = self.error_on_incorrect_await(await_sp, hi, &expr, is_question);
1970        let expr = self.mk_expr_err(await_sp.to(sp), guar);
1971        self.maybe_recover_from_bad_qpath(expr)
1972    }
1973
1974    fn recover_await_macro(&mut self) -> PResult<'a, (Span, P<Expr>, bool)> {
1975        self.expect(exp!(Bang))?;
1976        self.expect(exp!(OpenParen))?;
1977        let expr = self.parse_expr()?;
1978        self.expect(exp!(CloseParen))?;
1979        Ok((self.prev_token.span, expr, false))
1980    }
1981
1982    fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, P<Expr>, bool)> {
1983        let is_question = self.eat(exp!(Question)); // Handle `await? <expr>`.
1984        let expr = if self.token == token::OpenBrace {
1985            // Handle `await { <expr> }`.
1986            // This needs to be handled separately from the next arm to avoid
1987            // interpreting `await { <expr> }?` as `<expr>?.await`.
1988            self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)
1989        } else {
1990            self.parse_expr()
1991        }
1992        .map_err(|mut err| {
1993            err.span_label(await_sp, format!("while parsing this incorrect await expression"));
1994            err
1995        })?;
1996        Ok((expr.span, expr, is_question))
1997    }
1998
1999    fn error_on_incorrect_await(
2000        &self,
2001        lo: Span,
2002        hi: Span,
2003        expr: &Expr,
2004        is_question: bool,
2005    ) -> (Span, ErrorGuaranteed) {
2006        let span = lo.to(hi);
2007        let guar = self.dcx().emit_err(IncorrectAwait {
2008            span,
2009            suggestion: AwaitSuggestion {
2010                removal: lo.until(expr.span),
2011                dot_await: expr.span.shrink_to_hi(),
2012                question_mark: if is_question { "?" } else { "" },
2013            },
2014        });
2015        (span, guar)
2016    }
2017
2018    /// If encountering `future.await()`, consumes and emits an error.
2019    pub(super) fn recover_from_await_method_call(&mut self) {
2020        if self.token == token::OpenParen && self.look_ahead(1, |t| t == &token::CloseParen) {
2021            // future.await()
2022            let lo = self.token.span;
2023            self.bump(); // (
2024            let span = lo.to(self.token.span);
2025            self.bump(); // )
2026
2027            self.dcx().emit_err(IncorrectUseOfAwait { span });
2028        }
2029    }
2030    ///
2031    /// If encountering `x.use()`, consumes and emits an error.
2032    pub(super) fn recover_from_use(&mut self) {
2033        if self.token == token::OpenParen && self.look_ahead(1, |t| t == &token::CloseParen) {
2034            // var.use()
2035            let lo = self.token.span;
2036            self.bump(); // (
2037            let span = lo.to(self.token.span);
2038            self.bump(); // )
2039
2040            self.dcx().emit_err(IncorrectUseOfUse { span });
2041        }
2042    }
2043
2044    pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P<Expr>> {
2045        let is_try = self.token.is_keyword(kw::Try);
2046        let is_questionmark = self.look_ahead(1, |t| t == &token::Bang); //check for !
2047        let is_open = self.look_ahead(2, |t| t == &token::OpenParen); //check for (
2048
2049        if is_try && is_questionmark && is_open {
2050            let lo = self.token.span;
2051            self.bump(); //remove try
2052            self.bump(); //remove !
2053            let try_span = lo.to(self.token.span); //we take the try!( span
2054            self.bump(); //remove (
2055            let is_empty = self.token == token::CloseParen; //check if the block is empty
2056            self.consume_block(exp!(OpenParen), exp!(CloseParen), ConsumeClosingDelim::No); //eat the block
2057            let hi = self.token.span;
2058            self.bump(); //remove )
2059            let mut err = self.dcx().struct_span_err(lo.to(hi), "use of deprecated `try` macro");
2060            err.note("in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated");
2061            let prefix = if is_empty { "" } else { "alternatively, " };
2062            if !is_empty {
2063                err.multipart_suggestion(
2064                    "you can use the `?` operator instead",
2065                    vec![(try_span, "".to_owned()), (hi, "?".to_owned())],
2066                    Applicability::MachineApplicable,
2067                );
2068            }
2069            err.span_suggestion(lo.shrink_to_lo(), format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable);
2070            let guar = err.emit();
2071            Ok(self.mk_expr_err(lo.to(hi), guar))
2072        } else {
2073            Err(self.expected_expression_found()) // The user isn't trying to invoke the try! macro
2074        }
2075    }
2076
2077    /// When trying to close a generics list and encountering code like
2078    /// ```text
2079    /// impl<S: Into<std::borrow::Cow<'static, str>> From<S> for Canonical {}
2080    ///                                          // ^ missing > here
2081    /// ```
2082    /// we provide a structured suggestion on the error from `expect_gt`.
2083    pub(super) fn expect_gt_or_maybe_suggest_closing_generics(
2084        &mut self,
2085        params: &[ast::GenericParam],
2086    ) -> PResult<'a, ()> {
2087        let Err(mut err) = self.expect_gt() else {
2088            return Ok(());
2089        };
2090        // Attempt to find places where a missing `>` might belong.
2091        if let [.., ast::GenericParam { bounds, .. }] = params
2092            && let Some(poly) = bounds
2093                .iter()
2094                .filter_map(|bound| match bound {
2095                    ast::GenericBound::Trait(poly) => Some(poly),
2096                    _ => None,
2097                })
2098                .next_back()
2099        {
2100            err.span_suggestion_verbose(
2101                poly.span.shrink_to_hi(),
2102                "you might have meant to end the type parameters here",
2103                ">",
2104                Applicability::MaybeIncorrect,
2105            );
2106        }
2107        Err(err)
2108    }
2109
2110    pub(super) fn recover_seq_parse_error(
2111        &mut self,
2112        open: ExpTokenPair<'_>,
2113        close: ExpTokenPair<'_>,
2114        lo: Span,
2115        err: Diag<'a>,
2116    ) -> P<Expr> {
2117        let guar = err.emit();
2118        // Recover from parse error, callers expect the closing delim to be consumed.
2119        self.consume_block(open, close, ConsumeClosingDelim::Yes);
2120        self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err(guar))
2121    }
2122
2123    /// Eats tokens until we can be relatively sure we reached the end of the
2124    /// statement. This is something of a best-effort heuristic.
2125    ///
2126    /// We terminate when we find an unmatched `}` (without consuming it).
2127    pub(super) fn recover_stmt(&mut self) {
2128        self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore)
2129    }
2130
2131    /// If `break_on_semi` is `Break`, then we will stop consuming tokens after
2132    /// finding (and consuming) a `;` outside of `{}` or `[]` (note that this is
2133    /// approximate -- it can mean we break too early due to macros, but that
2134    /// should only lead to sub-optimal recovery, not inaccurate parsing).
2135    ///
2136    /// If `break_on_block` is `Break`, then we will stop consuming tokens
2137    /// after finding (and consuming) a brace-delimited block.
2138    pub(super) fn recover_stmt_(
2139        &mut self,
2140        break_on_semi: SemiColonMode,
2141        break_on_block: BlockMode,
2142    ) {
2143        let mut brace_depth = 0;
2144        let mut bracket_depth = 0;
2145        let mut in_block = false;
2146        debug!("recover_stmt_ enter loop (semi={:?}, block={:?})", break_on_semi, break_on_block);
2147        loop {
2148            debug!("recover_stmt_ loop {:?}", self.token);
2149            match self.token.kind {
2150                token::OpenBrace => {
2151                    brace_depth += 1;
2152                    self.bump();
2153                    if break_on_block == BlockMode::Break && brace_depth == 1 && bracket_depth == 0
2154                    {
2155                        in_block = true;
2156                    }
2157                }
2158                token::OpenBracket => {
2159                    bracket_depth += 1;
2160                    self.bump();
2161                }
2162                token::CloseBrace => {
2163                    if brace_depth == 0 {
2164                        debug!("recover_stmt_ return - close delim {:?}", self.token);
2165                        break;
2166                    }
2167                    brace_depth -= 1;
2168                    self.bump();
2169                    if in_block && bracket_depth == 0 && brace_depth == 0 {
2170                        debug!("recover_stmt_ return - block end {:?}", self.token);
2171                        break;
2172                    }
2173                }
2174                token::CloseBracket => {
2175                    bracket_depth -= 1;
2176                    if bracket_depth < 0 {
2177                        bracket_depth = 0;
2178                    }
2179                    self.bump();
2180                }
2181                token::Eof => {
2182                    debug!("recover_stmt_ return - Eof");
2183                    break;
2184                }
2185                token::Semi => {
2186                    self.bump();
2187                    if break_on_semi == SemiColonMode::Break
2188                        && brace_depth == 0
2189                        && bracket_depth == 0
2190                    {
2191                        debug!("recover_stmt_ return - Semi");
2192                        break;
2193                    }
2194                }
2195                token::Comma
2196                    if break_on_semi == SemiColonMode::Comma
2197                        && brace_depth == 0
2198                        && bracket_depth == 0 =>
2199                {
2200                    break;
2201                }
2202                _ => self.bump(),
2203            }
2204        }
2205    }
2206
2207    pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) {
2208        if self.eat_keyword(exp!(In)) {
2209            // a common typo: `for _ in in bar {}`
2210            self.dcx().emit_err(InInTypo {
2211                span: self.prev_token.span,
2212                sugg_span: in_span.until(self.prev_token.span),
2213            });
2214        }
2215    }
2216
2217    pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
2218        if let token::DocComment(..) = self.token.kind {
2219            self.dcx().emit_err(DocCommentOnParamType { span: self.token.span });
2220            self.bump();
2221        } else if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) {
2222            let lo = self.token.span;
2223            // Skip every token until next possible arg.
2224            while self.token != token::CloseBracket {
2225                self.bump();
2226            }
2227            let sp = lo.to(self.token.span);
2228            self.bump();
2229            self.dcx().emit_err(AttributeOnParamType { span: sp });
2230        }
2231    }
2232
2233    pub(super) fn parameter_without_type(
2234        &mut self,
2235        err: &mut Diag<'_>,
2236        pat: P<ast::Pat>,
2237        require_name: bool,
2238        first_param: bool,
2239    ) -> Option<Ident> {
2240        // If we find a pattern followed by an identifier, it could be an (incorrect)
2241        // C-style parameter declaration.
2242        if self.check_ident()
2243            && self.look_ahead(1, |t| *t == token::Comma || *t == token::CloseParen)
2244        {
2245            // `fn foo(String s) {}`
2246            let ident = self.parse_ident().unwrap();
2247            let span = pat.span.with_hi(ident.span.hi());
2248
2249            err.span_suggestion(
2250                span,
2251                "declare the type after the parameter binding",
2252                "<identifier>: <type>",
2253                Applicability::HasPlaceholders,
2254            );
2255            return Some(ident);
2256        } else if require_name
2257            && (self.token == token::Comma
2258                || self.token == token::Lt
2259                || self.token == token::CloseParen)
2260        {
2261            let rfc_note = "anonymous parameters are removed in the 2018 edition (see RFC 1685)";
2262
2263            let (ident, self_sugg, param_sugg, type_sugg, self_span, param_span, type_span) =
2264                match pat.kind {
2265                    PatKind::Ident(_, ident, _) => (
2266                        ident,
2267                        "self: ",
2268                        ": TypeName".to_string(),
2269                        "_: ",
2270                        pat.span.shrink_to_lo(),
2271                        pat.span.shrink_to_hi(),
2272                        pat.span.shrink_to_lo(),
2273                    ),
2274                    // Also catches `fn foo(&a)`.
2275                    PatKind::Ref(ref inner_pat, mutab)
2276                        if matches!(inner_pat.clone().into_inner().kind, PatKind::Ident(..)) =>
2277                    {
2278                        match inner_pat.clone().into_inner().kind {
2279                            PatKind::Ident(_, ident, _) => {
2280                                let mutab = mutab.prefix_str();
2281                                (
2282                                    ident,
2283                                    "self: ",
2284                                    format!("{ident}: &{mutab}TypeName"),
2285                                    "_: ",
2286                                    pat.span.shrink_to_lo(),
2287                                    pat.span,
2288                                    pat.span.shrink_to_lo(),
2289                                )
2290                            }
2291                            _ => unreachable!(),
2292                        }
2293                    }
2294                    _ => {
2295                        // Otherwise, try to get a type and emit a suggestion.
2296                        if let Some(_) = pat.to_ty() {
2297                            err.span_suggestion_verbose(
2298                                pat.span.shrink_to_lo(),
2299                                "explicitly ignore the parameter name",
2300                                "_: ".to_string(),
2301                                Applicability::MachineApplicable,
2302                            );
2303                            err.note(rfc_note);
2304                        }
2305
2306                        return None;
2307                    }
2308                };
2309
2310            // `fn foo(a, b) {}`, `fn foo(a<x>, b<y>) {}` or `fn foo(usize, usize) {}`
2311            if first_param {
2312                err.span_suggestion_verbose(
2313                    self_span,
2314                    "if this is a `self` type, give it a parameter name",
2315                    self_sugg,
2316                    Applicability::MaybeIncorrect,
2317                );
2318            }
2319            // Avoid suggesting that `fn foo(HashMap<u32>)` is fixed with a change to
2320            // `fn foo(HashMap: TypeName<u32>)`.
2321            if self.token != token::Lt {
2322                err.span_suggestion_verbose(
2323                    param_span,
2324                    "if this is a parameter name, give it a type",
2325                    param_sugg,
2326                    Applicability::HasPlaceholders,
2327                );
2328            }
2329            err.span_suggestion_verbose(
2330                type_span,
2331                "if this is a type, explicitly ignore the parameter name",
2332                type_sugg,
2333                Applicability::MachineApplicable,
2334            );
2335            err.note(rfc_note);
2336
2337            // Don't attempt to recover by using the `X` in `X<Y>` as the parameter name.
2338            return if self.token == token::Lt { None } else { Some(ident) };
2339        }
2340        None
2341    }
2342
2343    pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
2344        let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName), None)?;
2345        self.expect(exp!(Colon))?;
2346        let ty = self.parse_ty()?;
2347
2348        self.dcx().emit_err(PatternMethodParamWithoutBody { span: pat.span });
2349
2350        // Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
2351        let pat =
2352            P(Pat { kind: PatKind::Wild, span: pat.span, id: ast::DUMMY_NODE_ID, tokens: None });
2353        Ok((pat, ty))
2354    }
2355
2356    pub(super) fn recover_bad_self_param(&mut self, mut param: Param) -> PResult<'a, Param> {
2357        let span = param.pat.span;
2358        let guar = self.dcx().emit_err(SelfParamNotFirst { span });
2359        param.ty.kind = TyKind::Err(guar);
2360        Ok(param)
2361    }
2362
2363    pub(super) fn consume_block(
2364        &mut self,
2365        open: ExpTokenPair<'_>,
2366        close: ExpTokenPair<'_>,
2367        consume_close: ConsumeClosingDelim,
2368    ) {
2369        let mut brace_depth = 0;
2370        loop {
2371            if self.eat(open) {
2372                brace_depth += 1;
2373            } else if self.check(close) {
2374                if brace_depth == 0 {
2375                    if let ConsumeClosingDelim::Yes = consume_close {
2376                        // Some of the callers of this method expect to be able to parse the
2377                        // closing delimiter themselves, so we leave it alone. Otherwise we advance
2378                        // the parser.
2379                        self.bump();
2380                    }
2381                    return;
2382                } else {
2383                    self.bump();
2384                    brace_depth -= 1;
2385                    continue;
2386                }
2387            } else if self.token == token::Eof {
2388                return;
2389            } else {
2390                self.bump();
2391            }
2392        }
2393    }
2394
2395    pub(super) fn expected_expression_found(&self) -> Diag<'a> {
2396        let (span, msg) = match (&self.token.kind, self.subparser_name) {
2397            (&token::Eof, Some(origin)) => {
2398                let sp = self.prev_token.span.shrink_to_hi();
2399                (sp, format!("expected expression, found end of {origin}"))
2400            }
2401            _ => (
2402                self.token.span,
2403                format!("expected expression, found {}", super::token_descr(&self.token)),
2404            ),
2405        };
2406        let mut err = self.dcx().struct_span_err(span, msg);
2407        let sp = self.psess.source_map().start_point(self.token.span);
2408        if let Some(sp) = self.psess.ambiguous_block_expr_parse.borrow().get(&sp) {
2409            err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
2410        }
2411        err.span_label(span, "expected expression");
2412        err
2413    }
2414
2415    fn consume_tts(
2416        &mut self,
2417        mut acc: i64, // `i64` because malformed code can have more closing delims than opening.
2418        // Not using `FxHashMap` due to `token::TokenKind: !Eq + !Hash`.
2419        modifier: &[(token::TokenKind, i64)],
2420    ) {
2421        while acc > 0 {
2422            if let Some((_, val)) = modifier.iter().find(|(t, _)| self.token == *t) {
2423                acc += *val;
2424            }
2425            if self.token == token::Eof {
2426                break;
2427            }
2428            self.bump();
2429        }
2430    }
2431
2432    /// Replace duplicated recovered parameters with `_` pattern to avoid unnecessary errors.
2433    ///
2434    /// This is necessary because at this point we don't know whether we parsed a function with
2435    /// anonymous parameters or a function with names but no types. In order to minimize
2436    /// unnecessary errors, we assume the parameters are in the shape of `fn foo(a, b, c)` where
2437    /// the parameters are *names* (so we don't emit errors about not being able to find `b` in
2438    /// the local scope), but if we find the same name multiple times, like in `fn foo(i8, i8)`,
2439    /// we deduplicate them to not complain about duplicated parameter names.
2440    pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut ThinVec<Param>) {
2441        let mut seen_inputs = FxHashSet::default();
2442        for input in fn_inputs.iter_mut() {
2443            let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err(_)) =
2444                (&input.pat.kind, &input.ty.kind)
2445            {
2446                Some(*ident)
2447            } else {
2448                None
2449            };
2450            if let Some(ident) = opt_ident {
2451                if seen_inputs.contains(&ident) {
2452                    input.pat.kind = PatKind::Wild;
2453                }
2454                seen_inputs.insert(ident);
2455            }
2456        }
2457    }
2458
2459    /// Handle encountering a symbol in a generic argument list that is not a `,` or `>`. In this
2460    /// case, we emit an error and try to suggest enclosing a const argument in braces if it looks
2461    /// like the user has forgotten them.
2462    pub(super) fn handle_ambiguous_unbraced_const_arg(
2463        &mut self,
2464        args: &mut ThinVec<AngleBracketedArg>,
2465    ) -> PResult<'a, bool> {
2466        // If we haven't encountered a closing `>`, then the argument is malformed.
2467        // It's likely that the user has written a const expression without enclosing it
2468        // in braces, so we try to recover here.
2469        let arg = args.pop().unwrap();
2470        // FIXME: for some reason using `unexpected` or `expected_one_of_not_found` has
2471        // adverse side-effects to subsequent errors and seems to advance the parser.
2472        // We are causing this error here exclusively in case that a `const` expression
2473        // could be recovered from the current parser state, even if followed by more
2474        // arguments after a comma.
2475        let mut err = self.dcx().struct_span_err(
2476            self.token.span,
2477            format!("expected one of `,` or `>`, found {}", super::token_descr(&self.token)),
2478        );
2479        err.span_label(self.token.span, "expected one of `,` or `>`");
2480        match self.recover_const_arg(arg.span(), err) {
2481            Ok(arg) => {
2482                args.push(AngleBracketedArg::Arg(arg));
2483                if self.eat(exp!(Comma)) {
2484                    return Ok(true); // Continue
2485                }
2486            }
2487            Err(err) => {
2488                args.push(arg);
2489                // We will emit a more generic error later.
2490                err.delay_as_bug();
2491            }
2492        }
2493        Ok(false) // Don't continue.
2494    }
2495
2496    /// Attempt to parse a generic const argument that has not been enclosed in braces.
2497    /// There are a limited number of expressions that are permitted without being encoded
2498    /// in braces:
2499    /// - Literals.
2500    /// - Single-segment paths (i.e. standalone generic const parameters).
2501    /// All other expressions that can be parsed will emit an error suggesting the expression be
2502    /// wrapped in braces.
2503    pub(super) fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P<Expr>> {
2504        let start = self.token.span;
2505        let attrs = self.parse_outer_attributes()?;
2506        let (expr, _) =
2507            self.parse_expr_res(Restrictions::CONST_EXPR, attrs).map_err(|mut err| {
2508                err.span_label(
2509                    start.shrink_to_lo(),
2510                    "while parsing a const generic argument starting here",
2511                );
2512                err
2513            })?;
2514        if !self.expr_is_valid_const_arg(&expr) {
2515            self.dcx().emit_err(ConstGenericWithoutBraces {
2516                span: expr.span,
2517                sugg: ConstGenericWithoutBracesSugg {
2518                    left: expr.span.shrink_to_lo(),
2519                    right: expr.span.shrink_to_hi(),
2520                },
2521            });
2522        }
2523        Ok(expr)
2524    }
2525
2526    fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option<GenericArg> {
2527        let snapshot = self.create_snapshot_for_diagnostic();
2528        let param = match self.parse_const_param(AttrVec::new()) {
2529            Ok(param) => param,
2530            Err(err) => {
2531                err.cancel();
2532                self.restore_snapshot(snapshot);
2533                return None;
2534            }
2535        };
2536
2537        let ident = param.ident.to_string();
2538        let sugg = match (ty_generics, self.psess.source_map().span_to_snippet(param.span())) {
2539            (Some(Generics { params, span: impl_generics, .. }), Ok(snippet)) => {
2540                Some(match &params[..] {
2541                    [] => UnexpectedConstParamDeclarationSugg::AddParam {
2542                        impl_generics: *impl_generics,
2543                        incorrect_decl: param.span(),
2544                        snippet,
2545                        ident,
2546                    },
2547                    [.., generic] => UnexpectedConstParamDeclarationSugg::AppendParam {
2548                        impl_generics_end: generic.span().shrink_to_hi(),
2549                        incorrect_decl: param.span(),
2550                        snippet,
2551                        ident,
2552                    },
2553                })
2554            }
2555            _ => None,
2556        };
2557        let guar =
2558            self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg });
2559
2560        let value = self.mk_expr_err(param.span(), guar);
2561        Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }))
2562    }
2563
2564    pub(super) fn recover_const_param_declaration(
2565        &mut self,
2566        ty_generics: Option<&Generics>,
2567    ) -> PResult<'a, Option<GenericArg>> {
2568        // We have to check for a few different cases.
2569        if let Some(arg) = self.recover_const_param_decl(ty_generics) {
2570            return Ok(Some(arg));
2571        }
2572
2573        // We haven't consumed `const` yet.
2574        let start = self.token.span;
2575        self.bump(); // `const`
2576
2577        // Detect and recover from the old, pre-RFC2000 syntax for const generics.
2578        let mut err = UnexpectedConstInGenericParam { span: start, to_remove: None };
2579        if self.check_const_arg() {
2580            err.to_remove = Some(start.until(self.token.span));
2581            self.dcx().emit_err(err);
2582            Ok(Some(GenericArg::Const(self.parse_const_arg()?)))
2583        } else {
2584            let after_kw_const = self.token.span;
2585            self.recover_const_arg(after_kw_const, self.dcx().create_err(err)).map(Some)
2586        }
2587    }
2588
2589    /// Try to recover from possible generic const argument without `{` and `}`.
2590    ///
2591    /// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest
2592    /// `foo::<{ bar + 3 }>` and `foo::<{ bar - baz }>`, respectively. We only provide a suggestion
2593    /// if we think that the resulting expression would be well formed.
2594    pub(super) fn recover_const_arg(
2595        &mut self,
2596        start: Span,
2597        mut err: Diag<'a>,
2598    ) -> PResult<'a, GenericArg> {
2599        let is_op_or_dot = AssocOp::from_token(&self.token)
2600            .and_then(|op| {
2601                if let AssocOp::Binary(
2602                    BinOpKind::Gt
2603                    | BinOpKind::Lt
2604                    | BinOpKind::Shr
2605                    | BinOpKind::Ge
2606                )
2607                // Don't recover from `foo::<bar = baz>`, because this could be an attempt to
2608                // assign a value to a defaulted generic parameter.
2609                | AssocOp::Assign
2610                | AssocOp::AssignOp(_) = op
2611                {
2612                    None
2613                } else {
2614                    Some(op)
2615                }
2616            })
2617            .is_some()
2618            || self.token == TokenKind::Dot;
2619        // This will be true when a trait object type `Foo +` or a path which was a `const fn` with
2620        // type params has been parsed.
2621        let was_op = matches!(self.prev_token.kind, token::Plus | token::Shr | token::Gt);
2622        if !is_op_or_dot && !was_op {
2623            // We perform these checks and early return to avoid taking a snapshot unnecessarily.
2624            return Err(err);
2625        }
2626        let snapshot = self.create_snapshot_for_diagnostic();
2627        if is_op_or_dot {
2628            self.bump();
2629        }
2630        match (|| {
2631            let attrs = self.parse_outer_attributes()?;
2632            self.parse_expr_res(Restrictions::CONST_EXPR, attrs)
2633        })() {
2634            Ok((expr, _)) => {
2635                // Find a mistake like `MyTrait<Assoc == S::Assoc>`.
2636                if snapshot.token == token::EqEq {
2637                    err.span_suggestion(
2638                        snapshot.token.span,
2639                        "if you meant to use an associated type binding, replace `==` with `=`",
2640                        "=",
2641                        Applicability::MaybeIncorrect,
2642                    );
2643                    let guar = err.emit();
2644                    let value = self.mk_expr_err(start.to(expr.span), guar);
2645                    return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }));
2646                } else if snapshot.token == token::Colon
2647                    && expr.span.lo() == snapshot.token.span.hi()
2648                    && matches!(expr.kind, ExprKind::Path(..))
2649                {
2650                    // Find a mistake like "foo::var:A".
2651                    err.span_suggestion(
2652                        snapshot.token.span,
2653                        "write a path separator here",
2654                        "::",
2655                        Applicability::MaybeIncorrect,
2656                    );
2657                    let guar = err.emit();
2658                    return Ok(GenericArg::Type(
2659                        self.mk_ty(start.to(expr.span), TyKind::Err(guar)),
2660                    ));
2661                } else if self.token == token::Comma || self.token.kind.should_end_const_arg() {
2662                    // Avoid the following output by checking that we consumed a full const arg:
2663                    // help: expressions must be enclosed in braces to be used as const generic
2664                    //       arguments
2665                    //    |
2666                    // LL |     let sr: Vec<{ (u32, _, _) = vec![] };
2667                    //    |                 ^                      ^
2668                    return Ok(self.dummy_const_arg_needs_braces(err, start.to(expr.span)));
2669                }
2670            }
2671            Err(err) => {
2672                err.cancel();
2673            }
2674        }
2675        self.restore_snapshot(snapshot);
2676        Err(err)
2677    }
2678
2679    /// Try to recover from an unbraced const argument whose first token [could begin a type][ty].
2680    ///
2681    /// [ty]: token::Token::can_begin_type
2682    pub(crate) fn recover_unbraced_const_arg_that_can_begin_ty(
2683        &mut self,
2684        mut snapshot: SnapshotParser<'a>,
2685    ) -> Option<P<ast::Expr>> {
2686        match (|| {
2687            let attrs = self.parse_outer_attributes()?;
2688            snapshot.parse_expr_res(Restrictions::CONST_EXPR, attrs)
2689        })() {
2690            // Since we don't know the exact reason why we failed to parse the type or the
2691            // expression, employ a simple heuristic to weed out some pathological cases.
2692            Ok((expr, _)) if let token::Comma | token::Gt = snapshot.token.kind => {
2693                self.restore_snapshot(snapshot);
2694                Some(expr)
2695            }
2696            Ok(_) => None,
2697            Err(err) => {
2698                err.cancel();
2699                None
2700            }
2701        }
2702    }
2703
2704    /// Creates a dummy const argument, and reports that the expression must be enclosed in braces
2705    pub(super) fn dummy_const_arg_needs_braces(&self, mut err: Diag<'a>, span: Span) -> GenericArg {
2706        err.multipart_suggestion(
2707            "expressions must be enclosed in braces to be used as const generic \
2708             arguments",
2709            vec![(span.shrink_to_lo(), "{ ".to_string()), (span.shrink_to_hi(), " }".to_string())],
2710            Applicability::MaybeIncorrect,
2711        );
2712        let guar = err.emit();
2713        let value = self.mk_expr_err(span, guar);
2714        GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
2715    }
2716
2717    /// Some special error handling for the "top-level" patterns in a match arm,
2718    /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
2719    pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
2720        &mut self,
2721        mut first_pat: P<Pat>,
2722        expected: Option<Expected>,
2723    ) -> P<Pat> {
2724        if token::Colon != self.token.kind {
2725            return first_pat;
2726        }
2727        if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
2728            || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
2729        {
2730            let mut snapshot_type = self.create_snapshot_for_diagnostic();
2731            snapshot_type.bump(); // `:`
2732            match snapshot_type.parse_ty() {
2733                Err(inner_err) => {
2734                    inner_err.cancel();
2735                }
2736                Ok(ty) => {
2737                    let Err(mut err) = self.expected_one_of_not_found(&[], &[]) else {
2738                        return first_pat;
2739                    };
2740                    err.span_label(ty.span, "specifying the type of a pattern isn't supported");
2741                    self.restore_snapshot(snapshot_type);
2742                    let span = first_pat.span.to(ty.span);
2743                    first_pat = self.mk_pat(span, PatKind::Wild);
2744                    err.emit();
2745                }
2746            }
2747            return first_pat;
2748        }
2749        // The pattern looks like it might be a path with a `::` -> `:` typo:
2750        // `match foo { bar:baz => {} }`
2751        let colon_span = self.token.span;
2752        // We only emit "unexpected `:`" error here if we can successfully parse the
2753        // whole pattern correctly in that case.
2754        let mut snapshot_pat = self.create_snapshot_for_diagnostic();
2755        let mut snapshot_type = self.create_snapshot_for_diagnostic();
2756
2757        // Create error for "unexpected `:`".
2758        match self.expected_one_of_not_found(&[], &[]) {
2759            Err(mut err) => {
2760                // Skip the `:`.
2761                snapshot_pat.bump();
2762                snapshot_type.bump();
2763                match snapshot_pat.parse_pat_no_top_alt(expected, None) {
2764                    Err(inner_err) => {
2765                        inner_err.cancel();
2766                    }
2767                    Ok(mut pat) => {
2768                        // We've parsed the rest of the pattern.
2769                        let new_span = first_pat.span.to(pat.span);
2770                        let mut show_sugg = false;
2771                        // Try to construct a recovered pattern.
2772                        match &mut pat.kind {
2773                            PatKind::Struct(qself @ None, path, ..)
2774                            | PatKind::TupleStruct(qself @ None, path, _)
2775                            | PatKind::Path(qself @ None, path) => match &first_pat.kind {
2776                                PatKind::Ident(_, ident, _) => {
2777                                    path.segments.insert(0, PathSegment::from_ident(*ident));
2778                                    path.span = new_span;
2779                                    show_sugg = true;
2780                                    first_pat = pat;
2781                                }
2782                                PatKind::Path(old_qself, old_path) => {
2783                                    path.segments = old_path
2784                                        .segments
2785                                        .iter()
2786                                        .cloned()
2787                                        .chain(take(&mut path.segments))
2788                                        .collect();
2789                                    path.span = new_span;
2790                                    *qself = old_qself.clone();
2791                                    first_pat = pat;
2792                                    show_sugg = true;
2793                                }
2794                                _ => {}
2795                            },
2796                            PatKind::Ident(BindingMode::NONE, ident, None) => {
2797                                match &first_pat.kind {
2798                                    PatKind::Ident(_, old_ident, _) => {
2799                                        let path = PatKind::Path(
2800                                            None,
2801                                            Path {
2802                                                span: new_span,
2803                                                segments: thin_vec![
2804                                                    PathSegment::from_ident(*old_ident),
2805                                                    PathSegment::from_ident(*ident),
2806                                                ],
2807                                                tokens: None,
2808                                            },
2809                                        );
2810                                        first_pat = self.mk_pat(new_span, path);
2811                                        show_sugg = true;
2812                                    }
2813                                    PatKind::Path(old_qself, old_path) => {
2814                                        let mut segments = old_path.segments.clone();
2815                                        segments.push(PathSegment::from_ident(*ident));
2816                                        let path = PatKind::Path(
2817                                            old_qself.clone(),
2818                                            Path { span: new_span, segments, tokens: None },
2819                                        );
2820                                        first_pat = self.mk_pat(new_span, path);
2821                                        show_sugg = true;
2822                                    }
2823                                    _ => {}
2824                                }
2825                            }
2826                            _ => {}
2827                        }
2828                        if show_sugg {
2829                            err.span_suggestion_verbose(
2830                                colon_span.until(self.look_ahead(1, |t| t.span)),
2831                                "maybe write a path separator here",
2832                                "::",
2833                                Applicability::MaybeIncorrect,
2834                            );
2835                        } else {
2836                            first_pat = self.mk_pat(new_span, PatKind::Wild);
2837                        }
2838                        self.restore_snapshot(snapshot_pat);
2839                    }
2840                }
2841                match snapshot_type.parse_ty() {
2842                    Err(inner_err) => {
2843                        inner_err.cancel();
2844                    }
2845                    Ok(ty) => {
2846                        err.span_label(ty.span, "specifying the type of a pattern isn't supported");
2847                        self.restore_snapshot(snapshot_type);
2848                        let new_span = first_pat.span.to(ty.span);
2849                        first_pat = self.mk_pat(new_span, PatKind::Wild);
2850                    }
2851                }
2852                err.emit();
2853            }
2854            _ => {
2855                // Carry on as if we had not done anything. This should be unreachable.
2856            }
2857        };
2858        first_pat
2859    }
2860
2861    /// If `loop_header` is `Some` and an unexpected block label is encountered,
2862    /// it is suggested to be moved just before `loop_header`, else it is suggested to be removed.
2863    pub(crate) fn maybe_recover_unexpected_block_label(
2864        &mut self,
2865        loop_header: Option<Span>,
2866    ) -> bool {
2867        // Check for `'a : {`
2868        if !(self.check_lifetime()
2869            && self.look_ahead(1, |t| *t == token::Colon)
2870            && self.look_ahead(2, |t| *t == token::OpenBrace))
2871        {
2872            return false;
2873        }
2874        let label = self.eat_label().expect("just checked if a label exists");
2875        self.bump(); // eat `:`
2876        let span = label.ident.span.to(self.prev_token.span);
2877        let mut diag = self
2878            .dcx()
2879            .struct_span_err(span, "block label not supported here")
2880            .with_span_label(span, "not supported here");
2881        if let Some(loop_header) = loop_header {
2882            diag.multipart_suggestion(
2883                "if you meant to label the loop, move this label before the loop",
2884                vec![
2885                    (label.ident.span.until(self.token.span), String::from("")),
2886                    (loop_header.shrink_to_lo(), format!("{}: ", label.ident)),
2887                ],
2888                Applicability::MachineApplicable,
2889            );
2890        } else {
2891            diag.tool_only_span_suggestion(
2892                label.ident.span.until(self.token.span),
2893                "remove this block label",
2894                "",
2895                Applicability::MachineApplicable,
2896            );
2897        }
2898        diag.emit();
2899        true
2900    }
2901
2902    /// Some special error handling for the "top-level" patterns in a match arm,
2903    /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
2904    pub(crate) fn maybe_recover_unexpected_comma(
2905        &mut self,
2906        lo: Span,
2907        rt: CommaRecoveryMode,
2908    ) -> PResult<'a, ()> {
2909        if self.token != token::Comma {
2910            return Ok(());
2911        }
2912
2913        // An unexpected comma after a top-level pattern is a clue that the
2914        // user (perhaps more accustomed to some other language) forgot the
2915        // parentheses in what should have been a tuple pattern; return a
2916        // suggestion-enhanced error here rather than choking on the comma later.
2917        let comma_span = self.token.span;
2918        self.bump();
2919        if let Err(err) = self.skip_pat_list() {
2920            // We didn't expect this to work anyway; we just wanted to advance to the
2921            // end of the comma-sequence so we know the span to suggest parenthesizing.
2922            err.cancel();
2923        }
2924        let seq_span = lo.to(self.prev_token.span);
2925        let mut err = self.dcx().struct_span_err(comma_span, "unexpected `,` in pattern");
2926        if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
2927            err.multipart_suggestion(
2928                format!(
2929                    "try adding parentheses to match on a tuple{}",
2930                    if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
2931                ),
2932                vec![
2933                    (seq_span.shrink_to_lo(), "(".to_string()),
2934                    (seq_span.shrink_to_hi(), ")".to_string()),
2935                ],
2936                Applicability::MachineApplicable,
2937            );
2938            if let CommaRecoveryMode::EitherTupleOrPipe = rt {
2939                err.span_suggestion(
2940                    seq_span,
2941                    "...or a vertical bar to match on multiple alternatives",
2942                    seq_snippet.replace(',', " |"),
2943                    Applicability::MachineApplicable,
2944                );
2945            }
2946        }
2947        Err(err)
2948    }
2949
2950    pub(crate) fn maybe_recover_bounds_doubled_colon(&mut self, ty: &Ty) -> PResult<'a, ()> {
2951        let TyKind::Path(qself, path) = &ty.kind else { return Ok(()) };
2952        let qself_position = qself.as_ref().map(|qself| qself.position);
2953        for (i, segments) in path.segments.windows(2).enumerate() {
2954            if qself_position.is_some_and(|pos| i < pos) {
2955                continue;
2956            }
2957            if let [a, b] = segments {
2958                let (a_span, b_span) = (a.span(), b.span());
2959                let between_span = a_span.shrink_to_hi().to(b_span.shrink_to_lo());
2960                if self.span_to_snippet(between_span).as_deref() == Ok(":: ") {
2961                    return Err(self.dcx().create_err(DoubleColonInBound {
2962                        span: path.span.shrink_to_hi(),
2963                        between: between_span,
2964                    }));
2965                }
2966            }
2967        }
2968        Ok(())
2969    }
2970
2971    /// Check for exclusive ranges written as `..<`
2972    pub(crate) fn maybe_err_dotdotlt_syntax(&self, maybe_lt: Token, mut err: Diag<'a>) -> Diag<'a> {
2973        if maybe_lt == token::Lt
2974            && (self.expected_token_types.contains(TokenType::Gt)
2975                || matches!(self.token.kind, token::Literal(..)))
2976        {
2977            err.span_suggestion(
2978                maybe_lt.span,
2979                "remove the `<` to write an exclusive range",
2980                "",
2981                Applicability::MachineApplicable,
2982            );
2983        }
2984        err
2985    }
2986
2987    /// This checks if this is a conflict marker, depending of the parameter passed.
2988    ///
2989    /// * `<<<<<<<`
2990    /// * `|||||||`
2991    /// * `=======`
2992    /// * `>>>>>>>`
2993    ///
2994    pub(super) fn is_vcs_conflict_marker(
2995        &mut self,
2996        long_kind: &TokenKind,
2997        short_kind: &TokenKind,
2998    ) -> bool {
2999        (0..3).all(|i| self.look_ahead(i, |tok| tok == long_kind))
3000            && self.look_ahead(3, |tok| tok == short_kind)
3001    }
3002
3003    fn conflict_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> Option<Span> {
3004        if self.is_vcs_conflict_marker(long_kind, short_kind) {
3005            let lo = self.token.span;
3006            for _ in 0..4 {
3007                self.bump();
3008            }
3009            return Some(lo.to(self.prev_token.span));
3010        }
3011        None
3012    }
3013
3014    pub(super) fn recover_vcs_conflict_marker(&mut self) {
3015        // <<<<<<<
3016        let Some(start) = self.conflict_marker(&TokenKind::Shl, &TokenKind::Lt) else {
3017            return;
3018        };
3019        let mut spans = Vec::with_capacity(3);
3020        spans.push(start);
3021        // |||||||
3022        let mut middlediff3 = None;
3023        // =======
3024        let mut middle = None;
3025        // >>>>>>>
3026        let mut end = None;
3027        loop {
3028            if self.token == TokenKind::Eof {
3029                break;
3030            }
3031            if let Some(span) = self.conflict_marker(&TokenKind::OrOr, &TokenKind::Or) {
3032                middlediff3 = Some(span);
3033            }
3034            if let Some(span) = self.conflict_marker(&TokenKind::EqEq, &TokenKind::Eq) {
3035                middle = Some(span);
3036            }
3037            if let Some(span) = self.conflict_marker(&TokenKind::Shr, &TokenKind::Gt) {
3038                spans.push(span);
3039                end = Some(span);
3040                break;
3041            }
3042            self.bump();
3043        }
3044
3045        let mut err = self.dcx().struct_span_fatal(spans, "encountered diff marker");
3046        match middlediff3 {
3047            // We're using diff3
3048            Some(middlediff3) => {
3049                err.span_label(
3050                    start,
3051                    "between this marker and `|||||||` is the code that we're merging into",
3052                );
3053                err.span_label(middlediff3, "between this marker and `=======` is the base code (what the two refs diverged from)");
3054            }
3055            None => {
3056                err.span_label(
3057                    start,
3058                    "between this marker and `=======` is the code that we're merging into",
3059                );
3060            }
3061        };
3062
3063        if let Some(middle) = middle {
3064            err.span_label(middle, "between this marker and `>>>>>>>` is the incoming code");
3065        }
3066        if let Some(end) = end {
3067            err.span_label(end, "this marker concludes the conflict region");
3068        }
3069        err.note(
3070            "conflict markers indicate that a merge was started but could not be completed due \
3071             to merge conflicts\n\
3072             to resolve a conflict, keep only the code you want and then delete the lines \
3073             containing conflict markers",
3074        );
3075        err.help(
3076            "if you're having merge conflicts after pulling new code:\n\
3077             the top section is the code you already had and the bottom section is the remote code\n\
3078             if you're in the middle of a rebase:\n\
3079             the top section is the code being rebased onto and the bottom section is the code \
3080             coming from the current commit being rebased",
3081        );
3082
3083        err.note(
3084            "for an explanation on these markers from the `git` documentation:\n\
3085             visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>",
3086        );
3087
3088        err.emit();
3089    }
3090
3091    /// Parse and throw away a parenthesized comma separated
3092    /// sequence of patterns until `)` is reached.
3093    fn skip_pat_list(&mut self) -> PResult<'a, ()> {
3094        while !self.check(exp!(CloseParen)) {
3095            self.parse_pat_no_top_alt(None, None)?;
3096            if !self.eat(exp!(Comma)) {
3097                return Ok(());
3098            }
3099        }
3100        Ok(())
3101    }
3102}