1use std::mem::take;
2use std::ops::{Deref, DerefMut};
3
4use ast::token::IdentIsRaw;
5use rustc_ast as ast;
6use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind};
7use rustc_ast::util::parser::AssocOp;
8use rustc_ast::{
9    AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
10    BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind,
11    Path, PathSegment, QSelf, Recovered, Ty, TyKind,
12};
13use rustc_ast_pretty::pprust;
14use rustc_data_structures::fx::FxHashSet;
15use rustc_errors::{
16    Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, PResult, Subdiagnostic, Suggestions,
17    pluralize,
18};
19use rustc_session::errors::ExprParenthesesNeeded;
20use rustc_span::edit_distance::find_best_match_for_name;
21use rustc_span::source_map::Spanned;
22use rustc_span::symbol::used_keywords;
23use rustc_span::{BytePos, DUMMY_SP, Ident, Span, SpanSnippetError, Symbol, kw, sym};
24use thin_vec::{ThinVec, thin_vec};
25use tracing::{debug, trace};
26
27use super::pat::Expected;
28use super::{
29    BlockMode, CommaRecoveryMode, ExpTokenPair, Parser, PathStyle, Restrictions, SemiColonMode,
30    SeqSep, TokenType,
31};
32use crate::errors::{
33    AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType,
34    AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi,
35    ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
36    ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything,
37    DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
38    GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
39    HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
40    IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody,
41    QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
42    StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma,
43    TernaryOperator, TernaryOperatorSuggestion, UnexpectedConstInGenericParam,
44    UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets,
45    UseEqInstead, WrapType,
46};
47use crate::parser::FnContext;
48use crate::parser::attr::InnerAttrPolicy;
49use crate::{exp, fluent_generated as fluent};
50
51pub(super) fn dummy_arg(ident: Ident, guar: ErrorGuaranteed) -> Param {
53    let pat = Box::new(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: Box::new(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<Box<Ty>>;
73    fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self;
74}
75
76impl<T: RecoverQPath> RecoverQPath for Box<T> {
77    const PATH_STYLE: PathStyle = T::PATH_STYLE;
78    fn to_ty(&self) -> Option<Box<Ty>> {
79        T::to_ty(self)
80    }
81    fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self {
82        Box::new(T::recovered(qself, path))
83    }
84}
85
86impl RecoverQPath for Ty {
87    const PATH_STYLE: PathStyle = PathStyle::Type;
88    fn to_ty(&self) -> Option<Box<Ty>> {
89        Some(Box::new(self.clone()))
90    }
91    fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self {
92        Self {
93            span: path.span,
94            kind: TyKind::Path(qself, path),
95            id: ast::DUMMY_NODE_ID,
96            tokens: None,
97        }
98    }
99}
100
101impl RecoverQPath for Pat {
102    const PATH_STYLE: PathStyle = PathStyle::Pat;
103    fn to_ty(&self) -> Option<Box<Ty>> {
104        self.to_ty()
105    }
106    fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self {
107        Self {
108            span: path.span,
109            kind: PatKind::Path(qself, path),
110            id: ast::DUMMY_NODE_ID,
111            tokens: None,
112        }
113    }
114}
115
116impl RecoverQPath for Expr {
117    fn to_ty(&self) -> Option<Box<Ty>> {
118        self.to_ty()
119    }
120    fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self {
121        Self {
122            span: path.span,
123            kind: ExprKind::Path(qself, path),
124            attrs: AttrVec::new(),
125            id: ast::DUMMY_NODE_ID,
126            tokens: None,
127        }
128    }
129}
130
131pub(crate) enum ConsumeClosingDelim {
133    Yes,
134    No,
135}
136
137#[derive(Clone, Copy)]
138pub enum AttemptLocalParseRecovery {
139    Yes,
140    No,
141}
142
143impl AttemptLocalParseRecovery {
144    pub(super) fn yes(&self) -> bool {
145        match self {
146            AttemptLocalParseRecovery::Yes => true,
147            AttemptLocalParseRecovery::No => false,
148        }
149    }
150
151    pub(super) fn no(&self) -> bool {
152        match self {
153            AttemptLocalParseRecovery::Yes => false,
154            AttemptLocalParseRecovery::No => true,
155        }
156    }
157}
158
159#[derive(Debug, Copy, Clone)]
162struct IncDecRecovery {
163    standalone: IsStandalone,
165    op: IncOrDec,
167    fixity: UnaryFixity,
169}
170
171#[derive(Debug, Copy, Clone)]
173enum IsStandalone {
174    Standalone,
176    Subexpr,
178}
179
180#[derive(Debug, Copy, Clone, PartialEq, Eq)]
181enum IncOrDec {
182    Inc,
183    Dec,
184}
185
186#[derive(Debug, Copy, Clone, PartialEq, Eq)]
187enum UnaryFixity {
188    Pre,
189    Post,
190}
191
192impl IncOrDec {
193    fn chr(&self) -> char {
194        match self {
195            Self::Inc => '+',
196            Self::Dec => '-',
197        }
198    }
199
200    fn name(&self) -> &'static str {
201        match self {
202            Self::Inc => "increment",
203            Self::Dec => "decrement",
204        }
205    }
206}
207
208impl std::fmt::Display for UnaryFixity {
209    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210        match self {
211            Self::Pre => write!(f, "prefix"),
212            Self::Post => write!(f, "postfix"),
213        }
214    }
215}
216
217#[derive(Debug, rustc_macros::Subdiagnostic)]
218#[suggestion(
219    parse_misspelled_kw,
220    applicability = "machine-applicable",
221    code = "{similar_kw}",
222    style = "verbose"
223)]
224struct MisspelledKw {
225    similar_kw: String,
226    #[primary_span]
227    span: Span,
228    is_incorrect_case: bool,
229}
230
231fn find_similar_kw(lookup: Ident, candidates: &[Symbol]) -> Option<MisspelledKw> {
233    let lowercase = lookup.name.as_str().to_lowercase();
234    let lowercase_sym = Symbol::intern(&lowercase);
235    if candidates.contains(&lowercase_sym) {
236        Some(MisspelledKw { similar_kw: lowercase, span: lookup.span, is_incorrect_case: true })
237    } else if let Some(similar_sym) = find_best_match_for_name(candidates, lookup.name, None) {
238        Some(MisspelledKw {
239            similar_kw: similar_sym.to_string(),
240            span: lookup.span,
241            is_incorrect_case: false,
242        })
243    } else {
244        None
245    }
246}
247
248struct MultiSugg {
249    msg: String,
250    patches: Vec<(Span, String)>,
251    applicability: Applicability,
252}
253
254impl MultiSugg {
255    fn emit(self, err: &mut Diag<'_>) {
256        err.multipart_suggestion(self.msg, self.patches, self.applicability);
257    }
258
259    fn emit_verbose(self, err: &mut Diag<'_>) {
260        err.multipart_suggestion_verbose(self.msg, self.patches, self.applicability);
261    }
262}
263
264pub struct SnapshotParser<'a> {
268    parser: Parser<'a>,
269}
270
271impl<'a> Deref for SnapshotParser<'a> {
272    type Target = Parser<'a>;
273
274    fn deref(&self) -> &Self::Target {
275        &self.parser
276    }
277}
278
279impl<'a> DerefMut for SnapshotParser<'a> {
280    fn deref_mut(&mut self) -> &mut Self::Target {
281        &mut self.parser
282    }
283}
284
285impl<'a> Parser<'a> {
286    pub fn dcx(&self) -> DiagCtxtHandle<'a> {
287        self.psess.dcx()
288    }
289
290    pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
292        *self = snapshot.parser;
293    }
294
295    pub fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> {
297        let snapshot = self.clone();
298        SnapshotParser { parser: snapshot }
299    }
300
301    pub(super) fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> {
302        self.psess.source_map().span_to_snippet(span)
303    }
304
305    pub(super) fn expected_ident_found(
309        &mut self,
310        recover: bool,
311    ) -> PResult<'a, (Ident, IdentIsRaw)> {
312        let valid_follow = &[
313            TokenKind::Eq,
314            TokenKind::Colon,
315            TokenKind::Comma,
316            TokenKind::Semi,
317            TokenKind::PathSep,
318            TokenKind::OpenBrace,
319            TokenKind::OpenParen,
320            TokenKind::CloseBrace,
321            TokenKind::CloseParen,
322        ];
323        if let TokenKind::DocComment(..) = self.prev_token.kind
324            && valid_follow.contains(&self.token.kind)
325        {
326            let err = self.dcx().create_err(DocCommentDoesNotDocumentAnything {
327                span: self.prev_token.span,
328                missing_comma: None,
329            });
330            return Err(err);
331        }
332
333        let mut recovered_ident = None;
334        let bad_token = self.token;
337
338        let suggest_raw = if let Some((ident, IdentIsRaw::No)) = self.token.ident()
340            && ident.is_raw_guess()
341            && self.look_ahead(1, |t| valid_follow.contains(&t.kind))
342        {
343            recovered_ident = Some((ident, IdentIsRaw::Yes));
344
345            let ident_name = ident.name.to_string();
348
349            Some(SuggEscapeIdentifier { span: ident.span.shrink_to_lo(), ident_name })
350        } else {
351            None
352        };
353
354        let suggest_remove_comma =
355            if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
356                if recover {
357                    self.bump();
358                    recovered_ident = self.ident_or_err(false).ok();
359                };
360
361                Some(SuggRemoveComma { span: bad_token.span })
362            } else {
363                None
364            };
365
366        let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, valid_portion)| {
367            let (invalid, valid) = self.token.span.split_at(len as u32);
368
369            recovered_ident = Some((Ident::new(valid_portion, valid), IdentIsRaw::No));
370
371            HelpIdentifierStartsWithNumber { num_span: invalid }
372        });
373
374        let err = ExpectedIdentifier {
375            span: bad_token.span,
376            token: bad_token,
377            suggest_raw,
378            suggest_remove_comma,
379            help_cannot_start_number,
380        };
381        let mut err = self.dcx().create_err(err);
382
383        if self.token == token::Lt {
387            let valid_prev_keywords =
389                [kw::Fn, kw::Type, kw::Struct, kw::Enum, kw::Union, kw::Trait];
390
391            let maybe_keyword = self.prev_token;
397            if valid_prev_keywords.into_iter().any(|x| maybe_keyword.is_keyword(x)) {
398                match self.parse_generics() {
401                    Ok(generic) => {
402                        if let TokenKind::Ident(symbol, _) = maybe_keyword.kind {
403                            let ident_name = symbol;
404                            if !self.look_ahead(1, |t| *t == token::Lt)
410                                && let Ok(snippet) =
411                                    self.psess.source_map().span_to_snippet(generic.span)
412                            {
413                                err.multipart_suggestion_verbose(
414                                        format!("place the generic parameter name after the {ident_name} name"),
415                                        vec![
416                                            (self.token.span.shrink_to_hi(), snippet),
417                                            (generic.span, String::new())
418                                        ],
419                                        Applicability::MaybeIncorrect,
420                                    );
421                            } else {
422                                err.help(format!(
423                                    "place the generic parameter name after the {ident_name} name"
424                                ));
425                            }
426                        }
427                    }
428                    Err(err) => {
429                        err.cancel();
433                    }
434                }
435            }
436        }
437
438        if let Some(recovered_ident) = recovered_ident
439            && recover
440        {
441            err.emit();
442            Ok(recovered_ident)
443        } else {
444            Err(err)
445        }
446    }
447
448    pub(super) fn expected_ident_found_err(&mut self) -> Diag<'a> {
449        self.expected_ident_found(false).unwrap_err()
450    }
451
452    pub(super) fn is_lit_bad_ident(&mut self) -> Option<(usize, Symbol)> {
458        if let token::Literal(Lit {
462            kind: token::LitKind::Integer | token::LitKind::Float,
463            symbol,
464            suffix: Some(suffix), }) = self.token.kind
466            && rustc_ast::MetaItemLit::from_token(&self.token).is_none()
467        {
468            Some((symbol.as_str().len(), suffix))
469        } else {
470            None
471        }
472    }
473
474    pub(super) fn expected_one_of_not_found(
475        &mut self,
476        edible: &[ExpTokenPair],
477        inedible: &[ExpTokenPair],
478    ) -> PResult<'a, ErrorGuaranteed> {
479        debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
480        fn tokens_to_string(tokens: &[TokenType]) -> String {
481            let mut i = tokens.iter();
482            let b = i.next().map_or_else(String::new, |t| t.to_string());
484            i.enumerate().fold(b, |mut b, (i, a)| {
485                if tokens.len() > 2 && i == tokens.len() - 2 {
486                    b.push_str(", or ");
487                } else if tokens.len() == 2 && i == tokens.len() - 2 {
488                    b.push_str(" or ");
489                } else {
490                    b.push_str(", ");
491                }
492                b.push_str(&a.to_string());
493                b
494            })
495        }
496
497        for exp in edible.iter().chain(inedible.iter()) {
498            self.expected_token_types.insert(exp.token_type);
499        }
500        let mut expected: Vec<_> = self.expected_token_types.iter().collect();
501        expected.sort_by_cached_key(|x| x.to_string());
502        expected.dedup();
503
504        let sm = self.psess.source_map();
505
506        if expected.contains(&TokenType::Semi) {
508            if self.prev_token == token::Question
511                && let Err(e) = self.maybe_recover_from_ternary_operator(None)
512            {
513                return Err(e);
514            }
515
516            if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP {
517                } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) {
519                } else if [token::Comma, token::Colon].contains(&self.token.kind)
521                && self.prev_token == token::CloseParen
522            {
523                } else if self.look_ahead(1, |t| {
532                t == &token::CloseBrace || t.can_begin_expr() && *t != token::Colon
533            }) && [token::Comma, token::Colon].contains(&self.token.kind)
534            {
535                let guar = self.dcx().emit_err(ExpectedSemi {
542                    span: self.token.span,
543                    token: self.token,
544                    unexpected_token_label: None,
545                    sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span),
546                });
547                self.bump();
548                return Ok(guar);
549            } else if self.look_ahead(0, |t| {
550                t == &token::CloseBrace
551                    || ((t.can_begin_expr() || t.can_begin_item())
552                        && t != &token::Semi
553                        && t != &token::Pound)
554                    || (sm.is_multiline(
556                        self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()),
557                    ) && t == &token::Pound)
558            }) && !expected.contains(&TokenType::Comma)
559            {
560                let span = self.prev_token.span.shrink_to_hi();
566                let guar = self.dcx().emit_err(ExpectedSemi {
567                    span,
568                    token: self.token,
569                    unexpected_token_label: Some(self.token.span),
570                    sugg: ExpectedSemiSugg::AddSemi(span),
571                });
572                return Ok(guar);
573            }
574        }
575
576        if self.token == TokenKind::EqEq
577            && self.prev_token.is_ident()
578            && expected.contains(&TokenType::Eq)
579        {
580            return Err(self.dcx().create_err(UseEqInstead { span: self.token.span }));
582        }
583
584        if (self.token.is_keyword(kw::Move) || self.token.is_keyword(kw::Use))
585            && self.prev_token.is_keyword(kw::Async)
586        {
587            let span = self.prev_token.span.to(self.token.span);
589            if self.token.is_keyword(kw::Move) {
590                return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span }));
591            } else {
592                return Err(self.dcx().create_err(AsyncUseBlockIn2015 { span }));
594            }
595        }
596
597        let expect = tokens_to_string(&expected);
598        let actual = super::token_descr(&self.token);
599        let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
600            let fmt = format!("expected one of {expect}, found {actual}");
601            let short_expect = if expected.len() > 6 {
602                format!("{} possible tokens", expected.len())
603            } else {
604                expect
605            };
606            (fmt, (self.prev_token.span.shrink_to_hi(), format!("expected one of {short_expect}")))
607        } else if expected.is_empty() {
608            (
609                format!("unexpected token: {actual}"),
610                (self.prev_token.span, "unexpected token after this".to_string()),
611            )
612        } else {
613            (
614                format!("expected {expect}, found {actual}"),
615                (self.prev_token.span.shrink_to_hi(), format!("expected {expect}")),
616            )
617        };
618        self.last_unexpected_token_span = Some(self.token.span);
619        let mut err = self.dcx().struct_span_err(self.token.span, msg_exp);
621
622        self.label_expected_raw_ref(&mut err);
623
624        if self.token == token::FatArrow
626            && expected.iter().any(|tok| matches!(tok, TokenType::Operator | TokenType::Le))
627            && !expected.iter().any(|tok| matches!(tok, TokenType::FatArrow | TokenType::Comma))
628        {
629            err.span_suggestion(
630                self.token.span,
631                "you might have meant to write a \"greater than or equal to\" comparison",
632                ">=",
633                Applicability::MaybeIncorrect,
634            );
635        }
636
637        if let TokenKind::Ident(symbol, _) = &self.prev_token.kind {
638            if ["def", "fun", "func", "function"].contains(&symbol.as_str()) {
639                err.span_suggestion_short(
640                    self.prev_token.span,
641                    format!("write `fn` instead of `{symbol}` to declare a function"),
642                    "fn",
643                    Applicability::MachineApplicable,
644                );
645            }
646        }
647
648        if let TokenKind::Ident(prev, _) = &self.prev_token.kind
649            && let TokenKind::Ident(cur, _) = &self.token.kind
650        {
651            let concat = Symbol::intern(&format!("{prev}{cur}"));
652            let ident = Ident::new(concat, DUMMY_SP);
653            if ident.is_used_keyword() || ident.is_reserved() || ident.is_raw_guess() {
654                let concat_span = self.prev_token.span.to(self.token.span);
655                err.span_suggestion_verbose(
656                    concat_span,
657                    format!("consider removing the space to spell keyword `{concat}`"),
658                    concat,
659                    Applicability::MachineApplicable,
660                );
661            }
662        }
663
664        if ((self.prev_token == TokenKind::Ident(sym::c, IdentIsRaw::No)
672            && matches!(&self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. })))
673            || (self.prev_token == TokenKind::Ident(sym::cr, IdentIsRaw::No)
674                && matches!(
675                    &self.token.kind,
676                    TokenKind::Literal(token::Lit { kind: token::Str, .. }) | token::Pound
677                )))
678            && self.prev_token.span.hi() == self.token.span.lo()
679            && !self.token.span.at_least_rust_2021()
680        {
681            err.note("you may be trying to write a c-string literal");
682            err.note("c-string literals require Rust 2021 or later");
683            err.subdiagnostic(HelpUseLatestEdition::new());
684        }
685
686        if self.prev_token.is_ident_named(sym::public)
688            && (self.token.can_begin_item() || self.token == TokenKind::OpenParen)
689        {
690            err.span_suggestion_short(
691                self.prev_token.span,
692                "write `pub` instead of `public` to make the item public",
693                "pub",
694                Applicability::MachineApplicable,
695            );
696        }
697
698        if let token::DocComment(kind, style, _) = self.token.kind {
699            if !expected.contains(&TokenType::Comma) {
709                let pos = self.token.span.lo() + BytePos(2);
711                let span = self.token.span.with_lo(pos).with_hi(pos);
712                err.span_suggestion_verbose(
713                    span,
714                    format!(
715                        "add a space before {} to write a regular comment",
716                        match (kind, style) {
717                            (token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`",
718                            (token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`",
719                            (token::CommentKind::Line, ast::AttrStyle::Outer) => "the last `/`",
720                            (token::CommentKind::Block, ast::AttrStyle::Outer) => "the last `*`",
721                        },
722                    ),
723                    " ".to_string(),
724                    Applicability::MaybeIncorrect,
725                );
726            }
727        }
728
729        let sp = if self.token == token::Eof {
730            self.prev_token.span
732        } else {
733            label_sp
734        };
735
736        if self.check_too_many_raw_str_terminators(&mut err) {
737            if expected.contains(&TokenType::Semi) && self.eat(exp!(Semi)) {
738                let guar = err.emit();
739                return Ok(guar);
740            } else {
741                return Err(err);
742            }
743        }
744
745        if self.prev_token.span == DUMMY_SP {
746            err.span_label(self.token.span, label_exp);
749        } else if !sm.is_multiline(self.token.span.shrink_to_hi().until(sp.shrink_to_lo())) {
750            err.span_label(self.token.span, label_exp);
763        } else {
764            err.span_label(sp, label_exp);
765            err.span_label(self.token.span, "unexpected token");
766        }
767
768        if matches!(&err.suggestions, Suggestions::Enabled(list) if list.is_empty()) {
770            self.check_for_misspelled_kw(&mut err, &expected);
771        }
772        Err(err)
773    }
774
775    pub(super) fn label_expected_raw_ref(&mut self, err: &mut Diag<'_>) {
780        if self.prev_token.is_keyword(kw::Raw)
781            && self.expected_token_types.contains(TokenType::KwMut)
782            && self.expected_token_types.contains(TokenType::KwConst)
783            && self.token.can_begin_expr()
784        {
785            err.span_suggestions(
786                self.prev_token.span.shrink_to_hi(),
787                "`&raw` must be followed by `const` or `mut` to be a raw reference expression",
788                [" const".to_string(), " mut".to_string()],
789                Applicability::MaybeIncorrect,
790            );
791        }
792    }
793
794    fn check_for_misspelled_kw(&self, err: &mut Diag<'_>, expected: &[TokenType]) {
797        let Some((curr_ident, _)) = self.token.ident() else {
798            return;
799        };
800        let expected_token_types: &[TokenType] =
801            expected.len().checked_sub(10).map_or(&expected, |index| &expected[index..]);
802        let expected_keywords: Vec<Symbol> =
803            expected_token_types.iter().filter_map(|token| token.is_keyword()).collect();
804
805        if !expected_keywords.is_empty()
810            && !curr_ident.is_used_keyword()
811            && let Some(misspelled_kw) = find_similar_kw(curr_ident, &expected_keywords)
812        {
813            err.subdiagnostic(misspelled_kw);
814            err.seal_suggestions();
817        } else if let Some((prev_ident, _)) = self.prev_token.ident()
818            && !prev_ident.is_used_keyword()
819        {
820            let all_keywords = used_keywords(|| prev_ident.span.edition());
825
826            if let Some(misspelled_kw) = find_similar_kw(prev_ident, &all_keywords) {
831                err.subdiagnostic(misspelled_kw);
832                err.seal_suggestions();
835            }
836        }
837    }
838
839    pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) -> ErrorGuaranteed {
841        let span = self.prev_token.span.shrink_to_hi();
843        let mut err = self.dcx().create_err(ExpectedSemi {
844            span,
845            token: self.token,
846            unexpected_token_label: Some(self.token.span),
847            sugg: ExpectedSemiSugg::AddSemi(span),
848        });
849        let attr_span = match &expr.attrs[..] {
850            [] => unreachable!(),
851            [only] => only.span,
852            [first, rest @ ..] => {
853                for attr in rest {
854                    err.span_label(attr.span, "");
855                }
856                first.span
857            }
858        };
859        err.span_label(
860            attr_span,
861            format!(
862                "only `;` terminated statements or tail expressions are allowed after {}",
863                if expr.attrs.len() == 1 { "this attribute" } else { "these attributes" },
864            ),
865        );
866        if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) {
867            err.span_label(span, "expected `;` here");
873            err.multipart_suggestion(
874                "alternatively, consider surrounding the expression with a block",
875                vec![
876                    (expr.span.shrink_to_lo(), "{ ".to_string()),
877                    (expr.span.shrink_to_hi(), " }".to_string()),
878                ],
879                Applicability::MachineApplicable,
880            );
881
882            let mut snapshot = self.create_snapshot_for_diagnostic();
884            if let [attr] = &expr.attrs[..]
885                && let ast::AttrKind::Normal(attr_kind) = &attr.kind
886                && let [segment] = &attr_kind.item.path.segments[..]
887                && segment.ident.name == sym::cfg
888                && let Some(args_span) = attr_kind.item.args.span()
889                && let next_attr = match snapshot.parse_attribute(InnerAttrPolicy::Forbidden(None))
890                {
891                    Ok(next_attr) => next_attr,
892                    Err(inner_err) => {
893                        inner_err.cancel();
894                        return err.emit();
895                    }
896                }
897                && let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind
898                && let Some(next_attr_args_span) = next_attr_kind.item.args.span()
899                && let [next_segment] = &next_attr_kind.item.path.segments[..]
900                && segment.ident.name == sym::cfg
901            {
902                let next_expr = match snapshot.parse_expr() {
903                    Ok(next_expr) => next_expr,
904                    Err(inner_err) => {
905                        inner_err.cancel();
906                        return err.emit();
907                    }
908                };
909                let margin = self.psess.source_map().span_to_margin(next_expr.span).unwrap_or(0);
916                let sugg = vec![
917                    (attr.span.with_hi(segment.span().hi()), "if cfg!".to_string()),
918                    (args_span.shrink_to_hi().with_hi(attr.span.hi()), " {".to_string()),
919                    (expr.span.shrink_to_lo(), "    ".to_string()),
920                    (
921                        next_attr.span.with_hi(next_segment.span().hi()),
922                        "} else if cfg!".to_string(),
923                    ),
924                    (
925                        next_attr_args_span.shrink_to_hi().with_hi(next_attr.span.hi()),
926                        " {".to_string(),
927                    ),
928                    (next_expr.span.shrink_to_lo(), "    ".to_string()),
929                    (next_expr.span.shrink_to_hi(), format!("\n{}}}", " ".repeat(margin))),
930                ];
931                err.multipart_suggestion(
932                    "it seems like you are trying to provide different expressions depending on \
933                     `cfg`, consider using `if cfg!(..)`",
934                    sugg,
935                    Applicability::MachineApplicable,
936                );
937            }
938        }
939
940        err.emit()
941    }
942
943    fn check_too_many_raw_str_terminators(&mut self, err: &mut Diag<'_>) -> bool {
944        let sm = self.psess.source_map();
945        match (&self.prev_token.kind, &self.token.kind) {
946            (
947                TokenKind::Literal(Lit {
948                    kind: LitKind::StrRaw(n_hashes) | LitKind::ByteStrRaw(n_hashes),
949                    ..
950                }),
951                TokenKind::Pound,
952            ) if !sm.is_multiline(
953                self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()),
954            ) =>
955            {
956                let n_hashes: u8 = *n_hashes;
957                err.primary_message("too many `#` when terminating raw string");
958                let str_span = self.prev_token.span;
959                let mut span = self.token.span;
960                let mut count = 0;
961                while self.token == TokenKind::Pound
962                    && !sm.is_multiline(span.shrink_to_hi().until(self.token.span.shrink_to_lo()))
963                {
964                    span = span.with_hi(self.token.span.hi());
965                    self.bump();
966                    count += 1;
967                }
968                err.span(span);
969                err.span_suggestion(
970                    span,
971                    format!("remove the extra `#`{}", pluralize!(count)),
972                    "",
973                    Applicability::MachineApplicable,
974                );
975                err.span_label(
976                    str_span,
977                    format!("this raw string started with {n_hashes} `#`{}", pluralize!(n_hashes)),
978                );
979                true
980            }
981            _ => false,
982        }
983    }
984
985    pub(super) fn maybe_suggest_struct_literal(
986        &mut self,
987        lo: Span,
988        s: BlockCheckMode,
989        maybe_struct_name: token::Token,
990    ) -> Option<PResult<'a, Box<Block>>> {
991        if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) {
992            debug!(?maybe_struct_name, ?self.token);
997            let mut snapshot = self.create_snapshot_for_diagnostic();
998            let path = Path {
999                segments: ThinVec::new(),
1000                span: self.prev_token.span.shrink_to_lo(),
1001                tokens: None,
1002            };
1003            let struct_expr = snapshot.parse_expr_struct(None, path, false);
1004            let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No);
1005            return Some(match (struct_expr, block_tail) {
1006                (Ok(expr), Err(err)) => {
1007                    err.cancel();
1016                    self.restore_snapshot(snapshot);
1017                    let guar = self.dcx().emit_err(StructLiteralBodyWithoutPath {
1018                        span: expr.span,
1019                        sugg: StructLiteralBodyWithoutPathSugg {
1020                            before: expr.span.shrink_to_lo(),
1021                            after: expr.span.shrink_to_hi(),
1022                        },
1023                    });
1024                    Ok(self.mk_block(
1025                        thin_vec![self.mk_stmt_err(expr.span, guar)],
1026                        s,
1027                        lo.to(self.prev_token.span),
1028                    ))
1029                }
1030                (Err(err), Ok(tail)) => {
1031                    err.cancel();
1033                    Ok(tail)
1034                }
1035                (Err(snapshot_err), Err(err)) => {
1036                    snapshot_err.cancel();
1038                    self.consume_block(exp!(OpenBrace), exp!(CloseBrace), ConsumeClosingDelim::Yes);
1039                    Err(err)
1040                }
1041                (Ok(_), Ok(tail)) => Ok(tail),
1042            });
1043        }
1044        None
1045    }
1046
1047    pub(super) fn recover_closure_body(
1048        &mut self,
1049        mut err: Diag<'a>,
1050        before: token::Token,
1051        prev: token::Token,
1052        token: token::Token,
1053        lo: Span,
1054        decl_hi: Span,
1055    ) -> PResult<'a, Box<Expr>> {
1056        err.span_label(lo.to(decl_hi), "while parsing the body of this closure");
1057        let guar = match before.kind {
1058            token::OpenBrace if token.kind != token::OpenBrace => {
1059                err.multipart_suggestion(
1061                    "you might have meant to open the body of the closure, instead of enclosing \
1062                     the closure in a block",
1063                    vec![
1064                        (before.span, String::new()),
1065                        (prev.span.shrink_to_hi(), " {".to_string()),
1066                    ],
1067                    Applicability::MaybeIncorrect,
1068                );
1069                let guar = err.emit();
1070                self.eat_to_tokens(&[exp!(CloseBrace)]);
1071                guar
1072            }
1073            token::OpenParen if token.kind != token::OpenBrace => {
1074                self.eat_to_tokens(&[exp!(CloseParen), exp!(Comma)]);
1077
1078                err.multipart_suggestion_verbose(
1079                    "you might have meant to open the body of the closure",
1080                    vec![
1081                        (prev.span.shrink_to_hi(), " {".to_string()),
1082                        (self.token.span.shrink_to_lo(), "}".to_string()),
1083                    ],
1084                    Applicability::MaybeIncorrect,
1085                );
1086                err.emit()
1087            }
1088            _ if token.kind != token::OpenBrace => {
1089                err.multipart_suggestion_verbose(
1092                    "you might have meant to open the body of the closure",
1093                    vec![(prev.span.shrink_to_hi(), " {".to_string())],
1094                    Applicability::HasPlaceholders,
1095                );
1096                return Err(err);
1097            }
1098            _ => return Err(err),
1099        };
1100        Ok(self.mk_expr_err(lo.to(self.token.span), guar))
1101    }
1102
1103    pub(super) fn eat_to_tokens(&mut self, closes: &[ExpTokenPair]) {
1106        if let Err(err) = self
1107            .parse_seq_to_before_tokens(closes, &[], SeqSep::none(), |p| Ok(p.parse_token_tree()))
1108        {
1109            err.cancel();
1110        }
1111    }
1112
1113    pub(super) fn check_trailing_angle_brackets(
1124        &mut self,
1125        segment: &PathSegment,
1126        end: &[ExpTokenPair],
1127    ) -> Option<ErrorGuaranteed> {
1128        if !self.may_recover() {
1129            return None;
1130        }
1131
1132        let parsed_angle_bracket_args =
1157            segment.args.as_ref().is_some_and(|args| args.is_angle_bracketed());
1158
1159        debug!(
1160            "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}",
1161            parsed_angle_bracket_args,
1162        );
1163        if !parsed_angle_bracket_args {
1164            return None;
1165        }
1166
1167        let lo = self.token.span;
1170
1171        let mut position = 0;
1175
1176        let mut number_of_shr = 0;
1180        let mut number_of_gt = 0;
1181        while self.look_ahead(position, |t| {
1182            trace!("check_trailing_angle_brackets: t={:?}", t);
1183            if *t == token::Shr {
1184                number_of_shr += 1;
1185                true
1186            } else if *t == token::Gt {
1187                number_of_gt += 1;
1188                true
1189            } else {
1190                false
1191            }
1192        }) {
1193            position += 1;
1194        }
1195
1196        debug!(
1198            "check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?}",
1199            number_of_gt, number_of_shr,
1200        );
1201        if number_of_gt < 1 && number_of_shr < 1 {
1202            return None;
1203        }
1204
1205        if self.look_ahead(position, |t| {
1208            trace!("check_trailing_angle_brackets: t={:?}", t);
1209            end.iter().any(|exp| exp.tok == t.kind)
1210        }) {
1211            self.eat_to_tokens(end);
1214            let span = lo.to(self.prev_token.span);
1215
1216            let num_extra_brackets = number_of_gt + number_of_shr * 2;
1217            return Some(self.dcx().emit_err(UnmatchedAngleBrackets { span, num_extra_brackets }));
1218        }
1219        None
1220    }
1221
1222    pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut PathSegment) {
1225        if !self.may_recover() {
1226            return;
1227        }
1228
1229        if self.token == token::PathSep && segment.args.is_none() {
1230            let snapshot = self.create_snapshot_for_diagnostic();
1231            self.bump();
1232            let lo = self.token.span;
1233            match self.parse_angle_args(None) {
1234                Ok(args) => {
1235                    let span = lo.to(self.prev_token.span);
1236                    let mut trailing_span = self.prev_token.span.shrink_to_hi();
1238                    while self.token == token::Shr || self.token == token::Gt {
1239                        trailing_span = trailing_span.to(self.token.span);
1240                        self.bump();
1241                    }
1242                    if self.token == token::OpenParen {
1243                        segment.args = Some(AngleBracketedArgs { args, span }.into());
1245
1246                        self.dcx().emit_err(GenericParamsWithoutAngleBrackets {
1247                            span,
1248                            sugg: GenericParamsWithoutAngleBracketsSugg {
1249                                left: span.shrink_to_lo(),
1250                                right: trailing_span,
1251                            },
1252                        });
1253                    } else {
1254                        self.restore_snapshot(snapshot);
1256                    }
1257                }
1258                Err(err) => {
1259                    err.cancel();
1262                    self.restore_snapshot(snapshot);
1263                }
1264            }
1265        }
1266    }
1267
1268    pub(super) fn check_mistyped_turbofish_with_multiple_type_params(
1271        &mut self,
1272        mut e: Diag<'a>,
1273        expr: &mut Box<Expr>,
1274    ) -> PResult<'a, ErrorGuaranteed> {
1275        if let ExprKind::Binary(binop, _, _) = &expr.kind
1276            && let ast::BinOpKind::Lt = binop.node
1277            && self.eat(exp!(Comma))
1278        {
1279            let x = self.parse_seq_to_before_end(
1280                exp!(Gt),
1281                SeqSep::trailing_allowed(exp!(Comma)),
1282                |p| match p.parse_generic_arg(None)? {
1283                    Some(arg) => Ok(arg),
1284                    None => p.unexpected_any(),
1286                },
1287            );
1288            match x {
1289                Ok((_, _, Recovered::No)) => {
1290                    if self.eat(exp!(Gt)) {
1291                        e.span_suggestion_verbose(
1293                            binop.span.shrink_to_lo(),
1294                            fluent::parse_sugg_turbofish_syntax,
1295                            "::",
1296                            Applicability::MaybeIncorrect,
1297                        );
1298                        match self.parse_expr() {
1299                            Ok(_) => {
1300                                let guar = e.emit();
1304                                *expr = self.mk_expr_err(expr.span.to(self.prev_token.span), guar);
1305                                return Ok(guar);
1306                            }
1307                            Err(err) => {
1308                                err.cancel();
1309                            }
1310                        }
1311                    }
1312                }
1313                Ok((_, _, Recovered::Yes(_))) => {}
1314                Err(err) => {
1315                    err.cancel();
1316                }
1317            }
1318        }
1319        Err(e)
1320    }
1321
1322    pub(super) fn suggest_add_missing_let_for_stmt(&mut self, err: &mut Diag<'a>) {
1325        if self.token == token::Colon {
1326            let prev_span = self.prev_token.span.shrink_to_lo();
1327            let snapshot = self.create_snapshot_for_diagnostic();
1328            self.bump();
1329            match self.parse_ty() {
1330                Ok(_) => {
1331                    if self.token == token::Eq {
1332                        let sugg = SuggAddMissingLetStmt { span: prev_span };
1333                        sugg.add_to_diag(err);
1334                    }
1335                }
1336                Err(e) => {
1337                    e.cancel();
1338                }
1339            }
1340            self.restore_snapshot(snapshot);
1341        }
1342    }
1343
1344    fn attempt_chained_comparison_suggestion(
1348        &mut self,
1349        err: &mut ComparisonOperatorsCannotBeChained,
1350        inner_op: &Expr,
1351        outer_op: &Spanned<AssocOp>,
1352    ) -> bool {
1353        if let ExprKind::Binary(op, l1, r1) = &inner_op.kind {
1354            if let ExprKind::Field(_, ident) = l1.kind
1355                && !ident.is_numeric()
1356                && !matches!(r1.kind, ExprKind::Lit(_))
1357            {
1358                return false;
1361            }
1362            return match (op.node, &outer_op.node) {
1363                (BinOpKind::Eq, AssocOp::Binary(BinOpKind::Eq)) |
1365                (BinOpKind::Lt, AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le)) |
1367                (BinOpKind::Le, AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le)) |
1368                (BinOpKind::Gt, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) |
1370                (BinOpKind::Ge, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) => {
1371                    let expr_to_str = |e: &Expr| {
1372                        self.span_to_snippet(e.span)
1373                            .unwrap_or_else(|_| pprust::expr_to_string(e))
1374                    };
1375                    err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::SplitComparison {
1376                        span: inner_op.span.shrink_to_hi(),
1377                        middle_term: expr_to_str(r1),
1378                    });
1379                    false }
1381                (
1383                    BinOpKind::Eq,
1384                    AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge)
1385                ) => {
1386                    let snapshot = self.create_snapshot_for_diagnostic();
1388                    match self.parse_expr() {
1389                        Ok(r2) => {
1390                            err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize {
1393                                left: r1.span.shrink_to_lo(),
1394                                right: r2.span.shrink_to_hi(),
1395                            });
1396                            true
1397                        }
1398                        Err(expr_err) => {
1399                            expr_err.cancel();
1400                            self.restore_snapshot(snapshot);
1401                            true
1402                        }
1403                    }
1404                }
1405                (
1407                    BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge,
1408                    AssocOp::Binary(BinOpKind::Eq)
1409                ) => {
1410                    let snapshot = self.create_snapshot_for_diagnostic();
1411                    match self.parse_expr() {
1414                        Ok(_) => {
1415                            err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize {
1416                                left: l1.span.shrink_to_lo(),
1417                                right: r1.span.shrink_to_hi(),
1418                            });
1419                            true
1420                        }
1421                        Err(expr_err) => {
1422                            expr_err.cancel();
1423                            self.restore_snapshot(snapshot);
1424                            false
1425                        }
1426                    }
1427                }
1428                _ => false
1429            };
1430        }
1431        false
1432    }
1433
1434    pub(super) fn check_no_chained_comparison(
1453        &mut self,
1454        inner_op: &Expr,
1455        outer_op: &Spanned<AssocOp>,
1456    ) -> PResult<'a, Option<Box<Expr>>> {
1457        debug_assert!(
1458            outer_op.node.is_comparison(),
1459            "check_no_chained_comparison: {:?} is not comparison",
1460            outer_op.node,
1461        );
1462
1463        let mk_err_expr =
1464            |this: &Self, span, guar| Ok(Some(this.mk_expr(span, ExprKind::Err(guar))));
1465
1466        match &inner_op.kind {
1467            ExprKind::Binary(op, l1, r1) if op.node.is_comparison() => {
1468                let mut err = ComparisonOperatorsCannotBeChained {
1469                    span: vec![op.span, self.prev_token.span],
1470                    suggest_turbofish: None,
1471                    help_turbofish: false,
1472                    chaining_sugg: None,
1473                };
1474
1475                if op.node == BinOpKind::Lt && outer_op.node == AssocOp::Binary(BinOpKind::Lt)
1478                    || outer_op.node == AssocOp::Binary(BinOpKind::Gt)
1479                {
1480                    if outer_op.node == AssocOp::Binary(BinOpKind::Lt) {
1481                        let snapshot = self.create_snapshot_for_diagnostic();
1482                        self.bump();
1483                        let modifiers = [(token::Lt, 1), (token::Gt, -1), (token::Shr, -2)];
1485                        self.consume_tts(1, &modifiers);
1486
1487                        if !matches!(self.token.kind, token::OpenParen | token::PathSep) {
1488                            self.restore_snapshot(snapshot);
1491                        }
1492                    }
1493                    return if self.token == token::PathSep {
1494                        if let ExprKind::Binary(o, ..) = inner_op.kind
1497                            && o.node == BinOpKind::Lt
1498                        {
1499                            err.suggest_turbofish = Some(op.span.shrink_to_lo());
1500                        } else {
1501                            err.help_turbofish = true;
1502                        }
1503
1504                        let snapshot = self.create_snapshot_for_diagnostic();
1505                        self.bump(); match self.parse_expr() {
1509                            Ok(_) => {
1510                                let guar = self.dcx().emit_err(err);
1512                                mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar)
1516                            }
1517                            Err(expr_err) => {
1518                                expr_err.cancel();
1519                                self.restore_snapshot(snapshot);
1522                                Err(self.dcx().create_err(err))
1523                            }
1524                        }
1525                    } else if self.token == token::OpenParen {
1526                        if let ExprKind::Binary(o, ..) = inner_op.kind
1529                            && o.node == BinOpKind::Lt
1530                        {
1531                            err.suggest_turbofish = Some(op.span.shrink_to_lo());
1532                        } else {
1533                            err.help_turbofish = true;
1534                        }
1535                        match self.consume_fn_args() {
1537                            Err(()) => Err(self.dcx().create_err(err)),
1538                            Ok(()) => {
1539                                let guar = self.dcx().emit_err(err);
1540                                mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar)
1544                            }
1545                        }
1546                    } else {
1547                        if !matches!(l1.kind, ExprKind::Lit(_))
1548                            && !matches!(r1.kind, ExprKind::Lit(_))
1549                        {
1550                            err.help_turbofish = true;
1553                        }
1554
1555                        let recovered = self
1558                            .attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
1559                        if recovered {
1560                            let guar = self.dcx().emit_err(err);
1561                            mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar)
1562                        } else {
1563                            Err(self.dcx().create_err(err))
1565                        }
1566                    };
1567                }
1568                let recovered =
1569                    self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
1570                let guar = self.dcx().emit_err(err);
1571                if recovered {
1572                    return mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar);
1573                }
1574            }
1575            _ => {}
1576        }
1577        Ok(None)
1578    }
1579
1580    fn consume_fn_args(&mut self) -> Result<(), ()> {
1581        let snapshot = self.create_snapshot_for_diagnostic();
1582        self.bump(); let modifiers = [(token::OpenParen, 1), (token::CloseParen, -1)];
1586        self.consume_tts(1, &modifiers);
1587
1588        if self.token == token::Eof {
1589            self.restore_snapshot(snapshot);
1591            Err(())
1592        } else {
1593            Ok(())
1595        }
1596    }
1597
1598    pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) {
1599        if impl_dyn_multi {
1600            self.dcx().emit_err(AmbiguousPlus {
1601                span: ty.span,
1602                suggestion: AddParen { lo: ty.span.shrink_to_lo(), hi: ty.span.shrink_to_hi() },
1603            });
1604        }
1605    }
1606
1607    pub(super) fn maybe_recover_from_question_mark(&mut self, ty: Box<Ty>) -> Box<Ty> {
1609        if self.token == token::Question {
1610            self.bump();
1611            let guar = self.dcx().emit_err(QuestionMarkInType {
1612                span: self.prev_token.span,
1613                sugg: QuestionMarkInTypeSugg {
1614                    left: ty.span.shrink_to_lo(),
1615                    right: self.prev_token.span,
1616                },
1617            });
1618            self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err(guar))
1619        } else {
1620            ty
1621        }
1622    }
1623
1624    pub(super) fn maybe_recover_from_ternary_operator(
1630        &mut self,
1631        cond: Option<Span>,
1632    ) -> PResult<'a, ()> {
1633        if self.prev_token != token::Question {
1634            return PResult::Ok(());
1635        }
1636
1637        let question = self.prev_token.span;
1638        let lo = cond.unwrap_or(question).lo();
1639        let snapshot = self.create_snapshot_for_diagnostic();
1640
1641        if match self.parse_expr() {
1642            Ok(_) => true,
1643            Err(err) => {
1644                err.cancel();
1645                self.token == token::Colon
1648            }
1649        } {
1650            if self.eat_noexpect(&token::Colon) {
1651                let colon = self.prev_token.span;
1652                match self.parse_expr() {
1653                    Ok(expr) => {
1654                        let sugg = cond.map(|cond| TernaryOperatorSuggestion {
1655                            before_cond: cond.shrink_to_lo(),
1656                            question,
1657                            colon,
1658                            end: expr.span.shrink_to_hi(),
1659                        });
1660                        return Err(self.dcx().create_err(TernaryOperator {
1661                            span: self.prev_token.span.with_lo(lo),
1662                            sugg,
1663                            no_sugg: sugg.is_none(),
1664                        }));
1665                    }
1666                    Err(err) => {
1667                        err.cancel();
1668                    }
1669                };
1670            }
1671        }
1672        self.restore_snapshot(snapshot);
1673        Ok(())
1674    }
1675
1676    pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> {
1677        if !self.token.is_like_plus() {
1679            return Ok(());
1680        }
1681
1682        self.bump(); let _bounds = self.parse_generic_bounds()?;
1684        let sub = match &ty.kind {
1685            TyKind::Ref(_lifetime, mut_ty) => {
1686                let lo = mut_ty.ty.span.shrink_to_lo();
1687                let hi = self.prev_token.span.shrink_to_hi();
1688                BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } }
1689            }
1690            TyKind::Ptr(..) | TyKind::FnPtr(..) => {
1691                BadTypePlusSub::ForgotParen { span: ty.span.to(self.prev_token.span) }
1692            }
1693            _ => BadTypePlusSub::ExpectPath { span: ty.span },
1694        };
1695
1696        self.dcx().emit_err(BadTypePlus { span: ty.span, sub });
1697
1698        Ok(())
1699    }
1700
1701    pub(super) fn recover_from_prefix_increment(
1702        &mut self,
1703        operand_expr: Box<Expr>,
1704        op_span: Span,
1705        start_stmt: bool,
1706    ) -> PResult<'a, Box<Expr>> {
1707        let standalone = if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr };
1708        let kind = IncDecRecovery { standalone, op: IncOrDec::Inc, fixity: UnaryFixity::Pre };
1709        self.recover_from_inc_dec(operand_expr, kind, op_span)
1710    }
1711
1712    pub(super) fn recover_from_postfix_increment(
1713        &mut self,
1714        operand_expr: Box<Expr>,
1715        op_span: Span,
1716        start_stmt: bool,
1717    ) -> PResult<'a, Box<Expr>> {
1718        let kind = IncDecRecovery {
1719            standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr },
1720            op: IncOrDec::Inc,
1721            fixity: UnaryFixity::Post,
1722        };
1723        self.recover_from_inc_dec(operand_expr, kind, op_span)
1724    }
1725
1726    pub(super) fn recover_from_postfix_decrement(
1727        &mut self,
1728        operand_expr: Box<Expr>,
1729        op_span: Span,
1730        start_stmt: bool,
1731    ) -> PResult<'a, Box<Expr>> {
1732        let kind = IncDecRecovery {
1733            standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr },
1734            op: IncOrDec::Dec,
1735            fixity: UnaryFixity::Post,
1736        };
1737        self.recover_from_inc_dec(operand_expr, kind, op_span)
1738    }
1739
1740    fn recover_from_inc_dec(
1741        &mut self,
1742        base: Box<Expr>,
1743        kind: IncDecRecovery,
1744        op_span: Span,
1745    ) -> PResult<'a, Box<Expr>> {
1746        let mut err = self.dcx().struct_span_err(
1747            op_span,
1748            format!("Rust has no {} {} operator", kind.fixity, kind.op.name()),
1749        );
1750        err.span_label(op_span, format!("not a valid {} operator", kind.fixity));
1751
1752        let help_base_case = |mut err: Diag<'_, _>, base| {
1753            err.help(format!("use `{}= 1` instead", kind.op.chr()));
1754            err.emit();
1755            Ok(base)
1756        };
1757
1758        let spans = match kind.fixity {
1760            UnaryFixity::Pre => (op_span, base.span.shrink_to_hi()),
1761            UnaryFixity::Post => (base.span.shrink_to_lo(), op_span),
1762        };
1763
1764        match kind.standalone {
1765            IsStandalone::Standalone => {
1766                self.inc_dec_standalone_suggest(kind, spans).emit_verbose(&mut err)
1767            }
1768            IsStandalone::Subexpr => {
1769                let Ok(base_src) = self.span_to_snippet(base.span) else {
1770                    return help_base_case(err, base);
1771                };
1772                match kind.fixity {
1773                    UnaryFixity::Pre => {
1774                        self.prefix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
1775                    }
1776                    UnaryFixity::Post => {
1777                        if !matches!(base.kind, ExprKind::Binary(_, _, _)) {
1780                            self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
1781                        }
1782                    }
1783                }
1784            }
1785        }
1786        Err(err)
1787    }
1788
1789    fn prefix_inc_dec_suggest(
1790        &mut self,
1791        base_src: String,
1792        kind: IncDecRecovery,
1793        (pre_span, post_span): (Span, Span),
1794    ) -> MultiSugg {
1795        MultiSugg {
1796            msg: format!("use `{}= 1` instead", kind.op.chr()),
1797            patches: vec![
1798                (pre_span, "{ ".to_string()),
1799                (post_span, format!(" {}= 1; {} }}", kind.op.chr(), base_src)),
1800            ],
1801            applicability: Applicability::MachineApplicable,
1802        }
1803    }
1804
1805    fn postfix_inc_dec_suggest(
1806        &mut self,
1807        base_src: String,
1808        kind: IncDecRecovery,
1809        (pre_span, post_span): (Span, Span),
1810    ) -> MultiSugg {
1811        let tmp_var = if base_src.trim() == "tmp" { "tmp_" } else { "tmp" };
1812        MultiSugg {
1813            msg: format!("use `{}= 1` instead", kind.op.chr()),
1814            patches: vec![
1815                (pre_span, format!("{{ let {tmp_var} = ")),
1816                (post_span, format!("; {} {}= 1; {} }}", base_src, kind.op.chr(), tmp_var)),
1817            ],
1818            applicability: Applicability::HasPlaceholders,
1819        }
1820    }
1821
1822    fn inc_dec_standalone_suggest(
1823        &mut self,
1824        kind: IncDecRecovery,
1825        (pre_span, post_span): (Span, Span),
1826    ) -> MultiSugg {
1827        let mut patches = Vec::new();
1828
1829        if !pre_span.is_empty() {
1830            patches.push((pre_span, String::new()));
1831        }
1832
1833        patches.push((post_span, format!(" {}= 1", kind.op.chr())));
1834        MultiSugg {
1835            msg: format!("use `{}= 1` instead", kind.op.chr()),
1836            patches,
1837            applicability: Applicability::MachineApplicable,
1838        }
1839    }
1840
1841    pub(super) fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
1845        &mut self,
1846        base: T,
1847    ) -> PResult<'a, T> {
1848        if self.may_recover() && self.token == token::PathSep {
1850            return self.recover_from_bad_qpath(base);
1851        }
1852        Ok(base)
1853    }
1854
1855    #[cold]
1856    fn recover_from_bad_qpath<T: RecoverQPath>(&mut self, base: T) -> PResult<'a, T> {
1857        if let Some(ty) = base.to_ty() {
1858            return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
1859        }
1860        Ok(base)
1861    }
1862
1863    pub(super) fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
1866        &mut self,
1867        ty_span: Span,
1868        ty: Box<Ty>,
1869    ) -> PResult<'a, T> {
1870        self.expect(exp!(PathSep))?;
1871
1872        let mut path = ast::Path { segments: ThinVec::new(), span: DUMMY_SP, tokens: None };
1873        self.parse_path_segments(&mut path.segments, T::PATH_STYLE, None)?;
1874        path.span = ty_span.to(self.prev_token.span);
1875
1876        self.dcx().emit_err(BadQPathStage2 {
1877            span: ty_span,
1878            wrap: WrapType { lo: ty_span.shrink_to_lo(), hi: ty_span.shrink_to_hi() },
1879        });
1880
1881        let path_span = ty_span.shrink_to_hi(); Ok(T::recovered(Some(Box::new(QSelf { ty, path_span, position: 0 })), path))
1883    }
1884
1885    pub fn maybe_consume_incorrect_semicolon(&mut self, previous_item: Option<&Item>) -> bool {
1888        if self.token != TokenKind::Semi {
1889            return false;
1890        }
1891
1892        let err = match previous_item {
1895            Some(previous_item) => {
1896                let name = match previous_item.kind {
1897                    ItemKind::Struct(..) => "braced struct",
1900                    _ => previous_item.kind.descr(),
1901                };
1902                IncorrectSemicolon { span: self.token.span, name, show_help: true }
1903            }
1904            None => IncorrectSemicolon { span: self.token.span, name: "", show_help: false },
1905        };
1906        self.dcx().emit_err(err);
1907
1908        self.bump();
1909        true
1910    }
1911
1912    pub(super) fn unexpected_try_recover(&mut self, t: &TokenKind) -> PResult<'a, Recovered> {
1915        let token_str = pprust::token_kind_to_string(t);
1916        let this_token_str = super::token_descr(&self.token);
1917        let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) {
1918            (token::Eof, Some(_)) => {
1920                let sp = self.prev_token.span.shrink_to_hi();
1921                (sp, sp)
1922            }
1923            _ if self.prev_token.span == DUMMY_SP => (self.token.span, self.token.span),
1926            (token::Eof, None) => (self.prev_token.span, self.token.span),
1928            _ => (self.prev_token.span.shrink_to_hi(), self.token.span),
1929        };
1930        let msg = format!(
1931            "expected `{}`, found {}",
1932            token_str,
1933            match (&self.token.kind, self.subparser_name) {
1934                (token::Eof, Some(origin)) => format!("end of {origin}"),
1935                _ => this_token_str,
1936            },
1937        );
1938        let mut err = self.dcx().struct_span_err(sp, msg);
1939        let label_exp = format!("expected `{token_str}`");
1940        let sm = self.psess.source_map();
1941        if !sm.is_multiline(prev_sp.until(sp)) {
1942            err.span_label(sp, label_exp);
1945        } else {
1946            err.span_label(prev_sp, label_exp);
1947            err.span_label(sp, "unexpected token");
1948        }
1949        Err(err)
1950    }
1951
1952    pub(super) fn expect_semi(&mut self) -> PResult<'a, ()> {
1953        if self.eat(exp!(Semi)) || self.recover_colon_as_semi() {
1954            return Ok(());
1955        }
1956        self.expect(exp!(Semi)).map(drop) }
1958
1959    pub(super) fn recover_colon_as_semi(&mut self) -> bool {
1960        let line_idx = |span: Span| {
1961            self.psess
1962                .source_map()
1963                .span_to_lines(span)
1964                .ok()
1965                .and_then(|lines| Some(lines.lines.get(0)?.line_index))
1966        };
1967
1968        if self.may_recover()
1969            && self.token == token::Colon
1970            && self.look_ahead(1, |next| line_idx(self.token.span) < line_idx(next.span))
1971        {
1972            self.dcx().emit_err(ColonAsSemi { span: self.token.span });
1973            self.bump();
1974            return true;
1975        }
1976
1977        false
1978    }
1979
1980    pub(super) fn recover_incorrect_await_syntax(
1983        &mut self,
1984        await_sp: Span,
1985    ) -> PResult<'a, Box<Expr>> {
1986        let (hi, expr, is_question) = if self.token == token::Bang {
1987            self.recover_await_macro()?
1989        } else {
1990            self.recover_await_prefix(await_sp)?
1991        };
1992        let (sp, guar) = self.error_on_incorrect_await(await_sp, hi, &expr, is_question);
1993        let expr = self.mk_expr_err(await_sp.to(sp), guar);
1994        self.maybe_recover_from_bad_qpath(expr)
1995    }
1996
1997    fn recover_await_macro(&mut self) -> PResult<'a, (Span, Box<Expr>, bool)> {
1998        self.expect(exp!(Bang))?;
1999        self.expect(exp!(OpenParen))?;
2000        let expr = self.parse_expr()?;
2001        self.expect(exp!(CloseParen))?;
2002        Ok((self.prev_token.span, expr, false))
2003    }
2004
2005    fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, Box<Expr>, bool)> {
2006        let is_question = self.eat(exp!(Question)); let expr = if self.token == token::OpenBrace {
2008            self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)
2012        } else {
2013            self.parse_expr()
2014        }
2015        .map_err(|mut err| {
2016            err.span_label(await_sp, format!("while parsing this incorrect await expression"));
2017            err
2018        })?;
2019        Ok((expr.span, expr, is_question))
2020    }
2021
2022    fn error_on_incorrect_await(
2023        &self,
2024        lo: Span,
2025        hi: Span,
2026        expr: &Expr,
2027        is_question: bool,
2028    ) -> (Span, ErrorGuaranteed) {
2029        let span = lo.to(hi);
2030        let guar = self.dcx().emit_err(IncorrectAwait {
2031            span,
2032            suggestion: AwaitSuggestion {
2033                removal: lo.until(expr.span),
2034                dot_await: expr.span.shrink_to_hi(),
2035                question_mark: if is_question { "?" } else { "" },
2036            },
2037        });
2038        (span, guar)
2039    }
2040
2041    pub(super) fn recover_from_await_method_call(&mut self) {
2043        if self.token == token::OpenParen && self.look_ahead(1, |t| t == &token::CloseParen) {
2044            let lo = self.token.span;
2046            self.bump(); let span = lo.to(self.token.span);
2048            self.bump(); self.dcx().emit_err(IncorrectUseOfAwait { span });
2051        }
2052    }
2053    pub(super) fn recover_from_use(&mut self) {
2056        if self.token == token::OpenParen && self.look_ahead(1, |t| t == &token::CloseParen) {
2057            let lo = self.token.span;
2059            self.bump(); let span = lo.to(self.token.span);
2061            self.bump(); self.dcx().emit_err(IncorrectUseOfUse { span });
2064        }
2065    }
2066
2067    pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, Box<Expr>> {
2068        let is_try = self.token.is_keyword(kw::Try);
2069        let is_questionmark = self.look_ahead(1, |t| t == &token::Bang); let is_open = self.look_ahead(2, |t| t == &token::OpenParen); if is_try && is_questionmark && is_open {
2073            let lo = self.token.span;
2074            self.bump(); self.bump(); let try_span = lo.to(self.token.span); self.bump(); let is_empty = self.token == token::CloseParen; self.consume_block(exp!(OpenParen), exp!(CloseParen), ConsumeClosingDelim::No); let hi = self.token.span;
2081            self.bump(); let mut err = self.dcx().struct_span_err(lo.to(hi), "use of deprecated `try` macro");
2083            err.note("in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated");
2084            let prefix = if is_empty { "" } else { "alternatively, " };
2085            if !is_empty {
2086                err.multipart_suggestion(
2087                    "you can use the `?` operator instead",
2088                    vec![(try_span, "".to_owned()), (hi, "?".to_owned())],
2089                    Applicability::MachineApplicable,
2090                );
2091            }
2092            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);
2093            let guar = err.emit();
2094            Ok(self.mk_expr_err(lo.to(hi), guar))
2095        } else {
2096            Err(self.expected_expression_found()) }
2098    }
2099
2100    pub(super) fn expect_gt_or_maybe_suggest_closing_generics(
2107        &mut self,
2108        params: &[ast::GenericParam],
2109    ) -> PResult<'a, ()> {
2110        let Err(mut err) = self.expect_gt() else {
2111            return Ok(());
2112        };
2113        if let [.., ast::GenericParam { bounds, .. }] = params
2115            && let Some(poly) = bounds
2116                .iter()
2117                .filter_map(|bound| match bound {
2118                    ast::GenericBound::Trait(poly) => Some(poly),
2119                    _ => None,
2120                })
2121                .next_back()
2122        {
2123            err.span_suggestion_verbose(
2124                poly.span.shrink_to_hi(),
2125                "you might have meant to end the type parameters here",
2126                ">",
2127                Applicability::MaybeIncorrect,
2128            );
2129        }
2130        Err(err)
2131    }
2132
2133    pub(super) fn recover_seq_parse_error(
2134        &mut self,
2135        open: ExpTokenPair,
2136        close: ExpTokenPair,
2137        lo: Span,
2138        err: Diag<'a>,
2139    ) -> Box<Expr> {
2140        let guar = err.emit();
2141        self.consume_block(open, close, ConsumeClosingDelim::Yes);
2143        self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err(guar))
2144    }
2145
2146    pub(super) fn recover_stmt(&mut self) {
2151        self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore)
2152    }
2153
2154    pub(super) fn recover_stmt_(
2162        &mut self,
2163        break_on_semi: SemiColonMode,
2164        break_on_block: BlockMode,
2165    ) {
2166        let mut brace_depth = 0;
2167        let mut bracket_depth = 0;
2168        let mut in_block = false;
2169        debug!("recover_stmt_ enter loop (semi={:?}, block={:?})", break_on_semi, break_on_block);
2170        loop {
2171            debug!("recover_stmt_ loop {:?}", self.token);
2172            match self.token.kind {
2173                token::OpenBrace => {
2174                    brace_depth += 1;
2175                    self.bump();
2176                    if break_on_block == BlockMode::Break && brace_depth == 1 && bracket_depth == 0
2177                    {
2178                        in_block = true;
2179                    }
2180                }
2181                token::OpenBracket => {
2182                    bracket_depth += 1;
2183                    self.bump();
2184                }
2185                token::CloseBrace => {
2186                    if brace_depth == 0 {
2187                        debug!("recover_stmt_ return - close delim {:?}", self.token);
2188                        break;
2189                    }
2190                    brace_depth -= 1;
2191                    self.bump();
2192                    if in_block && bracket_depth == 0 && brace_depth == 0 {
2193                        debug!("recover_stmt_ return - block end {:?}", self.token);
2194                        break;
2195                    }
2196                }
2197                token::CloseBracket => {
2198                    bracket_depth -= 1;
2199                    if bracket_depth < 0 {
2200                        bracket_depth = 0;
2201                    }
2202                    self.bump();
2203                }
2204                token::Eof => {
2205                    debug!("recover_stmt_ return - Eof");
2206                    break;
2207                }
2208                token::Semi => {
2209                    self.bump();
2210                    if break_on_semi == SemiColonMode::Break
2211                        && brace_depth == 0
2212                        && bracket_depth == 0
2213                    {
2214                        debug!("recover_stmt_ return - Semi");
2215                        break;
2216                    }
2217                }
2218                token::Comma
2219                    if break_on_semi == SemiColonMode::Comma
2220                        && brace_depth == 0
2221                        && bracket_depth == 0 =>
2222                {
2223                    break;
2224                }
2225                _ => self.bump(),
2226            }
2227        }
2228    }
2229
2230    pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) {
2231        if self.eat_keyword(exp!(In)) {
2232            self.dcx().emit_err(InInTypo {
2234                span: self.prev_token.span,
2235                sugg_span: in_span.until(self.prev_token.span),
2236            });
2237        }
2238    }
2239
2240    pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
2241        if let token::DocComment(..) = self.token.kind {
2242            self.dcx().emit_err(DocCommentOnParamType { span: self.token.span });
2243            self.bump();
2244        } else if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) {
2245            let lo = self.token.span;
2246            while self.token != token::CloseBracket {
2248                self.bump();
2249            }
2250            let sp = lo.to(self.token.span);
2251            self.bump();
2252            self.dcx().emit_err(AttributeOnParamType { span: sp });
2253        }
2254    }
2255
2256    pub(super) fn parameter_without_type(
2257        &mut self,
2258        err: &mut Diag<'_>,
2259        pat: Box<ast::Pat>,
2260        require_name: bool,
2261        first_param: bool,
2262        fn_parse_mode: &crate::parser::item::FnParseMode,
2263    ) -> Option<Ident> {
2264        if self.check_ident()
2267            && self.look_ahead(1, |t| *t == token::Comma || *t == token::CloseParen)
2268        {
2269            let ident = self.parse_ident().unwrap();
2271            let span = pat.span.with_hi(ident.span.hi());
2272
2273            err.span_suggestion(
2274                span,
2275                "declare the type after the parameter binding",
2276                "<identifier>: <type>",
2277                Applicability::HasPlaceholders,
2278            );
2279            return Some(ident);
2280        } else if require_name
2281            && (self.token == token::Comma
2282                || self.token == token::Lt
2283                || self.token == token::CloseParen)
2284        {
2285            let maybe_emit_anon_params_note = |this: &mut Self, err: &mut Diag<'_>| {
2286                let ed = this.token.span.with_neighbor(this.prev_token.span).edition();
2287                if matches!(fn_parse_mode.context, crate::parser::item::FnContext::Trait)
2288                    && (fn_parse_mode.req_name)(ed)
2289                {
2290                    err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
2291                }
2292            };
2293
2294            let (ident, self_sugg, param_sugg, type_sugg, self_span, param_span, type_span) =
2295                match pat.kind {
2296                    PatKind::Ident(_, ident, _) => (
2297                        ident,
2298                        "self: ",
2299                        ": TypeName".to_string(),
2300                        "_: ",
2301                        pat.span.shrink_to_lo(),
2302                        pat.span.shrink_to_hi(),
2303                        pat.span.shrink_to_lo(),
2304                    ),
2305                    PatKind::Ref(ref inner_pat, mutab)
2307                        if let PatKind::Ident(_, ident, _) = inner_pat.clone().kind =>
2308                    {
2309                        let mutab = mutab.prefix_str();
2310                        (
2311                            ident,
2312                            "self: ",
2313                            format!("{ident}: &{mutab}TypeName"),
2314                            "_: ",
2315                            pat.span.shrink_to_lo(),
2316                            pat.span,
2317                            pat.span.shrink_to_lo(),
2318                        )
2319                    }
2320                    _ => {
2321                        if let Some(_) = pat.to_ty() {
2323                            err.span_suggestion_verbose(
2324                                pat.span.shrink_to_lo(),
2325                                "explicitly ignore the parameter name",
2326                                "_: ".to_string(),
2327                                Applicability::MachineApplicable,
2328                            );
2329                            maybe_emit_anon_params_note(self, err);
2330                        }
2331
2332                        return None;
2333                    }
2334                };
2335
2336            if first_param
2338                && matches!(
2340                    fn_parse_mode.context,
2341                    FnContext::Trait | FnContext::Impl
2342                )
2343            {
2344                err.span_suggestion_verbose(
2345                    self_span,
2346                    "if this is a `self` type, give it a parameter name",
2347                    self_sugg,
2348                    Applicability::MaybeIncorrect,
2349                );
2350            }
2351            if self.token != token::Lt {
2354                err.span_suggestion_verbose(
2355                    param_span,
2356                    "if this is a parameter name, give it a type",
2357                    param_sugg,
2358                    Applicability::HasPlaceholders,
2359                );
2360            }
2361            err.span_suggestion_verbose(
2362                type_span,
2363                "if this is a type, explicitly ignore the parameter name",
2364                type_sugg,
2365                Applicability::MachineApplicable,
2366            );
2367            maybe_emit_anon_params_note(self, err);
2368
2369            return if self.token == token::Lt { None } else { Some(ident) };
2371        }
2372        None
2373    }
2374
2375    #[cold]
2376    pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (Box<ast::Pat>, Box<ast::Ty>)> {
2377        let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName), None)?;
2378        self.expect(exp!(Colon))?;
2379        let ty = self.parse_ty()?;
2380
2381        self.dcx().emit_err(PatternMethodParamWithoutBody { span: pat.span });
2382
2383        let pat = Box::new(Pat {
2385            kind: PatKind::Wild,
2386            span: pat.span,
2387            id: ast::DUMMY_NODE_ID,
2388            tokens: None,
2389        });
2390        Ok((pat, ty))
2391    }
2392
2393    pub(super) fn recover_bad_self_param(&mut self, mut param: Param) -> PResult<'a, Param> {
2394        let span = param.pat.span;
2395        let guar = self.dcx().emit_err(SelfParamNotFirst { span });
2396        param.ty.kind = TyKind::Err(guar);
2397        Ok(param)
2398    }
2399
2400    pub(super) fn consume_block(
2401        &mut self,
2402        open: ExpTokenPair,
2403        close: ExpTokenPair,
2404        consume_close: ConsumeClosingDelim,
2405    ) {
2406        let mut brace_depth = 0;
2407        loop {
2408            if self.eat(open) {
2409                brace_depth += 1;
2410            } else if self.check(close) {
2411                if brace_depth == 0 {
2412                    if let ConsumeClosingDelim::Yes = consume_close {
2413                        self.bump();
2417                    }
2418                    return;
2419                } else {
2420                    self.bump();
2421                    brace_depth -= 1;
2422                    continue;
2423                }
2424            } else if self.token == token::Eof {
2425                return;
2426            } else {
2427                self.bump();
2428            }
2429        }
2430    }
2431
2432    pub(super) fn expected_expression_found(&self) -> Diag<'a> {
2433        let (span, msg) = match (&self.token.kind, self.subparser_name) {
2434            (&token::Eof, Some(origin)) => {
2435                let sp = self.prev_token.span.shrink_to_hi();
2436                (sp, format!("expected expression, found end of {origin}"))
2437            }
2438            _ => (
2439                self.token.span,
2440                format!("expected expression, found {}", super::token_descr(&self.token)),
2441            ),
2442        };
2443        let mut err = self.dcx().struct_span_err(span, msg);
2444        let sp = self.psess.source_map().start_point(self.token.span);
2445        if let Some(sp) = self.psess.ambiguous_block_expr_parse.borrow().get(&sp) {
2446            err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
2447        }
2448        err.span_label(span, "expected expression");
2449        err
2450    }
2451
2452    fn consume_tts(
2453        &mut self,
2454        mut acc: i64, modifier: &[(token::TokenKind, i64)],
2457    ) {
2458        while acc > 0 {
2459            if let Some((_, val)) = modifier.iter().find(|(t, _)| self.token == *t) {
2460                acc += *val;
2461            }
2462            if self.token == token::Eof {
2463                break;
2464            }
2465            self.bump();
2466        }
2467    }
2468
2469    pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut ThinVec<Param>) {
2478        let mut seen_inputs = FxHashSet::default();
2479        for input in fn_inputs.iter_mut() {
2480            let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err(_)) =
2481                (&input.pat.kind, &input.ty.kind)
2482            {
2483                Some(*ident)
2484            } else {
2485                None
2486            };
2487            if let Some(ident) = opt_ident {
2488                if seen_inputs.contains(&ident) {
2489                    input.pat.kind = PatKind::Wild;
2490                }
2491                seen_inputs.insert(ident);
2492            }
2493        }
2494    }
2495
2496    pub(super) fn handle_ambiguous_unbraced_const_arg(
2500        &mut self,
2501        args: &mut ThinVec<AngleBracketedArg>,
2502    ) -> PResult<'a, bool> {
2503        let arg = args.pop().unwrap();
2507        let mut err = self.dcx().struct_span_err(
2513            self.token.span,
2514            format!("expected one of `,` or `>`, found {}", super::token_descr(&self.token)),
2515        );
2516        err.span_label(self.token.span, "expected one of `,` or `>`");
2517        match self.recover_const_arg(arg.span(), err) {
2518            Ok(arg) => {
2519                args.push(AngleBracketedArg::Arg(arg));
2520                if self.eat(exp!(Comma)) {
2521                    return Ok(true); }
2523            }
2524            Err(err) => {
2525                args.push(arg);
2526                err.delay_as_bug();
2528            }
2529        }
2530        Ok(false) }
2532
2533    pub(super) fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, Box<Expr>> {
2541        let start = self.token.span;
2542        let attrs = self.parse_outer_attributes()?;
2543        let (expr, _) =
2544            self.parse_expr_res(Restrictions::CONST_EXPR, attrs).map_err(|mut err| {
2545                err.span_label(
2546                    start.shrink_to_lo(),
2547                    "while parsing a const generic argument starting here",
2548                );
2549                err
2550            })?;
2551        if !self.expr_is_valid_const_arg(&expr) {
2552            self.dcx().emit_err(ConstGenericWithoutBraces {
2553                span: expr.span,
2554                sugg: ConstGenericWithoutBracesSugg {
2555                    left: expr.span.shrink_to_lo(),
2556                    right: expr.span.shrink_to_hi(),
2557                },
2558            });
2559        }
2560        Ok(expr)
2561    }
2562
2563    fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option<GenericArg> {
2564        let snapshot = self.create_snapshot_for_diagnostic();
2565        let param = match self.parse_const_param(AttrVec::new()) {
2566            Ok(param) => param,
2567            Err(err) => {
2568                err.cancel();
2569                self.restore_snapshot(snapshot);
2570                return None;
2571            }
2572        };
2573
2574        let ident = param.ident.to_string();
2575        let sugg = match (ty_generics, self.psess.source_map().span_to_snippet(param.span())) {
2576            (Some(Generics { params, span: impl_generics, .. }), Ok(snippet)) => {
2577                Some(match ¶ms[..] {
2578                    [] => UnexpectedConstParamDeclarationSugg::AddParam {
2579                        impl_generics: *impl_generics,
2580                        incorrect_decl: param.span(),
2581                        snippet,
2582                        ident,
2583                    },
2584                    [.., generic] => UnexpectedConstParamDeclarationSugg::AppendParam {
2585                        impl_generics_end: generic.span().shrink_to_hi(),
2586                        incorrect_decl: param.span(),
2587                        snippet,
2588                        ident,
2589                    },
2590                })
2591            }
2592            _ => None,
2593        };
2594        let guar =
2595            self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg });
2596
2597        let value = self.mk_expr_err(param.span(), guar);
2598        Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }))
2599    }
2600
2601    pub(super) fn recover_const_param_declaration(
2602        &mut self,
2603        ty_generics: Option<&Generics>,
2604    ) -> PResult<'a, Option<GenericArg>> {
2605        if let Some(arg) = self.recover_const_param_decl(ty_generics) {
2607            return Ok(Some(arg));
2608        }
2609
2610        let start = self.token.span;
2612        self.bump(); let mut err = UnexpectedConstInGenericParam { span: start, to_remove: None };
2616        if self.check_const_arg() {
2617            err.to_remove = Some(start.until(self.token.span));
2618            self.dcx().emit_err(err);
2619            Ok(Some(GenericArg::Const(self.parse_const_arg()?)))
2620        } else {
2621            let after_kw_const = self.token.span;
2622            self.recover_const_arg(after_kw_const, self.dcx().create_err(err)).map(Some)
2623        }
2624    }
2625
2626    pub(super) fn recover_const_arg(
2632        &mut self,
2633        start: Span,
2634        mut err: Diag<'a>,
2635    ) -> PResult<'a, GenericArg> {
2636        let is_op_or_dot = AssocOp::from_token(&self.token)
2637            .and_then(|op| {
2638                if let AssocOp::Binary(
2639                    BinOpKind::Gt
2640                    | BinOpKind::Lt
2641                    | BinOpKind::Shr
2642                    | BinOpKind::Ge
2643                )
2644                | AssocOp::Assign
2647                | AssocOp::AssignOp(_) = op
2648                {
2649                    None
2650                } else {
2651                    Some(op)
2652                }
2653            })
2654            .is_some()
2655            || self.token == TokenKind::Dot;
2656        let was_op = matches!(self.prev_token.kind, token::Plus | token::Shr | token::Gt);
2659        if !is_op_or_dot && !was_op {
2660            return Err(err);
2662        }
2663        let snapshot = self.create_snapshot_for_diagnostic();
2664        if is_op_or_dot {
2665            self.bump();
2666        }
2667        match (|| {
2668            let attrs = self.parse_outer_attributes()?;
2669            self.parse_expr_res(Restrictions::CONST_EXPR, attrs)
2670        })() {
2671            Ok((expr, _)) => {
2672                if snapshot.token == token::EqEq {
2674                    err.span_suggestion(
2675                        snapshot.token.span,
2676                        "if you meant to use an associated type binding, replace `==` with `=`",
2677                        "=",
2678                        Applicability::MaybeIncorrect,
2679                    );
2680                    let guar = err.emit();
2681                    let value = self.mk_expr_err(start.to(expr.span), guar);
2682                    return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }));
2683                } else if snapshot.token == token::Colon
2684                    && expr.span.lo() == snapshot.token.span.hi()
2685                    && matches!(expr.kind, ExprKind::Path(..))
2686                {
2687                    err.span_suggestion(
2689                        snapshot.token.span,
2690                        "write a path separator here",
2691                        "::",
2692                        Applicability::MaybeIncorrect,
2693                    );
2694                    let guar = err.emit();
2695                    return Ok(GenericArg::Type(
2696                        self.mk_ty(start.to(expr.span), TyKind::Err(guar)),
2697                    ));
2698                } else if self.token == token::Comma || self.token.kind.should_end_const_arg() {
2699                    return Ok(self.dummy_const_arg_needs_braces(err, start.to(expr.span)));
2706                }
2707            }
2708            Err(err) => {
2709                err.cancel();
2710            }
2711        }
2712        self.restore_snapshot(snapshot);
2713        Err(err)
2714    }
2715
2716    pub(crate) fn recover_unbraced_const_arg_that_can_begin_ty(
2720        &mut self,
2721        mut snapshot: SnapshotParser<'a>,
2722    ) -> Option<Box<ast::Expr>> {
2723        match (|| {
2724            let attrs = self.parse_outer_attributes()?;
2725            snapshot.parse_expr_res(Restrictions::CONST_EXPR, attrs)
2726        })() {
2727            Ok((expr, _)) if let token::Comma | token::Gt = snapshot.token.kind => {
2730                self.restore_snapshot(snapshot);
2731                Some(expr)
2732            }
2733            Ok(_) => None,
2734            Err(err) => {
2735                err.cancel();
2736                None
2737            }
2738        }
2739    }
2740
2741    pub(super) fn dummy_const_arg_needs_braces(&self, mut err: Diag<'a>, span: Span) -> GenericArg {
2743        err.multipart_suggestion(
2744            "expressions must be enclosed in braces to be used as const generic \
2745             arguments",
2746            vec![(span.shrink_to_lo(), "{ ".to_string()), (span.shrink_to_hi(), " }".to_string())],
2747            Applicability::MaybeIncorrect,
2748        );
2749        let guar = err.emit();
2750        let value = self.mk_expr_err(span, guar);
2751        GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
2752    }
2753
2754    #[cold]
2757    pub(crate) fn recover_colon_colon_in_pat_typo(
2758        &mut self,
2759        mut first_pat: Pat,
2760        expected: Option<Expected>,
2761    ) -> Pat {
2762        if token::Colon != self.token.kind {
2763            return first_pat;
2764        }
2765
2766        let colon_span = self.token.span;
2769        let mut snapshot_pat = self.create_snapshot_for_diagnostic();
2772        let mut snapshot_type = self.create_snapshot_for_diagnostic();
2773
2774        match self.expected_one_of_not_found(&[], &[]) {
2776            Err(mut err) => {
2777                snapshot_pat.bump();
2779                snapshot_type.bump();
2780                match snapshot_pat.parse_pat_no_top_alt(expected, None) {
2781                    Err(inner_err) => {
2782                        inner_err.cancel();
2783                    }
2784                    Ok(mut pat) => {
2785                        let new_span = first_pat.span.to(pat.span);
2787                        let mut show_sugg = false;
2788                        match &mut pat.kind {
2790                            PatKind::Struct(qself @ None, path, ..)
2791                            | PatKind::TupleStruct(qself @ None, path, _)
2792                            | PatKind::Path(qself @ None, path) => match &first_pat.kind {
2793                                PatKind::Ident(_, ident, _) => {
2794                                    path.segments.insert(0, PathSegment::from_ident(*ident));
2795                                    path.span = new_span;
2796                                    show_sugg = true;
2797                                    first_pat = pat;
2798                                }
2799                                PatKind::Path(old_qself, old_path) => {
2800                                    path.segments = old_path
2801                                        .segments
2802                                        .iter()
2803                                        .cloned()
2804                                        .chain(take(&mut path.segments))
2805                                        .collect();
2806                                    path.span = new_span;
2807                                    *qself = old_qself.clone();
2808                                    first_pat = pat;
2809                                    show_sugg = true;
2810                                }
2811                                _ => {}
2812                            },
2813                            PatKind::Ident(BindingMode::NONE, ident, None) => {
2814                                match &first_pat.kind {
2815                                    PatKind::Ident(_, old_ident, _) => {
2816                                        let path = PatKind::Path(
2817                                            None,
2818                                            Path {
2819                                                span: new_span,
2820                                                segments: thin_vec![
2821                                                    PathSegment::from_ident(*old_ident),
2822                                                    PathSegment::from_ident(*ident),
2823                                                ],
2824                                                tokens: None,
2825                                            },
2826                                        );
2827                                        first_pat = self.mk_pat(new_span, path);
2828                                        show_sugg = true;
2829                                    }
2830                                    PatKind::Path(old_qself, old_path) => {
2831                                        let mut segments = old_path.segments.clone();
2832                                        segments.push(PathSegment::from_ident(*ident));
2833                                        let path = PatKind::Path(
2834                                            old_qself.clone(),
2835                                            Path { span: new_span, segments, tokens: None },
2836                                        );
2837                                        first_pat = self.mk_pat(new_span, path);
2838                                        show_sugg = true;
2839                                    }
2840                                    _ => {}
2841                                }
2842                            }
2843                            _ => {}
2844                        }
2845                        if show_sugg {
2846                            err.span_suggestion_verbose(
2847                                colon_span.until(self.look_ahead(1, |t| t.span)),
2848                                "maybe write a path separator here",
2849                                "::",
2850                                Applicability::MaybeIncorrect,
2851                            );
2852                        } else {
2853                            first_pat = self.mk_pat(
2854                                new_span,
2855                                PatKind::Err(
2856                                    self.dcx()
2857                                        .span_delayed_bug(colon_span, "recovered bad path pattern"),
2858                                ),
2859                            );
2860                        }
2861                        self.restore_snapshot(snapshot_pat);
2862                    }
2863                }
2864                match snapshot_type.parse_ty() {
2865                    Err(inner_err) => {
2866                        inner_err.cancel();
2867                    }
2868                    Ok(ty) => {
2869                        err.span_label(ty.span, "specifying the type of a pattern isn't supported");
2870                        self.restore_snapshot(snapshot_type);
2871                        let new_span = first_pat.span.to(ty.span);
2872                        first_pat =
2873                            self.mk_pat(
2874                                new_span,
2875                                PatKind::Err(self.dcx().span_delayed_bug(
2876                                    colon_span,
2877                                    "recovered bad pattern with type",
2878                                )),
2879                            );
2880                    }
2881                }
2882                err.emit();
2883            }
2884            _ => {
2885                }
2887        };
2888        first_pat
2889    }
2890
2891    pub(crate) fn maybe_recover_unexpected_block_label(
2894        &mut self,
2895        loop_header: Option<Span>,
2896    ) -> bool {
2897        if !(self.check_lifetime()
2899            && self.look_ahead(1, |t| *t == token::Colon)
2900            && self.look_ahead(2, |t| *t == token::OpenBrace))
2901        {
2902            return false;
2903        }
2904        let label = self.eat_label().expect("just checked if a label exists");
2905        self.bump(); let span = label.ident.span.to(self.prev_token.span);
2907        let mut diag = self
2908            .dcx()
2909            .struct_span_err(span, "block label not supported here")
2910            .with_span_label(span, "not supported here");
2911        if let Some(loop_header) = loop_header {
2912            diag.multipart_suggestion(
2913                "if you meant to label the loop, move this label before the loop",
2914                vec![
2915                    (label.ident.span.until(self.token.span), String::from("")),
2916                    (loop_header.shrink_to_lo(), format!("{}: ", label.ident)),
2917                ],
2918                Applicability::MachineApplicable,
2919            );
2920        } else {
2921            diag.tool_only_span_suggestion(
2922                label.ident.span.until(self.token.span),
2923                "remove this block label",
2924                "",
2925                Applicability::MachineApplicable,
2926            );
2927        }
2928        diag.emit();
2929        true
2930    }
2931
2932    pub(crate) fn maybe_recover_unexpected_comma(
2935        &mut self,
2936        lo: Span,
2937        rt: CommaRecoveryMode,
2938    ) -> PResult<'a, ()> {
2939        if self.token != token::Comma {
2940            return Ok(());
2941        }
2942        self.recover_unexpected_comma(lo, rt)
2943    }
2944
2945    #[cold]
2946    fn recover_unexpected_comma(&mut self, lo: Span, rt: CommaRecoveryMode) -> PResult<'a, ()> {
2947        let comma_span = self.token.span;
2952        self.bump();
2953        if let Err(err) = self.skip_pat_list() {
2954            err.cancel();
2957        }
2958        let seq_span = lo.to(self.prev_token.span);
2959        let mut err = self.dcx().struct_span_err(comma_span, "unexpected `,` in pattern");
2960        err.multipart_suggestion(
2961            format!(
2962                "try adding parentheses to match on a tuple{}",
2963                if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
2964            ),
2965            vec![
2966                (seq_span.shrink_to_lo(), "(".to_string()),
2967                (seq_span.shrink_to_hi(), ")".to_string()),
2968            ],
2969            Applicability::MachineApplicable,
2970        );
2971        if let CommaRecoveryMode::EitherTupleOrPipe = rt {
2972            err.span_suggestion(
2973                comma_span,
2974                "...or a vertical bar to match on alternatives",
2975                " |",
2976                Applicability::MachineApplicable,
2977            );
2978        }
2979        Err(err)
2980    }
2981
2982    pub(crate) fn maybe_recover_bounds_doubled_colon(&mut self, ty: &Ty) -> PResult<'a, ()> {
2983        let TyKind::Path(qself, path) = &ty.kind else { return Ok(()) };
2984        let qself_position = qself.as_ref().map(|qself| qself.position);
2985        for (i, segments) in path.segments.windows(2).enumerate() {
2986            if qself_position.is_some_and(|pos| i < pos) {
2987                continue;
2988            }
2989            if let [a, b] = segments {
2990                let (a_span, b_span) = (a.span(), b.span());
2991                let between_span = a_span.shrink_to_hi().to(b_span.shrink_to_lo());
2992                if self.span_to_snippet(between_span).as_deref() == Ok(":: ") {
2993                    return Err(self.dcx().create_err(DoubleColonInBound {
2994                        span: path.span.shrink_to_hi(),
2995                        between: between_span,
2996                    }));
2997                }
2998            }
2999        }
3000        Ok(())
3001    }
3002
3003    pub(crate) fn maybe_err_dotdotlt_syntax(&self, maybe_lt: Token, mut err: Diag<'a>) -> Diag<'a> {
3005        if maybe_lt == token::Lt
3006            && (self.expected_token_types.contains(TokenType::Gt)
3007                || matches!(self.token.kind, token::Literal(..)))
3008        {
3009            err.span_suggestion(
3010                maybe_lt.span,
3011                "remove the `<` to write an exclusive range",
3012                "",
3013                Applicability::MachineApplicable,
3014            );
3015        }
3016        err
3017    }
3018
3019    pub(super) fn is_vcs_conflict_marker(
3027        &mut self,
3028        long_kind: &TokenKind,
3029        short_kind: &TokenKind,
3030    ) -> bool {
3031        (0..3).all(|i| self.look_ahead(i, |tok| tok == long_kind))
3032            && self.look_ahead(3, |tok| tok == short_kind)
3033    }
3034
3035    fn conflict_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> Option<Span> {
3036        if self.is_vcs_conflict_marker(long_kind, short_kind) {
3037            let lo = self.token.span;
3038            for _ in 0..4 {
3039                self.bump();
3040            }
3041            return Some(lo.to(self.prev_token.span));
3042        }
3043        None
3044    }
3045
3046    pub(super) fn recover_vcs_conflict_marker(&mut self) {
3047        let Some(start) = self.conflict_marker(&TokenKind::Shl, &TokenKind::Lt) else {
3049            return;
3050        };
3051        let mut spans = Vec::with_capacity(3);
3052        spans.push(start);
3053        let mut middlediff3 = None;
3055        let mut middle = None;
3057        let mut end = None;
3059        loop {
3060            if self.token == TokenKind::Eof {
3061                break;
3062            }
3063            if let Some(span) = self.conflict_marker(&TokenKind::OrOr, &TokenKind::Or) {
3064                middlediff3 = Some(span);
3065            }
3066            if let Some(span) = self.conflict_marker(&TokenKind::EqEq, &TokenKind::Eq) {
3067                middle = Some(span);
3068            }
3069            if let Some(span) = self.conflict_marker(&TokenKind::Shr, &TokenKind::Gt) {
3070                spans.push(span);
3071                end = Some(span);
3072                break;
3073            }
3074            self.bump();
3075        }
3076
3077        let mut err = self.dcx().struct_span_fatal(spans, "encountered diff marker");
3078        match middlediff3 {
3079            Some(middlediff3) => {
3081                err.span_label(
3082                    start,
3083                    "between this marker and `|||||||` is the code that we're merging into",
3084                );
3085                err.span_label(middlediff3, "between this marker and `=======` is the base code (what the two refs diverged from)");
3086            }
3087            None => {
3088                err.span_label(
3089                    start,
3090                    "between this marker and `=======` is the code that we're merging into",
3091                );
3092            }
3093        };
3094
3095        if let Some(middle) = middle {
3096            err.span_label(middle, "between this marker and `>>>>>>>` is the incoming code");
3097        }
3098        if let Some(end) = end {
3099            err.span_label(end, "this marker concludes the conflict region");
3100        }
3101        err.note(
3102            "conflict markers indicate that a merge was started but could not be completed due \
3103             to merge conflicts\n\
3104             to resolve a conflict, keep only the code you want and then delete the lines \
3105             containing conflict markers",
3106        );
3107        err.help(
3108            "if you're having merge conflicts after pulling new code:\n\
3109             the top section is the code you already had and the bottom section is the remote code\n\
3110             if you're in the middle of a rebase:\n\
3111             the top section is the code being rebased onto and the bottom section is the code \
3112             coming from the current commit being rebased",
3113        );
3114
3115        err.note(
3116            "for an explanation on these markers from the `git` documentation:\n\
3117             visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>",
3118        );
3119
3120        err.emit();
3121    }
3122
3123    fn skip_pat_list(&mut self) -> PResult<'a, ()> {
3126        while !self.check(exp!(CloseParen)) {
3127            self.parse_pat_no_top_alt(None, None)?;
3128            if !self.eat(exp!(Comma)) {
3129                return Ok(());
3130            }
3131        }
3132        Ok(())
3133    }
3134}