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