rustc_parse/parser/
diagnostics.rs

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