compiler/rustc_parse/src/parser/ty.rs RUST 1,645 lines View on github.com → Search inside
1use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token, TokenKind};2use rustc_ast::util::case::Case;3use rustc_ast::{4    self as ast, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnPtrTy, FnRetTy,5    GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability,6    Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty,7    TyKind, UnsafeBinderTy,8};9use rustc_errors::{Applicability, Diag, E0516, PResult};10use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym};11use thin_vec::{ThinVec, thin_vec};1213use super::{Parser, PathStyle, SeqSep, TokenType, Trailing};14use crate::diagnostics::{15    self, AttributeOnEmptyType, AttributeOnType, DynAfterMut, ExpectedFnPathFoundFnKeyword,16    ExpectedMutOrConstInRawPointerType, FnPtrWithGenerics, FnPtrWithGenericsSugg,17    HelpUseLatestEdition, InvalidCVariadicType, InvalidDynKeyword, LifetimeAfterMut,18    NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow,19};20use crate::parser::{FnContext, FnParseMode, FrontMatterParsingMode};21use crate::{exp, maybe_recover_from_interpolated_ty_qpath};2223/// Signals whether parsing a type should allow `+`.24///25/// For example, let T be the type `impl Default + 'static`26/// With `AllowPlus::Yes`, T will be parsed successfully27/// With `AllowPlus::No`, parsing T will return a parse error28#[derive(Copy, Clone, PartialEq)]29pub(super) enum AllowPlus {30    Yes,31    No,32}3334#[derive(PartialEq)]35pub(super) enum RecoverQPath {36    Yes,37    No,38}3940pub(super) enum RecoverQuestionMark {41    Yes,42    No,43}4445/// Signals whether parsing a type should recover `->`.46///47/// More specifically, when parsing a function like:48/// ```compile_fail49/// fn foo() => u8 { 0 }50/// fn bar(): u8 { 0 }51/// ```52/// The compiler will try to recover interpreting `foo() => u8` as `foo() -> u8` when calling53/// `parse_ty` with anything except `RecoverReturnSign::No`, and it will try to recover `bar(): u8`54/// as `bar() -> u8` when passing `RecoverReturnSign::Yes` to `parse_ty`55#[derive(Copy, Clone, PartialEq)]56pub(super) enum RecoverReturnSign {57    Yes,58    OnlyFatArrow,59    No,60}6162impl RecoverReturnSign {63    /// [RecoverReturnSign::Yes] allows for recovering `fn foo() => u8` and `fn foo(): u8`,64    /// [RecoverReturnSign::OnlyFatArrow] allows for recovering only `fn foo() => u8` (recovering65    /// colons can cause problems when parsing where clauses), and66    /// [RecoverReturnSign::No] doesn't allow for any recovery of the return type arrow67    fn can_recover(self, token: &TokenKind) -> bool {68        match self {69            Self::Yes => matches!(token, token::FatArrow | token::Colon),70            Self::OnlyFatArrow => matches!(token, token::FatArrow),71            Self::No => false,72        }73    }74}7576// Is `...` (`CVarArgs`) legal at this level of type parsing?77#[derive(PartialEq)]78enum AllowCVariadic {79    Yes,80    No,81}8283/// Determine if the given token can begin a bound assuming it follows Rust 2015 identifier `dyn`.84///85/// In Rust 2015, `dyn` is a contextual keyword, not a full one.86fn can_begin_dyn_bound_in_edition_2015(t: Token) -> bool {87    if t.is_path_start() {88        // In `dyn::x`, `dyn<X>` and `dyn<<X>::Y>`, `dyn` should (continue to) denote a regular path89        // segment for backward compatibility. We make an exception for `dyn(X)` which used to be90        // interpreted as a path with parenthesized generic arguments which can be semantically91        // well-formed (consider: `use std::ops::Fn as dyn;`). Instead, we treat it as a trait92        // object type whose first bound is parenthesized.93        return t != token::PathSep && t != token::Lt && t != token::Shl;94    }9596    // Contrary to `Parser::can_begin_bound`, `!`, `const`, `[` and `async` are deliberately not97    // part of this list to contain the number of potential regressions esp. in MBE code.98    // `const` and `[` would regress UI test `macro-dyn-const-2015.rs` and99    // `!` would regress `dyn!(...)` macro calls in Rust 2015 for example.100    t == token::OpenParen || t == token::Question || t.is_lifetime() || t.is_keyword(kw::For)101}102103impl<'a> Parser<'a> {104    /// Parses a type.105    pub fn parse_ty(&mut self) -> PResult<'a, Box<Ty>> {106        if self.token == token::DotDotDot {107            // We special case this so that we don't talk about "nested C-variadics" in types.108            // We still pass in `AllowCVariadic::No` so that `parse_ty_common` can complain about109            // things like `Vec<...>`.110            let span = self.token.span;111            self.bump();112            let kind = TyKind::Err(self.dcx().emit_err(InvalidCVariadicType { span }));113            return Ok(self.mk_ty(span, kind));114        }115        self.parse_ty_common(116            AllowPlus::Yes,117            AllowCVariadic::No,118            RecoverQPath::Yes,119            RecoverReturnSign::Yes,120            None,121            RecoverQuestionMark::Yes,122        )123    }124125    pub(super) fn parse_ty_with_generics_recovery(126        &mut self,127        ty_params: &Generics,128    ) -> PResult<'a, Box<Ty>> {129        self.parse_ty_common(130            AllowPlus::Yes,131            AllowCVariadic::No,132            RecoverQPath::Yes,133            RecoverReturnSign::Yes,134            Some(ty_params),135            RecoverQuestionMark::Yes,136        )137    }138139    /// Parse a type suitable for a function or function pointer parameter.140    /// The difference from `parse_ty` is that this version allows `...`141    /// (`CVarArgs`) at the top level of the type.142    pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, Box<Ty>> {143        let ty = self.parse_ty_common(144            AllowPlus::Yes,145            AllowCVariadic::Yes,146            RecoverQPath::Yes,147            RecoverReturnSign::Yes,148            None,149            RecoverQuestionMark::Yes,150        )?;151152        // Recover a trailing `= EXPR` if present.153        if self.may_recover()154            && self.check_noexpect(&token::Eq)155            && self.look_ahead(1, |tok| tok.can_begin_expr())156        {157            let snapshot = self.create_snapshot_for_diagnostic();158            self.bump();159            let eq_span = self.prev_token.span;160            match self.parse_expr() {161                Ok(e) => {162                    self.dcx()163                        .struct_span_err(eq_span.to(e.span), "parameter defaults are not supported")164                        .emit();165                }166                Err(diag) => {167                    diag.cancel();168                    self.restore_snapshot(snapshot);169                }170            }171        }172173        Ok(ty)174    }175176    /// Parses a type in restricted contexts where `+` is not permitted.177    ///178    /// Example 1: `&'a TYPE`179    ///     `+` is prohibited to maintain operator priority (P(+) < P(&)).180    /// Example 2: `value1 as TYPE + value2`181    ///     `+` is prohibited to avoid interactions with expression grammar.182    pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, Box<Ty>> {183        self.parse_ty_common(184            AllowPlus::No,185            AllowCVariadic::No,186            RecoverQPath::Yes,187            RecoverReturnSign::Yes,188            None,189            RecoverQuestionMark::Yes,190        )191    }192193    /// Parses a type following an `as` cast. Similar to `parse_ty_no_plus`, but signaling origin194    /// for better diagnostics involving `?`.195    pub(super) fn parse_as_cast_ty(&mut self) -> PResult<'a, Box<Ty>> {196        self.parse_ty_common(197            AllowPlus::No,198            AllowCVariadic::No,199            RecoverQPath::Yes,200            RecoverReturnSign::Yes,201            None,202            RecoverQuestionMark::No,203        )204    }205206    pub(super) fn parse_ty_no_question_mark_recover(&mut self) -> PResult<'a, Box<Ty>> {207        self.parse_ty_common(208            AllowPlus::Yes,209            AllowCVariadic::No,210            RecoverQPath::Yes,211            RecoverReturnSign::Yes,212            None,213            RecoverQuestionMark::No,214        )215    }216217    /// Parse a type without recovering `:` as `->` to avoid breaking code such218    /// as `where fn() : for<'a>`.219    pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, Box<Ty>> {220        self.parse_ty_common(221            AllowPlus::Yes,222            AllowCVariadic::No,223            RecoverQPath::Yes,224            RecoverReturnSign::OnlyFatArrow,225            None,226            RecoverQuestionMark::Yes,227        )228    }229230    /// Parses an optional return type `[ -> TY ]` in a function declaration.231    pub(super) fn parse_ret_ty(232        &mut self,233        allow_plus: AllowPlus,234        recover_qpath: RecoverQPath,235        recover_return_sign: RecoverReturnSign,236    ) -> PResult<'a, FnRetTy> {237        let lo = self.prev_token.span;238        Ok(if self.eat(exp!(RArrow)) {239            // FIXME(Centril): Can we unconditionally `allow_plus`?240            let ty = self.parse_ty_common(241                allow_plus,242                AllowCVariadic::No,243                recover_qpath,244                recover_return_sign,245                None,246                RecoverQuestionMark::Yes,247            )?;248            FnRetTy::Ty(ty)249        } else if recover_return_sign.can_recover(&self.token.kind) {250            // Don't `eat` to prevent `=>` from being added as an expected token which isn't251            // actually expected and could only confuse users252            self.bump();253            self.dcx().emit_err(ReturnTypesUseThinArrow {254                span: self.prev_token.span,255                suggestion: lo.between(self.token.span),256            });257            let ty = self.parse_ty_common(258                allow_plus,259                AllowCVariadic::No,260                recover_qpath,261                recover_return_sign,262                None,263                RecoverQuestionMark::Yes,264            )?;265            FnRetTy::Ty(ty)266        } else {267            FnRetTy::Default(self.prev_token.span.shrink_to_hi())268        })269    }270271    fn parse_ty_common(272        &mut self,273        allow_plus: AllowPlus,274        allow_c_variadic: AllowCVariadic,275        recover_qpath: RecoverQPath,276        recover_return_sign: RecoverReturnSign,277        ty_generics: Option<&Generics>,278        recover_question_mark: RecoverQuestionMark,279    ) -> PResult<'a, Box<Ty>> {280        let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;281        maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);282        if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) {283            let attrs_wrapper = self.parse_outer_attributes()?;284            let raw_attrs = attrs_wrapper.take_for_recovery(self.psess);285            let attr_span = raw_attrs[0].span.to(raw_attrs.last().unwrap().span);286            let (full_span, guar) = match self.parse_ty() {287                Ok(ty) => {288                    let full_span = attr_span.until(ty.span);289                    let guar = self290                        .dcx()291                        .emit_err(AttributeOnType { span: attr_span, fix_span: full_span });292                    (attr_span, guar)293                }294                Err(err) => {295                    err.cancel();296                    let guar = self.dcx().emit_err(AttributeOnEmptyType { span: attr_span });297                    (attr_span, guar)298                }299            };300301            return Ok(self.mk_ty(full_span, TyKind::Err(guar)));302        }303        if let Some(ty) = self.eat_metavar_seq_with_matcher(304            |mv_kind| matches!(mv_kind, MetaVarKind::Ty { .. }),305            |this| this.parse_ty_no_question_mark_recover(),306        ) {307            return Ok(ty);308        }309310        let lo = self.token.span;311        let mut impl_dyn_multi = false;312        let kind = if self.check(exp!(OpenParen)) {313            self.parse_ty_tuple_or_parens(lo, allow_plus)?314        } else if self.eat(exp!(Bang)) {315            // Never type `!`316            TyKind::Never317        } else if self.eat(exp!(Star)) {318            self.parse_ty_ptr()?319        } else if self.eat(exp!(OpenBracket)) {320            self.parse_array_or_slice_ty()?321        } else if self.check(exp!(And)) || self.check(exp!(AndAnd)) {322            // Reference323            self.expect_and()?;324            self.parse_borrowed_pointee()?325        } else if self.eat_keyword_noexpect(kw::Typeof) {326            self.parse_typeof_ty(lo)?327        } else if self.is_builtin() {328            self.parse_builtin_ty()?329        } else if self.eat_keyword(exp!(Underscore)) {330            // A type to be inferred `_`331            TyKind::Infer332        } else if self.check_fn_front_matter(false, Case::Sensitive) {333            // Function pointer type334            self.parse_ty_fn_ptr(lo, ThinVec::new(), None, recover_return_sign)?335        } else if self.check_keyword(exp!(For)) {336            // Function pointer type or bound list (trait object type) starting with a poly-trait.337            //   `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`338            //   `for<'lt> Trait1<'lt> + Trait2 + 'a`339            let (bound_vars, _) = self.parse_higher_ranked_binder()?;340            if self.check_fn_front_matter(false, Case::Sensitive) {341                self.parse_ty_fn_ptr(342                    lo,343                    bound_vars,344                    Some(self.prev_token.span.shrink_to_lo()),345                    recover_return_sign,346                )?347            } else {348                // Try to recover `for<'a> dyn Trait` or `for<'a> impl Trait`.349                if self.may_recover()350                    && (self.eat_keyword_noexpect(kw::Impl) || self.eat_keyword_noexpect(kw::Dyn))351                {352                    let kw = self.prev_token.ident().unwrap().0;353                    let removal_span = kw.span.with_hi(self.token.span.lo());354                    let path = self.parse_path(PathStyle::Type)?;355                    let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();356                    let kind = self.parse_remaining_bounds_path(357                        bound_vars,358                        path,359                        lo,360                        parse_plus,361                        ast::Parens::No,362                    )?;363                    let err = self.dcx().create_err(diagnostics::TransposeDynOrImpl {364                        span: kw.span,365                        kw: kw.name.as_str(),366                        sugg: diagnostics::TransposeDynOrImplSugg {367                            removal_span,368                            insertion_span: lo.shrink_to_lo(),369                            kw: kw.name.as_str(),370                        },371                    });372373                    // Take the parsed bare trait object and turn it either374                    // into a `dyn` object or an `impl Trait`.375                    let kind = match (kind, kw.name) {376                        (TyKind::TraitObject(bounds, _), kw::Dyn) => {377                            TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)378                        }379                        (TyKind::TraitObject(bounds, _), kw::Impl) => {380                            TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)381                        }382                        _ => return Err(err),383                    };384                    err.emit();385                    kind386                } else {387                    let path = self.parse_path(PathStyle::Type)?;388                    let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();389                    self.parse_remaining_bounds_path(390                        bound_vars,391                        path,392                        lo,393                        parse_plus,394                        ast::Parens::No,395                    )?396                }397            }398        } else if self.eat_keyword(exp!(Impl)) {399            self.parse_impl_ty(&mut impl_dyn_multi)?400        } else if self.is_explicit_dyn_type() {401            self.parse_dyn_ty(&mut impl_dyn_multi)?402        } else if self.eat_lt() {403            // Qualified path404            let (qself, path) = self.parse_qpath(PathStyle::Type)?;405            TyKind::Path(Some(qself), path)406        } else if (self.token.is_keyword(kw::Const) || self.token.is_keyword(kw::Mut))407            && self.look_ahead(1, |t| *t == token::Star)408        {409            self.parse_ty_c_style_pointer()?410        } else if self.check_path() {411            self.parse_path_start_ty(lo, allow_plus, ty_generics)?412        } else if self.can_begin_bound() {413            self.parse_bare_trait_object(lo, allow_plus)?414        } else if self.eat(exp!(DotDotDot)) {415            match allow_c_variadic {416                AllowCVariadic::Yes => TyKind::CVarArgs,417                AllowCVariadic::No => {418                    // FIXME(c_variadic): Should we just allow `...` syntactically419                    // anywhere in a type and use semantic restrictions instead?420                    // NOTE: This may regress certain MBE calls if done incorrectly.421                    let guar = self.dcx().emit_err(NestedCVariadicType { span: lo });422                    TyKind::Err(guar)423                }424            }425        } else if self.check_keyword(exp!(Unsafe))426            && self.look_ahead(1, |tok| tok.kind == token::Lt)427        {428            self.parse_unsafe_binder_ty()?429        } else {430            let msg = format!("expected type, found {}", super::token_descr(&self.token));431            let mut err = self.dcx().struct_span_err(lo, msg);432            err.span_label(lo, "expected type");433            return Err(err);434        };435436        let span = lo.to(self.prev_token.span);437        let mut ty = self.mk_ty(span, kind);438439        // Try to recover from use of `+` with incorrect priority.440        match allow_plus {441            AllowPlus::Yes => self.maybe_recover_from_bad_type_plus(&ty)?,442            AllowPlus::No => self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty),443        }444        if let RecoverQuestionMark::Yes = recover_question_mark {445            ty = self.maybe_recover_from_question_mark(ty);446        }447        if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }448    }449450    fn parse_unsafe_binder_ty(&mut self) -> PResult<'a, TyKind> {451        let lo = self.token.span;452        assert!(self.eat_keyword(exp!(Unsafe)));453        self.expect_lt()?;454        let generic_params = self.parse_generic_params()?;455        self.expect_gt()?;456        let inner_ty = self.parse_ty()?;457        let span = lo.to(self.prev_token.span);458        self.psess.gated_spans.gate(sym::unsafe_binders, span);459460        Ok(TyKind::UnsafeBinder(Box::new(UnsafeBinderTy { generic_params, inner_ty })))461    }462463    /// Parses either:464    /// - `(TYPE)`, a parenthesized type.465    /// - `(TYPE,)`, a tuple with a single field of type TYPE.466    fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {467        let mut trailing_plus = false;468        let (ts, trailing) = self.parse_paren_comma_seq(|p| {469            let ty = p.parse_ty()?;470            trailing_plus = p.prev_token == TokenKind::Plus;471            Ok(ty)472        })?;473474        if ts.len() == 1 && matches!(trailing, Trailing::No) {475            let ty = ts.into_iter().next().unwrap();476            let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus();477            match ty.kind {478                // `"(" BareTraitBound ")" "+" Bound "+" ...`.479                TyKind::Path(None, path) if maybe_bounds => self.parse_remaining_bounds_path(480                    ThinVec::new(),481                    path,482                    lo,483                    true,484                    ast::Parens::Yes,485                ),486                // For `('a) + …`, we know that `'a` in type position already lead to an error being487                // emitted. To reduce output, let's indirectly suppress E0178 (bad `+` in type) and488                // other irrelevant consequential errors.489                TyKind::TraitObject(bounds, TraitObjectSyntax::None)490                    if maybe_bounds && bounds.len() == 1 && !trailing_plus =>491                {492                    self.parse_remaining_bounds(bounds, true)493                }494                // `(TYPE)`495                _ => Ok(TyKind::Paren(ty)),496            }497        } else {498            Ok(TyKind::Tup(ts))499        }500    }501502    fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {503        // A lifetime only begins a bare trait object type if it is followed by `+`!504        if self.token.is_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()) {505            // In Rust 2021 and beyond, we assume that the user didn't intend to write a bare trait506            // object type with a leading lifetime bound since that seems very unlikely given the507            // fact that `dyn`-less trait objects are *semantically* invalid.508            if self.psess.edition.at_least_rust_2021() {509                let lt = self.expect_lifetime();510                let mut err = self.dcx().struct_span_err(lo, "expected type, found lifetime");511                err.span_label(lo, "expected type");512                return Ok(match self.maybe_recover_ref_ty_no_leading_ampersand(lt, lo, err) {513                    Ok(ref_ty) => ref_ty,514                    Err(err) => TyKind::Err(err.emit()),515                });516            }517518            self.dcx().emit_err(NeedPlusAfterTraitObjectLifetime {519                span: lo,520                suggestion: lo.shrink_to_hi(),521            });522        }523        Ok(TyKind::TraitObject(524            self.parse_generic_bounds_common(allow_plus)?,525            TraitObjectSyntax::None,526        ))527    }528529    fn maybe_recover_ref_ty_no_leading_ampersand<'cx>(530        &mut self,531        lt: Lifetime,532        lo: Span,533        mut err: Diag<'cx>,534    ) -> Result<TyKind, Diag<'cx>> {535        if !self.may_recover() {536            return Err(err);537        }538        let snapshot = self.create_snapshot_for_diagnostic();539        let mutbl = self.parse_mutability();540        match self.parse_ty_no_plus() {541            Ok(ty) => {542                err.span_suggestion_verbose(543                    lo.shrink_to_lo(),544                    "you might have meant to write a reference type here",545                    "&",546                    Applicability::MaybeIncorrect,547                );548                err.emit();549                Ok(TyKind::Ref(Some(lt), MutTy { ty, mutbl }))550            }551            Err(diag) => {552                diag.cancel();553                self.restore_snapshot(snapshot);554                Err(err)555            }556        }557    }558559    fn parse_remaining_bounds_path(560        &mut self,561        generic_params: ThinVec<GenericParam>,562        path: ast::Path,563        lo: Span,564        parse_plus: bool,565        parens: ast::Parens,566    ) -> PResult<'a, TyKind> {567        let poly_trait_ref = PolyTraitRef::new(568            generic_params,569            path,570            TraitBoundModifiers::NONE,571            lo.to(self.prev_token.span),572            parens,573        );574        let bounds = thin_vec![GenericBound::Trait(poly_trait_ref)];575        self.parse_remaining_bounds(bounds, parse_plus)576    }577578    /// Parse the remainder of a bare trait object type given an already parsed list.579    fn parse_remaining_bounds(580        &mut self,581        mut bounds: GenericBounds,582        plus: bool,583    ) -> PResult<'a, TyKind> {584        if plus {585            self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded586            bounds.append(&mut self.parse_generic_bounds()?);587        }588        Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))589    }590591    /// Parses a raw pointer with a C-style typo592    fn parse_ty_c_style_pointer(&mut self) -> PResult<'a, TyKind> {593        let kw_span = self.token.span;594        let mutbl = self.parse_mut_or_const();595596        if let Some(mutbl) = mutbl597            && self.eat(exp!(Star))598        {599            let star_span = self.prev_token.span;600601            let mutability = match mutbl {602                Mutability::Not => "const",603                Mutability::Mut => "mut",604            };605606            let ty = self.parse_ty_no_question_mark_recover()?;607608            self.dcx()609                .struct_span_err(610                    kw_span,611                    format!("raw pointer types must be written as `*{mutability} T`"),612                )613                .with_multipart_suggestion(614                    format!("put the `*` before `{mutability}`"),615                    vec![(star_span, String::new()), (kw_span.shrink_to_lo(), "*".to_string())],616                    Applicability::MachineApplicable,617                )618                .emit();619620            return Ok(TyKind::Ptr(MutTy { ty, mutbl }));621        }622        // This is unreachable because we always get into if above and return from it623        unreachable!("this could never happen")624    }625626    /// Parses a raw pointer type: `*[const | mut] $type`.627    fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> {628        let mutbl = self.parse_mut_or_const().unwrap_or_else(|| {629            let span = self.prev_token.span;630            self.dcx().emit_err(ExpectedMutOrConstInRawPointerType {631                span,632                after_asterisk: span.shrink_to_hi(),633            });634            Mutability::Not635        });636        let ty = self.parse_ty_no_plus()?;637        Ok(TyKind::Ptr(MutTy { ty, mutbl }))638    }639640    /// Parses an array (`[TYPE; EXPR]`) or slice (`[TYPE]`) type.641    /// The opening `[` bracket is already eaten.642    fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> {643        let elt_ty = match self.parse_ty() {644            Ok(ty) => ty,645            Err(err)646                if self.look_ahead(1, |t| *t == token::CloseBracket)647                    | self.look_ahead(1, |t| *t == token::Semi) =>648            {649                // Recover from `[LIT; EXPR]` and `[LIT]`650                self.bump();651                let guar = err.emit();652                self.mk_ty(self.prev_token.span, TyKind::Err(guar))653            }654            Err(err) => return Err(err),655        };656657        let ty = if self.eat(exp!(Semi)) {658            let mut length = self.parse_expr_anon_const()?;659660            if let Err(e) = self.expect(exp!(CloseBracket)) {661                // Try to recover from `X<Y, ...>` when `X::<Y, ...>` works662                self.check_mistyped_turbofish_with_multiple_type_params(e, &mut length.value)?;663                self.expect(exp!(CloseBracket))?;664            }665            TyKind::Array(elt_ty, length)666        } else if self.eat(exp!(CloseBracket)) {667            TyKind::Slice(elt_ty)668        } else {669            self.maybe_recover_array_ty_without_semi(elt_ty)?670        };671672        Ok(ty)673    }674675    /// Recover from malformed array type syntax.676    ///677    /// This method attempts to recover from cases like:678    /// - `[u8, 5]` → suggests using `;`, return a Array type679    /// - `[u8 5]` → suggests using `;`, return a Array type680    /// Consider to add more cases in the future.681    fn maybe_recover_array_ty_without_semi(&mut self, elt_ty: Box<Ty>) -> PResult<'a, TyKind> {682        let span = self.token.span;683        let token_descr = super::token_descr(&self.token);684        let mut err =685            self.dcx().struct_span_err(span, format!("expected `;` or `]`, found {}", token_descr));686        err.span_label(span, "expected `;` or `]`");687688        // If we cannot recover, return the error immediately.689        if !self.may_recover() {690            return Err(err);691        }692693        let snapshot = self.create_snapshot_for_diagnostic();694695        // Consume common erroneous separators.696        let hi = self.prev_token.span.hi();697        _ = self.eat(exp!(Comma)) || self.eat(exp!(Colon)) || self.eat(exp!(Star));698        let suggestion_span = self.prev_token.span.with_lo(hi);699700        // FIXME(mgca): recovery is broken for `const {` args701        // we first try to parse pattern like `[u8 5]`702        let length = match self.parse_expr_anon_const() {703            Ok(length) => length,704            Err(e) => {705                e.cancel();706                self.restore_snapshot(snapshot);707                return Err(err);708            }709        };710711        if let Err(e) = self.expect(exp!(CloseBracket)) {712            e.cancel();713            self.restore_snapshot(snapshot);714            return Err(err);715        }716717        err.span_suggestion_verbose(718            suggestion_span,719            "you might have meant to use `;` as the separator",720            ";",721            Applicability::MaybeIncorrect,722        );723        err.emit();724        Ok(TyKind::Array(elt_ty, length))725    }726727    fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {728        let and_span = self.prev_token.span;729        let mut opt_lifetime = self.check_lifetime().then(|| self.expect_lifetime());730        let (pinned, mut mutbl) = self.parse_pin_and_mut();731        if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() {732            // A lifetime is invalid here: it would be part of a bare trait bound, which requires733            // it to be followed by a plus, but we disallow plus in the pointee type.734            // So we can handle this case as an error here, and suggest `'a mut`.735            // If there *is* a plus next though, handling the error later provides better suggestions736            // (like adding parentheses)737            if !self.look_ahead(1, |t| t.is_like_plus()) {738                let lifetime_span = self.token.span;739                let span = and_span.to(lifetime_span);740741                let (suggest_lifetime, snippet) =742                    if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) {743                        (Some(span), lifetime_src)744                    } else {745                        (None, String::new())746                    };747                self.dcx().emit_err(LifetimeAfterMut { span, suggest_lifetime, snippet });748749                opt_lifetime = Some(self.expect_lifetime());750            }751        } else if self.token.is_keyword(kw::Dyn)752            && mutbl == Mutability::Not753            && self.look_ahead(1, |t| t.is_keyword(kw::Mut))754        {755            // We have `&dyn mut ...`, which is invalid and should be `&mut dyn ...`.756            let span = and_span.to(self.look_ahead(1, |t| t.span));757            self.dcx().emit_err(DynAfterMut { span });758759            // Recovery760            mutbl = Mutability::Mut;761            let (dyn_tok, dyn_tok_sp) = (self.token, self.token_spacing);762            self.bump();763            self.bump_with((dyn_tok, dyn_tok_sp));764        }765        let ty = self.parse_ty_no_plus()?;766        Ok(match pinned {767            Pinnedness::Not => TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }),768            Pinnedness::Pinned => TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl }),769        })770    }771772    /// Parse nothing, mutability or `pin` followed by "explicit" mutability.773    ///774    /// ```ebnf775    /// PinAndMut = "pin" MutOrConst | "mut"776    /// ```777    pub(crate) fn parse_pin_and_mut(&mut self) -> (Pinnedness, Mutability) {778        if self.token.is_ident_named(sym::pin) && self.look_ahead(1, Token::is_mutability) {779            self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);780            assert!(self.eat_keyword(exp!(Pin)));781            let mutbl = self.parse_mut_or_const().unwrap();782            (Pinnedness::Pinned, mutbl)783        } else {784            (Pinnedness::Not, self.parse_mutability())785        }786    }787788    /// Parses the `typeof(EXPR)` for better diagnostics before returning789    /// an error type.790    fn parse_typeof_ty(&mut self, lo: Span) -> PResult<'a, TyKind> {791        self.expect(exp!(OpenParen))?;792        let _expr = self.parse_expr_anon_const()?;793        self.expect(exp!(CloseParen))?;794        let span = lo.to(self.prev_token.span);795        let guar = self796            .dcx()797            .struct_span_err(span, "`typeof` is a reserved keyword but unimplemented")798            .with_note("consider replacing `typeof(...)` with an actual type")799            .with_code(E0516)800            .emit();801        Ok(TyKind::Err(guar))802    }803804    fn parse_builtin_ty(&mut self) -> PResult<'a, TyKind> {805        self.parse_builtin(|this, lo, ident| {806            Ok(match ident.name {807                sym::field_of => Some(this.parse_ty_field_of(lo)?),808                _ => None,809            })810        })811    }812813    pub(crate) fn parse_ty_field_of(&mut self, _lo: Span) -> PResult<'a, TyKind> {814        let container = self.parse_ty()?;815        self.expect(exp!(Comma))?;816817        let fields = self.parse_floating_field_access()?;818        let trailing_comma = self.eat_noexpect(&TokenKind::Comma);819820        if let Err(mut e) = self.expect_one_of(&[], &[exp!(CloseParen)]) {821            if trailing_comma {822                e.note("unexpected third argument to field_of");823            } else {824                e.note("field_of expects dot-separated field and variant names");825            }826            e.emit();827        }828829        // Eat tokens until the macro call ends.830        if self.may_recover() {831            while !self.token.kind.is_close_delim_or_eof() {832                self.bump();833            }834        }835836        match *fields {837            [] => Err(self.dcx().struct_span_err(838                self.token.span,839                "`field_of!` expects dot-separated field and variant names",840            )),841            [field] => Ok(TyKind::FieldOf(container, None, field)),842            [variant, field] => Ok(TyKind::FieldOf(container, Some(variant), field)),843            _ => Err(self.dcx().struct_span_err(844                fields.iter().map(|f| f.span).collect::<Vec<_>>(),845                "`field_of!` only supports a single field or a variant with a field",846            )),847        }848    }849850    /// Parses a function pointer type (`TyKind::FnPtr`).851    /// ```ignore (illustrative)852    ///    [unsafe] [extern "ABI"] fn (S) -> T853    /// //  ^~~~~^          ^~~~^     ^~^    ^854    /// //    |               |        |     |855    /// //    |               |        |   Return type856    /// // Function Style    ABI  Parameter types857    /// ```858    /// We actually parse `FnHeader FnDecl`, but we error on `const` and `async` qualifiers.859    fn parse_ty_fn_ptr(860        &mut self,861        lo: Span,862        mut params: ThinVec<GenericParam>,863        param_insertion_point: Option<Span>,864        recover_return_sign: RecoverReturnSign,865    ) -> PResult<'a, TyKind> {866        let inherited_vis = rustc_ast::Visibility {867            span: rustc_span::DUMMY_SP,868            kind: rustc_ast::VisibilityKind::Inherited,869        };870        let span_start = self.token.span;871        let ast::FnHeader { ext, safety, .. } = self.parse_fn_front_matter(872            &inherited_vis,873            Case::Sensitive,874            FrontMatterParsingMode::FunctionPtrType,875        )?;876        if self.may_recover() && self.token == TokenKind::Lt {877            self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;878        }879        let mode = crate::parser::FnParseMode {880            req_name: |_, _| false,881            context: FnContext::FunctionPtrType,882            req_body: false,883        };884        let decl = self.parse_fn_decl(&mode, AllowPlus::No, recover_return_sign)?;885886        let decl_span = span_start.to(self.prev_token.span);887        Ok(TyKind::FnPtr(Box::new(FnPtrTy {888            ext,889            safety,890            generic_params: params,891            decl,892            decl_span,893        })))894    }895896    /// Recover from function pointer types with a generic parameter list (e.g. `fn<'a>(&'a str)`).897    fn recover_fn_ptr_with_generics(898        &mut self,899        lo: Span,900        params: &mut ThinVec<GenericParam>,901        param_insertion_point: Option<Span>,902    ) -> PResult<'a, ()> {903        let generics = self.parse_generics()?;904        let arity = generics.params.len();905906        let mut lifetimes: ThinVec<_> = generics907            .params908            .into_iter()909            .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime))910            .collect();911912        let sugg = if !lifetimes.is_empty() {913            let snippet =914                lifetimes.iter().map(|param| param.ident.as_str()).intersperse(", ").collect();915916            let (left, snippet) = if let Some(span) = param_insertion_point {917                (span, if params.is_empty() { snippet } else { format!(", {snippet}") })918            } else {919                (lo.shrink_to_lo(), format!("for<{snippet}> "))920            };921922            Some(FnPtrWithGenericsSugg {923                left,924                snippet,925                right: generics.span,926                arity,927                for_param_list_exists: param_insertion_point.is_some(),928            })929        } else {930            None931        };932933        self.dcx().emit_err(FnPtrWithGenerics { span: generics.span, sugg });934        params.append(&mut lifetimes);935        Ok(())936    }937938    /// Parses an `impl B0 + ... + Bn` type.939    fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {940        if self.token.is_lifetime() {941            self.look_ahead(1, |t| {942                if let token::Ident(sym, _) = t.kind {943                    // parse pattern with "'a Sized" we're supposed to give suggestion like944                    // "'a + Sized"945                    self.dcx().emit_err(diagnostics::MissingPlusBounds {946                        span: self.token.span,947                        hi: self.token.span.shrink_to_hi(),948                        sym,949                    });950                }951            })952        }953954        // Always parse bounds greedily for better error recovery.955        let bounds = self.parse_generic_bounds()?;956957        *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::Plus;958959        Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))960    }961962    /// Parse a use-bound aka precise capturing list.963    ///964    /// ```ebnf965    /// UseBound = "use" "<" (PreciseCapture ("," PreciseCapture)* ","?)? ">"966    /// PreciseCapture = "Self" | Ident | Lifetime967    /// ```968    fn parse_use_bound(&mut self, lo: Span, parens: ast::Parens) -> PResult<'a, GenericBound> {969        self.expect_lt()?;970        let (args, _, _) = self.parse_seq_to_before_tokens(971            &[exp!(Gt)],972            &[&TokenKind::Ge, &TokenKind::Shr, &TokenKind::Shr],973            SeqSep::trailing_allowed(exp!(Comma)),974            |self_| {975                if self_.check_keyword(exp!(SelfUpper)) {976                    self_.bump();977                    Ok(PreciseCapturingArg::Arg(978                        ast::Path::from_ident(self_.prev_token.ident().unwrap().0),979                        DUMMY_NODE_ID,980                    ))981                } else if self_.check_ident() {982                    Ok(PreciseCapturingArg::Arg(983                        ast::Path::from_ident(self_.parse_ident()?),984                        DUMMY_NODE_ID,985                    ))986                } else if self_.check_lifetime() {987                    Ok(PreciseCapturingArg::Lifetime(self_.expect_lifetime()))988                } else {989                    self_.unexpected_any()990                }991            },992        )?;993        self.expect_gt()?;994995        if let ast::Parens::Yes = parens {996            self.expect(exp!(CloseParen))?;997            self.report_parenthesized_bound(lo, self.prev_token.span, "precise capturing lists");998        }9991000        Ok(GenericBound::Use(args, lo.to(self.prev_token.span)))1001    }10021003    /// Is a `dyn B0 + ... + Bn` type allowed here?1004    fn is_explicit_dyn_type(&mut self) -> bool {1005        self.check_keyword(exp!(Dyn))1006            && (self.token_uninterpolated_span().at_least_rust_2018()1007                || self.look_ahead(1, |&t| can_begin_dyn_bound_in_edition_2015(t)))1008    }10091010    /// Parses a `dyn B0 + ... + Bn` type.1011    ///1012    /// Note that this does *not* parse bare trait objects.1013    fn parse_dyn_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {1014        self.bump(); // `dyn`10151016        // Always parse bounds greedily for better error recovery.1017        let bounds = self.parse_generic_bounds()?;1018        *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::Plus;10191020        Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn))1021    }10221023    /// Parses a type starting with a path.1024    ///1025    /// This can be:1026    /// 1. a type macro, `mac!(...)`,1027    /// 2. a bare trait object, `B0 + ... + Bn`,1028    /// 3. or a path, `path::to::MyType`.1029    fn parse_path_start_ty(1030        &mut self,1031        lo: Span,1032        allow_plus: AllowPlus,1033        ty_generics: Option<&Generics>,1034    ) -> PResult<'a, TyKind> {1035        // Simple path1036        let path = self.parse_path_inner(PathStyle::Type, ty_generics)?;1037        if self.eat(exp!(Bang)) {1038            // Macro invocation in type position1039            Ok(TyKind::MacCall(Box::new(MacCall { path, args: self.parse_delim_args()? })))1040        } else if allow_plus == AllowPlus::Yes && self.check_plus() {1041            // `Trait1 + Trait2 + 'a`1042            self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true, ast::Parens::No)1043        } else {1044            // Just a type path.1045            Ok(TyKind::Path(None, path))1046        }1047    }10481049    pub(super) fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> {1050        self.parse_generic_bounds_common(AllowPlus::Yes)1051    }10521053    /// Parse generic bounds.1054    ///1055    /// Only if `allow_plus` this parses a `+`-separated list of bounds (trailing `+` is admitted).1056    /// Otherwise, this only parses a single bound or none.1057    fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> {1058        let mut bounds = ThinVec::new();10591060        // In addition to looping while we find generic bounds:1061        // We continue even if we find a keyword. This is necessary for error recovery on,1062        // for example, `impl fn()`. The only keyword that can go after generic bounds is1063        // `where`, so stop if it's it.1064        // We also continue if we find types (not traits), again for error recovery.1065        while self.can_begin_bound()1066            || (self.may_recover()1067                && (self.token.can_begin_type()1068                    || (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where))))1069        {1070            if self.token.is_keyword(kw::Dyn) && self.token.span.edition().at_least_rust_2018() {1071                // Account for `&dyn Trait + dyn Other`.1072                self.bump();1073                self.dcx().emit_err(InvalidDynKeyword {1074                    span: self.prev_token.span,1075                    suggestion: self.prev_token.span.until(self.token.span),1076                });1077            }1078            bounds.push(self.parse_generic_bound()?);1079            if allow_plus == AllowPlus::No || !self.eat_plus() {1080                break;1081            }1082        }10831084        Ok(bounds)1085    }10861087    /// Can the current token begin a bound?1088    fn can_begin_bound(&mut self) -> bool {1089        self.check_path()1090            || self.check_lifetime()1091            || self.check(exp!(Bang))1092            || self.check(exp!(Question))1093            || self.check(exp!(Tilde))1094            || self.check_keyword(exp!(For))1095            || self.check(exp!(OpenParen))1096            || self.can_begin_maybe_const_bound()1097            || self.check_keyword(exp!(Const))1098            || self.check_keyword(exp!(Async))1099            || self.check_keyword(exp!(Use))1100    }11011102    fn can_begin_maybe_const_bound(&mut self) -> bool {1103        self.check(exp!(OpenBracket))1104            && self.look_ahead(1, |t| t.is_keyword(kw::Const))1105            && self.look_ahead(2, |t| *t == token::CloseBracket)1106    }11071108    /// Parse a bound.1109    ///1110    /// ```ebnf1111    /// Bound = LifetimeBound | UseBound | TraitBound1112    /// ```1113    fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {1114        let leading_token = self.prev_token;1115        let lo = self.token.span;11161117        // We only admit parenthesized *trait* bounds. However, we want to gracefully recover from1118        // other kinds of parenthesized bounds, so parse the opening parenthesis *here*.1119        //1120        // In the future we might want to lift this syntactic restriction and1121        // introduce "`GenericBound::Paren(Box<GenericBound>)`".1122        let parens = if self.eat(exp!(OpenParen)) { ast::Parens::Yes } else { ast::Parens::No };11231124        if self.token.is_lifetime() {1125            self.parse_lifetime_bound(lo, parens)1126        } else if self.eat_keyword(exp!(Use)) {1127            self.parse_use_bound(lo, parens)1128        } else {1129            self.parse_trait_bound(lo, parens, &leading_token)1130        }1131    }11321133    /// Parse a lifetime-bound aka outlives-bound.1134    ///1135    /// ```ebnf1136    /// LifetimeBound = Lifetime1137    /// ```1138    fn parse_lifetime_bound(&mut self, lo: Span, parens: ast::Parens) -> PResult<'a, GenericBound> {1139        let lt = self.expect_lifetime();11401141        if let ast::Parens::Yes = parens {1142            self.expect(exp!(CloseParen))?;1143            self.report_parenthesized_bound(lo, self.prev_token.span, "lifetime bounds");1144        }11451146        Ok(GenericBound::Outlives(lt))1147    }11481149    fn report_parenthesized_bound(&self, lo: Span, hi: Span, kind: &str) -> ErrorGuaranteed {1150        let mut diag =1151            self.dcx().struct_span_err(lo.to(hi), format!("{kind} may not be parenthesized"));1152        diag.multipart_suggestion(1153            "remove the parentheses",1154            vec![(lo, String::new()), (hi, String::new())],1155            Applicability::MachineApplicable,1156        );1157        diag.emit()1158    }11591160    /// Emits an error if any trait bound modifiers were present.1161    fn error_lt_bound_with_modifiers(1162        &self,1163        modifiers: TraitBoundModifiers,1164        binder_span: Option<Span>,1165    ) -> ErrorGuaranteed {1166        let TraitBoundModifiers { constness, asyncness, polarity } = modifiers;11671168        match constness {1169            BoundConstness::Never => {}1170            BoundConstness::Always(span) | BoundConstness::Maybe(span) => {1171                return self.dcx().emit_err(diagnostics::ModifierLifetime {1172                    span,1173                    modifier: constness.as_str(),1174                });1175            }1176        }11771178        match polarity {1179            BoundPolarity::Positive => {}1180            BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => {1181                return self1182                    .dcx()1183                    .emit_err(diagnostics::ModifierLifetime { span, modifier: polarity.as_str() });1184            }1185        }11861187        match asyncness {1188            BoundAsyncness::Normal => {}1189            BoundAsyncness::Async(span) => {1190                return self.dcx().emit_err(diagnostics::ModifierLifetime {1191                    span,1192                    modifier: asyncness.as_str(),1193                });1194            }1195        }11961197        if let Some(span) = binder_span {1198            return self1199                .dcx()1200                .emit_err(diagnostics::ModifierLifetime { span, modifier: "for<...>" });1201        }12021203        unreachable!("lifetime bound intercepted in `parse_generic_ty_bound` but no modifiers?")1204    }12051206    /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `[const] Trait`.1207    ///1208    /// If no modifiers are present, this does not consume any tokens.1209    ///1210    /// ```ebnf1211    /// Constness = ("const" | "[" "const" "]")?1212    /// Asyncness = "async"?1213    /// Polarity = ("?" | "!")?1214    /// ```1215    ///1216    /// See `parse_trait_bound` for more context.1217    fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {1218        let modifier_lo = self.token.span;1219        let constness = self.parse_bound_constness()?;12201221        let asyncness = if self.token_uninterpolated_span().at_least_rust_2018()1222            && self.eat_keyword(exp!(Async))1223        {1224            self.psess.gated_spans.gate(sym::async_trait_bounds, self.prev_token.span);1225            BoundAsyncness::Async(self.prev_token.span)1226        } else if self.may_recover()1227            && self.token_uninterpolated_span().is_rust_2015()1228            && self.is_kw_followed_by_ident(kw::Async)1229        {1230            self.bump(); // eat `async`1231            self.dcx().emit_err(diagnostics::AsyncBoundModifierIn2015 {1232                span: self.prev_token.span,1233                help: HelpUseLatestEdition::new(),1234            });1235            self.psess.gated_spans.gate(sym::async_trait_bounds, self.prev_token.span);1236            BoundAsyncness::Async(self.prev_token.span)1237        } else {1238            BoundAsyncness::Normal1239        };1240        let modifier_hi = self.prev_token.span;12411242        let polarity = if self.eat(exp!(Question)) {1243            BoundPolarity::Maybe(self.prev_token.span)1244        } else if self.eat(exp!(Bang)) {1245            self.psess.gated_spans.gate(sym::negative_bounds, self.prev_token.span);1246            BoundPolarity::Negative(self.prev_token.span)1247        } else {1248            BoundPolarity::Positive1249        };12501251        // Enforce the mutual-exclusivity of `const`/`async` and `?`/`!`.1252        match polarity {1253            BoundPolarity::Positive => {1254                // All trait bound modifiers allowed to combine with positive polarity1255            }1256            BoundPolarity::Maybe(polarity_span) | BoundPolarity::Negative(polarity_span) => {1257                match (asyncness, constness) {1258                    (BoundAsyncness::Normal, BoundConstness::Never) => {1259                        // Ok, no modifiers.1260                    }1261                    (_, _) => {1262                        let constness = constness.as_str();1263                        let asyncness = asyncness.as_str();1264                        let glue =1265                            if !constness.is_empty() && !asyncness.is_empty() { " " } else { "" };1266                        let modifiers_concatenated = format!("{constness}{glue}{asyncness}");1267                        self.dcx().emit_err(diagnostics::PolarityAndModifiers {1268                            polarity_span,1269                            polarity: polarity.as_str(),1270                            modifiers_span: modifier_lo.to(modifier_hi),1271                            modifiers_concatenated,1272                        });1273                    }1274                }1275            }1276        }12771278        Ok(TraitBoundModifiers { constness, asyncness, polarity })1279    }12801281    pub fn parse_bound_constness(&mut self) -> PResult<'a, BoundConstness> {1282        // FIXME(const_trait_impl): remove `~const` parser support once bootstrap has the new syntax1283        // in rustfmt1284        Ok(if self.eat(exp!(Tilde)) {1285            let tilde = self.prev_token.span;1286            self.expect_keyword(exp!(Const))?;1287            let span = tilde.to(self.prev_token.span);1288            self.psess.gated_spans.gate(sym::const_trait_impl, span);1289            BoundConstness::Maybe(span)1290        } else if self.can_begin_maybe_const_bound() {1291            let start = self.token.span;1292            self.bump();1293            self.expect_keyword(exp!(Const)).unwrap();1294            self.bump();1295            let span = start.to(self.prev_token.span);1296            self.psess.gated_spans.gate(sym::const_trait_impl, span);1297            BoundConstness::Maybe(span)1298        } else if self.eat_keyword(exp!(Const)) {1299            self.psess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span);1300            BoundConstness::Always(self.prev_token.span)1301        } else {1302            BoundConstness::Never1303        })1304    }13051306    /// Parse a trait bound.1307    ///1308    /// ```ebnf1309    /// TraitBound = BareTraitBound | "(" BareTraitBound ")"1310    /// BareTraitBound =1311    ///     (HigherRankedBinder Constness Asyncness | Polarity)1312    ///     TypePath1313    /// ```1314    fn parse_trait_bound(1315        &mut self,1316        lo: Span,1317        parens: ast::Parens,1318        leading_token: &Token,1319    ) -> PResult<'a, GenericBound> {1320        let (mut bound_vars, binder_span) = self.parse_higher_ranked_binder()?;13211322        let modifiers_lo = self.token.span;1323        let modifiers = self.parse_trait_bound_modifiers()?;1324        let modifiers_span = modifiers_lo.to(self.prev_token.span);13251326        if let Some(binder_span) = binder_span {1327            match modifiers.polarity {1328                BoundPolarity::Negative(polarity_span) | BoundPolarity::Maybe(polarity_span) => {1329                    self.dcx().emit_err(diagnostics::BinderAndPolarity {1330                        binder_span,1331                        polarity_span,1332                        polarity: modifiers.polarity.as_str(),1333                    });1334                }1335                BoundPolarity::Positive => {}1336            }1337        }13381339        // Recover erroneous lifetime bound with modifiers or binder.1340        // e.g. `T: for<'a> 'a` or `T: [const] 'a`.1341        if self.token.is_lifetime() {1342            let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span);1343            return self.parse_lifetime_bound(lo, parens);1344        }13451346        if let (more_bound_vars, Some(binder_span)) = self.parse_higher_ranked_binder()? {1347            bound_vars.extend(more_bound_vars);1348            self.dcx().emit_err(diagnostics::BinderBeforeModifiers { binder_span, modifiers_span });1349        }13501351        let mut path = if self.token.is_keyword(kw::Fn)1352            && self.look_ahead(1, |t| *t == TokenKind::OpenParen)1353            && let Some(path) = self.recover_path_from_fn()1354        {1355            path1356        } else if !self.token.is_path_start() && self.token.can_begin_type() {1357            let ty = self.parse_ty_no_plus()?;1358            // Instead of finding a path (a trait), we found a type.1359            let mut err = self.dcx().struct_span_err(ty.span, "expected a trait, found type");13601361            // If we can recover, try to extract a path from the type. Note1362            // that we do not use the try operator when parsing the type because1363            // if it fails then we get a parser error which we don't want (we're trying1364            // to recover from errors, not make more).1365            let path = if self.may_recover() {1366                let (span, message, sugg, path, applicability) = match &ty.kind {1367                    TyKind::Ptr(..) | TyKind::Ref(..)1368                        if let TyKind::Path(_, path) = &ty.peel_refs().kind =>1369                    {1370                        (1371                            ty.span.until(path.span),1372                            "consider removing the indirection",1373                            "",1374                            path,1375                            Applicability::MaybeIncorrect,1376                        )1377                    }1378                    TyKind::ImplTrait(_, bounds)1379                        if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() =>1380                    {1381                        (1382                            ty.span.until(tr.span),1383                            "use the trait bounds directly",1384                            "",1385                            &tr.trait_ref.path,1386                            Applicability::MachineApplicable,1387                        )1388                    }1389                    _ => return Err(err),1390                };13911392                err.span_suggestion_verbose(span, message, sugg, applicability);13931394                path.clone()1395            } else {1396                return Err(err);1397            };13981399            err.emit();14001401            path1402        } else {1403            self.parse_path(PathStyle::Type)?1404        };14051406        if self.may_recover() && self.token == TokenKind::OpenParen {1407            self.recover_fn_trait_with_lifetime_params(&mut path, &mut bound_vars)?;1408        }14091410        if let ast::Parens::Yes = parens {1411            // Someone has written something like `&dyn (Trait + Other)`. The correct code1412            // would be `&(dyn Trait + Other)`1413            if self.token.is_like_plus() && leading_token.is_keyword(kw::Dyn) {1414                let bounds = thin_vec![];1415                self.parse_remaining_bounds(bounds, true)?;1416                self.expect(exp!(CloseParen))?;1417                self.dcx().emit_err(diagnostics::IncorrectParensTraitBounds {1418                    span: vec![lo, self.prev_token.span],1419                    sugg: diagnostics::IncorrectParensTraitBoundsSugg {1420                        wrong_span: leading_token.span.shrink_to_hi().to(lo),1421                        new_span: leading_token.span.shrink_to_lo(),1422                    },1423                });1424            } else {1425                self.expect(exp!(CloseParen))?;1426            }1427        }14281429        let poly_trait =1430            PolyTraitRef::new(bound_vars, path, modifiers, lo.to(self.prev_token.span), parens);1431        Ok(GenericBound::Trait(poly_trait))1432    }14331434    // recovers a `Fn(..)` parenthesized-style path from `fn(..)`1435    fn recover_path_from_fn(&mut self) -> Option<ast::Path> {1436        let fn_token_span = self.token.span;1437        self.bump();1438        let args_lo = self.token.span;1439        let snapshot = self.create_snapshot_for_diagnostic();1440        let mode =1441            FnParseMode { req_name: |_, _| false, context: FnContext::Free, req_body: false };1442        match self.parse_fn_decl(&mode, AllowPlus::No, RecoverReturnSign::OnlyFatArrow) {1443            Ok(decl) => {1444                self.dcx().emit_err(ExpectedFnPathFoundFnKeyword { fn_token_span });1445                Some(ast::Path {1446                    span: fn_token_span.to(self.prev_token.span),1447                    segments: thin_vec![ast::PathSegment {1448                        ident: Ident::new(sym::Fn, fn_token_span),1449                        id: DUMMY_NODE_ID,1450                        args: Some(Box::new(ast::GenericArgs::Parenthesized(1451                            ast::ParenthesizedArgs {1452                                span: args_lo.to(self.prev_token.span),1453                                inputs: decl.inputs.iter().map(|a| a.clone()).collect(),1454                                inputs_span: args_lo.until(decl.output.span()),1455                                output: decl.output.clone(),1456                            }1457                        ))),1458                    }],1459                })1460            }1461            Err(diag) => {1462                diag.cancel();1463                self.restore_snapshot(snapshot);1464                None1465            }1466        }1467    }14681469    /// Parse an optional higher-ranked binder.1470    ///1471    /// ```ebnf1472    /// HigherRankedBinder = ("for" "<" GenericParams ">")?1473    /// ```1474    pub(super) fn parse_higher_ranked_binder(1475        &mut self,1476    ) -> PResult<'a, (ThinVec<GenericParam>, Option<Span>)> {1477        if self.eat_keyword(exp!(For)) {1478            let lo = self.token.span;1479            self.expect_lt()?;1480            let params = self.parse_generic_params()?;1481            self.expect_gt()?;1482            // We rely on AST validation to rule out invalid cases: There must not be1483            // type or const parameters, and parameters must not have bounds.1484            Ok((params, Some(lo.to(self.prev_token.span))))1485        } else {1486            Ok((ThinVec::new(), None))1487        }1488    }14891490    /// Recover from `Fn`-family traits (Fn, FnMut, FnOnce) with lifetime arguments1491    /// (e.g. `FnOnce<'a>(&'a str) -> bool`). Up to generic arguments have already1492    /// been eaten.1493    fn recover_fn_trait_with_lifetime_params(1494        &mut self,1495        fn_path: &mut ast::Path,1496        lifetime_defs: &mut ThinVec<GenericParam>,1497    ) -> PResult<'a, ()> {1498        let fn_path_segment = fn_path.segments.last_mut().unwrap();1499        let generic_args = if let Some(p_args) = &fn_path_segment.args {1500            *p_args.clone()1501        } else {1502            // Normally it wouldn't come here because the upstream should have parsed1503            // generic parameters (otherwise it's impossible to call this function).1504            return Ok(());1505        };1506        let lifetimes =1507            if let ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { span: _, args }) =1508                &generic_args1509            {1510                args.into_iter()1511                    .filter_map(|arg| {1512                        if let ast::AngleBracketedArg::Arg(generic_arg) = arg1513                            && let ast::GenericArg::Lifetime(lifetime) = generic_arg1514                        {1515                            Some(lifetime)1516                        } else {1517                            None1518                        }1519                    })1520                    .collect()1521            } else {1522                Vec::new()1523            };1524        // Only try to recover if the trait has lifetime params.1525        if lifetimes.is_empty() {1526            return Ok(());1527        }15281529        let snapshot = if self.parsing_generics {1530            // The snapshot is only relevant if we're parsing the generics of an `fn` to avoid1531            // incorrect recovery.1532            Some(self.create_snapshot_for_diagnostic())1533        } else {1534            None1535        };1536        // Parse `(T, U) -> R`.1537        let inputs_lo = self.token.span;1538        let mode =1539            FnParseMode { req_name: |_, _| false, context: FnContext::Free, req_body: false };1540        let inputs = match self.parse_fn_params(&mode) {1541            Ok(params) => params,1542            Err(err) => {1543                if let Some(snapshot) = snapshot {1544                    self.restore_snapshot(snapshot);1545                    err.cancel();1546                    return Ok(());1547                } else {1548                    return Err(err);1549                }1550            }1551        };1552        let inputs_span = inputs_lo.to(self.prev_token.span);1553        let output = match self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)1554        {1555            Ok(output) => output,1556            Err(err) => {1557                if let Some(snapshot) = snapshot {1558                    self.restore_snapshot(snapshot);1559                    err.cancel();1560                    return Ok(());1561                } else {1562                    return Err(err);1563                }1564            }1565        };1566        let args = ast::ParenthesizedArgs {1567            span: fn_path_segment.span().to(self.prev_token.span),1568            inputs,1569            inputs_span,1570            output,1571        }1572        .into();15731574        if let Some(snapshot) = snapshot1575            && ![token::Comma, token::Gt, token::Plus].contains(&self.token.kind)1576        {1577            // We would expect another bound or the end of type params by now. Most likely we've1578            // encountered a `(` *not* representing `Trait()`, but rather the start of the `fn`'s1579            // argument list where the generic param list wasn't properly closed.1580            self.restore_snapshot(snapshot);1581            return Ok(());1582        }15831584        *fn_path_segment = ast::PathSegment {1585            ident: fn_path_segment.ident,1586            args: Some(args),1587            id: ast::DUMMY_NODE_ID,1588        };15891590        // Convert parsed `<'a>` in `Fn<'a>` into `for<'a>`.1591        let mut generic_params = lifetimes1592            .iter()1593            .map(|lt| GenericParam {1594                id: lt.id,1595                ident: lt.ident,1596                attrs: ast::AttrVec::new(),1597                bounds: ThinVec::new(),1598                is_placeholder: false,1599                kind: ast::GenericParamKind::Lifetime,1600                colon_span: None,1601            })1602            .collect::<ThinVec<GenericParam>>();1603        lifetime_defs.append(&mut generic_params);16041605        let generic_args_span = generic_args.span();1606        let snippet = format!(1607            "for<{}> ",1608            lifetimes.iter().map(|lt| lt.ident.as_str()).intersperse(", ").collect::<String>(),1609        );1610        let before_fn_path = fn_path.span.shrink_to_lo();1611        self.dcx()1612            .struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters")1613            .with_multipart_suggestion(1614                "consider using a higher-ranked trait bound instead",1615                vec![(generic_args_span, "".to_owned()), (before_fn_path, snippet)],1616                Applicability::MaybeIncorrect,1617            )1618            .emit();1619        Ok(())1620    }16211622    pub(super) fn check_lifetime(&mut self) -> bool {1623        self.expected_token_types.insert(TokenType::Lifetime);1624        self.token.is_lifetime()1625    }16261627    /// Parses a single lifetime `'a` or panics.1628    pub(super) fn expect_lifetime(&mut self) -> Lifetime {1629        if let Some((ident, is_raw)) = self.token.lifetime() {1630            if is_raw == IdentIsRaw::No && ident.without_first_quote().is_reserved_lifetime() {1631                self.dcx().emit_err(diagnostics::KeywordLifetime { span: ident.span });1632            }16331634            self.bump();1635            Lifetime { ident, id: ast::DUMMY_NODE_ID }1636        } else {1637            self.dcx().span_bug(self.token.span, "not a lifetime")1638        }1639    }16401641    pub(super) fn mk_ty(&self, span: Span, kind: TyKind) -> Box<Ty> {1642        Box::new(Ty { kind, span, id: ast::DUMMY_NODE_ID })1643    }1644}

