Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lower.rs')
| -rw-r--r-- | crates/hir-ty/src/lower.rs | 1590 |
1 files changed, 973 insertions, 617 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index a181ae0157..9307868f39 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -8,26 +8,22 @@ pub(crate) mod diagnostics; pub(crate) mod path; -use std::{ - cell::OnceCell, - iter, mem, - ops::{self, Deref, Not as _}, -}; +use std::{cell::OnceCell, iter, mem}; -use base_db::Crate; +use arrayvec::ArrayVec; use either::Either; use hir_def::{ AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, - FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, - LocalFieldId, Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, TypeParamId, - UnionId, VariantId, + FunctionId, GeneralConstId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, + LifetimeParamId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, + TypeOrConstParamId, TypeParamId, UnionId, VariantId, builtin_type::BuiltinType, expr_store::{ExpressionStore, HygieneId, path::Path}, hir::generics::{ GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate, }, item_tree::FieldsShape, - lang_item::LangItem, + lang_item::LangItems, resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs}, signatures::{FunctionSignature, TraitFlags, TypeAliasFlags}, type_ref::{ @@ -43,55 +39,60 @@ use rustc_hash::FxHashSet; use rustc_pattern_analysis::Captures; use rustc_type_ir::{ AliasTyKind, BoundVarIndexKind, ConstKind, DebruijnIndex, ExistentialPredicate, - ExistentialProjection, ExistentialTraitRef, FnSig, OutlivesPredicate, + ExistentialProjection, ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind, TyKind::{self}, - TypeVisitableExt, - inherent::{GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, Ty as _}, + TypeFoldable, TypeVisitableExt, Upcast, UpcastFrom, elaborate, + inherent::{ + Clause as _, GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, + Ty as _, + }, }; -use salsa::plumbing::AsId; use smallvec::{SmallVec, smallvec}; use stdx::{impl_from, never}; +use tracing::debug; use triomphe::{Arc, ThinArc}; use crate::{ - FnAbi, ImplTraitId, TraitEnvironment, TyLoweringDiagnostic, TyLoweringDiagnosticKind, + FnAbi, ImplTraitId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, consteval::intern_const_ref, - db::HirDatabase, + db::{HirDatabase, InternedOpaqueTyId}, generics::{Generics, generics, trait_self_param_idx}, next_solver::{ - AliasTy, Binder, BoundExistentialPredicates, Clause, Clauses, Const, DbInterner, - EarlyBinder, EarlyParamRegion, ErrorGuaranteed, GenericArg, GenericArgs, ParamConst, - ParamEnv, PolyFnSig, Predicate, Region, SolverDefId, TraitPredicate, TraitRef, Ty, Tys, - UnevaluatedConst, abi::Safety, + AliasTy, Binder, BoundExistentialPredicates, Clause, ClauseKind, Clauses, Const, + DbInterner, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, FxIndexMap, GenericArg, + GenericArgs, ParamConst, ParamEnv, PolyFnSig, Predicate, Region, SolverDefId, + StoredClauses, StoredEarlyBinder, StoredGenericArg, StoredGenericArgs, StoredPolyFnSig, + StoredTy, TraitPredicate, TraitRef, Ty, Tys, UnevaluatedConst, abi::Safety, + util::BottomUpFolder, }, }; pub(crate) struct PathDiagnosticCallbackData(pub(crate) TypeRefId); #[derive(PartialEq, Eq, Debug, Hash)] -pub struct ImplTraits<'db> { - pub(crate) impl_traits: Arena<ImplTrait<'db>>, +pub struct ImplTraits { + pub(crate) impl_traits: Arena<ImplTrait>, } #[derive(PartialEq, Eq, Debug, Hash)] -pub struct ImplTrait<'db> { - pub(crate) predicates: Vec<Clause<'db>>, +pub struct ImplTrait { + pub(crate) predicates: StoredClauses, } -pub type ImplTraitIdx<'db> = Idx<ImplTrait<'db>>; +pub type ImplTraitIdx = Idx<ImplTrait>; #[derive(Debug, Default)] -struct ImplTraitLoweringState<'db> { +struct ImplTraitLoweringState { /// When turning `impl Trait` into opaque types, we have to collect the /// bounds at the same time to get the IDs correct (without becoming too /// 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<ImplTrait<'db>>, + opaque_type_data: Arena<ImplTrait>, } -impl<'db> ImplTraitLoweringState<'db> { - fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState<'db> { +impl ImplTraitLoweringState { + fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState { Self { mode, opaque_type_data: Arena::new() } } } @@ -169,12 +170,14 @@ impl<'db> LifetimeElisionKind<'db> { pub struct TyLoweringContext<'db, 'a> { pub db: &'db dyn HirDatabase, interner: DbInterner<'db>, + types: &'db crate::next_solver::DefaultAny<'db>, + lang_items: &'db LangItems, resolver: &'a Resolver<'db>, store: &'a ExpressionStore, def: GenericDefId, generics: OnceCell<Generics>, in_binders: DebruijnIndex, - impl_trait_mode: ImplTraitLoweringState<'db>, + impl_trait_mode: ImplTraitLoweringState, /// Tracks types with explicit `?Sized` bounds. pub(crate) unsized_types: FxHashSet<Ty<'db>>, pub(crate) diagnostics: Vec<TyLoweringDiagnostic>, @@ -194,9 +197,13 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { ) -> Self { let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed); let in_binders = DebruijnIndex::ZERO; + let interner = DbInterner::new_with(db, resolver.krate()); Self { db, - interner: DbInterner::new_with(db, Some(resolver.krate()), None), + // Can provide no block since we don't use it for trait solving. + interner, + types: crate::next_solver::default_types(db), + lang_items: interner.lang_items(), resolver, def, generics: Default::default(), @@ -334,11 +341,11 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } Some(ValueNs::ConstId(c)) => { - let args = GenericArgs::new_from_iter(self.interner, []); + let args = GenericArgs::empty(self.interner); Some(Const::new( self.interner, rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new( - SolverDefId::ConstId(c), + GeneralConstId::ConstId(c).into(), args, )), )) @@ -394,7 +401,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { let type_ref = &self.store[type_ref_id]; tracing::debug!(?type_ref); let ty = match type_ref { - TypeRef::Never => Ty::new(interner, TyKind::Never), + TypeRef::Never => self.types.types.never, TypeRef::Tuple(inner) => { let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr)); Ty::new_tup_from_iter(interner, inner_tys) @@ -473,7 +480,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { let idx = self .impl_trait_mode .opaque_type_data - .alloc(ImplTrait { predicates: Vec::default() }); + .alloc(ImplTrait { predicates: Clauses::empty(interner).store() }); let impl_trait_id = origin.either( |f| ImplTraitId::ReturnTypeImplTrait(f, idx), @@ -493,7 +500,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { // away instead of two. let actual_opaque_type_data = self .with_debruijn(DebruijnIndex::ZERO, |ctx| { - ctx.lower_impl_trait(opaque_ty_id, bounds, self.resolver.krate()) + ctx.lower_impl_trait(opaque_ty_id, bounds) }); self.impl_trait_mode.opaque_type_data[idx] = actual_opaque_type_data; @@ -661,6 +668,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { ignore_bindings: bool, ) -> impl Iterator<Item = Clause<'db>> + use<'b, 'a, 'db> { let interner = self.interner; + let meta_sized = self.lang_items.MetaSized; + let pointee_sized = self.lang_items.PointeeSized; let mut assoc_bounds = None; let mut clause = None; match bound { @@ -669,10 +678,6 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { if let Some((trait_ref, mut ctx)) = self.lower_trait_ref_from_path(path, self_ty) { // FIXME(sized-hierarchy): Remove this bound modifications once we have implemented // sized-hierarchy correctly. - let meta_sized = LangItem::MetaSized - .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate()); - let pointee_sized = LangItem::PointeeSized - .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate()); if meta_sized.is_some_and(|it| it == trait_ref.def_id.0) { // Ignore this bound } else if pointee_sized.is_some_and(|it| it == trait_ref.def_id.0) { @@ -695,7 +700,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } &TypeBound::Path(path, TraitBoundModifier::Maybe) => { - let sized_trait = LangItem::Sized.resolve_trait(self.db, self.resolver.krate()); + let sized_trait = self.lang_items.Sized; // Don't lower associated type bindings as the only possible relaxed trait bound // `?Sized` has no of them. // If we got another trait here ignore the bound completely. @@ -724,138 +729,250 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty<'db> { let interner = self.interner; - // FIXME: we should never create non-existential predicates in the first place - // For now, use an error type so we don't run into dummy binder issues - let self_ty = Ty::new_error(interner, ErrorGuaranteed); + let dummy_self_ty = dyn_trait_dummy_self(interner); + let mut region = None; // INVARIANT: The principal trait bound, if present, must come first. Others may be in any // order but should be in the same order for the same set but possibly different order of // bounds in the input. // INVARIANT: If this function returns `DynTy`, there should be at least one trait bound. // These invariants are utilized by `TyExt::dyn_trait()` and chalk. - let mut lifetime = None; let bounds = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| { - let mut lowered_bounds: Vec< - rustc_type_ir::Binder<DbInterner<'db>, ExistentialPredicate<DbInterner<'db>>>, - > = Vec::new(); + let mut principal = None; + let mut auto_traits = SmallVec::<[_; 3]>::new(); + let mut projections = Vec::new(); + let mut had_error = false; + for b in bounds { let db = ctx.db; - ctx.lower_type_bound(b, self_ty, false).for_each(|b| { - if let Some(bound) = b - .kind() - .map_bound(|c| match c { - rustc_type_ir::ClauseKind::Trait(t) => { - let id = t.def_id(); - let is_auto = - db.trait_signature(id.0).flags.contains(TraitFlags::AUTO); - if is_auto { - Some(ExistentialPredicate::AutoTrait(t.def_id())) - } else { - Some(ExistentialPredicate::Trait( - ExistentialTraitRef::new_from_args( - interner, - t.def_id(), - GenericArgs::new_from_iter( - interner, - t.trait_ref.args.iter().skip(1), - ), - ), - )) + ctx.lower_type_bound(b, dummy_self_ty, false).for_each(|b| { + match b.kind().skip_binder() { + rustc_type_ir::ClauseKind::Trait(t) => { + let id = t.def_id(); + let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO); + if is_auto { + auto_traits.push(t.def_id().0); + } else { + if principal.is_some() { + // FIXME: Report an error. + had_error = true; } + principal = Some(b.kind().rebind(t.trait_ref)); } - rustc_type_ir::ClauseKind::Projection(p) => { - Some(ExistentialPredicate::Projection( - ExistentialProjection::new_from_args( - interner, - p.def_id(), - GenericArgs::new_from_iter( - interner, - p.projection_term.args.iter().skip(1), - ), - p.term, - ), - )) - } - rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => { - lifetime = Some(outlives_predicate.1); - None + } + rustc_type_ir::ClauseKind::Projection(p) => { + projections.push(b.kind().rebind(p)); + } + rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => { + if region.is_some() { + // FIXME: Report an error. + had_error = true; } - rustc_type_ir::ClauseKind::RegionOutlives(_) - | rustc_type_ir::ClauseKind::ConstArgHasType(_, _) - | rustc_type_ir::ClauseKind::WellFormed(_) - | rustc_type_ir::ClauseKind::ConstEvaluatable(_) - | rustc_type_ir::ClauseKind::HostEffect(_) - | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(), - }) - .transpose() - { - lowered_bounds.push(bound); + region = Some(outlives_predicate.1); + } + rustc_type_ir::ClauseKind::RegionOutlives(_) + | rustc_type_ir::ClauseKind::ConstArgHasType(_, _) + | rustc_type_ir::ClauseKind::WellFormed(_) + | rustc_type_ir::ClauseKind::ConstEvaluatable(_) + | rustc_type_ir::ClauseKind::HostEffect(_) + | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(), } }) } - let mut multiple_regular_traits = false; - let mut multiple_same_projection = false; - lowered_bounds.sort_unstable_by(|lhs, rhs| { - use std::cmp::Ordering; - match ((*lhs).skip_binder(), (*rhs).skip_binder()) { - (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => { - multiple_regular_traits = true; - // Order doesn't matter - we error - Ordering::Equal - } - ( - ExistentialPredicate::AutoTrait(lhs_id), - ExistentialPredicate::AutoTrait(rhs_id), - ) => lhs_id.0.cmp(&rhs_id.0), - (ExistentialPredicate::Trait(_), _) => Ordering::Less, - (_, ExistentialPredicate::Trait(_)) => Ordering::Greater, - (ExistentialPredicate::AutoTrait(_), _) => Ordering::Less, - (_, ExistentialPredicate::AutoTrait(_)) => Ordering::Greater, - ( - ExistentialPredicate::Projection(lhs), - ExistentialPredicate::Projection(rhs), - ) => { - let lhs_id = match lhs.def_id { - SolverDefId::TypeAliasId(id) => id, - _ => unreachable!(), - }; - let rhs_id = match rhs.def_id { - SolverDefId::TypeAliasId(id) => id, - _ => unreachable!(), - }; - // We only compare the `associated_ty_id`s. We shouldn't have - // multiple bounds for an associated type in the correct Rust code, - // and if we do, we error out. - if lhs_id == rhs_id { - multiple_same_projection = true; - } - lhs_id.as_id().index().cmp(&rhs_id.as_id().index()) - } - } - }); + if had_error { + return None; + } - if multiple_regular_traits || multiple_same_projection { + if principal.is_none() && auto_traits.is_empty() { + // No traits is not allowed. return None; } - if !lowered_bounds.first().map_or(false, |b| { - matches!( - b.as_ref().skip_binder(), - ExistentialPredicate::Trait(_) | ExistentialPredicate::AutoTrait(_) + // `Send + Sync` is the same as `Sync + Send`. + auto_traits.sort_unstable(); + // Duplicate auto traits are permitted. + auto_traits.dedup(); + + // Map the projection bounds onto a key that makes it easy to remove redundant + // bounds that are constrained by supertraits of the principal def id. + // + // Also make sure we detect conflicting bounds from expanding a trait alias and + // also specifying it manually, like: + // ``` + // type Alias = Trait<Assoc = i32>; + // let _: &dyn Alias<Assoc = u32> = /* ... */; + // ``` + let mut projection_bounds = FxIndexMap::default(); + for proj in projections { + let key = ( + proj.skip_binder().def_id().expect_type_alias(), + interner.anonymize_bound_vars( + proj.map_bound(|proj| proj.projection_term.trait_ref(interner)), + ), + ); + if let Some(old_proj) = projection_bounds.insert(key, proj) + && interner.anonymize_bound_vars(proj) + != interner.anonymize_bound_vars(old_proj) + { + // FIXME: Report "conflicting associated type" error. + } + } + + // A stable ordering of associated types from the principal trait and all its + // supertraits. We use this to ensure that different substitutions of a trait + // don't result in `dyn Trait` types with different projections lists, which + // can be unsound: <https://github.com/rust-lang/rust/pull/136458>. + // We achieve a stable ordering by walking over the unsubstituted principal + // trait ref. + let mut ordered_associated_types = vec![]; + + if let Some(principal_trait) = principal { + for clause in elaborate::elaborate( + interner, + [Clause::upcast_from( + TraitRef::identity(interner, principal_trait.def_id()), + interner, + )], ) - }) { - return None; + .filter_only_self() + { + let clause = clause.instantiate_supertrait(interner, principal_trait); + debug!("observing object predicate `{clause:?}`"); + + let bound_predicate = clause.kind(); + match bound_predicate.skip_binder() { + ClauseKind::Trait(pred) => { + // FIXME(negative_bounds): Handle this correctly... + let trait_ref = interner + .anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref)); + ordered_associated_types.extend( + pred.trait_ref + .def_id + .0 + .trait_items(self.db) + .associated_types() + .map(|item| (item, trait_ref)), + ); + } + ClauseKind::Projection(pred) => { + let pred = bound_predicate.rebind(pred); + // A `Self` within the original bound will be instantiated with a + // `trait_object_dummy_self`, so check for that. + let references_self = match pred.skip_binder().term.kind() { + TermKind::Ty(ty) => { + ty.walk().any(|arg| arg == dummy_self_ty.into()) + } + // FIXME(associated_const_equality): We should walk the const instead of not doing anything + TermKind::Const(_) => false, + }; + + // If the projection output contains `Self`, force the user to + // elaborate it explicitly to avoid a lot of complexity. + // + // The "classically useful" case is the following: + // ``` + // trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput { + // type MyOutput; + // } + // ``` + // + // Here, the user could theoretically write `dyn MyTrait<MyOutput = X>`, + // but actually supporting that would "expand" to an infinitely-long type + // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`. + // + // Instead, we force the user to write + // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See + // the discussion in #56288 for alternatives. + if !references_self { + let key = ( + pred.skip_binder().projection_term.def_id.expect_type_alias(), + interner.anonymize_bound_vars(pred.map_bound(|proj| { + proj.projection_term.trait_ref(interner) + })), + ); + if !projection_bounds.contains_key(&key) { + projection_bounds.insert(key, pred); + } + } + } + _ => (), + } + } } - // As multiple occurrences of the same auto traits *are* permitted, we deduplicate the - // bounds. We shouldn't have repeated elements besides auto traits at this point. - lowered_bounds.dedup(); + // We compute the list of projection bounds taking the ordered associated types, + // and check if there was an entry in the collected `projection_bounds`. Those + // are computed by first taking the user-written associated types, then elaborating + // the principal trait ref, and only using those if there was no user-written. + // See note below about how we handle missing associated types with `Self: Sized`, + // which are not required to be provided, but are still used if they are provided. + let mut projection_bounds: Vec<_> = ordered_associated_types + .into_iter() + .filter_map(|key| projection_bounds.get(&key).copied()) + .collect(); + + projection_bounds.sort_unstable_by_key(|proj| proj.skip_binder().def_id()); + + let principal = principal.map(|principal| { + principal.map_bound(|principal| { + // Verify that `dummy_self` did not leak inside default type parameters. + let args: Vec<_> = principal + .args + .iter() + // Skip `Self` + .skip(1) + .map(|arg| { + if arg.walk().any(|arg| arg == dummy_self_ty.into()) { + // FIXME: Report an error. + Ty::new_error(interner, ErrorGuaranteed).into() + } else { + arg + } + }) + .collect(); + + ExistentialPredicate::Trait(ExistentialTraitRef::new( + interner, + principal.def_id, + args, + )) + }) + }); + + let projections = projection_bounds.into_iter().map(|proj| { + proj.map_bound(|mut proj| { + // Like for trait refs, verify that `dummy_self` did not leak inside default type + // parameters. + let references_self = proj.projection_term.args.iter().skip(1).any(|arg| { + if arg.walk().any(|arg| arg == dummy_self_ty.into()) { + return true; + } + false + }); + if references_self { + proj.projection_term = + replace_dummy_self_with_error(interner, proj.projection_term); + } + + ExistentialPredicate::Projection(ExistentialProjection::erase_self_ty( + interner, proj, + )) + }) + }); - Some(BoundExistentialPredicates::new_from_iter(interner, lowered_bounds)) + let auto_traits = auto_traits.into_iter().map(|auto_trait| { + Binder::dummy(ExistentialPredicate::AutoTrait(auto_trait.into())) + }); + + // N.b. principal, projections, auto traits + Some(BoundExistentialPredicates::new_from_iter( + interner, + principal.into_iter().chain(projections).chain(auto_traits), + )) }); if let Some(bounds) = bounds { - let region = match lifetime { + let region = match region { Some(it) => match it.kind() { rustc_type_ir::RegionKind::ReBound(BoundVarIndexKind::Bound(db), var) => { Region::new_bound( @@ -876,12 +993,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } - fn lower_impl_trait( - &mut self, - def_id: SolverDefId, - bounds: &[TypeBound], - krate: Crate, - ) -> ImplTrait<'db> { + fn lower_impl_trait(&mut self, def_id: SolverDefId, bounds: &[TypeBound]) -> ImplTrait { let interner = self.interner; cov_mark::hit!(lower_rpit); let args = GenericArgs::identity_for_item(interner, def_id); @@ -897,12 +1009,12 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } if !ctx.unsized_types.contains(&self_ty) { - let sized_trait = LangItem::Sized.resolve_trait(self.db, krate); + let sized_trait = self.lang_items.Sized; let sized_clause = sized_trait.map(|trait_id| { let trait_ref = TraitRef::new_from_args( interner, trait_id.into(), - GenericArgs::new_from_iter(interner, [self_ty.into()]), + GenericArgs::new_from_slice(&[self_ty.into()]), ); Clause(Predicate::new( interner, @@ -916,10 +1028,9 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { }); predicates.extend(sized_clause); } - predicates.shrink_to_fit(); predicates }); - ImplTrait { predicates } + ImplTrait { predicates: Clauses::new_from_slice(&predicates).store() } } pub(crate) fn lower_lifetime(&mut self, lifetime: LifetimeRefId) -> Region<'db> { @@ -939,6 +1050,26 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } +fn dyn_trait_dummy_self(interner: DbInterner<'_>) -> Ty<'_> { + // This type must not appear anywhere except here. + Ty::new_fresh(interner, 0) +} + +fn replace_dummy_self_with_error<'db, T: TypeFoldable<DbInterner<'db>>>( + interner: DbInterner<'db>, + t: T, +) -> T { + let dyn_trait_dummy_self = dyn_trait_dummy_self(interner); + t.fold_with(&mut BottomUpFolder { + interner, + ty_op: |ty| { + if ty == dyn_trait_dummy_self { Ty::new_error(interner, ErrorGuaranteed) } else { ty } + }, + lt_op: |lt| lt, + ct_op: |ct| ct, + }) +} + pub(crate) fn lower_mutability(m: hir_def::type_ref::Mutability) -> Mutability { match m { hir_def::type_ref::Mutability::Shared => Mutability::Not, @@ -963,69 +1094,129 @@ pub(crate) fn impl_trait_query<'db>( db.impl_trait_with_diagnostics(impl_id).map(|it| it.0) } -pub(crate) fn impl_trait_with_diagnostics_query<'db>( +pub(crate) fn impl_trait_with_diagnostics<'db>( db: &'db dyn HirDatabase, impl_id: ImplId, ) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)> { - let impl_data = db.impl_signature(impl_id); - let resolver = impl_id.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &impl_data.store, - impl_id.into(), - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, - ); - let self_ty = db.impl_self_ty(impl_id).skip_binder(); - let target_trait = impl_data.target_trait.as_ref()?; - let trait_ref = EarlyBinder::bind(ctx.lower_trait_ref(target_trait, self_ty)?); - Some((trait_ref, create_diagnostics(ctx.diagnostics))) + return impl_trait_with_diagnostics_query(db, impl_id).as_ref().map(|(binder, diags)| { + ( + binder.get_with(|(trait_id, args)| { + TraitRef::new_from_args( + DbInterner::new_no_crate(db), + (*trait_id).into(), + args.as_ref(), + ) + }), + diags.clone(), + ) + }); + + #[salsa::tracked(returns(ref))] + pub(crate) fn impl_trait_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + impl_id: ImplId, + ) -> Option<(StoredEarlyBinder<(TraitId, StoredGenericArgs)>, Diagnostics)> { + let impl_data = db.impl_signature(impl_id); + let resolver = impl_id.resolver(db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &impl_data.store, + impl_id.into(), + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, + ); + let self_ty = db.impl_self_ty(impl_id).skip_binder(); + let target_trait = impl_data.target_trait.as_ref()?; + let trait_ref = ctx.lower_trait_ref(target_trait, self_ty)?; + Some(( + StoredEarlyBinder::bind((trait_ref.def_id.0, trait_ref.args.store())), + create_diagnostics(ctx.diagnostics), + )) + } } -pub(crate) fn return_type_impl_traits<'db>( - db: &'db dyn HirDatabase, - def: hir_def::FunctionId, -) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>> { - // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe - let data = db.function_signature(def); - let resolver = def.resolver(db); - let mut ctx_ret = - TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); - if let Some(ret_type) = data.ret_type { - let _ret = ctx_ret.lower_ty(ret_type); +impl ImplTraitId { + #[inline] + pub fn predicates<'db>(self, db: &'db dyn HirDatabase) -> EarlyBinder<'db, &'db [Clause<'db>]> { + let (impl_traits, idx) = match self { + ImplTraitId::ReturnTypeImplTrait(owner, idx) => { + (ImplTraits::return_type_impl_traits(db, owner), idx) + } + ImplTraitId::TypeAliasImplTrait(owner, idx) => { + (ImplTraits::type_alias_impl_traits(db, owner), idx) + } + }; + impl_traits + .as_deref() + .expect("owner should have opaque type") + .get_with(|it| it.impl_traits[idx].predicates.as_ref().as_slice()) } - let return_type_impl_traits = - ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data }; - if return_type_impl_traits.impl_traits.is_empty() { - None - } else { - Some(Arc::new(EarlyBinder::bind(return_type_impl_traits))) +} + +impl InternedOpaqueTyId { + #[inline] + pub fn predicates<'db>(self, db: &'db dyn HirDatabase) -> EarlyBinder<'db, &'db [Clause<'db>]> { + self.loc(db).predicates(db) } } -pub(crate) fn type_alias_impl_traits<'db>( - db: &'db dyn HirDatabase, - def: hir_def::TypeAliasId, -) -> Option<Arc<EarlyBinder<'db, ImplTraits<'db>>>> { - let data = db.type_alias_signature(def); - let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &data.store, - def.into(), - LifetimeElisionKind::AnonymousReportError, - ) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); - if let Some(type_ref) = data.ty { - let _ty = ctx.lower_ty(type_ref); +#[salsa::tracked] +impl ImplTraits { + #[salsa::tracked(returns(ref))] + pub(crate) fn return_type_impl_traits( + db: &dyn HirDatabase, + def: hir_def::FunctionId, + ) -> Option<Box<StoredEarlyBinder<ImplTraits>>> { + // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe + let data = db.function_signature(def); + let resolver = def.resolver(db); + let mut ctx_ret = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::Infer, + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); + if let Some(ret_type) = data.ret_type { + let _ret = ctx_ret.lower_ty(ret_type); + } + let mut return_type_impl_traits = + ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data }; + if return_type_impl_traits.impl_traits.is_empty() { + None + } else { + return_type_impl_traits.impl_traits.shrink_to_fit(); + Some(Box::new(StoredEarlyBinder::bind(return_type_impl_traits))) + } } - let type_alias_impl_traits = ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data }; - if type_alias_impl_traits.impl_traits.is_empty() { - None - } else { - Some(Arc::new(EarlyBinder::bind(type_alias_impl_traits))) + + #[salsa::tracked(returns(ref))] + pub(crate) fn type_alias_impl_traits( + db: &dyn HirDatabase, + def: hir_def::TypeAliasId, + ) -> Option<Box<StoredEarlyBinder<ImplTraits>>> { + let data = db.type_alias_signature(def); + let resolver = def.resolver(db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::AnonymousReportError, + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); + if let Some(type_ref) = data.ty { + let _ty = ctx.lower_ty(type_ref); + } + let mut type_alias_impl_traits = + ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data }; + if type_alias_impl_traits.impl_traits.is_empty() { + None + } else { + type_alias_impl_traits.impl_traits.shrink_to_fit(); + Some(Box::new(StoredEarlyBinder::bind(type_alias_impl_traits))) + } } } @@ -1066,7 +1257,7 @@ impl ValueTyDefId { /// the constructor function `(usize) -> Foo` which lives in the values /// namespace. pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBinder<'db, Ty<'db>> { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); match def { TyDefId::BuiltinType(it) => EarlyBinder::bind(Ty::from_builtin_type(interner, it)), TyDefId::AdtId(it) => EarlyBinder::bind(Ty::new_adt( @@ -1080,17 +1271,20 @@ pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBind /// Build the declared type of a function. This should not need to look at the /// function body. -fn type_for_fn<'db>(db: &'db dyn HirDatabase, def: FunctionId) -> EarlyBinder<'db, Ty<'db>> { - let interner = DbInterner::new_with(db, None, None); - EarlyBinder::bind(Ty::new_fn_def( - interner, - CallableDefId::FunctionId(def).into(), - GenericArgs::identity_for_item(interner, def.into()), - )) +fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> StoredEarlyBinder<StoredTy> { + let interner = DbInterner::new_no_crate(db); + StoredEarlyBinder::bind( + Ty::new_fn_def( + interner, + CallableDefId::FunctionId(def).into(), + GenericArgs::identity_for_item(interner, def.into()), + ) + .store(), + ) } /// Build the declared type of a const. -fn type_for_const<'db>(db: &'db dyn HirDatabase, def: ConstId) -> EarlyBinder<'db, Ty<'db>> { +fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> StoredEarlyBinder<StoredTy> { let resolver = def.resolver(db); let data = db.const_signature(def); let parent = def.loc(db).container; @@ -1102,11 +1296,11 @@ fn type_for_const<'db>(db: &'db dyn HirDatabase, def: ConstId) -> EarlyBinder<'d LifetimeElisionKind::AnonymousReportError, ); ctx.set_lifetime_elision(LifetimeElisionKind::for_const(ctx.interner, parent)); - EarlyBinder::bind(ctx.lower_ty(data.type_ref)) + StoredEarlyBinder::bind(ctx.lower_ty(data.type_ref).store()) } /// Build the declared type of a static. -fn type_for_static<'db>(db: &'db dyn HirDatabase, def: StaticId) -> EarlyBinder<'db, Ty<'db>> { +fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> StoredEarlyBinder<StoredTy> { let resolver = def.resolver(db); let data = db.static_signature(def); let mut ctx = TyLoweringContext::new( @@ -1117,99 +1311,129 @@ fn type_for_static<'db>(db: &'db dyn HirDatabase, def: StaticId) -> EarlyBinder< LifetimeElisionKind::AnonymousReportError, ); ctx.set_lifetime_elision(LifetimeElisionKind::Elided(Region::new_static(ctx.interner))); - EarlyBinder::bind(ctx.lower_ty(data.type_ref)) + StoredEarlyBinder::bind(ctx.lower_ty(data.type_ref).store()) } /// Build the type of a tuple struct constructor. -fn type_for_struct_constructor<'db>( - db: &'db dyn HirDatabase, +fn type_for_struct_constructor( + db: &dyn HirDatabase, def: StructId, -) -> Option<EarlyBinder<'db, Ty<'db>>> { +) -> Option<StoredEarlyBinder<StoredTy>> { let struct_data = def.fields(db); match struct_data.shape { FieldsShape::Record => None, FieldsShape::Unit => Some(type_for_adt(db, def.into())), FieldsShape::Tuple => { - let interner = DbInterner::new_with(db, None, None); - Some(EarlyBinder::bind(Ty::new_fn_def( - interner, - CallableDefId::StructId(def).into(), - GenericArgs::identity_for_item(interner, def.into()), - ))) + let interner = DbInterner::new_no_crate(db); + Some(StoredEarlyBinder::bind( + Ty::new_fn_def( + interner, + CallableDefId::StructId(def).into(), + GenericArgs::identity_for_item(interner, def.into()), + ) + .store(), + )) } } } /// Build the type of a tuple enum variant constructor. -fn type_for_enum_variant_constructor<'db>( - db: &'db dyn HirDatabase, +fn type_for_enum_variant_constructor( + db: &dyn HirDatabase, def: EnumVariantId, -) -> Option<EarlyBinder<'db, Ty<'db>>> { +) -> Option<StoredEarlyBinder<StoredTy>> { let struct_data = def.fields(db); match struct_data.shape { FieldsShape::Record => None, FieldsShape::Unit => Some(type_for_adt(db, def.loc(db).parent.into())), FieldsShape::Tuple => { - let interner = DbInterner::new_with(db, None, None); - Some(EarlyBinder::bind(Ty::new_fn_def( - interner, - CallableDefId::EnumVariantId(def).into(), - GenericArgs::identity_for_item(interner, def.loc(db).parent.into()), - ))) + let interner = DbInterner::new_no_crate(db); + Some(StoredEarlyBinder::bind( + Ty::new_fn_def( + interner, + CallableDefId::EnumVariantId(def).into(), + GenericArgs::identity_for_item(interner, def.loc(db).parent.into()), + ) + .store(), + )) } } } -pub(crate) fn value_ty_query<'db>( +pub(crate) fn value_ty<'db>( db: &'db dyn HirDatabase, def: ValueTyDefId, ) -> Option<EarlyBinder<'db, Ty<'db>>> { - match def { - ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)), - ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), - ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())), - ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), - ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)), - ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)), + return value_ty_query(db, def).as_ref().map(|it| it.get()); + + #[salsa::tracked(returns(ref))] + pub(crate) fn value_ty_query<'db>( + db: &'db dyn HirDatabase, + def: ValueTyDefId, + ) -> Option<StoredEarlyBinder<StoredTy>> { + match def { + ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)), + ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), + ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())), + ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), + ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)), + ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)), + } } } -pub(crate) fn type_for_type_alias_with_diagnostics_query<'db>( +pub(crate) fn type_for_type_alias_with_diagnostics<'db>( db: &'db dyn HirDatabase, t: TypeAliasId, ) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { - let type_alias_data = db.type_alias_signature(t); - let mut diags = None; - let resolver = t.resolver(db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) { - EarlyBinder::bind(Ty::new_foreign(interner, t.into())) - } else { - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &type_alias_data.store, - t.into(), - LifetimeElisionKind::AnonymousReportError, - ) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); - let res = EarlyBinder::bind( - type_alias_data - .ty - .map(|type_ref| ctx.lower_ty(type_ref)) - .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)), - ); - diags = create_diagnostics(ctx.diagnostics); - res - }; - (inner, diags) -} + let (ty, diags) = type_for_type_alias_with_diagnostics_query(db, t); + return (ty.get(), diags.clone()); -pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result<'db>( - db: &'db dyn HirDatabase, - _adt: TypeAliasId, -) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { - (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None) + #[salsa::tracked(returns(ref), cycle_result = type_for_type_alias_with_diagnostics_cycle_result)] + pub(crate) fn type_for_type_alias_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + t: TypeAliasId, + ) -> (StoredEarlyBinder<StoredTy>, Diagnostics) { + let type_alias_data = db.type_alias_signature(t); + let mut diags = None; + let resolver = t.resolver(db); + let interner = DbInterner::new_no_crate(db); + let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) { + StoredEarlyBinder::bind(Ty::new_foreign(interner, t.into()).store()) + } else { + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &type_alias_data.store, + t.into(), + LifetimeElisionKind::AnonymousReportError, + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); + let res = StoredEarlyBinder::bind( + type_alias_data + .ty + .map(|type_ref| ctx.lower_ty(type_ref)) + .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)) + .store(), + ); + diags = create_diagnostics(ctx.diagnostics); + res + }; + (inner, diags) + } + + pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result( + db: &dyn HirDatabase, + _: salsa::Id, + _adt: TypeAliasId, + ) -> (StoredEarlyBinder<StoredTy>, Diagnostics) { + ( + StoredEarlyBinder::bind( + Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed).store(), + ), + None, + ) + } } pub(crate) fn impl_self_ty_query<'db>( @@ -1219,30 +1443,45 @@ pub(crate) fn impl_self_ty_query<'db>( db.impl_self_ty_with_diagnostics(impl_id).0 } -pub(crate) fn impl_self_ty_with_diagnostics_query<'db>( +pub(crate) fn impl_self_ty_with_diagnostics<'db>( db: &'db dyn HirDatabase, impl_id: ImplId, ) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { - let resolver = impl_id.resolver(db); + let (ty, diags) = impl_self_ty_with_diagnostics_query(db, impl_id); + return (ty.get(), diags.clone()); - let impl_data = db.impl_signature(impl_id); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &impl_data.store, - impl_id.into(), - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, - ); - let ty = ctx.lower_ty(impl_data.self_ty); - assert!(!ty.has_escaping_bound_vars()); - (EarlyBinder::bind(ty), create_diagnostics(ctx.diagnostics)) -} + #[salsa::tracked(returns(ref), cycle_result = impl_self_ty_with_diagnostics_cycle_result)] + pub(crate) fn impl_self_ty_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + impl_id: ImplId, + ) -> (StoredEarlyBinder<StoredTy>, Diagnostics) { + let resolver = impl_id.resolver(db); -pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( - db: &dyn HirDatabase, - _impl_id: ImplId, -) -> (EarlyBinder<'_, Ty<'_>>, Diagnostics) { - (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None) + let impl_data = db.impl_signature(impl_id); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &impl_data.store, + impl_id.into(), + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, + ); + let ty = ctx.lower_ty(impl_data.self_ty); + assert!(!ty.has_escaping_bound_vars()); + (StoredEarlyBinder::bind(ty.store()), create_diagnostics(ctx.diagnostics)) + } + + pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( + db: &dyn HirDatabase, + _: salsa::Id, + _impl_id: ImplId, + ) -> (StoredEarlyBinder<StoredTy>, Diagnostics) { + ( + StoredEarlyBinder::bind( + Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed).store(), + ), + None, + ) + } } pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> { @@ -1250,57 +1489,69 @@ pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstPara } // returns None if def is a type arg -pub(crate) fn const_param_ty_with_diagnostics_query<'db>( +pub(crate) fn const_param_ty_with_diagnostics<'db>( db: &'db dyn HirDatabase, def: ConstParamId, ) -> (Ty<'db>, Diagnostics) { - let (parent_data, store) = db.generic_params_and_store(def.parent()); - let data = &parent_data[def.local_id()]; - let resolver = def.parent().resolver(db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &store, - def.parent(), - LifetimeElisionKind::AnonymousReportError, - ); - let ty = match data { - TypeOrConstParamData::TypeParamData(_) => { - never!(); - Ty::new_error(interner, ErrorGuaranteed) - } - TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty), - }; - (ty, create_diagnostics(ctx.diagnostics)) -} + let (ty, diags) = const_param_ty_with_diagnostics_query(db, (), def); + return (ty.as_ref(), diags.clone()); -pub(crate) fn const_param_ty_with_diagnostics_cycle_result<'db>( - db: &'db dyn HirDatabase, - _: crate::db::HirDatabaseData, - def: ConstParamId, -) -> (Ty<'db>, Diagnostics) { - let resolver = def.parent().resolver(db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - (Ty::new_error(interner, ErrorGuaranteed), None) + // FIXME: Make this query non-interned. + #[salsa::tracked(returns(ref), cycle_result = const_param_ty_with_diagnostics_cycle_result)] + pub(crate) fn const_param_ty_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + _: (), + def: ConstParamId, + ) -> (StoredTy, Diagnostics) { + let (parent_data, store) = db.generic_params_and_store(def.parent()); + let data = &parent_data[def.local_id()]; + let resolver = def.parent().resolver(db); + let interner = DbInterner::new_no_crate(db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &store, + def.parent(), + LifetimeElisionKind::AnonymousReportError, + ); + let ty = match data { + TypeOrConstParamData::TypeParamData(_) => { + never!(); + Ty::new_error(interner, ErrorGuaranteed) + } + TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty), + }; + (ty.store(), create_diagnostics(ctx.diagnostics)) + } + + pub(crate) fn const_param_ty_with_diagnostics_cycle_result( + db: &dyn HirDatabase, + _: salsa::Id, + _: (), + _def: ConstParamId, + ) -> (StoredTy, Diagnostics) { + let interner = DbInterner::new_no_crate(db); + (Ty::new_error(interner, ErrorGuaranteed).store(), None) + } } -pub(crate) fn field_types_query<'db>( - db: &'db dyn HirDatabase, +pub(crate) fn field_types_query( + db: &dyn HirDatabase, variant_id: VariantId, -) -> Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>> { - db.field_types_with_diagnostics(variant_id).0 +) -> &ArenaMap<LocalFieldId, StoredEarlyBinder<StoredTy>> { + &db.field_types_with_diagnostics(variant_id).0 } /// Build the type of all specific fields of a struct or enum variant. +#[salsa::tracked(returns(ref))] pub(crate) fn field_types_with_diagnostics_query<'db>( db: &'db dyn HirDatabase, variant_id: VariantId, -) -> (Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>>, Diagnostics) { +) -> (ArenaMap<LocalFieldId, StoredEarlyBinder<StoredTy>>, Diagnostics) { let var_data = variant_id.fields(db); let fields = var_data.fields(); if fields.is_empty() { - return (Arc::new(ArenaMap::default()), None); + return (ArenaMap::default(), None); } let (resolver, def): (_, GenericDefId) = match variant_id { @@ -1317,9 +1568,9 @@ pub(crate) fn field_types_with_diagnostics_query<'db>( LifetimeElisionKind::AnonymousReportError, ); for (field_id, field_data) in var_data.fields().iter() { - res.insert(field_id, EarlyBinder::bind(ctx.lower_ty(field_data.type_ref))); + res.insert(field_id, StoredEarlyBinder::bind(ctx.lower_ty(field_data.type_ref).store())); } - (Arc::new(res), create_diagnostics(ctx.diagnostics)) + (res, create_diagnostics(ctx.diagnostics)) } /// This query exists only to be used when resolving short-hand associated types @@ -1331,14 +1582,15 @@ pub(crate) fn field_types_with_diagnostics_query<'db>( /// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but /// these are fine: `T: Foo<U::Item>, U: Foo<()>`. #[tracing::instrument(skip(db), ret)] -pub(crate) fn generic_predicates_for_param_query<'db>( +#[salsa::tracked(returns(ref), cycle_result = generic_predicates_for_param_cycle_result)] +pub(crate) fn generic_predicates_for_param<'db>( db: &'db dyn HirDatabase, def: GenericDefId, param_id: TypeOrConstParamId, assoc_name: Option<Name>, -) -> GenericPredicates<'db> { +) -> StoredEarlyBinder<StoredClauses> { let generics = generics(db, def); - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); let resolver = def.resolver(db); let mut ctx = TyLoweringContext::new( db, @@ -1365,9 +1617,7 @@ pub(crate) fn generic_predicates_for_param_query<'db>( let TypeRef::Path(path) = &ctx.store[path.type_ref()] else { return false; }; - let Some(pointee_sized) = - LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate()) - else { + let Some(pointee_sized) = ctx.lang_items.PointeeSized else { return false; }; // Lower the path directly with `Resolver` instead of PathLoweringContext` @@ -1430,213 +1680,231 @@ pub(crate) fn generic_predicates_for_param_query<'db>( let args = GenericArgs::identity_for_item(interner, def.into()); if !args.is_empty() { let explicitly_unsized_tys = ctx.unsized_types; - if let Some(implicitly_sized_predicates) = - implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &args, &resolver) - { + if let Some(implicitly_sized_predicates) = implicitly_sized_clauses( + db, + ctx.lang_items, + param_id.parent, + &explicitly_unsized_tys, + &args, + ) { predicates.extend(implicitly_sized_predicates); }; } - GenericPredicates(predicates.is_empty().not().then(|| predicates.into())) + StoredEarlyBinder::bind(Clauses::new_from_slice(&predicates).store()) } pub(crate) fn generic_predicates_for_param_cycle_result( - _db: &dyn HirDatabase, + db: &dyn HirDatabase, + _: salsa::Id, _def: GenericDefId, _param_id: TypeOrConstParamId, _assoc_name: Option<Name>, -) -> GenericPredicates<'_> { - GenericPredicates(None) +) -> StoredEarlyBinder<StoredClauses> { + StoredEarlyBinder::bind(Clauses::empty(DbInterner::new_no_crate(db)).store()) +} + +#[inline] +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).0.map_bound(|it| it.as_slice()) +} + +pub(crate) fn type_alias_bounds_with_diagnostics<'db>( + db: &'db dyn HirDatabase, + type_alias: TypeAliasId, +) -> (EarlyBinder<'db, Clauses<'db>>, Diagnostics) { + let (bounds, diags) = type_alias_bounds_with_diagnostics_query(db, type_alias); + return (bounds.get(), diags.clone()); + + #[salsa::tracked(returns(ref))] + pub fn type_alias_bounds_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + type_alias: TypeAliasId, + ) -> (StoredEarlyBinder<StoredClauses>, Diagnostics) { + let type_alias_data = db.type_alias_signature(type_alias); + let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &type_alias_data.store, + type_alias.into(), + LifetimeElisionKind::AnonymousReportError, + ); + let interner = ctx.interner; + let def_id = type_alias.into(); + + let item_args = GenericArgs::identity_for_item(interner, def_id); + let interner_ty = Ty::new_projection_from_args(interner, def_id, item_args); + + let mut bounds = Vec::new(); + for bound in &type_alias_data.bounds { + ctx.lower_type_bound(bound, interner_ty, false).for_each(|pred| { + bounds.push(pred); + }); + } + + if !ctx.unsized_types.contains(&interner_ty) { + let sized_trait = ctx.lang_items.Sized; + if let Some(sized_trait) = sized_trait { + let trait_ref = TraitRef::new_from_args( + interner, + sized_trait.into(), + GenericArgs::new_from_slice(&[interner_ty.into()]), + ); + bounds.push(trait_ref.upcast(interner)); + }; + } + + ( + StoredEarlyBinder::bind(Clauses::new_from_slice(&bounds).store()), + create_diagnostics(ctx.diagnostics), + ) + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct GenericPredicates<'db>(Option<Arc<[Clause<'db>]>>); +pub struct GenericPredicates { + // The order is the following: first, if `parent_is_trait == true`, comes the implicit trait predicate for the + // parent. Then come the explicit predicates for the parent, then the explicit trait predicate for the child, + // then the implicit trait predicate for the child, if `is_trait` is `true`. + predicates: StoredEarlyBinder<StoredClauses>, + own_predicates_start: u32, + is_trait: bool, + parent_is_trait: bool, +} + +#[salsa::tracked] +impl<'db> GenericPredicates { + /// Resolve the where clause(s) of an item with generics. + /// + /// Diagnostics are computed only for this item's predicates, not for parents. + #[salsa::tracked(returns(ref))] + pub fn query_with_diagnostics( + db: &'db dyn HirDatabase, + def: GenericDefId, + ) -> (GenericPredicates, Diagnostics) { + generic_predicates_filtered_by(db, def, PredicateFilter::All, |_| true) + } +} -impl<'db> GenericPredicates<'db> { +impl GenericPredicates { #[inline] - pub fn instantiate( - &self, - interner: DbInterner<'db>, - args: GenericArgs<'db>, - ) -> Option<impl Iterator<Item = Clause<'db>>> { - self.0 - .as_ref() - .map(|it| EarlyBinder::bind(it.iter().copied()).iter_instantiated(interner, args)) + pub(crate) fn from_explicit_own_predicates( + predicates: StoredEarlyBinder<StoredClauses>, + ) -> Self { + Self { predicates, own_predicates_start: 0, is_trait: false, parent_is_trait: false } } #[inline] - pub fn instantiate_identity(&self) -> Option<impl Iterator<Item = Clause<'db>>> { - self.0.as_ref().map(|it| it.iter().copied()) + pub fn query(db: &dyn HirDatabase, def: GenericDefId) -> &GenericPredicates { + &Self::query_with_diagnostics(db, def).0 + } + + #[inline] + pub fn query_all<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, + ) -> EarlyBinder<'db, &'db [Clause<'db>]> { + Self::query(db, def).all_predicates() + } + + #[inline] + pub fn query_own<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, + ) -> EarlyBinder<'db, &'db [Clause<'db>]> { + Self::query(db, def).own_predicates() } -} -impl<'db> ops::Deref for GenericPredicates<'db> { - type Target = [Clause<'db>]; + #[inline] + pub fn query_explicit<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, + ) -> EarlyBinder<'db, &'db [Clause<'db>]> { + Self::query(db, def).explicit_predicates() + } + + #[inline] + pub fn all_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> { + self.predicates.get().map_bound(|it| it.as_slice()) + } + + #[inline] + pub fn own_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> { + self.predicates.get().map_bound(|it| &it.as_slice()[self.own_predicates_start as usize..]) + } - fn deref(&self) -> &Self::Target { - self.0.as_deref().unwrap_or(&[]) + /// Returns the predicates, minus the implicit `Self: Trait` predicate for a trait. + #[inline] + pub fn explicit_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> { + self.predicates.get().map_bound(|it| { + &it.as_slice()[usize::from(self.parent_is_trait)..it.len() - usize::from(self.is_trait)] + }) } } pub(crate) fn trait_environment_for_body_query( db: &dyn HirDatabase, def: DefWithBodyId, -) -> Arc<TraitEnvironment<'_>> { +) -> ParamEnv<'_> { let Some(def) = def.as_generic_def_id(db) else { - let krate = def.module(db).krate(); - return TraitEnvironment::empty(krate); + return ParamEnv::empty(); }; db.trait_environment(def) } -pub(crate) fn trait_environment_query<'db>( - db: &'db dyn HirDatabase, - def: GenericDefId, -) -> Arc<TraitEnvironment<'db>> { - let generics = generics(db, def); - if generics.has_no_predicates() && generics.is_empty() { - return TraitEnvironment::empty(def.krate(db)); - } - - let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - generics.store(), - def, - LifetimeElisionKind::AnonymousReportError, +pub(crate) fn param_env_from_predicates<'db>( + interner: DbInterner<'db>, + predicates: &'db GenericPredicates, +) -> ParamEnv<'db> { + let clauses = rustc_type_ir::elaborate::elaborate( + interner, + predicates.all_predicates().iter_identity_copied(), ); - let mut traits_in_scope = Vec::new(); - let mut clauses = Vec::new(); - for maybe_parent_generics in - std::iter::successors(Some(&generics), |generics| generics.parent_generics()) - { - ctx.store = maybe_parent_generics.store(); - for pred in maybe_parent_generics.where_predicates() { - for pred in ctx.lower_where_predicate(pred, false, &generics, PredicateFilter::All) { - if let rustc_type_ir::ClauseKind::Trait(tr) = pred.kind().skip_binder() { - traits_in_scope.push((tr.self_ty(), tr.def_id().0)); - } - clauses.push(pred); - } - } - } + let clauses = Clauses::new_from_iter(interner, clauses); - if let Some(trait_id) = def.assoc_trait_container(db) { - // add `Self: Trait<T1, T2, ...>` to the environment in trait - // function default implementations (and speculative code - // inside consts or type aliases) - cov_mark::hit!(trait_self_implements_self); - let trait_ref = TraitRef::identity(ctx.interner, trait_id.into()); - let clause = Clause(Predicate::new( - ctx.interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait( - TraitPredicate { trait_ref, polarity: rustc_type_ir::PredicatePolarity::Positive }, - ))), - )); - clauses.push(clause); - } + // FIXME: We should normalize projections here, like rustc does. + ParamEnv { clauses } +} - let explicitly_unsized_tys = ctx.unsized_types; +pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId) -> ParamEnv<'db> { + return ParamEnv { clauses: trait_environment_query(db, def).as_ref() }; - let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()); - if let Some(sized_trait) = sized_trait { - let (mut generics, mut def_id) = - (crate::next_solver::generics::generics(db, def.into()), def); - loop { - let self_idx = trait_self_param_idx(db, def_id); - for (idx, p) in generics.own_params.iter().enumerate() { - if let Some(self_idx) = self_idx - && p.index() as usize == self_idx - { - continue; - } - let GenericParamId::TypeParamId(param_id) = p.id else { - continue; - }; - let idx = idx as u32 + generics.parent_count as u32; - let param_ty = Ty::new_param(ctx.interner, param_id, idx); - if explicitly_unsized_tys.contains(¶m_ty) { - continue; - } - let trait_ref = TraitRef::new_from_args( - ctx.interner, - sized_trait.into(), - GenericArgs::new_from_iter(ctx.interner, [param_ty.into()]), - ); - let clause = Clause(Predicate::new( - ctx.interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - )), - )); - clauses.push(clause); - } - - if let Some(g) = generics.parent { - generics = crate::next_solver::generics::generics(db, g.into()); - def_id = g; - } else { - break; - } - } + #[salsa::tracked(returns(ref))] + pub(crate) fn trait_environment_query<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, + ) -> StoredClauses { + let module = def.module(db); + let interner = DbInterner::new_with(db, module.krate(db)); + let predicates = GenericPredicates::query(db, def); + param_env_from_predicates(interner, predicates).clauses.store() } - - let clauses = rustc_type_ir::elaborate::elaborate(ctx.interner, clauses); - let clauses = Clauses::new_from_iter(ctx.interner, clauses); - let env = ParamEnv { clauses }; - - TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env) } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum PredicateFilter { SelfTrait, All, } -/// Resolve the where clause(s) of an item with generics. -#[tracing::instrument(skip(db))] -pub(crate) fn generic_predicates_query<'db>( - db: &'db dyn HirDatabase, - def: GenericDefId, -) -> GenericPredicates<'db> { - generic_predicates_filtered_by(db, def, PredicateFilter::All, |_| true).0 -} - -pub(crate) fn generic_predicates_without_parent_query<'db>( - db: &'db dyn HirDatabase, - def: GenericDefId, -) -> GenericPredicates<'db> { - generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def).0 -} - -/// Resolve the where clause(s) of an item with generics, -/// except the ones inherited from the parent -pub(crate) fn generic_predicates_without_parent_with_diagnostics_query<'db>( - db: &'db dyn HirDatabase, - def: GenericDefId, -) -> (GenericPredicates<'db>, Diagnostics) { - generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def) -} - /// Resolve the where clause(s) of an item with generics, /// with a given filter #[tracing::instrument(skip(db, filter), ret)] -pub(crate) fn generic_predicates_filtered_by<'db, F>( - db: &'db dyn HirDatabase, +pub(crate) fn generic_predicates_filtered_by<F>( + db: &dyn HirDatabase, def: GenericDefId, predicate_filter: PredicateFilter, filter: F, -) -> (GenericPredicates<'db>, Diagnostics) +) -> (GenericPredicates, Diagnostics) where F: Fn(GenericDefId) -> bool, { let generics = generics(db, def); let resolver = def.resolver(db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let interner = DbInterner::new_no_crate(db); let mut ctx = TyLoweringContext::new( db, &resolver, @@ -1644,15 +1912,35 @@ where def, LifetimeElisionKind::AnonymousReportError, ); + let sized_trait = ctx.lang_items.Sized; let mut predicates = Vec::new(); - for maybe_parent_generics in + let all_generics = std::iter::successors(Some(&generics), |generics| generics.parent_generics()) - { - ctx.store = maybe_parent_generics.store(); - for pred in maybe_parent_generics.where_predicates() { - tracing::debug!(?pred); - if filter(maybe_parent_generics.def()) { + .collect::<ArrayVec<_, 2>>(); + let mut is_trait = false; + let mut parent_is_trait = false; + if all_generics.len() > 1 { + add_implicit_trait_predicate( + interner, + all_generics.last().unwrap().def(), + predicate_filter, + &mut predicates, + &mut parent_is_trait, + ); + } + // We need to lower parent predicates first - see the comment below lowering of implicit `Sized` predicates + // for why. + let mut own_predicates_start = 0; + for &maybe_parent_generics in all_generics.iter().rev() { + let current_def_predicates_start = predicates.len(); + // Collect only diagnostics from the child, not including parents. + ctx.diagnostics.clear(); + + if filter(maybe_parent_generics.def()) { + ctx.store = maybe_parent_generics.store(); + for pred in maybe_parent_generics.where_predicates() { + tracing::debug!(?pred); predicates.extend(ctx.lower_where_predicate( pred, false, @@ -1660,79 +1948,145 @@ where predicate_filter, )); } - } - } - let explicitly_unsized_tys = ctx.unsized_types; + push_const_arg_has_type_predicates(db, &mut predicates, maybe_parent_generics); - let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()); - if let Some(sized_trait) = sized_trait { - let mut add_sized_clause = |param_idx, param_id, param_data| { - let ( - GenericParamId::TypeParamId(param_id), - GenericParamDataRef::TypeParamData(param_data), - ) = (param_id, param_data) - else { - return; - }; + if let Some(sized_trait) = sized_trait { + let mut add_sized_clause = |param_idx, param_id, param_data| { + let ( + GenericParamId::TypeParamId(param_id), + GenericParamDataRef::TypeParamData(param_data), + ) = (param_id, param_data) + else { + return; + }; - if param_data.provenance == TypeParamProvenance::TraitSelf { - return; - } + if param_data.provenance == TypeParamProvenance::TraitSelf { + return; + } - let param_ty = Ty::new_param(interner, param_id, param_idx); - if explicitly_unsized_tys.contains(¶m_ty) { - return; + let param_ty = Ty::new_param(interner, param_id, param_idx); + if ctx.unsized_types.contains(¶m_ty) { + return; + } + let trait_ref = TraitRef::new_from_args( + interner, + sized_trait.into(), + GenericArgs::new_from_slice(&[param_ty.into()]), + ); + let clause = Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + )); + predicates.push(clause); + }; + let parent_params_len = maybe_parent_generics.len_parent(); + maybe_parent_generics.iter_self().enumerate().for_each( + |(param_idx, (param_id, param_data))| { + add_sized_clause( + (param_idx + parent_params_len) as u32, + param_id, + param_data, + ); + }, + ); } - let trait_ref = TraitRef::new_from_args( - interner, - sized_trait.into(), - GenericArgs::new_from_iter(interner, [param_ty.into()]), - ); - let clause = Clause(Predicate::new( - interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - )), - )); - predicates.push(clause); - }; - if generics.parent_generics().is_some_and(|parent| filter(parent.def())) { - generics.iter_parent().enumerate().for_each(|(param_idx, (param_id, param_data))| { - add_sized_clause(param_idx as u32, param_id, param_data); - }); + + // We do not clear `ctx.unsized_types`, as the `?Sized` clause of a child (e.g. an associated type) can + // be declared on the parent (e.g. the trait). It is nevertheless fine to register the implicit `Sized` + // predicates before lowering the child, as a child cannot define a `?Sized` predicate for its parent. + // But we do have to lower the parent first. } - if filter(def) { - let parent_params_len = generics.len_parent(); - generics.iter_self().enumerate().for_each(|(param_idx, (param_id, param_data))| { - add_sized_clause((param_idx + parent_params_len) as u32, param_id, param_data); - }); + + if maybe_parent_generics.def() == def { + own_predicates_start = current_def_predicates_start as u32; } } - // FIXME: rustc gathers more predicates by recursing through resulting trait predicates. - // See https://github.com/rust-lang/rust/blob/76c5ed2847cdb26ef2822a3a165d710f6b772217/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L689-L715 + add_implicit_trait_predicate(interner, def, predicate_filter, &mut predicates, &mut is_trait); - ( - GenericPredicates(predicates.is_empty().not().then(|| predicates.into())), - create_diagnostics(ctx.diagnostics), - ) + let diagnostics = create_diagnostics(ctx.diagnostics); + let predicates = GenericPredicates { + own_predicates_start, + is_trait, + parent_is_trait, + predicates: StoredEarlyBinder::bind(Clauses::new_from_slice(&predicates).store()), + }; + return (predicates, diagnostics); + + fn add_implicit_trait_predicate<'db>( + interner: DbInterner<'db>, + def: GenericDefId, + predicate_filter: PredicateFilter, + predicates: &mut Vec<Clause<'db>>, + set_is_trait: &mut bool, + ) { + // For traits, add `Self: Trait` predicate. This is + // not part of the predicates that a user writes, but it + // is something that one must prove in order to invoke a + // method or project an associated type. + // + // In the chalk setup, this predicate is not part of the + // "predicates" for a trait item. But it is useful in + // rustc because if you directly (e.g.) invoke a trait + // method like `Trait::method(...)`, you must naturally + // prove that the trait applies to the types that were + // used, and adding the predicate into this list ensures + // that this is done. + if let GenericDefId::TraitId(def_id) = def + && predicate_filter == PredicateFilter::All + { + *set_is_trait = true; + predicates.push(TraitRef::identity(interner, def_id.into()).upcast(interner)); + } + } +} + +fn push_const_arg_has_type_predicates<'db>( + db: &'db dyn HirDatabase, + predicates: &mut Vec<Clause<'db>>, + generics: &Generics, +) { + let interner = DbInterner::new_no_crate(db); + let const_params_offset = generics.len_parent() + generics.len_lifetimes_self(); + for (param_index, (param_idx, param_data)) in generics.iter_self_type_or_consts().enumerate() { + if !matches!(param_data, TypeOrConstParamData::ConstParamData(_)) { + continue; + } + + let param_id = ConstParamId::from_unchecked(TypeOrConstParamId { + parent: generics.def(), + local_id: param_idx, + }); + predicates.push(Clause( + ClauseKind::ConstArgHasType( + Const::new_param( + interner, + ParamConst { id: param_id, index: (param_index + const_params_offset) as u32 }, + ), + db.const_param_ty_ns(param_id), + ) + .upcast(interner), + )); + } } /// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound. /// Exception is Self of a trait def. fn implicitly_sized_clauses<'a, 'subst, 'db>( db: &'db dyn HirDatabase, + lang_items: &LangItems, def: GenericDefId, explicitly_unsized_tys: &'a FxHashSet<Ty<'db>>, args: &'subst GenericArgs<'db>, - resolver: &Resolver<'db>, ) -> Option<impl Iterator<Item = Clause<'db>> + Captures<'a> + Captures<'subst>> { - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate())?; + let interner = DbInterner::new_no_crate(db); + let sized_trait = lang_items.Sized?; let trait_self_idx = trait_self_param_idx(db, def); @@ -1750,7 +2104,7 @@ fn implicitly_sized_clauses<'a, 'subst, 'db>( let trait_ref = TraitRef::new_from_args( interner, sized_trait.into(), - GenericArgs::new_from_iter(interner, [self_ty.into()]), + GenericArgs::new_from_slice(&[self_ty.into()]), ); Clause(Predicate::new( interner, @@ -1766,19 +2120,16 @@ fn implicitly_sized_clauses<'a, 'subst, 'db>( } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct GenericDefaults<'db>(Option<Arc<[Option<EarlyBinder<'db, GenericArg<'db>>>]>>); +pub struct GenericDefaults(Option<Arc<[Option<StoredEarlyBinder<StoredGenericArg>>]>>); -impl<'db> GenericDefaults<'db> { +impl GenericDefaults { #[inline] - pub fn get(&self, idx: usize) -> Option<EarlyBinder<'db, GenericArg<'db>>> { - self.0.as_ref()?[idx] + pub fn get<'db>(&self, idx: usize) -> Option<EarlyBinder<'db, GenericArg<'db>>> { + Some(self.0.as_ref()?[idx].as_ref()?.get_with(|it| it.as_ref())) } } -pub(crate) fn generic_defaults_query( - db: &dyn HirDatabase, - def: GenericDefId, -) -> GenericDefaults<'_> { +pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults { db.generic_defaults_with_diagnostics(def).0 } @@ -1788,7 +2139,7 @@ pub(crate) fn generic_defaults_query( pub(crate) fn generic_defaults_with_diagnostics_query( db: &dyn HirDatabase, def: GenericDefId, -) -> (GenericDefaults<'_>, Diagnostics) { +) -> (GenericDefaults, Diagnostics) { let generic_params = generics(db, def); if generic_params.is_empty() { return (GenericDefaults(None), None); @@ -1834,20 +2185,23 @@ pub(crate) fn generic_defaults_with_diagnostics_query( ctx: &mut TyLoweringContext<'db, '_>, idx: usize, p: GenericParamDataRef<'_>, - ) -> (Option<EarlyBinder<'db, GenericArg<'db>>>, bool) { + ) -> (Option<StoredEarlyBinder<StoredGenericArg>>, bool) { ctx.lowering_param_default(idx as u32); match p { GenericParamDataRef::TypeParamData(p) => { let ty = p.default.map(|ty| ctx.lower_ty(ty)); - (ty.map(|ty| EarlyBinder::bind(ty.into())), p.default.is_some()) + ( + ty.map(|ty| StoredEarlyBinder::bind(GenericArg::from(ty).store())), + p.default.is_some(), + ) } GenericParamDataRef::ConstParamData(p) => { let val = p.default.map(|c| { let param_ty = ctx.lower_ty(p.ty); let c = ctx.lower_const(c, param_ty); - c.into() + GenericArg::from(c).store() }); - (val.map(EarlyBinder::bind), p.default.is_some()) + (val.map(StoredEarlyBinder::bind), p.default.is_some()) } GenericParamDataRef::LifetimeParamData(_) => (None, false), } @@ -1856,30 +2210,36 @@ pub(crate) fn generic_defaults_with_diagnostics_query( pub(crate) fn generic_defaults_with_diagnostics_cycle_result( _db: &dyn HirDatabase, + _: salsa::Id, _def: GenericDefId, -) -> (GenericDefaults<'_>, Diagnostics) { +) -> (GenericDefaults, Diagnostics) { (GenericDefaults(None), None) } /// Build the signature of a callable item (function, struct or enum variant). -pub(crate) fn callable_item_signature_query<'db>( +pub(crate) fn callable_item_signature<'db>( db: &'db dyn HirDatabase, def: CallableDefId, ) -> EarlyBinder<'db, PolyFnSig<'db>> { - match def { - CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f), - CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s), - CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e), + return callable_item_signature_query(db, def).get_with(|sig| sig.get()); + + #[salsa::tracked(returns(ref))] + pub(crate) fn callable_item_signature_query<'db>( + db: &'db dyn HirDatabase, + def: CallableDefId, + ) -> StoredEarlyBinder<StoredPolyFnSig> { + match def { + CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f), + CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s), + CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e), + } } } -fn fn_sig_for_fn<'db>( - db: &'db dyn HirDatabase, - def: FunctionId, -) -> EarlyBinder<'db, PolyFnSig<'db>> { +fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> StoredEarlyBinder<StoredPolyFnSig> { let data = db.function_signature(def); let resolver = def.resolver(db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let interner = DbInterner::new_no_crate(db); let mut ctx_params = TyLoweringContext::new( db, &resolver, @@ -1906,56 +2266,56 @@ fn fn_sig_for_fn<'db>( let inputs_and_output = Tys::new_from_iter(interner, params.chain(Some(ret))); // If/when we track late bound vars, we need to switch this to not be `dummy` - EarlyBinder::bind(rustc_type_ir::Binder::dummy(FnSig { + StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig { abi: data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), c_variadic: data.is_varargs(), safety: if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe }, inputs_and_output, - })) + }))) } -fn type_for_adt<'db>(db: &'db dyn HirDatabase, adt: AdtId) -> EarlyBinder<'db, Ty<'db>> { - let interner = DbInterner::new_with(db, None, None); +fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> StoredEarlyBinder<StoredTy> { + let interner = DbInterner::new_no_crate(db); let args = GenericArgs::identity_for_item(interner, adt.into()); let ty = Ty::new_adt(interner, adt, args); - EarlyBinder::bind(ty) + StoredEarlyBinder::bind(ty.store()) } -fn fn_sig_for_struct_constructor<'db>( - db: &'db dyn HirDatabase, +fn fn_sig_for_struct_constructor( + db: &dyn HirDatabase, def: StructId, -) -> EarlyBinder<'db, PolyFnSig<'db>> { +) -> StoredEarlyBinder<StoredPolyFnSig> { let field_tys = db.field_types(def.into()); - let params = field_tys.iter().map(|(_, ty)| ty.skip_binder()); + let params = field_tys.iter().map(|(_, ty)| ty.get().skip_binder()); let ret = type_for_adt(db, def.into()).skip_binder(); let inputs_and_output = - Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret))); - EarlyBinder::bind(Binder::dummy(FnSig { + Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret.as_ref()))); + StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig { abi: FnAbi::RustCall, c_variadic: false, safety: Safety::Safe, inputs_and_output, - })) + }))) } -fn fn_sig_for_enum_variant_constructor<'db>( - db: &'db dyn HirDatabase, +fn fn_sig_for_enum_variant_constructor( + db: &dyn HirDatabase, def: EnumVariantId, -) -> EarlyBinder<'db, PolyFnSig<'db>> { +) -> StoredEarlyBinder<StoredPolyFnSig> { let field_tys = db.field_types(def.into()); - let params = field_tys.iter().map(|(_, ty)| ty.skip_binder()); + let params = field_tys.iter().map(|(_, ty)| ty.get().skip_binder()); let parent = def.lookup(db).parent; let ret = type_for_adt(db, parent.into()).skip_binder(); let inputs_and_output = - Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret))); - EarlyBinder::bind(Binder::dummy(FnSig { + Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret.as_ref()))); + StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig { abi: FnAbi::RustCall, c_variadic: false, safety: Safety::Safe, inputs_and_output, - })) + }))) } // FIXME(next-solver): should merge this with `explicit_item_bounds` in some way @@ -1965,7 +2325,7 @@ pub(crate) fn associated_ty_item_bounds<'db>( ) -> EarlyBinder<'db, BoundExistentialPredicates<'db>> { let type_alias_data = db.type_alias_signature(type_alias); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let interner = DbInterner::new_no_crate(db); let mut ctx = TyLoweringContext::new( db, &resolver, @@ -1992,10 +2352,7 @@ pub(crate) fn associated_ty_item_bounds<'db>( Some(ExistentialPredicate::Trait(ExistentialTraitRef::new_from_args( interner, t.def_id(), - GenericArgs::new_from_iter( - interner, - t.trait_ref.args.iter().skip(1), - ), + GenericArgs::new_from_slice(&t.trait_ref.args[1..]), ))) } } @@ -2003,10 +2360,7 @@ pub(crate) fn associated_ty_item_bounds<'db>( ExistentialPredicate::Projection(ExistentialProjection::new_from_args( interner, p.def_id(), - GenericArgs::new_from_iter( - interner, - p.projection_term.args.iter().skip(1), - ), + GenericArgs::new_from_slice(&p.projection_term.args[1..]), p.term, )), ), @@ -2026,7 +2380,7 @@ pub(crate) fn associated_ty_item_bounds<'db>( } if !ctx.unsized_types.contains(&self_ty) - && let Some(sized_trait) = LangItem::Sized.resolve_trait(db, resolver.krate()) + && let Some(sized_trait) = ctx.lang_items.Sized { let sized_clause = Binder::dummy(ExistentialPredicate::Trait(ExistentialTraitRef::new( interner, @@ -2036,7 +2390,7 @@ pub(crate) fn associated_ty_item_bounds<'db>( bounds.push(sized_clause); } - EarlyBinder::bind(BoundExistentialPredicates::new_from_iter(interner, bounds)) + EarlyBinder::bind(BoundExistentialPredicates::new_from_slice(&bounds)) } pub(crate) fn associated_type_by_name_including_super_traits<'db>( @@ -2044,7 +2398,8 @@ pub(crate) fn associated_type_by_name_including_super_traits<'db>( trait_ref: TraitRef<'db>, name: &Name, ) -> Option<(TraitRef<'db>, TypeAliasId)> { - let interner = DbInterner::new_with(db, None, None); + let module = trait_ref.def_id.0.module(db); + let interner = DbInterner::new_with(db, module.krate(db)); rustc_type_ir::elaborate::supertraits(interner, Binder::dummy(trait_ref)).find_map(|t| { let trait_id = t.as_ref().skip_binder().def_id.0; let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?; @@ -2058,7 +2413,7 @@ pub fn associated_type_shorthand_candidates( res: TypeNs, mut cb: impl FnMut(&Name, TypeAliasId) -> bool, ) -> Option<TypeAliasId> { - let interner = DbInterner::new_with(db, None, None); + let interner = DbInterner::new_no_crate(db); named_associated_type_shorthand_candidates(interner, def, res, None, |name, _, id| { cb(name, id).then_some(id) }) @@ -2101,7 +2456,7 @@ fn named_associated_type_shorthand_candidates<'db, R>( if let Some(alias) = check_trait(trait_ref) { return Some(alias); } - for pred in generic_predicates_filtered_by( + let predicates = generic_predicates_filtered_by( db, GenericDefId::TraitId(trait_ref.def_id.0), PredicateFilter::SelfTrait, @@ -2112,8 +2467,8 @@ fn named_associated_type_shorthand_candidates<'db, R>( |pred| pred != def && pred == GenericDefId::TraitId(trait_ref.def_id.0), ) .0 - .deref() - { + .predicates; + for pred in predicates.get().instantiate_identity() { tracing::debug!(?pred); let sup_trait_ref = match pred.kind().skip_binder() { rustc_type_ir::ClauseKind::Trait(pred) => pred.trait_ref, @@ -2158,10 +2513,11 @@ fn named_associated_type_shorthand_candidates<'db, R>( } let predicates = - db.generic_predicates_for_param(def, param_id.into(), assoc_name.clone()); + generic_predicates_for_param(db, def, param_id.into(), assoc_name.clone()); predicates - .iter() - .find_map(|pred| match (*pred).kind().skip_binder() { + .get() + .iter_identity() + .find_map(|pred| match pred.kind().skip_binder() { rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate), _ => None, }) |