From c3f41cb7082712ab795d4efa40a90edb65342eba Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Fri, 21 Aug 2026 09:46:19 +0300 Subject: [PATCH] Querify some things that are called by the solver and are fairly expensive to compute I'm conflicted about this. One one hand, the memory impact isn't large: 2mb on rust-analyzer, 13mb on buck2 and 14mb on omicron. On the other hand, the speed gains aren't large as well: ~2 seconds on rust-analyzer or 2 ginstructions (0.4%). So I figured I'll let others decide. --- crates/hir-ty/src/builtin_derive.rs | 9 ++ crates/hir-ty/src/db.rs | 9 +- crates/hir-ty/src/display.rs | 2 +- crates/hir-ty/src/dyn_compatibility.rs | 52 ++++--- crates/hir-ty/src/dyn_compatibility/tests.rs | 4 +- crates/hir-ty/src/lower.rs | 119 ++++++++------- crates/hir-ty/src/next_solver/interner.rs | 79 +++------- crates/hir-ty/src/next_solver/ty.rs | 8 + crates/hir-ty/src/next_solver/util.rs | 146 +++++++++++++++---- crates/hir-ty/src/opaques.rs | 21 ++- crates/hir-ty/src/tests/incremental.rs | 1 + 11 files changed, 258 insertions(+), 192 deletions(-) diff --git a/crates/hir-ty/src/builtin_derive.rs b/crates/hir-ty/src/builtin_derive.rs index baa7b87e457f..9ea717ae22e8 100644 --- a/crates/hir-ty/src/builtin_derive.rs +++ b/crates/hir-ty/src/builtin_derive.rs @@ -157,6 +157,15 @@ pub fn impl_trait<'db>( } } +#[inline] +pub fn impl_super_outlives<'db>( + _interner: DbInterner<'db>, + _id: BuiltinDeriveImplId, +) -> EarlyBinder<'db, &'db [Clause<'db>]> { + // Currently no builtin-derived traits have super outlive bounds. + EarlyBinder::bind(&[]) +} + #[salsa::tracked(returns(ref))] pub fn predicates(db: &dyn HirDatabase, impl_: BuiltinDeriveImplId) -> GenericPredicates { let loc = impl_.loc(db); diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index f42a428bbdd2..13c7f5897fc0 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -30,14 +30,13 @@ use crate::{ dyn_compatibility::DynCompatibilityViolation, layout::{Layout, LayoutError}, lower::{ - ConstParamTypes, FieldTypes, GenericDefaults, TrackedStructToken, TypeAliasBounds, + ConstParamTypes, FieldTypes, GenericDefaults, SelfAndAssocBounds, TrackedStructToken, WithDefinedOpaques, }, mir::{MirBody, MirLowerError}, next_solver::{ - Allocation, Clause, EarlyBinder, GenericArgs, ParamEnv, PolyFnSig, StoredClauses, - StoredEarlyBinder, StoredGenericArgs, StoredPolyFnSig, StoredTraitRef, StoredTy, TraitRef, - Ty, VariancesOf, + Allocation, Clause, EarlyBinder, GenericArgs, ParamEnv, PolyFnSig, StoredEarlyBinder, + StoredGenericArgs, StoredPolyFnSig, StoredTraitRef, StoredTy, TraitRef, Ty, VariancesOf, }, traits::{ParamEnvAndCrate, StoredParamEnvAndCrate}, }; @@ -319,7 +318,7 @@ pub trait HirDatabase: SourceDatabase + 'static { fn type_alias_bounds_with_diagnostics<'db>( &'db self, type_alias: TypeAliasId, - ) -> &'db TyLoweringResult<'db, TypeAliasBounds>> { + ) -> &'db TyLoweringResult<'db, SelfAndAssocBounds> { let db = self.as_dyn(); crate::lower::type_alias_bounds_with_diagnostics(db, type_alias) } diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 9bb0e5b66bee..fdb69d0b9e02 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -1505,7 +1505,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { )); } let impl_trait_id = opaque_ty_id.loc(db); - let data = impl_trait_id.predicates(db); + let data = impl_trait_id.all_bounds(db); let bounds = data .iter_instantiated_copied(interner, alias_ty.args.as_slice()) .map(Unnormalized::skip_norm_wip) diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs index 4fd65398d0ba..ea5e016a7b52 100644 --- a/crates/hir-ty/src/dyn_compatibility.rs +++ b/crates/hir-ty/src/dyn_compatibility.rs @@ -31,7 +31,7 @@ use crate::{ }, }; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum DynCompatibilityViolation { SizedSelf, SelfReferential, @@ -42,7 +42,7 @@ pub enum DynCompatibilityViolation { HasNonCompatibleSuperTrait(TraitId), } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum MethodViolationCode { StaticMethod, ReferencesSelfInput, @@ -122,7 +122,7 @@ where ControlFlow::Continue(()) } -#[salsa::tracked(returns(clone))] +#[salsa::tracked(returns(copy))] pub fn dyn_compatibility_of_trait_query( db: &dyn HirDatabase, trait_: TraitId, @@ -136,33 +136,31 @@ pub fn dyn_compatibility_of_trait_query( res } -pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool { - let krate = def.module(db).krate(db); +#[salsa::tracked(returns(copy))] +pub fn generics_require_sized_self(db: &dyn HirDatabase, def_id: GenericDefId) -> bool { + let krate = def_id.krate(db); let interner = DbInterner::new_with(db, krate); - let Some(sized) = interner.lang_items().Sized else { - return false; + let Some(sized_def_id) = interner.lang_items().Sized else { + return false; /* No Sized trait, can't require it! */ }; - let predicates = GenericPredicates::query_explicit(db, def); - // FIXME: We should use `explicit_predicates_of` here, which hasn't been implemented to - // rust-analyzer yet - // https://github.com/rust-lang/rust/blob/ddaf12390d3ffb7d5ba74491a48f3cd528e5d777/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L490 - elaborate::elaborate(interner, predicates.iter_identity().map(Unnormalized::skip_norm_wip)).any( - |pred| match pred.kind().skip_binder() { - ClauseKind::Trait(trait_pred) => { - if sized == trait_pred.def_id().0 - && let rustc_type_ir::TyKind::Param(param_ty) = - trait_pred.trait_ref.self_ty().kind() - && param_ty.index == 0 - { - true - } else { - false - } - } - _ => false, - }, - ) + // Search for a clause like `Self: Sized` amongst the trait bounds. + let clauses = GenericPredicates::query_own_explicit(db, def_id) + .iter_identity() + .map(Unnormalized::skip_norm_wip); + elaborate::elaborate(interner, clauses).any(|clause| match clause.kind().skip_binder() { + ClauseKind::Trait(ref trait_pred) => { + trait_pred.def_id().0 == sized_def_id && trait_pred.self_ty().is_param(0) + } + ClauseKind::RegionOutlives(_) + | ClauseKind::TypeOutlives(_) + | ClauseKind::Projection(_) + | ClauseKind::ConstArgHasType(_, _) + | ClauseKind::WellFormed(_) + | ClauseKind::ConstEvaluatable(_) + | ClauseKind::UnstableFeature(_) + | ClauseKind::HostEffect(..) => false, + }) } // rustc gathers all the spans that references `Self` for error rendering, diff --git a/crates/hir-ty/src/dyn_compatibility/tests.rs b/crates/hir-ty/src/dyn_compatibility/tests.rs index a70f98a0fe7b..d7c45f35ed61 100644 --- a/crates/hir-ty/src/dyn_compatibility/tests.rs +++ b/crates/hir-ty/src/dyn_compatibility/tests.rs @@ -209,7 +209,7 @@ trait Bar: Sized { fn bar(&self, t: T); } "#, - [("Bar", vec![SizedSelf])], + [("Bar", vec![SizedSelf, Method(Generic)])], ); check_dyn_compatibility( @@ -221,7 +221,7 @@ trait Bar fn bar(&self, t: T); } "#, - [("Bar", vec![SizedSelf])], + [("Bar", vec![SizedSelf, Method(Generic)])], ); } diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 5f7e6782fdd2..f0322cd441e9 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -38,7 +38,7 @@ use hir_def::{ }, }; use hir_expand::name::Name; -use la_arena::{Arena, ArenaMap, Idx}; +use la_arena::ArenaMap; use path::{PathDiagnosticCallback, PathLoweringContext}; use rustc_abi::ExternAbi; use rustc_ast_ir::Mutability; @@ -81,16 +81,30 @@ pub(crate) struct PathDiagnosticCallbackData(pub(crate) TypeRefId); #[derive(PartialEq, Eq, Debug, Hash, SalsaValue)] pub struct WithDefinedOpaques { value: T, - impl_traits: Option>>, + impl_traits: ThinVec, } -#[derive(PartialEq, Eq, Debug, Hash)] -pub struct ImplTrait { - pub(crate) predicates: StoredEarlyBinder, - pub(crate) assoc_ty_bounds_start: u32, +pub enum ImplTrait {} + +pub type ImplTraitIdx = la_arena::Idx; + +#[derive(PartialEq, Eq, Debug, Hash, SalsaValue)] +pub struct SelfAndAssocBounds { + bounds: StoredEarlyBinder, + assoc_ty_bounds_start: u32, } -pub type ImplTraitIdx = Idx; +impl SelfAndAssocBounds { + #[inline] + pub fn all_bounds(&self) -> EarlyBinder<'_, &[Clause<'_>]> { + self.bounds.get().map_bound(|it| it.as_slice()) + } + + #[inline] + pub fn self_bounds(&self) -> EarlyBinder<'_, &[Clause<'_>]> { + self.bounds.get().map_bound(|it| &it.as_slice()[..self.assoc_ty_bounds_start as usize]) + } +} #[derive(Debug, Default)] struct ImplTraitLoweringState { @@ -99,12 +113,12 @@ struct ImplTraitLoweringState { /// complicated). mode: ImplTraitLoweringMode, // This is structured as a struct with fields and not as an enum because it helps with the borrow checker. - opaque_type_data: Arena, + opaque_type_data: ThinVec, } impl ImplTraitLoweringState { fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState { - Self { mode, opaque_type_data: Arena::new() } + Self { mode, opaque_type_data: ThinVec::new() } } } @@ -418,13 +432,9 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { BoundVarKinds::new_from_iter(interner, args) } - fn take_defined_opaques(&mut self) -> Option>> { - if self.impl_trait_mode.opaque_type_data.is_empty() { - None - } else { - self.impl_trait_mode.opaque_type_data.shrink_to_fit(); - Some(Box::new(mem::take(&mut self.impl_trait_mode.opaque_type_data))) - } + fn take_defined_opaques(&mut self) -> ThinVec { + self.impl_trait_mode.opaque_type_data.shrink_to_fit(); + mem::take(&mut self.impl_trait_mode.opaque_type_data) } } @@ -639,8 +649,11 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { // this dance is to make sure the data is in the right // place even if we encounter more opaque types while // lowering the bounds - let idx = self.impl_trait_mode.opaque_type_data.alloc(ImplTrait { - predicates: StoredEarlyBinder::bind(Clauses::empty(interner).store()), + let idx = ImplTraitIdx::from_raw(la_arena::RawIdx::from_u32( + self.impl_trait_mode.opaque_type_data.len() as u32, + )); + self.impl_trait_mode.opaque_type_data.push(SelfAndAssocBounds { + bounds: StoredEarlyBinder::bind(Clauses::empty(interner).store()), assoc_ty_bounds_start: 0, }); @@ -663,7 +676,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { .with_debruijn(DebruijnIndex::ZERO, |ctx| { ctx.lower_impl_trait(opaque_ty_id, bounds) }); - self.impl_trait_mode.opaque_type_data[idx] = actual_opaque_type_data; + self.impl_trait_mode.opaque_type_data[idx.into_raw().into_u32() as usize] = + actual_opaque_type_data; let mut late_bound_index = 0; let args = GenericArgs::for_item( @@ -1290,7 +1304,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { &mut self, def_id: InternedOpaqueTyId<'db>, bounds: &[TypeBound], - ) -> ImplTrait { + ) -> SelfAndAssocBounds { let interner = self.interner; cov_mark::hit!(lower_rpit); let args = GenericArgs::identity_for_item(interner, def_id.into()); @@ -1337,8 +1351,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { predicates.extend(assoc_ty_bounds); self.is_lowering_impl_trait_bounds = prev_is_lowering_impl_trait_bounds; - ImplTrait { - predicates: StoredEarlyBinder::bind(Clauses::new_from_slice(&predicates).store()), + SelfAndAssocBounds { + bounds: StoredEarlyBinder::bind(Clauses::new_from_slice(&predicates).store()), assoc_ty_bounds_start, } } @@ -1514,37 +1528,36 @@ pub(crate) fn impl_trait_with_diagnostics_cycle_result<'db>( impl ImplTraitId { #[inline] - fn data(self, db: &dyn HirDatabase) -> &ImplTrait { + pub fn bounds(self, db: &dyn HirDatabase) -> &SelfAndAssocBounds { let (impl_traits, idx) = match self { ImplTraitId::ReturnTypeImplTrait(owner, idx) => { - (ImplTrait::return_type_impl_traits(db, owner), idx) + (SelfAndAssocBounds::return_type_impl_traits(db, owner), idx) } ImplTraitId::TypeAliasImplTrait(owner, idx) => { - (ImplTrait::type_alias_impl_traits(db, owner), idx) + (SelfAndAssocBounds::type_alias_impl_traits(db, owner), idx) } }; - &impl_traits[idx] + &impl_traits[idx.into_raw().into_u32() as usize] } #[inline] - pub fn predicates<'db>(self, db: &'db dyn HirDatabase) -> EarlyBinder<'db, &'db [Clause<'db>]> { - self.data(db).predicates.get().map_bound(|it| it.as_slice()) + pub fn all_bounds<'db>(self, db: &'db dyn HirDatabase) -> EarlyBinder<'db, &'db [Clause<'db>]> { + self.bounds(db).all_bounds() } #[inline] - pub fn self_predicates<'db>( + pub fn self_bounds<'db>( self, db: &'db dyn HirDatabase, ) -> EarlyBinder<'db, &'db [Clause<'db>]> { - let data = self.data(db); - data.predicates.get().map_bound(|it| &it.as_slice()[..data.assoc_ty_bounds_start as usize]) + self.bounds(db).self_bounds() } } impl InternedOpaqueTyId<'_> { #[inline] pub fn predicates<'db>(self, db: &'db dyn HirDatabase) -> EarlyBinder<'db, &'db [Clause<'db>]> { - self.loc(db).predicates(db) + self.loc(db).all_bounds(db) } #[inline] @@ -1552,29 +1565,25 @@ impl InternedOpaqueTyId<'_> { self, db: &'db dyn HirDatabase, ) -> EarlyBinder<'db, &'db [Clause<'db>]> { - self.loc(db).self_predicates(db) + self.loc(db).self_bounds(db) } } -impl ImplTrait { +impl SelfAndAssocBounds { #[inline] pub(crate) fn return_type_impl_traits( db: &dyn HirDatabase, def: FunctionId, - ) -> &Arena { - fn_sig_for_fn(db, def).value.impl_traits.as_deref().unwrap_or(const { &Arena::new() }) + ) -> &[SelfAndAssocBounds] { + &fn_sig_for_fn(db, def).value.impl_traits } #[inline] pub(crate) fn type_alias_impl_traits( db: &dyn HirDatabase, def: TypeAliasId, - ) -> &Arena { - type_for_type_alias_with_diagnostics(db, def) - .value - .impl_traits - .as_deref() - .unwrap_or(const { &Arena::new() }) + ) -> &[SelfAndAssocBounds] { + &type_for_type_alias_with_diagnostics(db, def).value.impl_traits } } @@ -1767,7 +1776,7 @@ pub(crate) fn type_for_type_alias_with_diagnostics<'db>( if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) { TyLoweringResult::empty(WithDefinedOpaques { value: StoredEarlyBinder::bind(Ty::new_foreign(interner, t.into()).store()), - impl_traits: None, + impl_traits: ThinVec::new(), }) } else { let resolver = t.resolver(db); @@ -1806,7 +1815,7 @@ pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result<'db>( value: StoredEarlyBinder::bind( Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed).store(), ), - impl_traits: None, + impl_traits: ThinVec::new(), }) } @@ -2259,11 +2268,7 @@ pub(crate) fn type_alias_bounds<'db>( db: &'db dyn HirDatabase, type_alias: TypeAliasId, ) -> EarlyBinder<'db, &'db [Clause<'db>]> { - type_alias_bounds_with_diagnostics(db, type_alias) - .value - .predicates - .get() - .map_bound(|it| it.as_slice()) + type_alias_bounds_with_diagnostics(db, type_alias).value.all_bounds() } #[inline] @@ -2271,22 +2276,14 @@ pub(crate) fn type_alias_self_bounds<'db>( db: &'db dyn HirDatabase, type_alias: TypeAliasId, ) -> EarlyBinder<'db, &'db [Clause<'db>]> { - let TypeAliasBounds { predicates, assoc_ty_bounds_start } = - &type_alias_bounds_with_diagnostics(db, type_alias).value; - predicates.get().map_bound(|it| &it.as_slice()[..*assoc_ty_bounds_start as usize]) -} - -#[derive(PartialEq, Eq, Debug, Hash, SalsaValue)] -pub struct TypeAliasBounds { - predicates: T, - assoc_ty_bounds_start: u32, + type_alias_bounds_with_diagnostics(db, type_alias).value.self_bounds() } #[salsa::tracked(returns(ref))] pub(crate) fn type_alias_bounds_with_diagnostics<'db>( db: &'db dyn HirDatabase, type_alias: TypeAliasId, -) -> TyLoweringResult<'db, TypeAliasBounds>> { +) -> TyLoweringResult<'db, SelfAndAssocBounds> { let type_alias_data = TypeAliasSignature::of(db, type_alias); let resolver = type_alias.resolver(db); let generics = OnceCell::new(); @@ -2334,8 +2331,8 @@ pub(crate) fn type_alias_bounds_with_diagnostics<'db>( bounds.extend(assoc_ty_bounds); TyLoweringResult::from_ctx( - TypeAliasBounds { - predicates: StoredEarlyBinder::bind(Clauses::new_from_slice(&bounds).store()), + SelfAndAssocBounds { + bounds: StoredEarlyBinder::bind(Clauses::new_from_slice(&bounds).store()), assoc_ty_bounds_start, }, ctx, diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs index 7b2a811a01af..c95ede784864 100644 --- a/crates/hir-ty/src/next_solver/interner.rs +++ b/crates/hir-ty/src/next_solver/interner.rs @@ -12,8 +12,8 @@ pub use tls_db::{attach_db, attach_db_allow_change, with_attached_db}; use base_db::Crate; use hir_def::{ - AdtId, CallableDefId, EnumId, GenericParamId, HasModule, ItemContainerId, StructId, TraitId, - TypeAliasId, UnionId, VariantId, + AdtId, CallableDefId, EnumId, GenericDefId, GenericParamId, HasModule, ItemContainerId, + StructId, TraitId, TypeAliasId, UnionId, VariantId, attrs::AttrFlags, expr_store::{ExpressionStore, StoreVisitor}, hir::{ClosureKind as HirClosureKind, CoroutineKind as HirCoroutineKind, ExprId, PatId}, @@ -24,13 +24,11 @@ use hir_def::{ }, }; use rustc_abi::ExternAbi; -use rustc_hash::FxHashSet; use rustc_index::bit_set::DenseBitSet; use rustc_type_ir::{ AliasTy, BoundVar, CoroutineWitnessTypes, DebruijnIndex, EarlyBinder, FlagComputation, Flags, FnSigKind, GenericArgKind, GenericTypeVisitable, ImplPolarity, InferTy, Interner, TraitRef, - TypeFlags, TypeVisitableExt, Upcast, Variance, VisitorResult, - elaborate::elaborate, + TypeFlags, TypeVisitableExt, Variance, VisitorResult, error::TypeError, fast_reject, inherent::{self, Const as _, GenericsOf, IntoKind, SliceLike as _, Span as _, Ty as _}, @@ -52,8 +50,8 @@ use crate::{ ImplOrTraitAssocTyId, InherentAssocConstId, InherentAssocTermId, InherentAssocTyId, LateParamRegion, OpaqueTyIdWrapper, OpaqueTypeKey, RegionAssumptions, ScalarInt, SimplifiedType, SolverContext, SolverDefIds, TermId, TraitAssocConstId, TraitAssocTermId, - TraitAssocTyId, TraitIdWrapper, TypeAliasIdWrapper, UnevaluatedConst, Unnormalized, - util::{explicit_item_bounds, explicit_item_self_bounds}, + TraitAssocTyId, TraitIdWrapper, TypeAliasIdWrapper, UnevaluatedConst, + util::{ItemBounds, impl_super_outlives}, }, }; @@ -1291,33 +1289,10 @@ impl<'db> Interner for DbInterner<'db> { } fn generics_require_sized_self(self, def_id: Self::DefId) -> bool { - let sized_trait = self.lang_items().Sized; - let Some(sized_id) = sized_trait else { - return false; /* No Sized trait, can't require it! */ - }; - let sized_def_id = sized_id.into(); - - // Search for a predicate like `Self : Sized` amongst the trait bounds. - let predicates = self.predicates_of(def_id); - elaborate(self, predicates.iter_identity().map(Unnormalized::skip_norm_wip)).any(|pred| { - match pred.kind().skip_binder() { - ClauseKind::Trait(ref trait_pred) => { - trait_pred.def_id() == sized_def_id - && matches!( - trait_pred.self_ty().kind(), - TyKind::Param(ParamTy { index: 0, .. }) - ) - } - ClauseKind::RegionOutlives(_) - | ClauseKind::TypeOutlives(_) - | ClauseKind::Projection(_) - | ClauseKind::ConstArgHasType(_, _) - | ClauseKind::WellFormed(_) - | ClauseKind::ConstEvaluatable(_) - | ClauseKind::HostEffect(..) - | ClauseKind::UnstableFeature(_) => false, - } - }) + match GenericDefId::try_from(def_id) { + Ok(def_id) => crate::dyn_compatibility::generics_require_sized_self(self.db, def_id), + Err(_) => false, + } } #[tracing::instrument(skip(self))] @@ -1325,7 +1300,7 @@ impl<'db> Interner for DbInterner<'db> { self, def_id: Self::DefId, ) -> EarlyBinder> { - explicit_item_bounds(self, def_id).map_bound(|bounds| elaborate(self, bounds)) + ItemBounds::of_solver_def(self.db, def_id).all_bounds() } #[tracing::instrument(skip(self))] @@ -1333,25 +1308,14 @@ impl<'db> Interner for DbInterner<'db> { self, def_id: Self::DefId, ) -> EarlyBinder> { - explicit_item_self_bounds(self, def_id) - .map_bound(|bounds| elaborate(self, bounds).filter_only_self()) + ItemBounds::of_solver_def(self.db, def_id).self_bounds() } fn item_non_self_bounds( self, def_id: Self::DefId, ) -> EarlyBinder> { - let all_bounds: FxHashSet<_> = self.item_bounds(def_id).skip_binder().into_iter().collect(); - let own_bounds: FxHashSet<_> = - self.item_self_bounds(def_id).skip_binder().into_iter().collect(); - if all_bounds.len() == own_bounds.len() { - EarlyBinder::bind(Clauses::empty(self)) - } else { - EarlyBinder::bind(Clauses::new_from_iter( - self, - all_bounds.difference(&own_bounds).cloned(), - )) - } + ItemBounds::of_solver_def(self.db, def_id).non_self_bounds() } fn predicates_of( @@ -1411,16 +1375,15 @@ impl<'db> Interner for DbInterner<'db> { self, impl_id: Self::ImplId, ) -> EarlyBinder> { - let trait_ref = self.impl_trait_ref(impl_id); - trait_ref.map_bound(|trait_ref| { - let clause: Clause<'_> = trait_ref.upcast(self); - elaborate(self, [clause]).filter(|clause| { - matches!( - clause.kind().skip_binder(), - ClauseKind::TypeOutlives(_) | ClauseKind::RegionOutlives(_) - ) - }) - }) + let bounds = match impl_id { + AnyImplId::ImplId(id) => { + impl_super_outlives(self.db, id).get().map_bound(|it| it.as_slice()) + } + AnyImplId::BuiltinDeriveImplId(id) => { + crate::builtin_derive::impl_super_outlives(self, id) + } + }; + bounds.map_bound(|it| it.iter().copied()) } #[expect(unreachable_code)] diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs index 6faf0357e358..cb88b681eaa6 100644 --- a/crates/hir-ty/src/next_solver/ty.rs +++ b/crates/hir-ty/src/next_solver/ty.rs @@ -414,6 +414,14 @@ impl<'db> Ty<'db> { } } + #[inline] + pub fn is_param(self, index: u32) -> bool { + match self.kind() { + TyKind::Param(data) => data.index == index, + _ => false, + } + } + #[inline] pub fn is_never(self) -> bool { matches!(self.kind(), TyKind::Never) diff --git a/crates/hir-ty/src/next_solver/util.rs b/crates/hir-ty/src/next_solver/util.rs index 7e40e3c17d51..746440d1f48c 100644 --- a/crates/hir-ty/src/next_solver/util.rs +++ b/crates/hir-ty/src/next_solver/util.rs @@ -2,21 +2,26 @@ use std::ops::ControlFlow; -use hir_def::TraitId; +use hir_def::{HasModule, ImplId, TraitId, TypeAliasId}; use rustc_abi::{Float, HasDataLayout, Integer, IntegerType, Primitive, ReprOptions}; +use rustc_hash::FxHashSet; use rustc_type_ir::{ ConstKind, CoroutineArgs, DebruijnIndex, FloatTy, INNERMOST, IntTy, Interner, PredicatePolarity, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, - TypeVisitableExt, TypeVisitor, UintTy, UniverseIndex, elaborate, + TypeVisitableExt, TypeVisitor, UintTy, UniverseIndex, Upcast, + elaborate::{self, elaborate}, inherent::{AdtDef, GenericArg as _, IntoKind, ParamEnv as _, SliceLike, Ty as _}, lang_items::SolverTraitLangItem, solve::SizedTraitKind, }; +use stdx::impl_from; use crate::{ + ImplTraitId, + db::{HirDatabase, InternedOpaqueTyId}, next_solver::{ - BoundConst, FxIndexMap, ParamEnv, PlaceholderConst, PlaceholderRegion, PlaceholderType, - PolyTraitRef, + BoundConst, Clauses, FxIndexMap, ParamEnv, PlaceholderConst, PlaceholderRegion, + PlaceholderType, PolyTraitRef, StoredClauses, StoredEarlyBinder, infer::{ InferCtxt, traits::{Obligation, ObligationCause, PredicateObligation}, @@ -454,32 +459,113 @@ pub fn apply_args_to_binder<'db, T: TypeFoldable>>( b.skip_binder().fold_with(&mut instantiate) } -pub fn explicit_item_bounds<'db>( - interner: DbInterner<'db>, - def_id: SolverDefId<'db>, -) -> EarlyBinder<'db, impl DoubleEndedIterator> + ExactSizeIterator> { - let db = interner.db(); - let clauses = match def_id { - SolverDefId::TypeAliasId(type_alias) => crate::lower::type_alias_bounds(db, type_alias), - SolverDefId::InternedOpaqueTyId(id) => id.predicates(db), - _ => panic!("Unexpected GenericDefId"), - }; - clauses.map_bound(|clauses| clauses.iter().copied()) -} - -pub fn explicit_item_self_bounds<'db>( - interner: DbInterner<'db>, - def_id: SolverDefId<'db>, -) -> EarlyBinder<'db, impl DoubleEndedIterator> + ExactSizeIterator> { - let db = interner.db(); - let clauses = match def_id { - SolverDefId::TypeAliasId(type_alias) => { - crate::lower::type_alias_self_bounds(db, type_alias) - } - SolverDefId::InternedOpaqueTyId(id) => id.self_predicates(db), - _ => panic!("Unexpected GenericDefId"), - }; - clauses.map_bound(|clauses| clauses.iter().copied()) +#[derive(salsa::Supertype)] +pub(crate) enum ItemWithBounds<'db> { + TypeAliasId(TypeAliasId), + InternedOpaqueTyId(InternedOpaqueTyId<'db>), +} +impl_from!(impl<'db> TypeAliasId, InternedOpaqueTyId<'db> for ItemWithBounds<'db>); + +#[derive(Debug, PartialEq, Eq)] +pub(crate) struct ItemBounds { + bounds: StoredEarlyBinder, + non_self_bounds_start: u32, +} + +impl ItemBounds { + #[inline] + pub(crate) fn of_solver_def<'db>( + db: &'db dyn HirDatabase, + def_id: SolverDefId<'db>, + ) -> &'db ItemBounds { + let def_id = match def_id { + SolverDefId::TypeAliasId(def_id) => def_id.into(), + SolverDefId::InternedOpaqueTyId(def_id) => def_id.into(), + _ => panic!("unexpected SolverDefId"), + }; + ItemBounds::of(db, def_id) + } + + #[inline] + pub(crate) fn all_bounds(&self) -> EarlyBinder<'_, impl Iterator>> { + self.bounds.get().map_bound(|it| it.iter()) + } + + #[inline] + pub(crate) fn self_bounds(&self) -> EarlyBinder<'_, impl Iterator>> { + self.bounds + .get() + .map_bound(|it| it.as_slice()[..self.non_self_bounds_start as usize].iter().copied()) + } + + #[inline] + pub(crate) fn non_self_bounds(&self) -> EarlyBinder<'_, impl Iterator>> { + self.bounds + .get() + .map_bound(|it| it.as_slice()[self.non_self_bounds_start as usize..].iter().copied()) + } +} + +#[salsa::tracked] +impl ItemBounds { + #[allow( + clippy::drop_non_drop, + reason = "this happens in a Salsa macro, not sure why only here" + )] + #[salsa::tracked] + fn of(db: &dyn HirDatabase, def_id: ItemWithBounds<'_>) -> ItemBounds { + let (krate, explicit_bounds) = match def_id { + ItemWithBounds::TypeAliasId(type_alias) => ( + type_alias.krate(db), + &crate::lower::type_alias_bounds_with_diagnostics(db, type_alias).value, + ), + ItemWithBounds::InternedOpaqueTyId(id) => { + let loc = id.loc(db); + let krate = match loc { + ImplTraitId::ReturnTypeImplTrait(def, _) => def.krate(db), + ImplTraitId::TypeAliasImplTrait(def, _) => def.krate(db), + }; + (krate, loc.bounds(db)) + } + }; + let interner = DbInterner::new_with(db, krate); + + let all_bounds = + elaborate(interner, explicit_bounds.all_bounds().skip_binder().iter().copied()); + let self_bounds = + elaborate(interner, explicit_bounds.self_bounds().skip_binder().iter().copied()) + .filter_only_self(); + + let self_bounds = FxHashSet::from_iter(self_bounds); + let non_self_bounds = all_bounds.filter(|bound| !self_bounds.contains(bound)); + + let non_self_bounds_start = self_bounds.len() as u32; + let bounds = StoredEarlyBinder::bind( + Clauses::new_from_iter(interner, self_bounds.iter().copied().chain(non_self_bounds)) + .store(), + ); + + ItemBounds { bounds, non_self_bounds_start } + } +} + +#[salsa::tracked] +pub(crate) fn impl_super_outlives( + db: &dyn HirDatabase, + impl_: ImplId, +) -> StoredEarlyBinder { + let interner = DbInterner::new_with(db, impl_.krate(db)); + let trait_ref = db.impl_trait(impl_).expect("invalid impl passed to trait solver"); + let result = trait_ref.map_bound(|trait_ref| { + let clause: Clause<'_> = trait_ref.upcast(interner); + elaborate(interner, [clause]).filter(|clause| { + matches!( + clause.kind().skip_binder(), + ClauseKind::TypeOutlives(_) | ClauseKind::RegionOutlives(_) + ) + }) + }); + StoredEarlyBinder::bind(Clauses::new_from_iter(interner, result.skip_binder()).store()) } pub struct ContainsTypeErrors; diff --git a/crates/hir-ty/src/opaques.rs b/crates/hir-ty/src/opaques.rs index 194c866c6805..858886df2d52 100644 --- a/crates/hir-ty/src/opaques.rs +++ b/crates/hir-ty/src/opaques.rs @@ -5,14 +5,14 @@ use hir_def::{ signatures::ImplSignature, }; use hir_expand::name::Name; -use la_arena::{Arena, ArenaMap}; +use la_arena::ArenaMap; use rustc_type_ir::inherent::Ty as _; use syntax::ast; use crate::{ ImplTraitId, InferBodyId, InferenceResult, db::{HirDatabase, InternedOpaqueTyId}, - lower::{ImplTrait, ImplTraitIdx}, + lower::{ImplTraitIdx, SelfAndAssocBounds}, next_solver::{ DbInterner, ErrorGuaranteed, SolverDefId, StoredEarlyBinder, StoredTy, Ty, TypingMode, infer::{DbInternerInferExt, traits::ObligationCause}, @@ -29,7 +29,7 @@ pub(crate) fn opaque_types_defined_by<'db>( // A function may define its own RPITs. extend_with_opaques( db, - ImplTrait::return_type_impl_traits(db, func), + SelfAndAssocBounds::return_type_impl_traits(db, func), |opaque_idx| ImplTraitId::ReturnTypeImplTrait(func, opaque_idx), result, ); @@ -38,7 +38,7 @@ pub(crate) fn opaque_types_defined_by<'db>( let extend_with_taits = |type_alias| { extend_with_opaques( db, - ImplTrait::type_alias_impl_traits(db, type_alias), + SelfAndAssocBounds::type_alias_impl_traits(db, type_alias), |opaque_idx| ImplTraitId::TypeAliasImplTrait(type_alias, opaque_idx), result, ); @@ -81,12 +81,17 @@ pub(crate) fn opaque_types_defined_by<'db>( fn extend_with_opaques<'db>( db: &'db dyn HirDatabase, - opaques: &Arena, + opaques: &[SelfAndAssocBounds], mut make_impl_trait: impl FnMut(ImplTraitIdx) -> ImplTraitId, result: &mut Vec>, ) { - for (opaque_idx, _) in opaques.iter() { - let opaque_id = InternedOpaqueTyId::new(db, make_impl_trait(opaque_idx)); + for (opaque_idx, _) in opaques.iter().enumerate() { + let opaque_id = InternedOpaqueTyId::new( + db, + make_impl_trait(ImplTraitIdx::from_raw(la_arena::RawIdx::from_u32( + opaque_idx as u32, + ))), + ); result.push(opaque_id.into()); } } @@ -114,7 +119,7 @@ pub(crate) fn tait_hidden_types( type_alias: TypeAliasId, ) -> ArenaMap> { // Call this first, to not perform redundant work if there are no TAITs. - let taits_count = ImplTrait::type_alias_impl_traits(db, type_alias).len(); + let taits_count = SelfAndAssocBounds::type_alias_impl_traits(db, type_alias).len(); let loc = type_alias.loc(db); let module = loc.module(db); diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs index 4574e095e91f..d0f1ceff185a 100644 --- a/crates/hir-ty/src/tests/incremental.rs +++ b/crates/hir-ty/src/tests/incremental.rs @@ -621,6 +621,7 @@ fn main() { "impl_self_ty_with_diagnostics", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", + "impl_super_outlives", "body_upvars_mentioned", ] "#]],