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