//! HIR ty lowering: Lowers type-system entities[^1] from the [HIR][hir] to //! the [`rustc_middle::ty`] representation. //! //! Not to be confused with *AST lowering* which lowers AST constructs to HIR ones //! or with *THIR* / *MIR* *lowering* / *building* which lowers HIR *bodies* //! (i.e., “executable code”) to THIR / MIR. //! //! Most lowering routines are defined on [`dyn HirTyLowerer`](HirTyLowerer) directly, //! like the main routine of this module, `lower_ty`. //! //! This module used to be called `astconv`. //! //! [^1]: This includes types, lifetimes / regions, constants in type positions, //! trait references and bounds. mod bounds; mod cmse; mod dyn_trait; pub mod errors; pub mod generics; use std::assert_matches::assert_matches; use std::slice; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err, }; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::DynCompatibilityViolation; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_session::parse::feature_err; use rustc_span::{DUMMY_SP, Ident, Span, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, FulfillmentError}; use tracing::{debug, instrument}; use crate::check::check_abi; use crate::check_c_variadic_abi; use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; /// A path segment that is semantically allowed to have generic arguments. #[derive(Debug)] pub struct GenericPathSegment(pub DefId, pub usize); #[derive(Copy, Clone, Debug)] pub enum PredicateFilter { /// All predicates may be implied by the trait. All, /// Only traits that reference `Self: ..` are implied by the trait. SelfOnly, /// Only traits that reference `Self: ..` and define an associated type /// with the given ident are implied by the trait. This mode exists to /// side-step query cycles when lowering associated types. SelfTraitThatDefines(Ident), /// Only traits that reference `Self: ..` and their associated type bounds. /// For example, given `Self: Tr`, this would expand to `Self: Tr` /// and `::A: B`. SelfAndAssociatedTypeBounds, /// Filter only the `[const]` bounds, which are lowered into `HostEffect` clauses. ConstIfConst, /// Filter only the `[const]` bounds which are *also* in the supertrait position. SelfConstIfConst, } #[derive(Debug)] pub enum RegionInferReason<'a> { /// Lifetime on a trait object that is spelled explicitly, e.g. `+ 'a` or `+ '_`. ExplicitObjectLifetime, /// A trait object's lifetime when it is elided, e.g. `dyn Any`. ObjectLifetimeDefault, /// Generic lifetime parameter Param(&'a ty::GenericParamDef), RegionPredicate, Reference, OutlivesBound, } #[derive(Copy, Clone, TypeFoldable, TypeVisitable, Debug)] pub struct InherentAssocCandidate { pub impl_: DefId, pub assoc_item: DefId, pub scope: DefId, } /// A context which can lower type-system entities from the [HIR][hir] to /// the [`rustc_middle::ty`] representation. /// /// This trait used to be called `AstConv`. pub trait HirTyLowerer<'tcx> { fn tcx(&self) -> TyCtxt<'tcx>; fn dcx(&self) -> DiagCtxtHandle<'_>; /// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered. fn item_def_id(&self) -> LocalDefId; /// Returns the region to use when a lifetime is omitted (and not elided). fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx>; /// Returns the type to use when a type is omitted. fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>; /// Returns the const to use when a const is omitted. fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx>; fn register_trait_ascription_bounds( &self, bounds: Vec<(ty::Clause<'tcx>, Span)>, hir_id: HirId, span: Span, ); /// Probe bounds in scope where the bounded type coincides with the given type parameter. /// /// Rephrased, this returns bounds of the form `T: Trait`, where `T` is a type parameter /// with the given `def_id`. This is a subset of the full set of bounds. /// /// This method may use the given `assoc_name` to disregard bounds whose trait reference /// doesn't define an associated item with the provided name. /// /// This is used for one specific purpose: Resolving “short-hand” associated type references /// like `T::Item` where `T` is a type parameter. In principle, we would do that by first /// getting the full set of predicates in scope and then filtering down to find those that /// apply to `T`, but this can lead to cycle errors. The problem is that we have to do this /// resolution *in order to create the predicates in the first place*. /// Hence, we have this “special pass”. fn probe_ty_param_bounds( &self, span: Span, def_id: LocalDefId, assoc_ident: Ident, ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>; fn select_inherent_assoc_candidates( &self, span: Span, self_ty: Ty<'tcx>, candidates: Vec, ) -> (Vec, Vec>); /// Lower a path to an associated item (of a trait) to a projection. /// /// This method has to be defined by the concrete lowering context because /// dealing with higher-ranked trait references depends on its capabilities: /// /// If the context can make use of type inference, it can simply instantiate /// any late-bound vars bound by the trait reference with inference variables. /// If it doesn't support type inference, there is nothing reasonable it can /// do except reject the associated type. /// /// The canonical example of this is associated type `T::P` where `T` is a type /// param constrained by `T: for<'a> Trait<'a>` and where `Trait` defines `P`. fn lower_assoc_item_path( &self, span: Span, item_def_id: DefId, item_segment: &hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>; fn lower_fn_sig( &self, decl: &hir::FnDecl<'tcx>, generics: Option<&hir::Generics<'_>>, hir_id: HirId, hir_ty: Option<&hir::Ty<'_>>, ) -> (Vec>, Ty<'tcx>); /// Returns `AdtDef` if `ty` is an ADT. /// /// Note that `ty` might be a alias type that needs normalization. /// This used to get the enum variants in scope of the type. /// For example, `Self::A` could refer to an associated type /// or to an enum variant depending on the result of this function. fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option>; /// Record the lowered type of a HIR node in this context. fn record_ty(&self, hir_id: HirId, ty: Ty<'tcx>, span: Span); /// The inference context of the lowering context if applicable. fn infcx(&self) -> Option<&InferCtxt<'tcx>>; /// Convenience method for coercing the lowering context into a trait object type. /// /// Most lowering routines are defined on the trait object type directly /// necessitating a coercion step from the concrete lowering context. fn lowerer(&self) -> &dyn HirTyLowerer<'tcx> where Self: Sized, { self } /// Performs minimalistic dyn compat checks outside of bodies, but full within bodies. /// Outside of bodies we could end up in cycles, so we delay most checks to later phases. fn dyn_compatibility_violations(&self, trait_def_id: DefId) -> Vec; } /// The "qualified self" of an associated item path. /// /// For diagnostic purposes only. enum AssocItemQSelf { Trait(DefId), TyParam(LocalDefId, Span), SelfTyAlias, } impl AssocItemQSelf { fn to_string(&self, tcx: TyCtxt<'_>) -> String { match *self { Self::Trait(def_id) => tcx.def_path_str(def_id), Self::TyParam(def_id, _) => tcx.hir_ty_param_name(def_id).to_string(), Self::SelfTyAlias => kw::SelfUpper.to_string(), } } } /// In some cases, [`hir::ConstArg`]s that are being used in the type system /// through const generics need to have their type "fed" to them /// using the query system. /// /// Use this enum with `::lower_const_arg` to instruct it with the /// desired behavior. #[derive(Debug, Clone, Copy)] pub enum FeedConstTy<'a, 'tcx> { /// Feed the type. /// /// The `DefId` belongs to the const param that we are supplying /// this (anon) const arg to. /// /// The list of generic args is used to instantiate the parameters /// used by the type of the const param specified by `DefId`. Param(DefId, &'a [ty::GenericArg<'tcx>]), /// Don't feed the type. No, } #[derive(Debug, Clone, Copy)] enum LowerTypeRelativePathMode { Type(PermitVariants), Const, } impl LowerTypeRelativePathMode { fn assoc_tag(self) -> ty::AssocTag { match self { Self::Type(_) => ty::AssocTag::Type, Self::Const => ty::AssocTag::Const, } } fn def_kind(self) -> DefKind { match self { Self::Type(_) => DefKind::AssocTy, Self::Const => DefKind::AssocConst, } } fn permit_variants(self) -> PermitVariants { match self { Self::Type(permit_variants) => permit_variants, // FIXME(mgca): Support paths like `Option::::None` or `Option::::Some` which // resolve to const ctors/fn items respectively. Self::Const => PermitVariants::No, } } } /// Whether to permit a path to resolve to an enum variant. #[derive(Debug, Clone, Copy)] pub enum PermitVariants { Yes, No, } #[derive(Debug, Clone, Copy)] enum TypeRelativePath<'tcx> { AssocItem(DefId, GenericArgsRef<'tcx>), Variant { adt: Ty<'tcx>, variant_did: DefId }, } /// New-typed boolean indicating whether explicit late-bound lifetimes /// are present in a set of generic arguments. /// /// For example if we have some method `fn f<'a>(&'a self)` implemented /// for some type `T`, although `f` is generic in the lifetime `'a`, `'a` /// is late-bound so should not be provided explicitly. Thus, if `f` is /// instantiated with some generic arguments providing `'a` explicitly, /// we taint those arguments with `ExplicitLateBound::Yes` so that we /// can provide an appropriate diagnostic later. #[derive(Copy, Clone, PartialEq, Debug)] pub enum ExplicitLateBound { Yes, No, } #[derive(Copy, Clone, PartialEq)] pub enum IsMethodCall { Yes, No, } /// Denotes the "position" of a generic argument, indicating if it is a generic type, /// generic function or generic method call. #[derive(Copy, Clone, PartialEq)] pub(crate) enum GenericArgPosition { Type, Value, // e.g., functions MethodCall, } /// Whether to allow duplicate associated iten constraints in a trait ref, e.g. /// `Trait`. This is forbidden in `dyn Trait<...>` /// but allowed everywhere else. #[derive(Clone, Copy, Debug, PartialEq)] pub(crate) enum OverlappingAsssocItemConstraints { Allowed, Forbidden, } /// A marker denoting that the generic arguments that were /// provided did not match the respective generic parameters. #[derive(Clone, Debug)] pub struct GenericArgCountMismatch { pub reported: ErrorGuaranteed, /// A list of indices of arguments provided that were not valid. pub invalid_args: Vec, } /// Decorates the result of a generic argument count mismatch /// check with whether explicit late bounds were provided. #[derive(Clone, Debug)] pub struct GenericArgCountResult { pub explicit_late_bound: ExplicitLateBound, pub correct: Result<(), GenericArgCountMismatch>, } /// A context which can lower HIR's [`GenericArg`] to `rustc_middle`'s [`ty::GenericArg`]. /// /// Its only consumer is [`generics::lower_generic_args`]. /// Read its documentation to learn more. pub trait GenericArgsLowerer<'a, 'tcx> { fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool); fn provided_kind( &mut self, preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx>; fn inferred_kind( &mut self, preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, infer_args: bool, ) -> ty::GenericArg<'tcx>; } impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*. #[instrument(level = "debug", skip(self), ret)] pub fn lower_lifetime( &self, lifetime: &hir::Lifetime, reason: RegionInferReason<'_>, ) -> ty::Region<'tcx> { if let Some(resolved) = self.tcx().named_bound_var(lifetime.hir_id) { self.lower_resolved_lifetime(resolved) } else { self.re_infer(lifetime.ident.span, reason) } } /// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*. #[instrument(level = "debug", skip(self), ret)] pub fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> { let tcx = self.tcx(); match resolved { rbv::ResolvedArg::StaticLifetime => tcx.lifetimes.re_static, rbv::ResolvedArg::LateBound(debruijn, index, def_id) => { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(index), kind: ty::BoundRegionKind::Named(def_id.to_def_id()), }; ty::Region::new_bound(tcx, debruijn, br) } rbv::ResolvedArg::EarlyBound(def_id) => { let name = tcx.hir_ty_param_name(def_id); let item_def_id = tcx.hir_ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name }) } rbv::ResolvedArg::Free(scope, id) => { ty::Region::new_late_param( tcx, scope.to_def_id(), ty::LateParamRegionKind::Named(id.to_def_id()), ) // (*) -- not late-bound, won't change } rbv::ResolvedArg::Error(guar) => ty::Region::new_error(tcx, guar), } } pub fn lower_generic_args_of_path_segment( &self, span: Span, def_id: DefId, item_segment: &hir::PathSegment<'tcx>, ) -> GenericArgsRef<'tcx> { let (args, _) = self.lower_generic_args_of_path(span, def_id, &[], item_segment, None); if let Some(c) = item_segment.args().constraints.first() { prohibit_assoc_item_constraint(self, c, Some((def_id, item_segment, span))); } args } /// Lower the generic arguments provided to some path. /// /// If this is a trait reference, you also need to pass the self type `self_ty`. /// The lowering process may involve applying defaulted type parameters. /// /// Associated item constraints are not handled here! They are either lowered via /// `lower_assoc_item_constraint` or rejected via `prohibit_assoc_item_constraint`. /// /// ### Example /// /// ```ignore (illustrative) /// T: std::ops::Index /// // ^1 ^^^^^^^^^^^^^^2 ^^^^3 ^^^^^^^^^^^4 /// ``` /// /// 1. The `self_ty` here would refer to the type `T`. /// 2. The path in question is the path to the trait `std::ops::Index`, /// which will have been resolved to a `def_id` /// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type /// parameters are returned in the `GenericArgsRef` /// 4. Associated item constraints like `Output = u32` are contained in `generic_args.constraints`. /// /// Note that the type listing given here is *exactly* what the user provided. /// /// For (generic) associated types /// /// ```ignore (illustrative) /// as Iterable>::Iter::<'a> /// ``` /// /// We have the parent args are the args for the parent trait: /// `[Vec, u8]` and `generic_args` are the arguments for the associated /// type itself: `['a]`. The returned `GenericArgsRef` concatenates these two /// lists: `[Vec, u8, 'a]`. #[instrument(level = "debug", skip(self, span), ret)] fn lower_generic_args_of_path( &self, span: Span, def_id: DefId, parent_args: &[ty::GenericArg<'tcx>], segment: &hir::PathSegment<'tcx>, self_ty: Option>, ) -> (GenericArgsRef<'tcx>, GenericArgCountResult) { // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). let tcx = self.tcx(); let generics = tcx.generics_of(def_id); debug!(?generics); if generics.has_self { if generics.parent.is_some() { // The parent is a trait so it should have at least one // generic parameter for the `Self` type. assert!(!parent_args.is_empty()) } else { // This item (presumably a trait) needs a self-type. assert!(self_ty.is_some()); } } else { assert!(self_ty.is_none()); } let arg_count = check_generic_arg_count( self, def_id, segment, generics, GenericArgPosition::Type, self_ty.is_some(), ); // Skip processing if type has no generic parameters. // Traits always have `Self` as a generic parameter, which means they will not return early // here and so associated item constraints will be handled regardless of whether there are // any non-`Self` generic parameters. if generics.is_own_empty() { return (tcx.mk_args(parent_args), arg_count); } struct GenericArgsCtxt<'a, 'tcx> { lowerer: &'a dyn HirTyLowerer<'tcx>, def_id: DefId, generic_args: &'a GenericArgs<'tcx>, span: Span, infer_args: bool, incorrect_args: &'a Result<(), GenericArgCountMismatch>, } impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for GenericArgsCtxt<'a, 'tcx> { fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool) { if did == self.def_id { (Some(self.generic_args), self.infer_args) } else { // The last component of this tuple is unimportant. (None, false) } } fn provided_kind( &mut self, preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { let tcx = self.lowerer.tcx(); if let Err(incorrect) = self.incorrect_args { if incorrect.invalid_args.contains(&(param.index as usize)) { return param.to_error(tcx); } } let handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| { if has_default { tcx.check_optional_stability( param.def_id, Some(arg.hir_id()), arg.span(), None, AllowUnstable::No, |_, _| { // Default generic parameters may not be marked // with stability attributes, i.e. when the // default parameter was defined at the same time // as the rest of the type. As such, we ignore missing // stability attributes. }, ); } self.lowerer.lower_ty(ty).into() }; match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { self.lowerer.lower_lifetime(lt, RegionInferReason::Param(param)).into() } (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { // We handle the other parts of `Ty` in the match arm below handle_ty_args(has_default, ty.as_unambig_ty()) } (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Infer(inf)) => { handle_ty_args(has_default, &inf.to_ty()) } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self .lowerer // Ambig portions of `ConstArg` are handled in the match arm below .lower_const_arg( ct.as_unambig_ct(), FeedConstTy::Param(param.def_id, preceding_args), ) .into(), (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { self.lowerer.ct_infer(Some(param), inf.span).into() } (kind, arg) => span_bug!( self.span, "mismatched path argument for kind {kind:?}: found arg {arg:?}" ), } } fn inferred_kind( &mut self, preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, infer_args: bool, ) -> ty::GenericArg<'tcx> { let tcx = self.lowerer.tcx(); if let Err(incorrect) = self.incorrect_args { if incorrect.invalid_args.contains(&(param.index as usize)) { return param.to_error(tcx); } } match param.kind { GenericParamDefKind::Lifetime => { self.lowerer.re_infer(self.span, RegionInferReason::Param(param)).into() } GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { // No type parameter provided, but a default exists. if let Some(prev) = preceding_args.iter().find_map(|arg| match arg.kind() { GenericArgKind::Type(ty) => ty.error_reported().err(), _ => None, }) { // Avoid ICE #86756 when type error recovery goes awry. return Ty::new_error(tcx, prev).into(); } tcx.at(self.span) .type_of(param.def_id) .instantiate(tcx, preceding_args) .into() } else if infer_args { self.lowerer.ty_infer(Some(param), self.span).into() } else { // We've already errored above about the mismatch. Ty::new_misc_error(tcx).into() } } GenericParamDefKind::Const { has_default, .. } => { let ty = tcx .at(self.span) .type_of(param.def_id) .instantiate(tcx, preceding_args); if let Err(guar) = ty.error_reported() { return ty::Const::new_error(tcx, guar).into(); } if !infer_args && has_default { tcx.const_param_default(param.def_id) .instantiate(tcx, preceding_args) .into() } else if infer_args { self.lowerer.ct_infer(Some(param), self.span).into() } else { // We've already errored above about the mismatch. ty::Const::new_misc_error(tcx).into() } } } } } let mut args_ctx = GenericArgsCtxt { lowerer: self, def_id, span, generic_args: segment.args(), infer_args: segment.infer_args, incorrect_args: &arg_count.correct, }; let args = lower_generic_args( self, def_id, parent_args, self_ty.is_some(), self_ty, &arg_count, &mut args_ctx, ); (args, arg_count) } #[instrument(level = "debug", skip(self))] pub fn lower_generic_args_of_assoc_item( &self, span: Span, item_def_id: DefId, item_segment: &hir::PathSegment<'tcx>, parent_args: GenericArgsRef<'tcx>, ) -> GenericArgsRef<'tcx> { let (args, _) = self.lower_generic_args_of_path(span, item_def_id, parent_args, item_segment, None); if let Some(c) = item_segment.args().constraints.first() { prohibit_assoc_item_constraint(self, c, Some((item_def_id, item_segment, span))); } args } /// Lower a trait reference as found in an impl header as the implementee. /// /// The self type `self_ty` is the implementer of the trait. pub fn lower_impl_trait_ref( &self, trait_ref: &hir::TraitRef<'tcx>, self_ty: Ty<'tcx>, ) -> ty::TraitRef<'tcx> { let _ = self.prohibit_generic_args( trait_ref.path.segments.split_last().unwrap().1.iter(), GenericsArgsErrExtend::None, ); self.lower_mono_trait_ref( trait_ref.path.span, trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()), self_ty, trait_ref.path.segments.last().unwrap(), true, ) } /// Lower a polymorphic trait reference given a self type into `bounds`. /// /// *Polymorphic* in the sense that it may bind late-bound vars. /// /// This may generate auxiliary bounds iff the trait reference contains associated item constraints. /// /// ### Example /// /// Given the trait ref `Iterator` and the self type `Ty`, this will add the /// /// 1. *trait predicate* `` (known as `Ty: Iterator` in the surface syntax) and the /// 2. *projection predicate* `::Item = u32` /// /// to `bounds`. /// /// ### A Note on Binders /// /// Against our usual convention, there is an implied binder around the `self_ty` and the /// `trait_ref` here. So they may reference late-bound vars. /// /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>` /// where `'a` is a bound region at depth 0. Similarly, the `trait_ref` would be `Bar<'a>`. /// The lowered poly-trait-ref will track this binder explicitly, however. #[instrument(level = "debug", skip(self, bounds))] pub(crate) fn lower_poly_trait_ref( &self, poly_trait_ref: &hir::PolyTraitRef<'tcx>, self_ty: Ty<'tcx>, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, predicate_filter: PredicateFilter, overlapping_assoc_item_constraints: OverlappingAsssocItemConstraints, ) -> GenericArgCountResult { let tcx = self.tcx(); // We use the *resolved* bound vars later instead of the HIR ones since the former // also include the bound vars of the overarching predicate if applicable. let hir::PolyTraitRef { bound_generic_params: _, modifiers, ref trait_ref, span } = *poly_trait_ref; let hir::TraitBoundModifiers { constness, polarity } = modifiers; let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); // Relaxed bounds `?Trait` and `PointeeSized` bounds aren't represented in the `middle::ty` IR // as they denote the *absence* of a default bound. However, we can't bail out early here since // we still need to perform several validation steps (see below). Instead, simply "pour" all // resulting bounds "down the drain", i.e., into a new `Vec` that just gets dropped at the end. let (polarity, bounds) = match polarity { rustc_ast::BoundPolarity::Positive if tcx.is_lang_item(trait_def_id, hir::LangItem::PointeeSized) => { // To elaborate on the comment directly above, regarding `PointeeSized` specifically, // we don't "reify" such bounds to avoid trait system limitations -- namely, // non-global where-clauses being preferred over item bounds (where `PointeeSized` // bounds would be proven) -- which can result in errors when a `PointeeSized` // supertrait / bound / predicate is added to some items. (ty::PredicatePolarity::Positive, &mut Vec::new()) } rustc_ast::BoundPolarity::Positive => (ty::PredicatePolarity::Positive, bounds), rustc_ast::BoundPolarity::Negative(_) => (ty::PredicatePolarity::Negative, bounds), rustc_ast::BoundPolarity::Maybe(_) => { (ty::PredicatePolarity::Positive, &mut Vec::new()) } }; let trait_segment = trait_ref.path.segments.last().unwrap(); let _ = self.prohibit_generic_args( trait_ref.path.segments.split_last().unwrap().1.iter(), GenericsArgsErrExtend::None, ); self.report_internal_fn_trait(span, trait_def_id, trait_segment, false); let (generic_args, arg_count) = self.lower_generic_args_of_path( trait_ref.path.span, trait_def_id, &[], trait_segment, Some(self_ty), ); let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id); debug!(?bound_vars); let poly_trait_ref = ty::Binder::bind_with_vars( ty::TraitRef::new_from_args(tcx, trait_def_id, generic_args), bound_vars, ); debug!(?poly_trait_ref); // We deal with const conditions later. match predicate_filter { PredicateFilter::All | PredicateFilter::SelfOnly | PredicateFilter::SelfTraitThatDefines(..) | PredicateFilter::SelfAndAssociatedTypeBounds => { let bound = poly_trait_ref.map_bound(|trait_ref| { ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity }) }); let bound = (bound.upcast(tcx), span); // FIXME(-Znext-solver): We can likely remove this hack once the // new trait solver lands. This fixed an overflow in the old solver. // This may have performance implications, so please check perf when // removing it. // This was added in . if tcx.is_lang_item(trait_def_id, rustc_hir::LangItem::Sized) { bounds.insert(0, bound); } else { bounds.push(bound); } } PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} } if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness && !self.tcx().is_const_trait(trait_def_id) { let (def_span, suggestion, suggestion_pre) = match (trait_def_id.is_local(), self.tcx().sess.is_nightly_build()) { (true, true) => ( None, Some(tcx.def_span(trait_def_id).shrink_to_lo()), if self.tcx().features().const_trait_impl() { "" } else { "enable `#![feature(const_trait_impl)]` in your crate and " }, ), (false, _) | (_, false) => (Some(tcx.def_span(trait_def_id)), None, ""), }; self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { span, modifier: constness.as_str(), def_span, trait_name: self.tcx().def_path_str(trait_def_id), suggestion_pre, suggestion, }); } else { match predicate_filter { // This is only concerned with trait predicates. PredicateFilter::SelfTraitThatDefines(..) => {} PredicateFilter::All | PredicateFilter::SelfOnly | PredicateFilter::SelfAndAssociatedTypeBounds => { match constness { hir::BoundConstness::Always(_) => { if polarity == ty::PredicatePolarity::Positive { bounds.push(( poly_trait_ref .to_host_effect_clause(tcx, ty::BoundConstness::Const), span, )); } } hir::BoundConstness::Maybe(_) => { // We don't emit a const bound here, since that would mean that we // unconditionally need to prove a `HostEffect` predicate, even when // the predicates are being instantiated in a non-const context. This // is instead handled in the `const_conditions` query. } hir::BoundConstness::Never => {} } } // On the flip side, when filtering `ConstIfConst` bounds, we only need to convert // `[const]` bounds. All other predicates are handled in their respective queries. // // Note that like `PredicateFilter::SelfOnly`, we don't need to do any filtering // here because we only call this on self bounds, and deal with the recursive case // in `lower_assoc_item_constraint`. PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => { match constness { hir::BoundConstness::Maybe(_) => { if polarity == ty::PredicatePolarity::Positive { bounds.push(( poly_trait_ref .to_host_effect_clause(tcx, ty::BoundConstness::Maybe), span, )); } } hir::BoundConstness::Always(_) | hir::BoundConstness::Never => {} } } } } let mut dup_constraints = (overlapping_assoc_item_constraints == OverlappingAsssocItemConstraints::Forbidden) .then_some(FxIndexMap::default()); for constraint in trait_segment.args().constraints { // Don't register any associated item constraints for negative bounds, // since we should have emitted an error for them earlier, and they // would not be well-formed! if polarity == ty::PredicatePolarity::Negative { self.dcx().span_delayed_bug( constraint.span, "negative trait bounds should not have assoc item constraints", ); break; } // Specify type to assert that error was already reported in `Err` case. let _: Result<_, ErrorGuaranteed> = self.lower_assoc_item_constraint( trait_ref.hir_ref_id, poly_trait_ref, constraint, bounds, dup_constraints.as_mut(), constraint.span, predicate_filter, ); // Okay to ignore `Err` because of `ErrorGuaranteed` (see above). } arg_count } /// Lower a monomorphic trait reference given a self type while prohibiting associated item bindings. /// /// *Monomorphic* in the sense that it doesn't bind any late-bound vars. fn lower_mono_trait_ref( &self, span: Span, trait_def_id: DefId, self_ty: Ty<'tcx>, trait_segment: &hir::PathSegment<'tcx>, is_impl: bool, ) -> ty::TraitRef<'tcx> { self.report_internal_fn_trait(span, trait_def_id, trait_segment, is_impl); let (generic_args, _) = self.lower_generic_args_of_path(span, trait_def_id, &[], trait_segment, Some(self_ty)); if let Some(c) = trait_segment.args().constraints.first() { prohibit_assoc_item_constraint(self, c, Some((trait_def_id, trait_segment, span))); } ty::TraitRef::new_from_args(self.tcx(), trait_def_id, generic_args) } fn probe_trait_that_defines_assoc_item( &self, trait_def_id: DefId, assoc_tag: ty::AssocTag, assoc_ident: Ident, ) -> bool { self.tcx() .associated_items(trait_def_id) .find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_tag, trait_def_id) .is_some() } fn lower_path_segment( &self, span: Span, did: DefId, item_segment: &hir::PathSegment<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx(); let args = self.lower_generic_args_of_path_segment(span, did, item_segment); if let DefKind::TyAlias = tcx.def_kind(did) && tcx.type_alias_is_lazy(did) { // Type aliases defined in crates that have the // feature `lazy_type_alias` enabled get encoded as a type alias that normalization will // then actually instantiate the where bounds of. let alias_ty = ty::AliasTy::new_from_args(tcx, did, args); Ty::new_alias(tcx, ty::Free, alias_ty) } else { tcx.at(span).type_of(did).instantiate(tcx, args) } } /// Search for a trait bound on a type parameter whose trait defines the associated item /// given by `assoc_ident` and `kind`. /// /// This fails if there is no such bound in the list of candidates or if there are multiple /// candidates in which case it reports ambiguity. /// /// `ty_param_def_id` is the `LocalDefId` of the type parameter. #[instrument(level = "debug", skip_all, ret)] fn probe_single_ty_param_bound_for_assoc_item( &self, ty_param_def_id: LocalDefId, ty_param_span: Span, assoc_tag: ty::AssocTag, assoc_ident: Ident, span: Span, ) -> Result, ErrorGuaranteed> { debug!(?ty_param_def_id, ?assoc_ident, ?span); let tcx = self.tcx(); let predicates = &self.probe_ty_param_bounds(span, ty_param_def_id, assoc_ident); debug!("predicates={:#?}", predicates); self.probe_single_bound_for_assoc_item( || { let trait_refs = predicates .iter_identity_copied() .filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))); traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_ident) }, AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span), assoc_tag, assoc_ident, span, None, ) } /// Search for a single trait bound whose trait defines the associated item given by /// `assoc_ident`. /// /// This fails if there is no such bound in the list of candidates or if there are multiple /// candidates in which case it reports ambiguity. #[instrument(level = "debug", skip(self, all_candidates, qself, constraint), ret)] fn probe_single_bound_for_assoc_item( &self, all_candidates: impl Fn() -> I, qself: AssocItemQSelf, assoc_tag: ty::AssocTag, assoc_ident: Ident, span: Span, constraint: Option<&hir::AssocItemConstraint<'tcx>>, ) -> Result, ErrorGuaranteed> where I: Iterator>, { let tcx = self.tcx(); let mut matching_candidates = all_candidates().filter(|r| { self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_tag, assoc_ident) }); let Some(bound) = matching_candidates.next() else { return Err(self.report_unresolved_assoc_item( all_candidates, qself, assoc_tag, assoc_ident, span, constraint, )); }; debug!(?bound); if let Some(bound2) = matching_candidates.next() { debug!(?bound2); let assoc_kind_str = errors::assoc_tag_str(assoc_tag); let qself_str = qself.to_string(tcx); let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem { span, assoc_kind: assoc_kind_str, assoc_ident, qself: &qself_str, }); // Provide a more specific error code index entry for equality bindings. err.code( if let Some(constraint) = constraint && let hir::AssocItemConstraintKind::Equality { .. } = constraint.kind { E0222 } else { E0221 }, ); // FIXME(#97583): Print associated item bindings properly (i.e., not as equality // predicates!). // FIXME: Turn this into a structured, translatable & more actionable suggestion. let mut where_bounds = vec![]; for bound in [bound, bound2].into_iter().chain(matching_candidates) { let bound_id = bound.def_id(); let bound_span = tcx .associated_items(bound_id) .find_by_ident_and_kind(tcx, assoc_ident, assoc_tag, bound_id) .and_then(|item| tcx.hir_span_if_local(item.def_id)); if let Some(bound_span) = bound_span { err.span_label( bound_span, format!("ambiguous `{assoc_ident}` from `{}`", bound.print_trait_sugared(),), ); if let Some(constraint) = constraint { match constraint.kind { hir::AssocItemConstraintKind::Equality { term } => { let term: ty::Term<'_> = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), hir::Term::Const(ct) => { self.lower_const_arg(ct, FeedConstTy::No).into() } }; if term.references_error() { continue; } // FIXME(#97583): This isn't syntactically well-formed! where_bounds.push(format!( " T: {trait}::{assoc_ident} = {term}", trait = bound.print_only_trait_path(), )); } // FIXME: Provide a suggestion. hir::AssocItemConstraintKind::Bound { bounds: _ } => {} } } else { err.span_suggestion_verbose( span.with_hi(assoc_ident.span.lo()), "use fully-qualified syntax to disambiguate", format!("<{qself_str} as {}>::", bound.print_only_trait_path()), Applicability::MaybeIncorrect, ); } } else { let trait_ = tcx.short_string(bound.print_only_trait_path(), err.long_ty_path()); err.note(format!( "associated {assoc_kind_str} `{assoc_ident}` could derive from `{trait_}`", )); } } if !where_bounds.is_empty() { err.help(format!( "consider introducing a new type parameter `T` and adding `where` constraints:\ \n where\n T: {qself_str},\n{}", where_bounds.join(",\n"), )); let reported = err.emit(); return Err(reported); } err.emit(); } Ok(bound) } /// Lower a [type-relative](hir::QPath::TypeRelative) path in type position to a type. /// /// If the path refers to an enum variant and `permit_variants` holds, /// the returned type is simply the provided self type `qself_ty`. /// /// A path like `A::B::C::D` is understood as `::D`. I.e., /// `qself_ty` / `qself` is `A::B::C` and `assoc_segment` is `D`. /// We return the lowered type and the `DefId` for the whole path. /// /// We only support associated type paths whose self type is a type parameter or a `Self` /// type alias (in a trait impl) like `T::Ty` (where `T` is a ty param) or `Self::Ty`. /// We **don't** support paths whose self type is an arbitrary type like `Struct::Ty` where /// struct `Struct` impls an in-scope trait that defines an associated type called `Ty`. /// For the latter case, we report ambiguity. /// While desirable to support, the implementation would be non-trivial. Tracked in [#22519]. /// /// At the time of writing, *inherent associated types* are also resolved here. This however /// is [problematic][iat]. A proper implementation would be as non-trivial as the one /// described in the previous paragraph and their modeling of projections would likely be /// very similar in nature. /// /// [#22519]: https://github.com/rust-lang/rust/issues/22519 /// [iat]: https://github.com/rust-lang/rust/issues/8995#issuecomment-1569208403 // // NOTE: When this function starts resolving `Trait::AssocTy` successfully // it should also start reporting the `BARE_TRAIT_OBJECTS` lint. #[instrument(level = "debug", skip_all, ret)] pub fn lower_type_relative_ty_path( &self, self_ty: Ty<'tcx>, hir_self_ty: &'tcx hir::Ty<'tcx>, segment: &'tcx hir::PathSegment<'tcx>, qpath_hir_id: HirId, span: Span, permit_variants: PermitVariants, ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> { let tcx = self.tcx(); match self.lower_type_relative_path( self_ty, hir_self_ty, segment, qpath_hir_id, span, LowerTypeRelativePathMode::Type(permit_variants), )? { TypeRelativePath::AssocItem(def_id, args) => { let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args); let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty); Ok((ty, tcx.def_kind(def_id), def_id)) } TypeRelativePath::Variant { adt, variant_did } => { Ok((adt, DefKind::Variant, variant_did)) } } } /// Lower a [type-relative][hir::QPath::TypeRelative] path to a (type-level) constant. #[instrument(level = "debug", skip_all, ret)] fn lower_type_relative_const_path( &self, self_ty: Ty<'tcx>, hir_self_ty: &'tcx hir::Ty<'tcx>, segment: &'tcx hir::PathSegment<'tcx>, qpath_hir_id: HirId, span: Span, ) -> Result, ErrorGuaranteed> { let tcx = self.tcx(); let (def_id, args) = match self.lower_type_relative_path( self_ty, hir_self_ty, segment, qpath_hir_id, span, LowerTypeRelativePathMode::Const, )? { TypeRelativePath::AssocItem(def_id, args) => { if !tcx.associated_item(def_id).is_type_const_capable(tcx) { let mut err = self.dcx().struct_span_err( span, "use of trait associated const without `#[type_const]`", ); err.note("the declaration in the trait must be marked with `#[type_const]`"); return Err(err.emit()); } (def_id, args) } // FIXME(mgca): implement support for this once ready to support all adt ctor expressions, // not just const ctors TypeRelativePath::Variant { .. } => { span_bug!(span, "unexpected variant res for type associated const path") } }; Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args))) } /// Lower a [type-relative][hir::QPath::TypeRelative] (and type-level) path. #[instrument(level = "debug", skip_all, ret)] fn lower_type_relative_path( &self, self_ty: Ty<'tcx>, hir_self_ty: &'tcx hir::Ty<'tcx>, segment: &'tcx hir::PathSegment<'tcx>, qpath_hir_id: HirId, span: Span, mode: LowerTypeRelativePathMode, ) -> Result, ErrorGuaranteed> { debug!(%self_ty, ?segment.ident); let tcx = self.tcx(); // Check if we have an enum variant or an inherent associated type. let mut variant_def_id = None; if let Some(adt_def) = self.probe_adt(span, self_ty) { if adt_def.is_enum() { let variant_def = adt_def .variants() .iter() .find(|vd| tcx.hygienic_eq(segment.ident, vd.ident(tcx), adt_def.did())); if let Some(variant_def) = variant_def { if let PermitVariants::Yes = mode.permit_variants() { tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None); let _ = self.prohibit_generic_args( slice::from_ref(segment).iter(), GenericsArgsErrExtend::EnumVariant { qself: hir_self_ty, assoc_segment: segment, adt_def, }, ); return Ok(TypeRelativePath::Variant { adt: self_ty, variant_did: variant_def.def_id, }); } else { variant_def_id = Some(variant_def.def_id); } } } // FIXME(inherent_associated_types, #106719): Support self types other than ADTs. if let Some((did, args)) = self.probe_inherent_assoc_item( segment, adt_def.did(), self_ty, qpath_hir_id, span, mode.assoc_tag(), )? { return Ok(TypeRelativePath::AssocItem(did, args)); } } let (item_def_id, bound) = self.resolve_type_relative_path( self_ty, hir_self_ty, mode.assoc_tag(), segment, qpath_hir_id, span, variant_def_id, )?; let (item_def_id, args) = self.lower_assoc_item_path(span, item_def_id, segment, bound)?; if let Some(variant_def_id) = variant_def_id { tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, qpath_hir_id, span, |lint| { lint.primary_message("ambiguous associated item"); let mut could_refer_to = |kind: DefKind, def_id, also| { let note_msg = format!( "`{}` could{} refer to the {} defined here", segment.ident, also, tcx.def_kind_descr(kind, def_id) ); lint.span_note(tcx.def_span(def_id), note_msg); }; could_refer_to(DefKind::Variant, variant_def_id, ""); could_refer_to(mode.def_kind(), item_def_id, " also"); lint.span_suggestion( span, "use fully-qualified syntax", format!( "<{} as {}>::{}", self_ty, tcx.item_name(bound.def_id()), segment.ident ), Applicability::MachineApplicable, ); }); } Ok(TypeRelativePath::AssocItem(item_def_id, args)) } /// Resolve a [type-relative](hir::QPath::TypeRelative) (and type-level) path. fn resolve_type_relative_path( &self, self_ty: Ty<'tcx>, hir_self_ty: &'tcx hir::Ty<'tcx>, assoc_tag: ty::AssocTag, segment: &'tcx hir::PathSegment<'tcx>, qpath_hir_id: HirId, span: Span, variant_def_id: Option, ) -> Result<(DefId, ty::PolyTraitRef<'tcx>), ErrorGuaranteed> { let tcx = self.tcx(); let self_ty_res = match hir_self_ty.kind { hir::TyKind::Path(hir::QPath::Resolved(_, path)) => path.res, _ => Res::Err, }; // Find the type of the assoc item, and the trait where the associated item is declared. let bound = match (self_ty.kind(), self_ty_res) { (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => { // `Self` in an impl of a trait -- we have a concrete self type and a // trait reference. let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else { // A cycle error occurred, most likely. self.dcx().span_bug(span, "expected cycle error"); }; self.probe_single_bound_for_assoc_item( || { let trait_ref = ty::Binder::dummy(trait_ref.instantiate_identity()); traits::supertraits(tcx, trait_ref) }, AssocItemQSelf::SelfTyAlias, assoc_tag, segment.ident, span, None, )? } ( &ty::Param(_), Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did), ) => self.probe_single_ty_param_bound_for_assoc_item( param_did.expect_local(), hir_self_ty.span, assoc_tag, segment.ident, span, )?, _ => { return Err(self.report_unresolved_type_relative_path( self_ty, hir_self_ty, assoc_tag, segment.ident, qpath_hir_id, span, variant_def_id, )); } }; let assoc_item = self .probe_assoc_item(segment.ident, assoc_tag, qpath_hir_id, span, bound.def_id()) .expect("failed to find associated item"); Ok((assoc_item.def_id, bound)) } /// Search for inherent associated items for use at the type level. fn probe_inherent_assoc_item( &self, segment: &hir::PathSegment<'tcx>, adt_did: DefId, self_ty: Ty<'tcx>, block: HirId, span: Span, assoc_tag: ty::AssocTag, ) -> Result)>, ErrorGuaranteed> { let tcx = self.tcx(); if !tcx.features().inherent_associated_types() { match assoc_tag { // Don't attempt to look up inherent associated types when the feature is not // enabled. Theoretically it'd be fine to do so since we feature-gate their // definition site. However, due to current limitations of the implementation // (caused by us performing selection during HIR ty lowering instead of in the // trait solver), IATs can lead to cycle errors (#108491) which mask the // feature-gate error, needlessly confusing users who use IATs by accident // (#113265). ty::AssocTag::Type => return Ok(None), ty::AssocTag::Const => { // We also gate the mgca codepath for type-level uses of inherent consts // with the inherent_associated_types feature gate since it relies on the // same machinery and has similar rough edges. return Err(feature_err( &tcx.sess, sym::inherent_associated_types, span, "inherent associated types are unstable", ) .emit()); } ty::AssocTag::Fn => unreachable!(), } } let name = segment.ident; let candidates: Vec<_> = tcx .inherent_impls(adt_did) .iter() .filter_map(|&impl_| { let (item, scope) = self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?; Some(InherentAssocCandidate { impl_, assoc_item: item.def_id, scope }) }) .collect(); let (applicable_candidates, fulfillment_errors) = self.select_inherent_assoc_candidates(span, self_ty, candidates.clone()); let InherentAssocCandidate { impl_, assoc_item, scope: def_scope } = match &applicable_candidates[..] { &[] => Err(self.report_unresolved_inherent_assoc_item( name, self_ty, candidates, fulfillment_errors, span, assoc_tag, )), &[applicable_candidate] => Ok(applicable_candidate), &[_, ..] => Err(self.report_ambiguous_inherent_assoc_item( name, candidates.into_iter().map(|cand| cand.assoc_item).collect(), span, )), }?; self.check_assoc_item(assoc_item, name, def_scope, block, span); // FIXME(fmease): Currently creating throwaway `parent_args` to please // `lower_generic_args_of_assoc_item`. Modify the latter instead (or sth. similar) to // not require the parent args logic. let parent_args = ty::GenericArgs::identity_for_item(tcx, impl_); let args = self.lower_generic_args_of_assoc_item(span, assoc_item, segment, parent_args); let args = tcx.mk_args_from_iter( std::iter::once(ty::GenericArg::from(self_ty)) .chain(args.into_iter().skip(parent_args.len())), ); Ok(Some((assoc_item, args))) } /// Given name and kind search for the assoc item in the provided scope and check if it's accessible[^1]. /// /// [^1]: I.e., accessible in the provided scope wrt. visibility and stability. fn probe_assoc_item( &self, ident: Ident, assoc_tag: ty::AssocTag, block: HirId, span: Span, scope: DefId, ) -> Option { let (item, scope) = self.probe_assoc_item_unchecked(ident, assoc_tag, block, scope)?; self.check_assoc_item(item.def_id, ident, scope, block, span); Some(item) } /// Given name and kind search for the assoc item in the provided scope /// *without* checking if it's accessible[^1]. /// /// [^1]: I.e., accessible in the provided scope wrt. visibility and stability. fn probe_assoc_item_unchecked( &self, ident: Ident, assoc_tag: ty::AssocTag, block: HirId, scope: DefId, ) -> Option<(ty::AssocItem, /*scope*/ DefId)> { let tcx = self.tcx(); let (ident, def_scope) = tcx.adjust_ident_and_get_scope(ident, scope, block); // We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()` // instead of calling `filter_by_name_and_kind` which would needlessly normalize the // `ident` again and again. let item = tcx .associated_items(scope) .filter_by_name_unhygienic(ident.name) .find(|i| i.as_tag() == assoc_tag && i.ident(tcx).normalize_to_macros_2_0() == ident)?; Some((*item, def_scope)) } /// Check if the given assoc item is accessible in the provided scope wrt. visibility and stability. fn check_assoc_item( &self, item_def_id: DefId, ident: Ident, scope: DefId, block: HirId, span: Span, ) { let tcx = self.tcx(); if !tcx.visibility(item_def_id).is_accessible_from(scope, tcx) { self.dcx().emit_err(crate::errors::AssocItemIsPrivate { span, kind: tcx.def_descr(item_def_id), name: ident, defined_here_label: tcx.def_span(item_def_id), }); } tcx.check_stability(item_def_id, Some(block), span, None); } fn probe_traits_that_match_assoc_ty( &self, qself_ty: Ty<'tcx>, assoc_ident: Ident, ) -> Vec { let tcx = self.tcx(); // In contexts that have no inference context, just make a new one. // We do need a local variable to store it, though. let infcx_; let infcx = if let Some(infcx) = self.infcx() { infcx } else { assert!(!qself_ty.has_infer()); infcx_ = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); &infcx_ }; tcx.all_traits_including_private() .filter(|trait_def_id| { // Consider only traits with the associated type tcx.associated_items(*trait_def_id) .in_definition_order() .any(|i| { i.is_type() && !i.is_impl_trait_in_trait() && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident }) // Consider only accessible traits && tcx.visibility(*trait_def_id) .is_accessible_from(self.item_def_id(), tcx) && tcx.all_impls(*trait_def_id) .any(|impl_def_id| { let header = tcx.impl_trait_header(impl_def_id).unwrap(); let trait_ref = header.trait_ref.instantiate( tcx, infcx.fresh_args_for_item(DUMMY_SP, impl_def_id), ); let value = fold_regions(tcx, qself_ty, |_, _| tcx.lifetimes.re_erased); // FIXME: Don't bother dealing with non-lifetime binders here... if value.has_escaping_bound_vars() { return false; } infcx .can_eq( ty::ParamEnv::empty(), trait_ref.self_ty(), value, ) && header.polarity != ty::ImplPolarity::Negative }) }) .map(|trait_def_id| tcx.def_path_str(trait_def_id)) .collect() } /// Lower a [resolved][hir::QPath::Resolved] associated type path to a projection. #[instrument(level = "debug", skip_all)] fn lower_resolved_assoc_ty_path( &self, span: Span, opt_self_ty: Option>, item_def_id: DefId, trait_segment: Option<&hir::PathSegment<'tcx>>, item_segment: &hir::PathSegment<'tcx>, ) -> Ty<'tcx> { match self.lower_resolved_assoc_item_path( span, opt_self_ty, item_def_id, trait_segment, item_segment, ty::AssocTag::Type, ) { Ok((item_def_id, item_args)) => { Ty::new_projection_from_args(self.tcx(), item_def_id, item_args) } Err(guar) => Ty::new_error(self.tcx(), guar), } } /// Lower a [resolved][hir::QPath::Resolved] associated const path to a (type-level) constant. #[instrument(level = "debug", skip_all)] fn lower_resolved_assoc_const_path( &self, span: Span, opt_self_ty: Option>, item_def_id: DefId, trait_segment: Option<&hir::PathSegment<'tcx>>, item_segment: &hir::PathSegment<'tcx>, ) -> Const<'tcx> { match self.lower_resolved_assoc_item_path( span, opt_self_ty, item_def_id, trait_segment, item_segment, ty::AssocTag::Const, ) { Ok((item_def_id, item_args)) => { let uv = ty::UnevaluatedConst::new(item_def_id, item_args); Const::new_unevaluated(self.tcx(), uv) } Err(guar) => Const::new_error(self.tcx(), guar), } } /// Lower a [resolved][hir::QPath::Resolved] (type-level) associated item path. #[instrument(level = "debug", skip_all)] fn lower_resolved_assoc_item_path( &self, span: Span, opt_self_ty: Option>, item_def_id: DefId, trait_segment: Option<&hir::PathSegment<'tcx>>, item_segment: &hir::PathSegment<'tcx>, assoc_tag: ty::AssocTag, ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> { let tcx = self.tcx(); let trait_def_id = tcx.parent(item_def_id); debug!(?trait_def_id); let Some(self_ty) = opt_self_ty else { return Err(self.report_missing_self_ty_for_resolved_path( trait_def_id, span, item_segment, assoc_tag, )); }; debug!(?self_ty); let trait_ref = self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment.unwrap(), false); debug!(?trait_ref); let item_args = self.lower_generic_args_of_assoc_item(span, item_def_id, item_segment, trait_ref.args); Ok((item_def_id, item_args)) } pub fn prohibit_generic_args<'a>( &self, segments: impl Iterator> + Clone, err_extend: GenericsArgsErrExtend<'a>, ) -> Result<(), ErrorGuaranteed> { let args_visitors = segments.clone().flat_map(|segment| segment.args().args); let mut result = Ok(()); if let Some(_) = args_visitors.clone().next() { result = Err(self.report_prohibited_generic_args( segments.clone(), args_visitors, err_extend, )); } for segment in segments { // Only emit the first error to avoid overloading the user with error messages. if let Some(c) = segment.args().constraints.first() { return Err(prohibit_assoc_item_constraint(self, c, None)); } } result } /// Probe path segments that are semantically allowed to have generic arguments. /// /// ### Example /// /// ```ignore (illustrative) /// Option::None::<()> /// // ^^^^ permitted to have generic args /// /// // ==> [GenericPathSegment(Option_def_id, 1)] /// /// Option::<()>::None /// // ^^^^^^ ^^^^ *not* permitted to have generic args /// // permitted to have generic args /// /// // ==> [GenericPathSegment(Option_def_id, 0)] /// ``` // FIXME(eddyb, varkor) handle type paths here too, not just value ones. pub fn probe_generic_path_segments( &self, segments: &[hir::PathSegment<'_>], self_ty: Option>, kind: DefKind, def_id: DefId, span: Span, ) -> Vec { // We need to extract the generic arguments supplied by the user in // the path `path`. Due to the current setup, this is a bit of a // tricky process; the problem is that resolve only tells us the // end-point of the path resolution, and not the intermediate steps. // Luckily, we can (at least for now) deduce the intermediate steps // just from the end-point. // // There are basically five cases to consider: // // 1. Reference to a constructor of a struct: // // struct Foo(...) // // In this case, the generic arguments are declared in the type space. // // 2. Reference to a constructor of an enum variant: // // enum E { Foo(...) } // // In this case, the generic arguments are defined in the type space, // but may be specified either on the type or the variant. // // 3. Reference to a free function or constant: // // fn foo() {} // // In this case, the path will again always have the form // `a::b::foo::` where only the final segment should have generic // arguments. However, in this case, those arguments are declared on // a value, and hence are in the value space. // // 4. Reference to an associated function or constant: // // impl SomeStruct { // fn foo(...) {} // } // // Here we can have a path like `a::b::SomeStruct::::foo::`, // in which case generic arguments may appear in two places. The // penultimate segment, `SomeStruct::`, contains generic arguments // in the type space, and the final segment, `foo::` contains // generic arguments in value space. // // The first step then is to categorize the segments appropriately. let tcx = self.tcx(); assert!(!segments.is_empty()); let last = segments.len() - 1; let mut generic_segments = vec![]; match kind { // Case 1. Reference to a struct constructor. DefKind::Ctor(CtorOf::Struct, ..) => { // Everything but the final segment should have no // parameters at all. let generics = tcx.generics_of(def_id); // Variant and struct constructors use the // generics of their parent type definition. let generics_def_id = generics.parent.unwrap_or(def_id); generic_segments.push(GenericPathSegment(generics_def_id, last)); } // Case 2. Reference to a variant constructor. DefKind::Ctor(CtorOf::Variant, ..) | DefKind::Variant => { let (generics_def_id, index) = if let Some(self_ty) = self_ty { let adt_def = self.probe_adt(span, self_ty).unwrap(); debug_assert!(adt_def.is_enum()); (adt_def.did(), last) } else if last >= 1 && segments[last - 1].args.is_some() { // Everything but the penultimate segment should have no // parameters at all. let mut def_id = def_id; // `DefKind::Ctor` -> `DefKind::Variant` if let DefKind::Ctor(..) = kind { def_id = tcx.parent(def_id); } // `DefKind::Variant` -> `DefKind::Enum` let enum_def_id = tcx.parent(def_id); (enum_def_id, last - 1) } else { // FIXME: lint here recommending `Enum::<...>::Variant` form // instead of `Enum::Variant::<...>` form. // Everything but the final segment should have no // parameters at all. let generics = tcx.generics_of(def_id); // Variant and struct constructors use the // generics of their parent type definition. (generics.parent.unwrap_or(def_id), last) }; generic_segments.push(GenericPathSegment(generics_def_id, index)); } // Case 3. Reference to a top-level value. DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static { .. } => { generic_segments.push(GenericPathSegment(def_id, last)); } // Case 4. Reference to a method or associated const. DefKind::AssocFn | DefKind::AssocConst => { if segments.len() >= 2 { let generics = tcx.generics_of(def_id); generic_segments.push(GenericPathSegment(generics.parent.unwrap(), last - 1)); } generic_segments.push(GenericPathSegment(def_id, last)); } kind => bug!("unexpected definition kind {:?} for {:?}", kind, def_id), } debug!(?generic_segments); generic_segments } /// Lower a [resolved][hir::QPath::Resolved] path to a type. #[instrument(level = "debug", skip_all)] pub fn lower_resolved_ty_path( &self, opt_self_ty: Option>, path: &hir::Path<'tcx>, hir_id: HirId, permit_variants: PermitVariants, ) -> Ty<'tcx> { debug!(?path.res, ?opt_self_ty, ?path.segments); let tcx = self.tcx(); let span = path.span; match path.res { Res::Def(DefKind::OpaqueTy, did) => { // Check for desugared `impl Trait`. assert_matches!(tcx.opaque_ty_origin(did), hir::OpaqueTyOrigin::TyAlias { .. }); let item_segment = path.segments.split_last().unwrap(); let _ = self .prohibit_generic_args(item_segment.1.iter(), GenericsArgsErrExtend::OpaqueTy); let args = self.lower_generic_args_of_path_segment(span, did, item_segment.0); Ty::new_opaque(tcx, did, args) } Res::Def( DefKind::Enum | DefKind::TyAlias | DefKind::Struct | DefKind::Union | DefKind::ForeignTy, did, ) => { assert_eq!(opt_self_ty, None); let _ = self.prohibit_generic_args( path.segments.split_last().unwrap().1.iter(), GenericsArgsErrExtend::None, ); self.lower_path_segment(span, did, path.segments.last().unwrap()) } Res::Def(kind @ DefKind::Variant, def_id) if let PermitVariants::Yes = permit_variants => { // Lower "variant type" as if it were a real type. // The resulting `Ty` is type of the variant's enum for now. assert_eq!(opt_self_ty, None); let generic_segments = self.probe_generic_path_segments(path.segments, None, kind, def_id, span); let indices: FxHashSet<_> = generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect(); let _ = self.prohibit_generic_args( path.segments.iter().enumerate().filter_map(|(index, seg)| { if !indices.contains(&index) { Some(seg) } else { None } }), GenericsArgsErrExtend::DefVariant(&path.segments), ); let GenericPathSegment(def_id, index) = generic_segments.last().unwrap(); self.lower_path_segment(span, *def_id, &path.segments[*index]) } Res::Def(DefKind::TyParam, def_id) => { assert_eq!(opt_self_ty, None); let _ = self.prohibit_generic_args( path.segments.iter(), GenericsArgsErrExtend::Param(def_id), ); self.lower_ty_param(hir_id) } Res::SelfTyParam { .. } => { // `Self` in trait or type alias. assert_eq!(opt_self_ty, None); let _ = self.prohibit_generic_args( path.segments.iter(), if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments { GenericsArgsErrExtend::SelfTyParam( ident.span.shrink_to_hi().to(args.span_ext), ) } else { GenericsArgsErrExtend::None }, ); tcx.types.self_param } Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => { // `Self` in impl (we know the concrete type). assert_eq!(opt_self_ty, None); // Try to evaluate any array length constants. let ty = tcx.at(span).type_of(def_id).instantiate_identity(); let _ = self.prohibit_generic_args( path.segments.iter(), GenericsArgsErrExtend::SelfTyAlias { def_id, span }, ); // HACK(min_const_generics): Forbid generic `Self` types // here as we can't easily do that during nameres. // // We do this before normalization as we otherwise allow // ```rust // trait AlwaysApplicable { type Assoc; } // impl AlwaysApplicable for T { type Assoc = usize; } // // trait BindsParam { // type ArrayTy; // } // impl BindsParam for ::Assoc { // type ArrayTy = [u8; Self::MAX]; // } // ``` // Note that the normalization happens in the param env of // the anon const, which is empty. This is why the // `AlwaysApplicable` impl needs a `T: ?Sized` bound for // this to compile if we were to normalize here. if forbid_generic && ty.has_param() { let mut err = self.dcx().struct_span_err( path.span, "generic `Self` types are currently not permitted in anonymous constants", ); if let Some(hir::Node::Item(&hir::Item { kind: hir::ItemKind::Impl(impl_), .. })) = tcx.hir_get_if_local(def_id) { err.span_note(impl_.self_ty.span, "not a concrete type"); } let reported = err.emit(); Ty::new_error(tcx, reported) } else { ty } } Res::Def(DefKind::AssocTy, def_id) => { let trait_segment = if let [modules @ .., trait_, _item] = path.segments { let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None); Some(trait_) } else { None }; self.lower_resolved_assoc_ty_path( span, opt_self_ty, def_id, trait_segment, path.segments.last().unwrap(), ) } Res::PrimTy(prim_ty) => { assert_eq!(opt_self_ty, None); let _ = self.prohibit_generic_args( path.segments.iter(), GenericsArgsErrExtend::PrimTy(prim_ty), ); match prim_ty { hir::PrimTy::Bool => tcx.types.bool, hir::PrimTy::Char => tcx.types.char, hir::PrimTy::Int(it) => Ty::new_int(tcx, it), hir::PrimTy::Uint(uit) => Ty::new_uint(tcx, uit), hir::PrimTy::Float(ft) => Ty::new_float(tcx, ft), hir::PrimTy::Str => tcx.types.str_, } } Res::Err => { let e = self .tcx() .dcx() .span_delayed_bug(path.span, "path with `Res::Err` but no error emitted"); Ty::new_error(tcx, e) } Res::Def(..) => { assert_eq!( path.segments.get(0).map(|seg| seg.ident.name), Some(kw::SelfUpper), "only expected incorrect resolution for `Self`" ); Ty::new_error( self.tcx(), self.dcx().span_delayed_bug(span, "incorrect resolution for `Self`"), ) } _ => span_bug!(span, "unexpected resolution: {:?}", path.res), } } /// Lower a type parameter from the HIR to our internal notion of a type. /// /// Early-bound type parameters get lowered to [`ty::Param`] /// and late-bound ones to [`ty::Bound`]. pub(crate) fn lower_ty_param(&self, hir_id: HirId) -> Ty<'tcx> { let tcx = self.tcx(); match tcx.named_bound_var(hir_id) { Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { let br = ty::BoundTy { var: ty::BoundVar::from_u32(index), kind: ty::BoundTyKind::Param(def_id.to_def_id()), }; Ty::new_bound(tcx, debruijn, br) } Some(rbv::ResolvedArg::EarlyBound(def_id)) => { let item_def_id = tcx.hir_ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; Ty::new_param(tcx, index, tcx.hir_ty_param_name(def_id)) } Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar), arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"), } } /// Lower a const parameter from the HIR to our internal notion of a constant. /// /// Early-bound const parameters get lowered to [`ty::ConstKind::Param`] /// and late-bound ones to [`ty::ConstKind::Bound`]. pub(crate) fn lower_const_param(&self, param_def_id: DefId, path_hir_id: HirId) -> Const<'tcx> { let tcx = self.tcx(); match tcx.named_bound_var(path_hir_id) { Some(rbv::ResolvedArg::EarlyBound(_)) => { // Find the name and index of the const parameter by indexing the generics of // the parent item and construct a `ParamConst`. let item_def_id = tcx.parent(param_def_id); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[¶m_def_id]; let name = tcx.item_name(param_def_id); ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => ty::Const::new_bound( tcx, debruijn, ty::BoundConst { var: ty::BoundVar::from_u32(index) }, ), Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", path_hir_id), } } /// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`](Const). #[instrument(skip(self), level = "debug")] pub fn lower_const_arg( &self, const_arg: &hir::ConstArg<'tcx>, feed: FeedConstTy<'_, 'tcx>, ) -> Const<'tcx> { let tcx = self.tcx(); if let FeedConstTy::Param(param_def_id, args) = feed && let hir::ConstArgKind::Anon(anon) = &const_arg.kind { let anon_const_type = tcx.type_of(param_def_id).instantiate(tcx, args); // FIXME(generic_const_parameter_types): Ideally we remove these errors below when // we have the ability to intermix typeck of anon const const args with the parent // bodies typeck. // We also error if the type contains any regions as effectively any region will wind // up as a region variable in mir borrowck. It would also be somewhat concerning if // hir typeck was using equality but mir borrowck wound up using subtyping as that could // result in a non-infer in hir typeck but a region variable in borrowck. if tcx.features().generic_const_parameter_types() && (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions()) { let e = self.dcx().span_err( const_arg.span(), "anonymous constants with lifetimes in their type are not yet supported", ); tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e))); return ty::Const::new_error(tcx, e); } // We must error if the instantiated type has any inference variables as we will // use this type to feed the `type_of` and query results must not contain inference // variables otherwise we will ICE. if anon_const_type.has_non_region_infer() { let e = self.dcx().span_err( const_arg.span(), "anonymous constants with inferred types are not yet supported", ); tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e))); return ty::Const::new_error(tcx, e); } // We error when the type contains unsubstituted generics since we do not currently // give the anon const any of the generics from the parent. if anon_const_type.has_non_region_param() { let e = self.dcx().span_err( const_arg.span(), "anonymous constants referencing generics are not yet supported", ); tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e))); return ty::Const::new_error(tcx, e); } tcx.feed_anon_const_type( anon.def_id, ty::EarlyBinder::bind(tcx.type_of(param_def_id).instantiate(tcx, args)), ); } let hir_id = const_arg.hir_id; match const_arg.kind { hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); self.lower_resolved_const_path(opt_self_ty, path, hir_id) } hir::ConstArgKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => { debug!(?hir_self_ty, ?segment); let self_ty = self.lower_ty(hir_self_ty); self.lower_type_relative_const_path( self_ty, hir_self_ty, segment, hir_id, const_arg.span(), ) .unwrap_or_else(|guar| Const::new_error(tcx, guar)) } hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => { ty::Const::new_error_with_message( tcx, qpath.span(), format!("Const::lower_const_arg: invalid qpath {qpath:?}"), ) } hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon), hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span), } } /// Lower a [resolved][hir::QPath::Resolved] path to a (type-level) constant. fn lower_resolved_const_path( &self, opt_self_ty: Option>, path: &hir::Path<'tcx>, hir_id: HirId, ) -> Const<'tcx> { let tcx = self.tcx(); let span = path.span; match path.res { Res::Def(DefKind::ConstParam, def_id) => { assert_eq!(opt_self_ty, None); let _ = self.prohibit_generic_args( path.segments.iter(), GenericsArgsErrExtend::Param(def_id), ); self.lower_const_param(def_id, hir_id) } Res::Def(DefKind::Const | DefKind::Ctor(_, CtorKind::Const), did) => { assert_eq!(opt_self_ty, None); let _ = self.prohibit_generic_args( path.segments.split_last().unwrap().1.iter(), GenericsArgsErrExtend::None, ); let args = self.lower_generic_args_of_path_segment( span, did, path.segments.last().unwrap(), ); ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args)) } Res::Def(DefKind::AssocConst, did) => { let trait_segment = if let [modules @ .., trait_, _item] = path.segments { let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None); Some(trait_) } else { None }; self.lower_resolved_assoc_const_path( span, opt_self_ty, did, trait_segment, path.segments.last().unwrap(), ) } Res::Def(DefKind::Static { .. }, _) => { span_bug!(span, "use of bare `static` ConstArgKind::Path's not yet supported") } // FIXME(const_generics): create real const to allow fn items as const paths Res::Def(DefKind::Fn | DefKind::AssocFn, did) => { self.dcx().span_delayed_bug(span, "function items cannot be used as const args"); let args = self.lower_generic_args_of_path_segment( span, did, path.segments.last().unwrap(), ); ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, did, args)) } // Exhaustive match to be clear about what exactly we're considering to be // an invalid Res for a const path. res @ (Res::Def( DefKind::Mod | DefKind::Enum | DefKind::Variant | DefKind::Ctor(CtorOf::Variant, CtorKind::Fn) | DefKind::Struct | DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) | DefKind::OpaqueTy | DefKind::TyAlias | DefKind::TraitAlias | DefKind::AssocTy | DefKind::Union | DefKind::Trait | DefKind::ForeignTy | DefKind::TyParam | DefKind::Macro(_) | DefKind::LifetimeParam | DefKind::Use | DefKind::ForeignMod | DefKind::AnonConst | DefKind::InlineConst | DefKind::Field | DefKind::Impl { .. } | DefKind::Closure | DefKind::ExternCrate | DefKind::GlobalAsm | DefKind::SyntheticCoroutineBody, _, ) | Res::PrimTy(_) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::SelfCtor(_) | Res::Local(_) | Res::ToolMod | Res::NonMacroAttr(_) | Res::Err) => Const::new_error_with_message( tcx, span, format!("invalid Res {res:?} for const path"), ), } } /// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`. #[instrument(skip(self), level = "debug")] fn lower_anon_const(&self, anon: &AnonConst) -> Const<'tcx> { let tcx = self.tcx(); let expr = &tcx.hir_body(anon.body).value; debug!(?expr); // FIXME(generic_const_parameter_types): We should use the proper generic args // here. It's only used as a hint for literals so doesn't matter too much to use the right // generic arguments, just weaker type inference. let ty = tcx.type_of(anon.def_id).instantiate_identity(); match self.try_lower_anon_const_lit(ty, expr) { Some(v) => v, None => ty::Const::new_unevaluated( tcx, ty::UnevaluatedConst { def: anon.def_id.to_def_id(), args: ty::GenericArgs::identity_for_item(tcx, anon.def_id.to_def_id()), }, ), } } #[instrument(skip(self), level = "debug")] fn try_lower_anon_const_lit( &self, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>, ) -> Option> { let tcx = self.tcx(); // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments // currently have to be wrapped in curly brackets, so it's necessary to special-case. let expr = match &expr.kind { hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => { block.expr.as_ref().unwrap() } _ => expr, }; if let hir::ExprKind::Path(hir::QPath::Resolved( _, &hir::Path { res: Res::Def(DefKind::ConstParam, _), .. }, )) = expr.kind { span_bug!( expr.span, "try_lower_anon_const_lit: received const param which shouldn't be possible" ); }; let lit_input = match expr.kind { hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: false }), hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind { hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: true }), _ => None, }, _ => None, }; lit_input // Allow the `ty` to be an alias type, though we cannot handle it here, we just go through // the more expensive anon const code path. .filter(|l| !l.ty.has_aliases()) .map(|l| tcx.at(expr.span).lit_to_const(l)) } fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> { let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id()); match idx { hir::InferDelegationKind::Input(idx) => delegation_sig[idx], hir::InferDelegationKind::Output => *delegation_sig.last().unwrap(), } } /// Lower a type from the HIR to our internal notion of a type. #[instrument(level = "debug", skip(self), ret)] pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let tcx = self.tcx(); let result_ty = match &hir_ty.kind { hir::TyKind::InferDelegation(_, idx) => self.lower_delegation_ty(*idx), hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)), hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl), hir::TyKind::Ref(region, mt) => { let r = self.lower_lifetime(region, RegionInferReason::Reference); debug!(?r); let t = self.lower_ty(mt.ty); Ty::new_ref(tcx, r, t, mt.mutbl) } hir::TyKind::Never => tcx.types.never, hir::TyKind::Tup(fields) => { Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.lower_ty(t))) } hir::TyKind::FnPtr(bf) => { check_c_variadic_abi(tcx, bf.decl, bf.abi, hir_ty.span); Ty::new_fn_ptr( tcx, self.lower_fn_ty(hir_ty.hir_id, bf.safety, bf.abi, bf.decl, None, Some(hir_ty)), ) } hir::TyKind::UnsafeBinder(binder) => Ty::new_unsafe_binder( tcx, ty::Binder::bind_with_vars( self.lower_ty(binder.inner_ty), tcx.late_bound_vars(hir_ty.hir_id), ), ), hir::TyKind::TraitObject(bounds, tagged_ptr) => { let lifetime = tagged_ptr.pointer(); let syntax = tagged_ptr.tag(); self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, syntax) } // If we encounter a fully qualified path with RTN generics, then it must have // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore // it's certainly in an illegal position. hir::TyKind::Path(hir::QPath::Resolved(_, path)) if path.segments.last().and_then(|segment| segment.args).is_some_and(|args| { matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) }) => { let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span }); Ty::new_error(tcx, guar) } hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); self.lower_resolved_ty_path(opt_self_ty, path, hir_ty.hir_id, PermitVariants::No) } &hir::TyKind::OpaqueDef(opaque_ty) => { // If this is an RPITIT and we are using the new RPITIT lowering scheme, we // generate the def_id of an associated type for the trait and return as // type a projection. let in_trait = match opaque_ty.origin { hir::OpaqueTyOrigin::FnReturn { parent, in_trait_or_impl: Some(hir::RpitContext::Trait), .. } | hir::OpaqueTyOrigin::AsyncFn { parent, in_trait_or_impl: Some(hir::RpitContext::Trait), .. } => Some(parent), hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. } | hir::OpaqueTyOrigin::AsyncFn { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. } | hir::OpaqueTyOrigin::TyAlias { .. } => None, }; self.lower_opaque_ty(opaque_ty.def_id, in_trait) } hir::TyKind::TraitAscription(hir_bounds) => { // Impl trait in bindings lower as an infer var with additional // set of type bounds. let self_ty = self.ty_infer(None, hir_ty.span); let mut bounds = Vec::new(); self.lower_bounds( self_ty, hir_bounds.iter(), &mut bounds, ty::List::empty(), PredicateFilter::All, OverlappingAsssocItemConstraints::Allowed, ); self.add_sizedness_bounds( &mut bounds, self_ty, hir_bounds, None, None, hir_ty.span, ); self.register_trait_ascription_bounds(bounds, hir_ty.hir_id, hir_ty.span); self_ty } // If we encounter a type relative path with RTN generics, then it must have // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore // it's certainly in an illegal position. hir::TyKind::Path(hir::QPath::TypeRelative(_, segment)) if segment.args.is_some_and(|args| { matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) }) => { let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span }); Ty::new_error(tcx, guar) } hir::TyKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => { debug!(?hir_self_ty, ?segment); let self_ty = self.lower_ty(hir_self_ty); self.lower_type_relative_ty_path( self_ty, hir_self_ty, segment, hir_ty.hir_id, hir_ty.span, PermitVariants::No, ) .map(|(ty, _, _)| ty) .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) } &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => { let def_id = tcx.require_lang_item(lang_item, span); let (args, _) = self.lower_generic_args_of_path( span, def_id, &[], &hir::PathSegment::invalid(), None, ); tcx.at(span).type_of(def_id).instantiate(tcx, args) } hir::TyKind::Array(ty, length) => { let length = self.lower_const_arg(length, FeedConstTy::No); Ty::new_array_with_const_len(tcx, self.lower_ty(ty), length) } hir::TyKind::Typeof(e) => tcx.type_of(e.def_id).instantiate_identity(), hir::TyKind::Infer(()) => { // Infer also appears as the type of arguments or return // values in an ExprKind::Closure, or as // the type of local variables. Both of these cases are // handled specially and will not descend into this routine. self.ty_infer(None, hir_ty.span) } hir::TyKind::Pat(ty, pat) => { let ty_span = ty.span; let ty = self.lower_ty(ty); let pat_ty = match self.lower_pat_ty_pat(ty, ty_span, pat) { Ok(kind) => Ty::new_pat(tcx, ty, tcx.mk_pat(kind)), Err(guar) => Ty::new_error(tcx, guar), }; self.record_ty(pat.hir_id, ty, pat.span); pat_ty } hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar), }; self.record_ty(hir_ty.hir_id, result_ty, hir_ty.span); result_ty } fn lower_pat_ty_pat( &self, ty: Ty<'tcx>, ty_span: Span, pat: &hir::TyPat<'tcx>, ) -> Result, ErrorGuaranteed> { let tcx = self.tcx(); match pat.kind { hir::TyPatKind::Range(start, end) => { match ty.kind() { // Keep this list of types in sync with the list of types that // the `RangePattern` trait is implemented for. ty::Int(_) | ty::Uint(_) | ty::Char => { let start = self.lower_const_arg(start, FeedConstTy::No); let end = self.lower_const_arg(end, FeedConstTy::No); Ok(ty::PatternKind::Range { start, end }) } _ => Err(self .dcx() .span_delayed_bug(ty_span, "invalid base type for range pattern")), } } hir::TyPatKind::Or(patterns) => { self.tcx() .mk_patterns_from_iter(patterns.iter().map(|pat| { self.lower_pat_ty_pat(ty, ty_span, pat).map(|pat| tcx.mk_pat(pat)) })) .map(ty::PatternKind::Or) } hir::TyPatKind::Err(e) => Err(e), } } /// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR. #[instrument(level = "debug", skip(self), ret)] fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: Option) -> Ty<'tcx> { let tcx = self.tcx(); let lifetimes = tcx.opaque_captured_lifetimes(def_id); debug!(?lifetimes); // If this is an RPITIT and we are using the new RPITIT lowering scheme, // do a linear search to map this to the synthetic associated type that // it will be lowered to. let def_id = if let Some(parent_def_id) = in_trait { *tcx.associated_types_for_impl_traits_in_associated_fn(parent_def_id.to_def_id()) .iter() .find(|rpitit| match tcx.opt_rpitit_info(**rpitit) { Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { opaque_def_id.expect_local() == def_id } _ => unreachable!(), }) .unwrap() } else { def_id.to_def_id() }; let generics = tcx.generics_of(def_id); debug!(?generics); // We use `generics.count() - lifetimes.len()` here instead of `generics.parent_count` // since return-position impl trait in trait squashes all of the generics from its source fn // into its own generics, so the opaque's "own" params isn't always just lifetimes. let offset = generics.count() - lifetimes.len(); let args = ty::GenericArgs::for_item(tcx, def_id, |param, _| { if let Some(i) = (param.index as usize).checked_sub(offset) { let (lifetime, _) = lifetimes[i]; self.lower_resolved_lifetime(lifetime).into() } else { tcx.mk_param_from_def(param) } }); debug!(?args); if in_trait.is_some() { Ty::new_projection_from_args(tcx, def_id, args) } else { Ty::new_opaque(tcx, def_id, args) } } /// Lower a function type from the HIR to our internal notion of a function signature. #[instrument(level = "debug", skip(self, hir_id, safety, abi, decl, generics, hir_ty), ret)] pub fn lower_fn_ty( &self, hir_id: HirId, safety: hir::Safety, abi: rustc_abi::ExternAbi, decl: &hir::FnDecl<'tcx>, generics: Option<&hir::Generics<'_>>, hir_ty: Option<&hir::Ty<'_>>, ) -> ty::PolyFnSig<'tcx> { let tcx = self.tcx(); let bound_vars = tcx.late_bound_vars(hir_id); debug!(?bound_vars); let (input_tys, output_ty) = self.lower_fn_sig(decl, generics, hir_id, hir_ty); debug!(?output_ty); let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi); let fn_ptr_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars); if let hir::Node::Ty(hir::Ty { kind: hir::TyKind::FnPtr(fn_ptr_ty), span, .. }) = tcx.hir_node(hir_id) { check_abi(tcx, hir_id, *span, fn_ptr_ty.abi); } // reject function types that violate cmse ABI requirements cmse::validate_cmse_abi(self.tcx(), self.dcx(), hir_id, abi, fn_ptr_ty); if !fn_ptr_ty.references_error() { // Find any late-bound regions declared in return type that do // not appear in the arguments. These are not well-formed. // // Example: // for<'a> fn() -> &'a str <-- 'a is bad // for<'a> fn(&'a String) -> &'a str <-- 'a is ok let inputs = fn_ptr_ty.inputs(); let late_bound_in_args = tcx.collect_constrained_late_bound_regions(inputs.map_bound(|i| i.to_owned())); let output = fn_ptr_ty.output(); let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(output); self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { struct_span_code_err!( self.dcx(), decl.output.span(), E0581, "return type references {}, which is not constrained by the fn input types", br_name ) }); } fn_ptr_ty } /// Given a fn_hir_id for a impl function, suggest the type that is found on the /// corresponding function in the trait that the impl implements, if it exists. /// If arg_idx is Some, then it corresponds to an input type index, otherwise it /// corresponds to the return type. pub(super) fn suggest_trait_fn_ty_for_impl_fn_infer( &self, fn_hir_id: HirId, arg_idx: Option, ) -> Option> { let tcx = self.tcx(); let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) = tcx.hir_node(fn_hir_id) else { return None; }; let i = tcx.parent_hir_node(fn_hir_id).expect_item().expect_impl(); let trait_ref = self.lower_impl_trait_ref(&i.of_trait?.trait_ref, self.lower_ty(i.self_ty)); let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind( tcx, *ident, ty::AssocTag::Fn, trait_ref.def_id, )?; let fn_sig = tcx.fn_sig(assoc.def_id).instantiate( tcx, trait_ref.args.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)), ); let fn_sig = tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), fn_sig); Some(if let Some(arg_idx) = arg_idx { *fn_sig.inputs().get(arg_idx)? } else { fn_sig.output() }) } #[instrument(level = "trace", skip(self, generate_err))] fn validate_late_bound_regions<'cx>( &'cx self, constrained_regions: FxIndexSet, referenced_regions: FxIndexSet, generate_err: impl Fn(&str) -> Diag<'cx>, ) { for br in referenced_regions.difference(&constrained_regions) { let br_name = if let Some(name) = br.get_name(self.tcx()) { format!("lifetime `{name}`") } else { "an anonymous lifetime".to_string() }; let mut err = generate_err(&br_name); if !br.is_named(self.tcx()) { // The only way for an anonymous lifetime to wind up // in the return type but **also** be unconstrained is // if it only appears in "associated types" in the // input. See #47511 and #62200 for examples. In this case, // though we can easily give a hint that ought to be // relevant. err.note( "lifetimes appearing in an associated or opaque type are not considered constrained", ); err.note("consider introducing a named lifetime parameter"); } err.emit(); } } /// Given the bounds on an object, determines what single region bound (if any) we can /// use to summarize this type. /// /// The basic idea is that we will use the bound the user /// provided, if they provided one, and otherwise search the supertypes of trait bounds /// for region bounds. It may be that we can derive no bound at all, in which case /// we return `None`. #[instrument(level = "debug", skip(self, span), ret)] fn compute_object_lifetime_bound( &self, span: Span, existential_predicates: &'tcx ty::List>, ) -> Option> // if None, use the default { let tcx = self.tcx(); // No explicit region bound specified. Therefore, examine trait // bounds and see if we can derive region bounds from those. let derived_region_bounds = object_region_bounds(tcx, existential_predicates); // If there are no derived region bounds, then report back that we // can find no region bound. The caller will use the default. if derived_region_bounds.is_empty() { return None; } // If any of the derived region bounds are 'static, that is always // the best choice. if derived_region_bounds.iter().any(|r| r.is_static()) { return Some(tcx.lifetimes.re_static); } // Determine whether there is exactly one unique region in the set // of derived region bounds. If so, use that. Otherwise, report an // error. let r = derived_region_bounds[0]; if derived_region_bounds[1..].iter().any(|r1| r != *r1) { self.dcx().emit_err(AmbiguousLifetimeBound { span }); } Some(r) } }