Skip to main content

rustc_parse/parser/
diagnostics.rs

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