Code quality findings 24

Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let attr_span = raw_attrs[0].span.to(raw_attrs.last().unwrap().span);
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
let attr_span = raw_attrs[0].span.to(raw_attrs.last().unwrap().span);
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
let kw = self.prev_token.ident().unwrap().0;
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
let ty = ts.into_iter().next().unwrap();
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
if let Err(e) = self.expect(exp!(CloseBracket)) {
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
self.expect(exp!(CloseBracket))?;
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
if let Err(e) = self.expect(exp!(CloseBracket)) {
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
let mutbl = self.parse_mut_or_const().unwrap();
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
self.expect(exp!(OpenParen))?;
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
self.expect(exp!(CloseParen))?;
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
self.expect(exp!(Comma))?;
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
/// [unsafe] [extern "ABI"] fn (S) -> T
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
ast::Path::from_ident(self_.prev_token.ident().unwrap().0),
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
self.expect(exp!(CloseParen))?;
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
self.expect(exp!(CloseParen))?;
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
self.expect_keyword(exp!(Const)).unwrap();
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() =>
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
self.expect(exp!(CloseParen))?;
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
self.expect(exp!(CloseParen))?;
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
let fn_path_segment = fn_path.segments.last_mut().unwrap();
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
let kind = match (kind, kw.name) {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
Ok(match ident.name {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match *fields {

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.