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.rs1590
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(&param_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(&param_ty) {
- return;
+ let param_ty = Ty::new_param(interner, param_id, param_idx);
+ if ctx.unsized_types.contains(&param_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,
})