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