compiler/rustc_parse/src/parser/ty.rs RUST 1,668 lines View on github.com → Search inside
1use rustc_ast::token::{self, IdentKind, 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, Mutability, Path,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, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,16    FnPtrWithGenerics, FnPtrWithGenericsSugg, HelpUseLatestEdition, InvalidCVariadicType,17    InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType,18    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_rust_2015(t: Token) -> bool {87    // In `dyn::x`, `dyn<X>` and `dyn<<X>::Y>`, `dyn` should (continue to) denote a regular path88    // segment for backward compatibility. We make an exception for `dyn(X)` which used to be89    // interpreted as a path with parenthesized generic arguments which can be semantically90    // well-formed (consider: `use std::ops::Fn as dyn;`). Instead, we treat it as a trait91    // object type whose first bound is parenthesized.9293    // Contrary to `Parser::can_begin_bound`, `!`, `const`, `[` and `async` are deliberately not94    // part of this list to contain the number of potential regressions esp. in MBE code.95    // `const` and `[` would regress UI test `macro-dyn-const-2015.rs` and96    // `!` would regress `dyn!(...)` macro calls in Rust 2015 for example.9798    if t.is_path_start() {99        return t != token::PathSep && t != token::Lt && t != token::Shl;100    }101102    t == token::OpenParen || t == token::Question || t.is_lifetime() || t.is_keyword(kw::For)103}104105impl<'a> Parser<'a> {106    /// Parses a type.107    pub fn parse_ty(&mut self) -> PResult<'a, Box<Ty>> {108        if self.token == token::DotDotDot {109            // We special case this so that we don't talk about "nested C-variadics" in types.110            // We still pass in `AllowCVariadic::No` so that `parse_ty_common` can complain about111            // things like `Vec<...>`.112            let span = self.token.span;113            self.bump();114            let kind = TyKind::Err(self.dcx().emit_err(InvalidCVariadicType { span }));115            return Ok(self.mk_ty(span, kind));116        }117        self.parse_ty_common(118            AllowPlus::Yes,119            AllowCVariadic::No,120            RecoverQPath::Yes,121            RecoverReturnSign::Yes,122            None,123            RecoverQuestionMark::Yes,124        )125    }126127    pub(super) fn parse_ty_with_generics_recovery(128        &mut self,129        ty_params: &Generics,130    ) -> PResult<'a, Box<Ty>> {131        self.parse_ty_common(132            AllowPlus::Yes,133            AllowCVariadic::No,134            RecoverQPath::Yes,135            RecoverReturnSign::Yes,136            Some(ty_params),137            RecoverQuestionMark::Yes,138        )139    }140141    /// Parse a type suitable for a function or function pointer parameter.142    /// The difference from `parse_ty` is that this version allows `...`143    /// (`CVarArgs`) at the top level of the type.144    pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, Box<Ty>> {145        let ty = self.parse_ty_common(146            AllowPlus::Yes,147            AllowCVariadic::Yes,148            RecoverQPath::Yes,149            RecoverReturnSign::Yes,150            None,151            RecoverQuestionMark::Yes,152        )?;153154        // Recover a trailing `= EXPR` if present.155        if self.may_recover()156            && self.check_noexpect(&token::Eq)157            && self.look_ahead(1, |tok| tok.can_begin_expr())158        {159            let snapshot = self.create_snapshot_for_diagnostic();160            self.bump();161            let eq_span = self.prev_token.span;162            match self.parse_expr() {163                Ok(e) => {164                    self.dcx()165                        .struct_span_err(eq_span.to(e.span), "parameter defaults are not supported")166                        .emit();167                }168                Err(diag) => {169                    diag.cancel();170                    self.restore_snapshot(snapshot);171                }172            }173        }174175        Ok(ty)176    }177178    /// Parses a type in restricted contexts where `+` is not permitted.179    ///180    /// Example 1: `&'a TYPE`181    ///     `+` is prohibited to maintain operator priority (P(+) < P(&)).182    /// Example 2: `value1 as TYPE + value2`183    ///     `+` is prohibited to avoid interactions with expression grammar.184    pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, Box<Ty>> {185        self.parse_ty_common(186            AllowPlus::No,187            AllowCVariadic::No,188            RecoverQPath::Yes,189            RecoverReturnSign::Yes,190            None,191            RecoverQuestionMark::Yes,192        )193    }194195    /// Parses a type following an `as` cast. Similar to `parse_ty_no_plus`, but signaling origin196    /// for better diagnostics involving `?`.197    pub(super) fn parse_as_cast_ty(&mut self) -> PResult<'a, Box<Ty>> {198        self.parse_ty_common(199            AllowPlus::No,200            AllowCVariadic::No,201            RecoverQPath::Yes,202            RecoverReturnSign::Yes,203            None,204            RecoverQuestionMark::No,205        )206    }207208    pub(super) fn parse_ty_no_question_mark_recover(&mut self) -> PResult<'a, Box<Ty>> {209        self.parse_ty_common(210            AllowPlus::Yes,211            AllowCVariadic::No,212            RecoverQPath::Yes,213            RecoverReturnSign::Yes,214            None,215            RecoverQuestionMark::No,216        )217    }218219    /// Parse a type without recovering `:` as `->` to avoid breaking code such220    /// as `where fn() : for<'a>`.221    pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, Box<Ty>> {222        self.parse_ty_common(223            AllowPlus::Yes,224            AllowCVariadic::No,225            RecoverQPath::Yes,226            RecoverReturnSign::OnlyFatArrow,227            None,228            RecoverQuestionMark::Yes,229        )230    }231232    /// Parses an optional return type `[ -> TY ]` in a function declaration.233    pub(super) fn parse_ret_ty(234        &mut self,235        allow_plus: AllowPlus,236        recover_qpath: RecoverQPath,237        recover_return_sign: RecoverReturnSign,238    ) -> PResult<'a, FnRetTy> {239        let lo = self.prev_token.span;240        Ok(if self.eat(exp!(RArrow)) {241            // FIXME(Centril): Can we unconditionally `allow_plus`?242            let ty = self.parse_ty_common(243                allow_plus,244                AllowCVariadic::No,245                recover_qpath,246                recover_return_sign,247                None,248                RecoverQuestionMark::Yes,249            )?;250            FnRetTy::Ty(ty)251        } else if recover_return_sign.can_recover(&self.token.kind) {252            // Don't `eat` to prevent `=>` from being added as an expected token which isn't253            // actually expected and could only confuse users254            self.bump();255            self.dcx().emit_err(ReturnTypesUseThinArrow {256                span: self.prev_token.span,257                suggestion: lo.between(self.token.span),258            });259            let ty = self.parse_ty_common(260                allow_plus,261                AllowCVariadic::No,262                recover_qpath,263                recover_return_sign,264                None,265                RecoverQuestionMark::Yes,266            )?;267            FnRetTy::Ty(ty)268        } else {269            FnRetTy::Default(self.prev_token.span.shrink_to_hi())270        })271    }272273    fn parse_ty_common(274        &mut self,275        allow_plus: AllowPlus,276        allow_c_variadic: AllowCVariadic,277        recover_qpath: RecoverQPath,278        recover_return_sign: RecoverReturnSign,279        ty_generics: Option<&Generics>,280        recover_question_mark: RecoverQuestionMark,281    ) -> PResult<'a, Box<Ty>> {282        let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;283        maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);284285        if let Some(ty) = self.eat_metavar_seq_with_matcher(286            |mv_kind| matches!(mv_kind, MetaVarKind::Ty { .. }),287            |this| this.parse_ty_no_question_mark_recover(),288        ) {289            return Ok(ty);290        }291292        self.recover_from_outer_attributes("types")?;293294        let lo = self.token.span;295        let mut impl_dyn_multi = false;296        let kind = if self.check(exp!(OpenParen)) {297            self.parse_paren_start_ty(lo, allow_plus)?298        } else if self.eat(exp!(Bang)) {299            // Never type `!`300            TyKind::Never301        } else if self.eat(exp!(Star)) {302            self.parse_ty_ptr()?303        } else if self.eat(exp!(OpenBracket)) {304            self.parse_array_or_slice_ty()?305        } else if self.check(exp!(And)) || self.check(exp!(AndAnd)) {306            // Reference307            self.expect_and()?;308            self.parse_borrowed_pointee()?309        } else if self.eat_keyword_noexpect(kw::Typeof) {310            self.parse_typeof_ty(lo)?311        } else if self.is_builtin() {312            self.parse_builtin_ty()?313        } else if self.eat_keyword(exp!(Underscore)) {314            // A type to be inferred `_`315            TyKind::Infer316        } else if self.check_fn_front_matter(false, Case::Sensitive) {317            // Function pointer type318            self.parse_ty_fn_ptr(lo, ThinVec::new(), None, recover_return_sign)?319        } else if self.check_keyword(exp!(For)) {320            // Function pointer type or bound list (trait object type) starting with a poly-trait.321            //   `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`322            //   `for<'lt> Trait1<'lt> + Trait2 + 'a`323            let (bound_vars, _) = self.parse_higher_ranked_binder()?;324            if self.check_fn_front_matter(false, Case::Sensitive) {325                self.parse_ty_fn_ptr(326                    lo,327                    bound_vars,328                    Some(self.prev_token.span.shrink_to_lo()),329                    recover_return_sign,330                )?331            } else {332                // Try to recover `for<'a> dyn Trait` or `for<'a> impl Trait`.333                if self.may_recover()334                    && (self.token.is_keyword(kw::Impl) || self.can_begin_dyn_ty())335                {336                    self.bump();337                    let (kw, _) = self.prev_token.ident().unwrap();338                    let removal_span = kw.span.with_hi(self.token.span.lo());339                    let path = self.parse_path(PathStyle::Type)?;340                    let mut bounds = thin_vec![GenericBound::Trait(PolyTraitRef::new(341                        bound_vars,342                        path,343                        TraitBoundModifiers::NONE,344                        lo.to(self.prev_token.span),345                        ast::Parens::No,346                    ))];347                    if allow_plus == AllowPlus::Yes && self.check_plus() {348                        self.eat_plus();349                        bounds.append(&mut self.parse_generic_bounds()?);350                    }351                    self.dcx().emit_err(diagnostics::TransposeDynOrImpl {352                        span: kw.span,353                        kw: kw.name.as_str(),354                        sugg: diagnostics::TransposeDynOrImplSugg {355                            removal_span,356                            insertion_span: lo.shrink_to_lo(),357                            kw: kw.name.as_str(),358                        },359                    });360                    match kw.name {361                        kw::Dyn => TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn),362                        kw::Impl => TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds),363                        _ => unreachable!(),364                    }365                } else {366                    let path = self.parse_path(PathStyle::Type)?;367                    let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();368                    self.finish_parsing_bare_trait_object_ty(369                        bound_vars,370                        path,371                        lo,372                        parse_plus,373                        ast::Parens::No,374                    )?375                }376            }377        } else if self.eat_keyword(exp!(Impl)) {378            self.parse_impl_ty(&mut impl_dyn_multi)?379        } else if self.can_begin_dyn_ty() {380            self.parse_dyn_ty(&mut impl_dyn_multi)?381        } else if self.eat_lt() {382            // Qualified path383            let (qself, path) = self.parse_qpath(PathStyle::Type)?;384            TyKind::Path(Some(qself), path)385        } else if (self.token.is_keyword(kw::Const) || self.token.is_keyword(kw::Mut))386            && self.look_ahead(1, |t| *t == token::Star)387        {388            self.parse_ty_c_style_pointer()?389        } else if self.check_path() {390            self.parse_path_start_ty(lo, allow_plus, ty_generics)?391        } else if self.can_begin_bound() {392            self.parse_bare_trait_object_ty(lo, allow_plus)?393        } else if self.eat(exp!(DotDotDot)) {394            match allow_c_variadic {395                AllowCVariadic::Yes => TyKind::CVarArgs,396                AllowCVariadic::No => {397                    // FIXME(c_variadic): Should we just allow `...` syntactically398                    // anywhere in a type and use semantic restrictions instead?399                    // NOTE: This may regress certain MBE calls if done incorrectly.400                    let guar = self.dcx().emit_err(NestedCVariadicType { span: lo });401                    TyKind::Err(guar)402                }403            }404        } else if self.check_keyword(exp!(Unsafe))405            && self.look_ahead(1, |tok| tok.kind == token::Lt)406        {407            self.parse_unsafe_binder_ty()?408        } else {409            let msg = format!("expected type, found {}", super::token_descr(&self.token));410            let mut err = self.dcx().struct_span_err(lo, msg);411            err.span_label(lo, "expected type");412            if self.may_recover()413                && (self.eat_keyword_noexpect(kw::True) || self.eat_keyword_noexpect(kw::False))414            {415                err.span_suggestion(416                    self.prev_token.span,417                    "the type is called",418                    "bool",419                    Applicability::MachineApplicable,420                );421                err.emit();422                TyKind::Path(423                    None,424                    Path::from_ident(Ident { span: self.prev_token.span, name: sym::bool }),425                )426            } else {427                return Err(err);428            }429        };430431        let span = lo.to(self.prev_token.span);432        let mut ty = self.mk_ty(span, kind);433434        // Try to recover from use of `+` with incorrect priority.435        match allow_plus {436            AllowPlus::Yes => self.maybe_recover_from_bad_type_plus(&ty)?,437            AllowPlus::No => self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty),438        }439        if let RecoverQuestionMark::Yes = recover_question_mark {440            ty = self.maybe_recover_from_question_mark(ty);441        }442        if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }443    }444445    fn parse_unsafe_binder_ty(&mut self) -> PResult<'a, TyKind> {446        let lo = self.token.span;447        assert!(self.eat_keyword(exp!(Unsafe)));448        self.expect_lt()?;449        let generic_params = self.parse_generic_params()?;450        self.expect_gt()?;451        let inner_ty = self.parse_ty()?;452        let span = lo.to(self.prev_token.span);453        self.psess.gated_spans.gate(sym::unsafe_binders, span);454455        Ok(TyKind::UnsafeBinder(Box::new(UnsafeBinderTy { generic_params, inner_ty })))456    }457458    /// Parse a type that begins with an opening parenthesis `(`.459    ///460    /// More specifically, it parses one of the following:461    ///462    /// 1. parenthesized type463    /// 2. tuple type464    /// 3. bare trait object type where the first trait bound is parenthesized465    fn parse_paren_start_ty(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {466        let mut inside_has_trailing_plus = false;467        let (ts, trailing_comma) = self.parse_paren_comma_seq(|p| {468            let ty = p.parse_ty()?;469            inside_has_trailing_plus = p.prev_token == TokenKind::Plus;470            Ok(ty)471        })?;472473        if ts.len() == 1 && matches!(trailing_comma, Trailing::No) {474            let ty = ts.into_iter().next().unwrap();475476            // Let's check if we actually have a bare trait object type where the first trait bound477            // is parenthesized. That's the case if the parentheses are followed by a `+` and if478            // what's contained between the parentheses resembles a *BareTraitBound*.479            //480            // For context, looking at bounds in general (see *Bound*), only trait bounds are481            // allowed to be wrapped in parentheses, not however outlives and use bounds.482            let outside_has_eligible_trailing_plus =483                allow_plus == AllowPlus::Yes && self.token.is_like_plus();484            match ty.kind {485                // `"(" TypePath ")" "+"`486                TyKind::Path(None, path) if outside_has_eligible_trailing_plus => self487                    .finish_parsing_bare_trait_object_ty(488                        ThinVec::new(),489                        path,490                        lo,491                        true,492                        ast::Parens::Yes,493                    ),494                // `"(" BareTraitBound\TypePath ")" "+"`495                //496                // We actually accept outlives bounds here, too, purely to reduce diagnostic output497                // for ill-formed code like `('a)+`: We know for a fact that the `parse_ty` above498                // has already emitted an error for the inner `'a` as it's not followed by `+`.499                // This way we indirectly suppress unhelpful follow-up diagnostics like E0178500                // ("bad `+` in type") and E0224 ("no trait bound in trait object type").501                TyKind::TraitObject(mut bounds, TraitObjectSyntax::None)502                    if outside_has_eligible_trailing_plus503                        && !inside_has_trailing_plus504                        && let [ast::GenericBound::Trait(_) | ast::GenericBound::Outlives(_)] =505                            bounds.as_slice() =>506                {507                    self.eat_plus();508                    bounds.append(&mut self.parse_generic_bounds()?);509                    Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))510                }511                _ => Ok(TyKind::Paren(ty)),512            }513        } else {514            Ok(TyKind::Tup(ts))515        }516    }517518    fn parse_bare_trait_object_ty(519        &mut self,520        lo: Span,521        allow_plus: AllowPlus,522    ) -> PResult<'a, TyKind> {523        // A lifetime only begins a bare trait object type if it is followed by `+`!524        if self.token.is_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()) {525            // In Rust 2021 and beyond, we assume that the user didn't intend to write a bare trait526            // object type with a leading lifetime bound since that seems very unlikely given the527            // fact that `dyn`-less trait objects are *semantically* invalid.528            if self.psess.edition.at_least_rust_2021() {529                let lt = self.expect_lifetime();530                let mut err = self.dcx().struct_span_err(lo, "expected type, found lifetime");531                err.span_label(lo, "expected type");532                return Ok(match self.maybe_recover_ref_ty_no_leading_ampersand(lt, lo, err) {533                    Ok(ref_ty) => ref_ty,534                    Err(err) => TyKind::Err(err.emit_err()),535                });536            }537538            self.dcx().emit_err(NeedPlusAfterTraitObjectLifetime {539                span: lo,540                suggestion: lo.shrink_to_hi(),541            });542        }543        Ok(TyKind::TraitObject(544            self.parse_generic_bounds_common(allow_plus)?,545            TraitObjectSyntax::None,546        ))547    }548549    pub(super) fn parse_ref_ty_no_leading_ampersand(&mut self) -> (Mutability, Option<Box<Ty>>) {550        let mutbl = self.parse_mutability();551        match self.parse_ty_no_plus() {552            Ok(ty) => (mutbl, Some(ty)),553            Err(err) => {554                err.cancel();555                (mutbl, None)556            }557        }558    }559560    fn maybe_recover_ref_ty_no_leading_ampersand<'cx>(561        &mut self,562        lt: Lifetime,563        lo: Span,564        mut err: Diag<'cx>,565    ) -> Result<TyKind, Diag<'cx>> {566        if !self.may_recover() {567            return Err(err);568        }569        let snapshot = self.create_snapshot_for_diagnostic();570        match self.parse_ref_ty_no_leading_ampersand() {571            (_, None) => {572                self.restore_snapshot(snapshot);573                Err(err)574            }575            (mutbl, Some(ty)) => {576                err.span_suggestion_verbose(577                    lo.shrink_to_lo(),578                    "you might have meant to write a reference type here",579                    "&",580                    Applicability::MaybeIncorrect,581                );582                err.emit();583                Ok(TyKind::Ref(Some(lt), ty, mutbl))584            }585        }586    }587588    fn finish_parsing_bare_trait_object_ty(589        &mut self,590        generic_params: ThinVec<GenericParam>,591        path: ast::Path,592        lo: Span,593        parse_plus: bool,594        parens: ast::Parens,595    ) -> PResult<'a, TyKind> {596        let mut bounds = thin_vec![GenericBound::Trait(PolyTraitRef::new(597            generic_params,598            path,599            TraitBoundModifiers::NONE,600            lo.to(self.prev_token.span),601            parens,602        ))];603        if parse_plus {604            self.eat_plus();605            bounds.append(&mut self.parse_generic_bounds()?);606        }607        Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))608    }609610    /// Parses a raw pointer with a C-style typo611    fn parse_ty_c_style_pointer(&mut self) -> PResult<'a, TyKind> {612        let kw_span = self.token.span;613        let mutbl = self.parse_mut_or_const();614615        if let Some(mutbl) = mutbl616            && self.eat(exp!(Star))617        {618            let star_span = self.prev_token.span;619620            let mutability = match mutbl {621                Mutability::Not => "const",622                Mutability::Mut => "mut",623            };624625            let ty = self.parse_ty_no_question_mark_recover()?;626627            self.dcx()628                .struct_span_err(629                    kw_span,630                    format!("raw pointer types must be written as `*{mutability} T`"),631                )632                .with_multipart_suggestion(633                    format!("put the `*` before `{mutability}`"),634                    vec![(star_span, String::new()), (kw_span.shrink_to_lo(), "*".to_string())],635                    Applicability::MachineApplicable,636                )637                .emit();638639            return Ok(TyKind::Ptr(ty, mutbl));640        }641        // This is unreachable because we always get into if above and return from it642        unreachable!("this could never happen")643    }644645    /// Parses a raw pointer type: `*[const | mut] $type`.646    fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> {647        let mutbl = self.parse_mut_or_const().unwrap_or_else(|| {648            let span = self.prev_token.span;649            self.dcx().emit_err(ExpectedMutOrConstInRawPointerType {650                span,651                after_asterisk: span.shrink_to_hi(),652            });653            Mutability::Not654        });655        let ty = self.parse_ty_no_plus()?;656        Ok(TyKind::Ptr(ty, mutbl))657    }658659    /// Parses an array (`[TYPE; EXPR]`) or slice (`[TYPE]`) type.660    /// The opening `[` bracket is already eaten.661    fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> {662        let elt_ty = self.parse_ty()?;663664        let ty = if self.eat(exp!(Semi)) {665            let mut length = self.parse_expr_anon_const()?;666667            if let Err(e) = self.expect(exp!(CloseBracket)) {668                // Try to recover from `X<Y, ...>` when `X::<Y, ...>` works669                self.check_mistyped_turbofish_with_multiple_type_params(e, &mut length.value)?;670                self.expect(exp!(CloseBracket))?;671            }672            TyKind::Array(elt_ty, length)673        } else if self.eat(exp!(CloseBracket)) {674            TyKind::Slice(elt_ty)675        } else {676            self.maybe_recover_array_ty_without_semi(elt_ty)?677        };678679        Ok(ty)680    }681682    /// Recover from malformed array type syntax.683    ///684    /// This method attempts to recover from cases like:685    /// - `[u8, 5]` → suggests using `;`, return a Array type686    /// - `[u8 5]` → suggests using `;`, return a Array type687    /// Consider to add more cases in the future.688    fn maybe_recover_array_ty_without_semi(&mut self, elt_ty: Box<Ty>) -> PResult<'a, TyKind> {689        let span = self.token.span;690        let token_descr = super::token_descr(&self.token);691        let mut err =692            self.dcx().struct_span_err(span, format!("expected `;` or `]`, found {}", token_descr));693        err.span_label(span, "expected `;` or `]`");694695        // If we cannot recover, return the error immediately.696        if !self.may_recover() {697            return Err(err);698        }699700        let snapshot = self.create_snapshot_for_diagnostic();701702        // Consume common erroneous separators.703        let hi = self.prev_token.span.hi();704        _ = self.eat(exp!(Comma)) || self.eat(exp!(Colon)) || self.eat(exp!(Star));705        let suggestion_span = self.prev_token.span.with_lo(hi);706707        // FIXME(mgca): recovery is broken for `const {` args708        // we first try to parse pattern like `[u8 5]`709        let length = match self.parse_expr_anon_const() {710            Ok(length) => length,711            Err(e) => {712                e.cancel();713                self.restore_snapshot(snapshot);714                return Err(err);715            }716        };717718        if let Err(e) = self.expect(exp!(CloseBracket)) {719            e.cancel();720            self.restore_snapshot(snapshot);721            return Err(err);722        }723724        err.span_suggestion_verbose(725            suggestion_span,726            "you might have meant to use `;` as the separator",727            ";",728            Applicability::MaybeIncorrect,729        );730        err.emit();731        Ok(TyKind::Array(elt_ty, length))732    }733734    fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {735        let and_span = self.prev_token.span;736        let mut opt_lifetime = self.check_lifetime().then(|| self.expect_lifetime());737        let (pinned, mut mutbl) = self.parse_pin_and_mut();738        if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() {739            // A lifetime is invalid here: it would be part of a bare trait bound, which requires740            // it to be followed by a plus, but we disallow plus in the pointee type.741            // So we can handle this case as an error here, and suggest `'a mut`.742            // If there *is* a plus next though, handling the error later provides better suggestions743            // (like adding parentheses)744            if !self.look_ahead(1, |t| t.is_like_plus()) {745                let lifetime_span = self.token.span;746                let span = and_span.to(lifetime_span);747748                let (suggest_lifetime, snippet) =749                    if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) {750                        (Some(span), lifetime_src)751                    } else {752                        (None, String::new())753                    };754                self.dcx().emit_err(LifetimeAfterMut { span, suggest_lifetime, snippet });755756                opt_lifetime = Some(self.expect_lifetime());757            }758        } else if self.token.is_keyword(kw::Dyn)759            && mutbl == Mutability::Not760            && self.look_ahead(1, |t| t.is_keyword(kw::Mut))761        {762            // We have `&dyn mut ...`, which is invalid and should be `&mut dyn ...`.763            let span = and_span.to(self.look_ahead(1, |t| t.span));764            self.dcx().emit_err(DynAfterMut { span });765766            // Recovery767            mutbl = Mutability::Mut;768            let (dyn_tok, dyn_tok_sp) = (self.token, self.token_spacing);769            self.bump();770            self.bump_with((dyn_tok, dyn_tok_sp));771        }772        let ty = self.parse_ty_no_plus()?;773        Ok(match pinned {774            Pinnedness::Not => TyKind::Ref(opt_lifetime, ty, mutbl),775            Pinnedness::Pinned => TyKind::PinnedRef(opt_lifetime, ty, mutbl),776        })777    }778779    /// Parse nothing, mutability or `pin` followed by "explicit" mutability.780    ///781    /// ```ebnf782    /// PinAndMut = "pin" MutOrConst | "mut"783    /// ```784    pub(crate) fn parse_pin_and_mut(&mut self) -> (Pinnedness, Mutability) {785        if self.token.is_keyword(kw::Pin) && self.look_ahead(1, Token::is_mutability) {786            self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);787            assert!(self.eat_keyword(exp!(Pin)));788            let mutbl = self.parse_mut_or_const().unwrap();789            (Pinnedness::Pinned, mutbl)790        } else {791            (Pinnedness::Not, self.parse_mutability())792        }793    }794795    /// Parses the `typeof(EXPR)` for better diagnostics before returning796    /// an error type.797    fn parse_typeof_ty(&mut self, lo: Span) -> PResult<'a, TyKind> {798        self.expect(exp!(OpenParen))?;799        let _expr = self.parse_expr_anon_const()?;800        self.expect(exp!(CloseParen))?;801        let span = lo.to(self.prev_token.span);802        let guar = self803            .dcx()804            .struct_span_err(span, "`typeof` is a reserved keyword but unimplemented")805            .with_note("consider replacing `typeof(...)` with an actual type")806            .with_code(E0516)807            .emit_err();808        Ok(TyKind::Err(guar))809    }810811    fn parse_builtin_ty(&mut self) -> PResult<'a, TyKind> {812        self.parse_builtin(|this, lo, ident| {813            Ok(match ident.name {814                sym::field_of => Some(this.parse_ty_field_of(lo)?),815                _ => None,816            })817        })818    }819820    pub(crate) fn parse_ty_field_of(&mut self, _lo: Span) -> PResult<'a, TyKind> {821        let container = self.parse_ty()?;822        self.expect(exp!(Comma))?;823824        let fields = self.parse_floating_field_access()?;825        let trailing_comma = self.eat_noexpect(&TokenKind::Comma);826827        if let Err(mut e) = self.expect_one_of(&[], &[exp!(CloseParen)]) {828            if trailing_comma {829                e.note("unexpected third argument to field_of");830            } else {831                e.note("field_of expects dot-separated field and variant names");832            }833            e.emit();834        }835836        // Eat tokens until the macro call ends.837        if self.may_recover() {838            while !self.token.kind.is_close_delim_or_eof() {839                self.bump();840            }841        }842843        match *fields {844            [] => Err(self.dcx().struct_span_err(845                self.token.span,846                "`field_of!` expects dot-separated field and variant names",847            )),848            [field] => Ok(TyKind::FieldOf(container, None, field)),849            [variant, field] => Ok(TyKind::FieldOf(container, Some(variant), field)),850            _ => Err(self.dcx().struct_span_err(851                fields.iter().map(|f| f.span).collect::<Vec<_>>(),852                "`field_of!` only supports a single field or a variant with a field",853            )),854        }855    }856857    /// Parses a function pointer type (`TyKind::FnPtr`).858    /// ```ignore (illustrative)859    ///    [unsafe] [extern "ABI"] fn (S) -> T860    /// //  ^~~~~^          ^~~~^     ^~^    ^861    /// //    |               |        |     |862    /// //    |               |        |   Return type863    /// // Function Style    ABI  Parameter types864    /// ```865    /// We actually parse `FnHeader FnDecl`, but we error on `const` and `async` qualifiers.866    fn parse_ty_fn_ptr(867        &mut self,868        lo: Span,869        mut params: ThinVec<GenericParam>,870        param_insertion_point: Option<Span>,871        recover_return_sign: RecoverReturnSign,872    ) -> PResult<'a, TyKind> {873        let inherited_vis = rustc_ast::Visibility {874            span: rustc_span::DUMMY_SP,875            kind: rustc_ast::VisibilityKind::Inherited,876        };877        let span_start = self.token.span;878        let ast::FnHeader { ext, safety, .. } = self.parse_fn_front_matter(879            &inherited_vis,880            Case::Sensitive,881            FrontMatterParsingMode::FunctionPtrType,882        )?;883        if self.may_recover() && self.token == TokenKind::Lt {884            self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;885        }886        let mode = crate::parser::FnParseMode {887            req_name: |_, _| false,888            context: FnContext::FunctionPtrType,889            req_body: false,890            allow_const_params: false,891        };892        let decl = self.parse_fn_decl(&mode, AllowPlus::No, recover_return_sign)?;893        let decl = Box::new(decl);894895        let decl_span = span_start.to(self.prev_token.span);896        Ok(TyKind::FnPtr(Box::new(FnPtrTy {897            ext,898            safety,899            generic_params: params,900            decl,901            decl_span,902        })))903    }904905    /// Recover from function pointer types with a generic parameter list (e.g. `fn<'a>(&'a str)`).906    fn recover_fn_ptr_with_generics(907        &mut self,908        lo: Span,909        params: &mut ThinVec<GenericParam>,910        param_insertion_point: Option<Span>,911    ) -> PResult<'a, ()> {912        let generics = self.parse_generics()?;913        let arity = generics.params.len();914915        let mut lifetimes: ThinVec<_> = generics916            .params917            .into_iter()918            .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime))919            .collect();920921        let sugg = if !lifetimes.is_empty() {922            let snippet =923                lifetimes.iter().map(|param| param.ident.as_str()).intersperse(", ").collect();924925            let (left, snippet) = if let Some(span) = param_insertion_point {926                (span, if params.is_empty() { snippet } else { format!(", {snippet}") })927            } else {928                (lo.shrink_to_lo(), format!("for<{snippet}> "))929            };930931            Some(FnPtrWithGenericsSugg {932                left,933                snippet,934                right: generics.span,935                arity,936                for_param_list_exists: param_insertion_point.is_some(),937            })938        } else {939            None940        };941942        self.dcx().emit_err(FnPtrWithGenerics { span: generics.span, sugg });943        params.append(&mut lifetimes);944        Ok(())945    }946947    /// Parses an `impl B0 + ... + Bn` type.948    fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {949        // If we encounter a type like `impl 'a Sized`, suggest `impl 'a + Sized`.950        if self.token.is_lifetime()951            && let Some(ident) = self.look_ahead(1, |t| t.non_reserved_ident())952        {953            self.dcx().emit_err(diagnostics::MissingPlusBounds {954                span: self.token.span,955                hi: self.token.span.shrink_to_hi(),956                sym: ident.name,957            });958        }959960        // Always parse bounds greedily for better error recovery.961        let bounds = self.parse_generic_bounds()?;962963        *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::Plus;964965        Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))966    }967968    /// Parse a use-bound aka precise capturing list.969    ///970    /// ```ebnf971    /// UseBound = "use" "<" (PreciseCapture ("," PreciseCapture)* ","?)? ">"972    /// PreciseCapture = "Self" | Ident | Lifetime973    /// ```974    fn parse_use_bound(&mut self, lo: Span, parens: ast::Parens) -> PResult<'a, GenericBound> {975        self.expect_lt()?;976        let (args, _, _) = self.parse_seq_to_before_tokens(977            &[exp!(Gt)],978            &[&TokenKind::Ge, &TokenKind::Shr, &TokenKind::Shr],979            SeqSep::trailing_allowed(exp!(Comma)),980            |self_| {981                if self_.check_keyword(exp!(SelfUpper)) {982                    self_.bump();983                    Ok(PreciseCapturingArg::Arg(984                        ast::Path::from_ident(self_.prev_token.ident().unwrap().0),985                        DUMMY_NODE_ID,986                    ))987                } else if self_.check_ident() {988                    Ok(PreciseCapturingArg::Arg(989                        ast::Path::from_ident(self_.parse_ident()?),990                        DUMMY_NODE_ID,991                    ))992                } else if self_.check_lifetime() {993                    Ok(PreciseCapturingArg::Lifetime(self_.expect_lifetime()))994                } else {995                    self_.unexpected_any()996                }997            },998        )?;999        self.expect_gt()?;10001001        if let ast::Parens::Yes = parens {1002            self.expect(exp!(CloseParen))?;1003            self.report_parenthesized_bound(lo, self.prev_token.span, "precise capturing lists");1004        }10051006        Ok(GenericBound::Use(args, lo.to(self.prev_token.span)))1007    }10081009    /// Can the current token begin a `dyn`-prefixed trait object type?1010    fn can_begin_dyn_ty(&mut self) -> bool {1011        self.token.is_keyword(kw::Dyn)1012            && (self.token_uninterpolated_span().at_least_rust_2018()1013                || self.look_ahead(1, |&t| can_begin_dyn_bound_in_rust_2015(t)))1014    }10151016    /// Parse a `dyn`-prefixed trait object type.1017    fn parse_dyn_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {1018        self.bump(); // `dyn`10191020        // Always parse bounds greedily for better error recovery.1021        let bounds = self.parse_generic_bounds()?;1022        *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::Plus;10231024        Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn))1025    }10261027    /// Parse a type that begins with a path.1028    ///1029    /// This can be:1030    /// 1. a type macro, `mac!(...)`,1031    /// 2. a bare trait object type, `B0 + ... + Bn`,1032    /// 3. or a path, `path::to::MyType`.1033    fn parse_path_start_ty(1034        &mut self,1035        lo: Span,1036        allow_plus: AllowPlus,1037        ty_generics: Option<&Generics>,1038    ) -> PResult<'a, TyKind> {1039        // Simple path1040        let path = self.parse_path_inner(PathStyle::Type, ty_generics)?;1041        if self.eat(exp!(Bang)) {1042            // Macro invocation in type position1043            Ok(TyKind::MacCall(Box::new(MacCall { path, args: self.parse_delim_args()? })))1044        } else if allow_plus == AllowPlus::Yes && self.check_plus() {1045            // `Trait1 + Trait2 + 'a`1046            self.finish_parsing_bare_trait_object_ty(1047                ThinVec::new(),1048                path,1049                lo,1050                true,1051                ast::Parens::No,1052            )1053        } else {1054            // Just a type path.1055            Ok(TyKind::Path(None, path))1056        }1057    }10581059    pub(super) fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> {1060        self.parse_generic_bounds_common(AllowPlus::Yes)1061    }10621063    /// Parse generic bounds.1064    ///1065    /// Only if `allow_plus` this parses a `+`-separated list of bounds (trailing `+` is admitted).1066    /// Otherwise, this only parses a single bound or none.1067    fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> {1068        let mut bounds = ThinVec::new();10691070        // In addition to looping while we find generic bounds:1071        // We continue even if we find a keyword. This is necessary for error recovery on,1072        // for example, `impl fn()`. The only keyword that can go after generic bounds is1073        // `where`, so stop if it's it.1074        // We also continue if we find types (not traits), again for error recovery.1075        while self.can_begin_bound()1076            || (self.may_recover()1077                && (self.token.can_begin_type()1078                    || (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where))))1079        {1080            // Account for `&dyn Trait + dyn Other`.1081            if self.can_begin_dyn_ty() {1082                self.bump();1083                self.dcx().emit_err(InvalidDynKeyword {1084                    span: self.prev_token.span,1085                    suggestion: self.prev_token.span.until(self.token.span),1086                });1087            }1088            bounds.push(self.parse_generic_bound()?);1089            if allow_plus == AllowPlus::No || !self.eat_plus() {1090                break;1091            }1092        }10931094        Ok(bounds)1095    }10961097    /// Can the current token begin a bound?1098    fn can_begin_bound(&mut self) -> bool {1099        // NOTE: Tokens `!`, `~`, `const` & `async` which represent the start of currently unstable1100        //       trait bound modifiers are intentionally not included in `Token::can_begin_type` to1101        //       avoid affecting stable macro matching behavior.11021103        self.check_path()1104            || self.check_lifetime()1105            || self.check(exp!(Bang))1106            || self.check(exp!(Question))1107            || self.check(exp!(Tilde))1108            || self.check_keyword(exp!(For))1109            || self.check(exp!(OpenParen))1110            || self.can_begin_maybe_const_bound()1111            || self.check_keyword(exp!(Const))1112            || self.check_keyword(exp!(Async))1113            || self.check_keyword(exp!(Use))1114    }11151116    fn can_begin_maybe_const_bound(&mut self) -> bool {1117        self.check(exp!(OpenBracket))1118            && self.look_ahead(1, |t| t.is_keyword(kw::Const))1119            && self.look_ahead(2, |t| *t == token::CloseBracket)1120    }11211122    /// Parse a bound.1123    ///1124    /// ```ebnf1125    /// Bound = LifetimeBound | UseBound | TraitBound1126    /// ```1127    fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {1128        let leading_token = self.prev_token;1129        let lo = self.token.span;11301131        // We only admit parenthesized *trait* bounds. However, we want to gracefully recover from1132        // other kinds of parenthesized bounds, so parse the opening parenthesis *here*.1133        //1134        // In the future we might want to lift this syntactic restriction and1135        // introduce "`GenericBound::Paren(Box<GenericBound>)`".1136        let parens = if self.eat(exp!(OpenParen)) { ast::Parens::Yes } else { ast::Parens::No };11371138        if self.token.is_lifetime() {1139            self.parse_lifetime_bound(lo, parens)1140        } else if self.eat_keyword(exp!(Use)) {1141            self.parse_use_bound(lo, parens)1142        } else {1143            self.parse_trait_bound(lo, parens, &leading_token)1144        }1145    }11461147    /// Parse a lifetime-bound aka outlives-bound.1148    ///1149    /// ```ebnf1150    /// LifetimeBound = Lifetime1151    /// ```1152    fn parse_lifetime_bound(&mut self, lo: Span, parens: ast::Parens) -> PResult<'a, GenericBound> {1153        let lt = self.expect_lifetime();11541155        if let ast::Parens::Yes = parens {1156            self.expect(exp!(CloseParen))?;1157            self.report_parenthesized_bound(lo, self.prev_token.span, "lifetime bounds");1158        }11591160        Ok(GenericBound::Outlives(lt))1161    }11621163    fn report_parenthesized_bound(&self, lo: Span, hi: Span, kind: &str) -> ErrorGuaranteed {1164        let mut diag =1165            self.dcx().struct_span_err(lo.to(hi), format!("{kind} may not be parenthesized"));1166        diag.multipart_suggestion(1167            "remove the parentheses",1168            vec![(lo, String::new()), (hi, String::new())],1169            Applicability::MachineApplicable,1170        );1171        diag.emit_err()1172    }11731174    /// Emits an error if any trait bound modifiers were present.1175    fn error_lt_bound_with_modifiers(1176        &self,1177        modifiers: TraitBoundModifiers,1178        binder_span: Option<Span>,1179    ) -> ErrorGuaranteed {1180        let TraitBoundModifiers { constness, asyncness, polarity } = modifiers;11811182        match constness {1183            BoundConstness::Never => {}1184            BoundConstness::Always(span) | BoundConstness::Maybe(span) => {1185                return self.dcx().emit_err(diagnostics::ModifierLifetime {1186                    span,1187                    modifier: constness.as_str(),1188                });1189            }1190        }11911192        match polarity {1193            BoundPolarity::Positive => {}1194            BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => {1195                return self1196                    .dcx()1197                    .emit_err(diagnostics::ModifierLifetime { span, modifier: polarity.as_str() });1198            }1199        }12001201        match asyncness {1202            BoundAsyncness::Normal => {}1203            BoundAsyncness::Async(span) => {1204                return self.dcx().emit_err(diagnostics::ModifierLifetime {1205                    span,1206                    modifier: asyncness.as_str(),1207                });1208            }1209        }12101211        if let Some(span) = binder_span {1212            return self1213                .dcx()1214                .emit_err(diagnostics::ModifierLifetime { span, modifier: "for<...>" });1215        }12161217        unreachable!("lifetime bound intercepted in `parse_generic_ty_bound` but no modifiers?")1218    }12191220    /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `[const] Trait`.1221    ///1222    /// If no modifiers are present, this does not consume any tokens.1223    ///1224    /// ```ebnf1225    /// Constness = ("const" | "[" "const" "]")?1226    /// Asyncness = "async"?1227    /// Polarity = ("?" | "!")?1228    /// ```1229    ///1230    /// See `parse_trait_bound` for more context.1231    fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {1232        let modifier_lo = self.token.span;1233        let constness = self.parse_bound_constness()?;12341235        let asyncness = if self.token_uninterpolated_span().at_least_rust_2018()1236            && self.eat_keyword(exp!(Async))1237        {1238            self.psess.gated_spans.gate(sym::async_trait_bounds, self.prev_token.span);1239            BoundAsyncness::Async(self.prev_token.span)1240        } else if self.may_recover()1241            && self.token_uninterpolated_span().is_rust_2015()1242            && self.is_kw_followed_by_ident(kw::Async)1243        {1244            self.bump(); // eat `async`1245            self.dcx().emit_err(diagnostics::AsyncBoundModifierIn2015 {1246                span: self.prev_token.span,1247                help: HelpUseLatestEdition::new(),1248            });1249            self.psess.gated_spans.gate(sym::async_trait_bounds, self.prev_token.span);1250            BoundAsyncness::Async(self.prev_token.span)1251        } else {1252            BoundAsyncness::Normal1253        };1254        let modifier_hi = self.prev_token.span;12551256        let polarity = if self.eat(exp!(Question)) {1257            BoundPolarity::Maybe(self.prev_token.span)1258        } else if self.eat(exp!(Bang)) {1259            self.psess.gated_spans.gate(sym::negative_bounds, self.prev_token.span);1260            BoundPolarity::Negative(self.prev_token.span)1261        } else {1262            BoundPolarity::Positive1263        };12641265        // Enforce the mutual-exclusivity of `const`/`async` and `?`/`!`.1266        match polarity {1267            BoundPolarity::Positive => {1268                // All trait bound modifiers allowed to combine with positive polarity1269            }1270            BoundPolarity::Maybe(polarity_span) | BoundPolarity::Negative(polarity_span) => {1271                match (asyncness, constness) {1272                    (BoundAsyncness::Normal, BoundConstness::Never) => {1273                        // Ok, no modifiers.1274                    }1275                    (_, _) => {1276                        let constness = constness.as_str();1277                        let asyncness = asyncness.as_str();1278                        let glue =1279                            if !constness.is_empty() && !asyncness.is_empty() { " " } else { "" };1280                        let modifiers_concatenated = format!("{constness}{glue}{asyncness}");1281                        self.dcx().emit_err(diagnostics::PolarityAndModifiers {1282                            polarity_span,1283                            polarity: polarity.as_str(),1284                            modifiers_span: modifier_lo.to(modifier_hi),1285                            modifiers_concatenated,1286                        });1287                    }1288                }1289            }1290        }12911292        Ok(TraitBoundModifiers { constness, asyncness, polarity })1293    }12941295    pub fn parse_bound_constness(&mut self) -> PResult<'a, BoundConstness> {1296        // FIXME(const_trait_impl): remove `~const` parser support once bootstrap has the new syntax1297        // in rustfmt1298        Ok(if self.eat(exp!(Tilde)) {1299            let tilde = self.prev_token.span;1300            self.expect_keyword(exp!(Const))?;1301            let span = tilde.to(self.prev_token.span);1302            self.psess.gated_spans.gate(sym::const_trait_impl, span);1303            BoundConstness::Maybe(span)1304        } else if self.can_begin_maybe_const_bound() {1305            let start = self.token.span;1306            self.bump();1307            self.expect_keyword(exp!(Const)).unwrap();1308            self.bump();1309            let span = start.to(self.prev_token.span);1310            self.psess.gated_spans.gate(sym::const_trait_impl, span);1311            BoundConstness::Maybe(span)1312        } else if self.eat_keyword(exp!(Const)) {1313            self.psess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span);1314            BoundConstness::Always(self.prev_token.span)1315        } else {1316            BoundConstness::Never1317        })1318    }13191320    /// Parse a trait bound.1321    ///1322    /// ```ebnf1323    /// TraitBound = BareTraitBound | "(" BareTraitBound ")"1324    /// BareTraitBound =1325    ///     (HigherRankedBinder Constness Asyncness | Polarity)1326    ///     TypePath1327    /// ```1328    fn parse_trait_bound(1329        &mut self,1330        lo: Span,1331        parens: ast::Parens,1332        leading_token: &Token,1333    ) -> PResult<'a, GenericBound> {1334        let (mut bound_vars, binder_span) = self.parse_higher_ranked_binder()?;13351336        let modifiers_lo = self.token.span;1337        let modifiers = self.parse_trait_bound_modifiers()?;1338        let modifiers_span = modifiers_lo.to(self.prev_token.span);13391340        if let Some(binder_span) = binder_span {1341            match modifiers.polarity {1342                BoundPolarity::Negative(polarity_span) | BoundPolarity::Maybe(polarity_span) => {1343                    self.dcx().emit_err(diagnostics::BinderAndPolarity {1344                        binder_span,1345                        polarity_span,1346                        polarity: modifiers.polarity.as_str(),1347                    });1348                }1349                BoundPolarity::Positive => {}1350            }1351        }13521353        // Recover erroneous lifetime bound with modifiers or binder.1354        // e.g. `T: for<'a> 'a` or `T: [const] 'a`.1355        if self.token.is_lifetime() {1356            let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span);1357            return self.parse_lifetime_bound(lo, parens);1358        }13591360        if let (more_bound_vars, Some(binder_span)) = self.parse_higher_ranked_binder()? {1361            bound_vars.extend(more_bound_vars);1362            self.dcx().emit_err(diagnostics::BinderBeforeModifiers { binder_span, modifiers_span });1363        }13641365        let mut path = if self.token.is_keyword(kw::Fn)1366            && self.look_ahead(1, |t| *t == TokenKind::OpenParen)1367            && let Some(path) = self.recover_path_from_fn()1368        {1369            path1370        } else if !self.token.is_path_start() && self.token.can_begin_type() {1371            let ty = self.parse_ty_no_plus()?;1372            // Instead of finding a path (a trait), we found a type.1373            let mut err = self.dcx().struct_span_err(ty.span, "expected a trait, found type");13741375            // If we can recover, try to extract a path from the type. Note1376            // that we do not use the try operator when parsing the type because1377            // if it fails then we get a parser error which we don't want (we're trying1378            // to recover from errors, not make more).1379            let path = if self.may_recover() {1380                let (span, message, sugg, path, applicability) = match &ty.kind {1381                    TyKind::Ptr(..) | TyKind::Ref(..)1382                        if let TyKind::Path(_, path) = &ty.peel_refs().kind =>1383                    {1384                        (1385                            ty.span.until(path.span),1386                            "consider removing the indirection",1387                            "",1388                            path,1389                            Applicability::MaybeIncorrect,1390                        )1391                    }1392                    TyKind::ImplTrait(_, bounds)1393                        if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() =>1394                    {1395                        (1396                            ty.span.until(tr.span),1397                            "use the trait bounds directly",1398                            "",1399                            &tr.trait_ref.path,1400                            Applicability::MachineApplicable,1401                        )1402                    }1403                    _ => return Err(err),1404                };14051406                err.span_suggestion_verbose(span, message, sugg, applicability);14071408                path.clone()1409            } else {1410                return Err(err);1411            };14121413            err.emit();14141415            path1416        } else {1417            self.parse_path(PathStyle::Type)?1418        };14191420        if self.may_recover() && self.token == TokenKind::OpenParen {1421            self.recover_fn_trait_with_lifetime_params(&mut path, &mut bound_vars)?;1422        }14231424        if let ast::Parens::Yes = parens {1425            // Someone has written something like `&dyn (Trait + Other)`. The correct code1426            // would be `&(dyn Trait + Other)`1427            if self.token.is_like_plus() && leading_token.is_keyword(kw::Dyn) {1428                self.eat_plus();1429                self.parse_generic_bounds()?;1430                self.expect(exp!(CloseParen))?;14311432                self.dcx().emit_err(diagnostics::IncorrectParensTraitBounds {1433                    span: vec![lo, self.prev_token.span],1434                    sugg: diagnostics::IncorrectParensTraitBoundsSugg {1435                        wrong_span: leading_token.span.shrink_to_hi().to(lo),1436                        new_span: leading_token.span.shrink_to_lo(),1437                    },1438                });1439            } else {1440                self.expect(exp!(CloseParen))?;1441            }1442        }14431444        let poly_trait =1445            PolyTraitRef::new(bound_vars, path, modifiers, lo.to(self.prev_token.span), parens);1446        Ok(GenericBound::Trait(poly_trait))1447    }14481449    // recovers a `Fn(..)` parenthesized-style path from `fn(..)`1450    fn recover_path_from_fn(&mut self) -> Option<ast::Path> {1451        let fn_token_span = self.token.span;1452        self.bump();1453        let args_lo = self.token.span;1454        let snapshot = self.create_snapshot_for_diagnostic();1455        let mode = FnParseMode {1456            req_name: |_, _| false,1457            context: FnContext::Free,1458            req_body: false,1459            allow_const_params: false,1460        };1461        match self.parse_fn_decl(&mode, AllowPlus::No, RecoverReturnSign::OnlyFatArrow) {1462            Ok(decl) => {1463                self.dcx().emit_err(ExpectedFnPathFoundFnKeyword { fn_token_span });1464                Some(ast::Path {1465                    span: fn_token_span.to(self.prev_token.span),1466                    segments: thin_vec![ast::PathSegment {1467                        ident: Ident::new(sym::Fn, fn_token_span),1468                        id: DUMMY_NODE_ID,1469                        args: Some(Box::new(ast::GenericArgs::Parenthesized(1470                            ast::ParenthesizedArgs {1471                                span: args_lo.to(self.prev_token.span),1472                                inputs: decl.inputs.iter().map(|a| a.clone()).collect(),1473                                inputs_span: args_lo.until(decl.output.span()),1474                                output: decl.output.clone(),1475                            }1476                        ))),1477                    }],1478                })1479            }1480            Err(diag) => {1481                diag.cancel();1482                self.restore_snapshot(snapshot);1483                None1484            }1485        }1486    }14871488    /// Parse an optional higher-ranked binder.1489    ///1490    /// ```ebnf1491    /// HigherRankedBinder = ("for" "<" GenericParams ">")?1492    /// ```1493    pub(super) fn parse_higher_ranked_binder(1494        &mut self,1495    ) -> PResult<'a, (ThinVec<GenericParam>, Option<Span>)> {1496        if self.eat_keyword(exp!(For)) {1497            let lo = self.token.span;1498            self.expect_lt()?;1499            let params = self.parse_generic_params()?;1500            self.expect_gt()?;1501            // We rely on AST validation to rule out invalid cases: There must not be1502            // type or const parameters, and parameters must not have bounds.1503            Ok((params, Some(lo.to(self.prev_token.span))))1504        } else {1505            Ok((ThinVec::new(), None))1506        }1507    }15081509    /// Recover from `Fn`-family traits (Fn, FnMut, FnOnce) with lifetime arguments1510    /// (e.g. `FnOnce<'a>(&'a str) -> bool`). Up to generic arguments have already1511    /// been eaten.1512    fn recover_fn_trait_with_lifetime_params(1513        &mut self,1514        fn_path: &mut ast::Path,1515        lifetime_defs: &mut ThinVec<GenericParam>,1516    ) -> PResult<'a, ()> {1517        let fn_path_segment = fn_path.segments.last_mut().unwrap();1518        let generic_args = if let Some(p_args) = &fn_path_segment.args {1519            *p_args.clone()1520        } else {1521            // Normally it wouldn't come here because the upstream should have parsed1522            // generic parameters (otherwise it's impossible to call this function).1523            return Ok(());1524        };1525        let lifetimes =1526            if let ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { span: _, args }) =1527                &generic_args1528            {1529                args.into_iter()1530                    .filter_map(|arg| {1531                        if let ast::AngleBracketedArg::Arg(generic_arg) = arg1532                            && let ast::GenericArg::Lifetime(lifetime) = generic_arg1533                        {1534                            Some(lifetime)1535                        } else {1536                            None1537                        }1538                    })1539                    .collect()1540            } else {1541                Vec::new()1542            };1543        // Only try to recover if the trait has lifetime params.1544        if lifetimes.is_empty() {1545            return Ok(());1546        }15471548        let snapshot = if self.parsing_generics {1549            // The snapshot is only relevant if we're parsing the generics of an `fn` to avoid1550            // incorrect recovery.1551            Some(self.create_snapshot_for_diagnostic())1552        } else {1553            None1554        };1555        // Parse `(T, U) -> R`.1556        let inputs_lo = self.token.span;1557        let mode = FnParseMode {1558            req_name: |_, _| false,1559            context: FnContext::Free,1560            req_body: false,1561            allow_const_params: false,1562        };1563        let inputs = match self.parse_fn_params(&mode) {1564            Ok(params) => params,1565            Err(err) => {1566                if let Some(snapshot) = snapshot {1567                    self.restore_snapshot(snapshot);1568                    err.cancel();1569                    return Ok(());1570                } else {1571                    return Err(err);1572                }1573            }1574        };1575        let inputs_span = inputs_lo.to(self.prev_token.span);1576        let output = match self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)1577        {1578            Ok(output) => output,1579            Err(err) => {1580                if let Some(snapshot) = snapshot {1581                    self.restore_snapshot(snapshot);1582                    err.cancel();1583                    return Ok(());1584                } else {1585                    return Err(err);1586                }1587            }1588        };1589        let args = ast::ParenthesizedArgs {1590            span: fn_path_segment.span().to(self.prev_token.span),1591            inputs,1592            inputs_span,1593            output,1594        }1595        .into();15961597        if let Some(snapshot) = snapshot1598            && ![token::Comma, token::Gt, token::Plus].contains(&self.token.kind)1599        {1600            // We would expect another bound or the end of type params by now. Most likely we've1601            // encountered a `(` *not* representing `Trait()`, but rather the start of the `fn`'s1602            // argument list where the generic param list wasn't properly closed.1603            self.restore_snapshot(snapshot);1604            return Ok(());1605        }16061607        *fn_path_segment = ast::PathSegment {1608            ident: fn_path_segment.ident,1609            args: Some(args),1610            id: ast::DUMMY_NODE_ID,1611        };16121613        // Convert parsed `<'a>` in `Fn<'a>` into `for<'a>`.1614        let mut generic_params = lifetimes1615            .iter()1616            .map(|lt| GenericParam {1617                id: lt.id,1618                ident: lt.ident,1619                attrs: ast::AttrVec::new(),1620                bounds: ThinVec::new(),1621                is_placeholder: false,1622                kind: ast::GenericParamKind::Lifetime,1623                colon_span: None,1624            })1625            .collect::<ThinVec<GenericParam>>();1626        lifetime_defs.append(&mut generic_params);16271628        let generic_args_span = generic_args.span();1629        let snippet = format!(1630            "for<{}> ",1631            lifetimes.iter().map(|lt| lt.ident.as_str()).intersperse(", ").collect::<String>(),1632        );1633        let before_fn_path = fn_path.span.shrink_to_lo();1634        self.dcx()1635            .struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters")1636            .with_multipart_suggestion(1637                "consider using a higher-ranked trait bound instead",1638                vec![(generic_args_span, "".to_owned()), (before_fn_path, snippet)],1639                Applicability::MaybeIncorrect,1640            )1641            .emit();1642        Ok(())1643    }16441645    pub(super) fn check_lifetime(&mut self) -> bool {1646        self.expected_token_types.insert(TokenType::Lifetime);1647        self.token.is_lifetime()1648    }16491650    /// Parses a single lifetime `'a` or panics.1651    pub(super) fn expect_lifetime(&mut self) -> Lifetime {1652        if let Some((ident, kind)) = self.token.lifetime() {1653            if kind == IdentKind::Normal && ident.without_first_quote().is_reserved_lifetime() {1654                self.dcx().emit_err(diagnostics::KeywordLifetime { span: ident.span });1655            }16561657            self.bump();1658            Lifetime { ident, id: ast::DUMMY_NODE_ID }1659        } else {1660            self.dcx().span_bug(self.token.span, "not a lifetime")1661        }1662    }16631664    pub(super) fn mk_ty(&self, span: Span, kind: TyKind) -> Box<Ty> {1665        Box::new(Ty { kind, span, id: ast::DUMMY_NODE_ID })1666    }1667}

Code quality findings 19

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();
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: '.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: '.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
match 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.

Generated by searchcode.com · powered by code_get_file + code_get_findings