rustc_parse/parser/
diagnostics.rs

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