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