Skip to main content

rustc_parse/parser/
diagnostics.rs

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