Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/next_solver/predicate.rs')
| -rw-r--r-- | crates/hir-ty/src/next_solver/predicate.rs | 301 |
1 files changed, 167 insertions, 134 deletions
diff --git a/crates/hir-ty/src/next_solver/predicate.rs b/crates/hir-ty/src/next_solver/predicate.rs index 3438b755fb..5758e2dc7e 100644 --- a/crates/hir-ty/src/next_solver/predicate.rs +++ b/crates/hir-ty/src/next_solver/predicate.rs @@ -2,20 +2,25 @@ use std::cmp::Ordering; -use macros::{TypeFoldable, TypeVisitable}; +use intern::{ + Interned, InternedRef, InternedSlice, InternedSliceRef, impl_internable, impl_slice_internable, +}; +use macros::{GenericTypeVisitable, TypeFoldable, TypeVisitable}; use rustc_type_ir::{ - self as ty, CollectAndApply, DebruijnIndex, EarlyBinder, FlagComputation, Flags, - PredicatePolarity, TypeFlags, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, - TypeVisitable, Upcast, UpcastFrom, WithCachedTypeInfo, + self as ty, CollectAndApply, EarlyBinder, FlagComputation, Flags, GenericTypeVisitable, + PredicatePolarity, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, Upcast, + UpcastFrom, WithCachedTypeInfo, elaborate::Elaboratable, error::{ExpectedFound, TypeError}, inherent::{IntoKind, SliceLike}, }; -use smallvec::SmallVec; -use crate::next_solver::{InternedWrapperNoDebug, TraitIdWrapper}; +use crate::next_solver::{ + GenericArg, TraitIdWrapper, impl_foldable_for_interned_slice, impl_stored_interned_slice, + interned_slice, +}; -use super::{Binder, BoundVarKinds, DbInterner, Region, Ty, interned_vec_db}; +use super::{Binder, BoundVarKinds, DbInterner, Region, Ty}; pub type BoundExistentialPredicate<'db> = Binder<'db, ExistentialPredicate<'db>>; @@ -43,6 +48,7 @@ pub type PolyProjectionPredicate<'db> = Binder<'db, ProjectionPredicate<'db>>; pub type PolyTraitRef<'db> = Binder<'db, TraitRef<'db>>; pub type PolyExistentialTraitRef<'db> = Binder<'db, ExistentialTraitRef<'db>>; pub type PolyExistentialProjection<'db> = Binder<'db, ExistentialProjection<'db>>; +pub type ArgOutlivesPredicate<'db> = OutlivesPredicate<'db, GenericArg<'db>>; /// Compares via an ordering that will not change if modules are reordered or other changes are /// made to the tree. In particular, this ordering is preserved across incremental compilations. @@ -67,7 +73,15 @@ fn stable_cmp_existential_predicate<'db>( (ExistentialPredicate::AutoTrait(_), _) => Ordering::Greater, } } -interned_vec_db!(BoundExistentialPredicates, BoundExistentialPredicate); +interned_slice!( + BoundExistentialPredicatesStorage, + BoundExistentialPredicates, + StoredBoundExistentialPredicates, + bound_existential_predicates, + BoundExistentialPredicate<'db>, + BoundExistentialPredicate<'static>, +); +impl_foldable_for_interned_slice!(BoundExistentialPredicates); impl<'db> rustc_type_ir::inherent::BoundExistentialPredicates<DbInterner<'db>> for BoundExistentialPredicates<'db> @@ -81,7 +95,7 @@ impl<'db> rustc_type_ir::inherent::BoundExistentialPredicates<DbInterner<'db>> ) -> Option< rustc_type_ir::Binder<DbInterner<'db>, rustc_type_ir::ExistentialTraitRef<DbInterner<'db>>>, > { - self.inner()[0] + self[0] .map_bound(|this| match this { ExistentialPredicate::Trait(tr) => Some(tr), _ => None, @@ -165,74 +179,50 @@ impl<'db> rustc_type_ir::relate::Relate<DbInterner<'db>> for BoundExistentialPre }, ); - CollectAndApply::collect_and_apply(v, |g| { - BoundExistentialPredicates::new_from_iter(interner, g.iter().cloned()) - }) + BoundExistentialPredicates::new_from_iter(interner, v) } } -#[salsa::interned(constructor = new_)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct Predicate<'db> { - #[returns(ref)] - kind_: InternedWrapperNoDebug<WithCachedTypeInfo<Binder<'db, PredicateKind<'db>>>>, + interned: InternedRef<'db, PredicateInterned>, } -impl<'db> std::fmt::Debug for Predicate<'db> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.inner().internee.fmt(f) - } -} +#[derive(PartialEq, Eq, Hash, GenericTypeVisitable)] +pub(super) struct PredicateInterned(WithCachedTypeInfo<Binder<'static, PredicateKind<'static>>>); -impl<'db> std::fmt::Debug - for InternedWrapperNoDebug<WithCachedTypeInfo<Binder<'db, PredicateKind<'db>>>> -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Binder<")?; - match self.0.internee.skip_binder() { - rustc_type_ir::PredicateKind::Clause(clause_kind) => { - write!(f, "{clause_kind:?}") - } - rustc_type_ir::PredicateKind::DynCompatible(trait_def_id) => { - write!(f, "the trait `{trait_def_id:?}` is dyn-compatible") - } - rustc_type_ir::PredicateKind::Subtype(subtype_predicate) => { - write!(f, "{subtype_predicate:?}") - } - rustc_type_ir::PredicateKind::Coerce(coerce_predicate) => { - write!(f, "{coerce_predicate:?}") - } - rustc_type_ir::PredicateKind::ConstEquate(c1, c2) => { - write!(f, "the constant `{c1:?}` equals `{c2:?}`") - } - rustc_type_ir::PredicateKind::Ambiguous => write!(f, "ambiguous"), - rustc_type_ir::PredicateKind::NormalizesTo(data) => write!(f, "{data:?}"), - rustc_type_ir::PredicateKind::AliasRelate(t1, t2, dir) => { - write!(f, "{t1:?} {dir:?} {t2:?}") - } - }?; - write!(f, ", [{:?}]>", self.0.internee.bound_vars())?; - Ok(()) - } -} +impl_internable!(gc; PredicateInterned); + +const _: () = { + const fn is_copy<T: Copy>() {} + is_copy::<Predicate<'static>>(); +}; impl<'db> Predicate<'db> { - pub fn new(interner: DbInterner<'db>, kind: Binder<'db, PredicateKind<'db>>) -> Self { + pub fn new(_interner: DbInterner<'db>, kind: Binder<'db, PredicateKind<'db>>) -> Self { + let kind = unsafe { + std::mem::transmute::< + Binder<'db, PredicateKind<'db>>, + Binder<'static, PredicateKind<'static>>, + >(kind) + }; let flags = FlagComputation::for_predicate(kind); let cached = WithCachedTypeInfo { internee: kind, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, }; - Predicate::new_(interner.db(), InternedWrapperNoDebug(cached)) + Self { interned: Interned::new_gc(PredicateInterned(cached)) } } pub fn inner(&self) -> &WithCachedTypeInfo<Binder<'db, PredicateKind<'db>>> { - crate::with_attached_db(|db| { - let inner = &self.kind_(db).0; - // SAFETY: The caller already has access to a `Predicate<'db>`, so borrowchecking will - // make sure that our returned value is valid for the lifetime `'db`. - unsafe { std::mem::transmute(inner) } - }) + let inner = &self.interned.0; + unsafe { + std::mem::transmute::< + &WithCachedTypeInfo<Binder<'static, PredicateKind<'static>>>, + &WithCachedTypeInfo<Binder<'db, PredicateKind<'db>>>, + >(inner) + } } /// Flips the polarity of a Predicate. @@ -258,110 +248,135 @@ impl<'db> Predicate<'db> { } } -// FIXME: should make a "header" in interned_vec - -#[derive(Debug, Clone)] -pub struct InternedClausesWrapper<'db>(SmallVec<[Clause<'db>; 2]>, TypeFlags, DebruijnIndex); - -impl<'db> PartialEq for InternedClausesWrapper<'db> { - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) +impl<'db> std::fmt::Debug for Predicate<'db> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.kind().fmt(f) } } -impl<'db> Eq for InternedClausesWrapper<'db> {} +#[derive(Clone, Copy, PartialEq, Eq, Hash, GenericTypeVisitable)] +pub struct ClausesCachedTypeInfo(WithCachedTypeInfo<()>); -impl<'db> std::hash::Hash for InternedClausesWrapper<'db> { - fn hash<H: std::hash::Hasher>(&self, state: &mut H) { - self.0.hash(state) - } -} +impl_slice_internable!(gc; ClausesStorage, ClausesCachedTypeInfo, Clause<'static>); +impl_stored_interned_slice!(ClausesStorage, Clauses, StoredClauses); -#[salsa::interned(constructor = new_)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct Clauses<'db> { - #[returns(ref)] - inner_: InternedClausesWrapper<'db>, + interned: InternedSliceRef<'db, ClausesStorage>, } -impl<'db> Clauses<'db> { - pub fn new_from_iter( - interner: DbInterner<'db>, - data: impl IntoIterator<Item = Clause<'db>>, - ) -> Self { - let clauses: SmallVec<_> = data.into_iter().collect(); - let flags = FlagComputation::<DbInterner<'db>>::for_clauses(&clauses); - let wrapper = InternedClausesWrapper(clauses, flags.flags, flags.outer_exclusive_binder); - Clauses::new_(interner.db(), wrapper) - } - - pub fn inner(&self) -> &InternedClausesWrapper<'db> { - crate::with_attached_db(|db| { - let inner = self.inner_(db); - // SAFETY: The caller already has access to a `Clauses<'db>`, so borrowchecking will - // make sure that our returned value is valid for the lifetime `'db`. - unsafe { std::mem::transmute(inner) } - }) +impl<'db> std::fmt::Debug for Clauses<'db> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.as_slice().fmt(fmt) } } -impl<'db> std::fmt::Debug for Clauses<'db> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.inner().0.fmt(f) +impl<'db> Clauses<'db> { + #[inline] + pub fn empty(_interner: DbInterner<'db>) -> Self { + // FIXME: Get from a static. + Self::new_from_slice(&[]) + } + + #[inline] + pub fn new_from_slice(slice: &[Clause<'db>]) -> Self { + let slice = unsafe { ::std::mem::transmute::<&[Clause<'db>], &[Clause<'static>]>(slice) }; + let flags = FlagComputation::<DbInterner<'db>>::for_clauses(slice); + let flags = ClausesCachedTypeInfo(WithCachedTypeInfo { + internee: (), + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + }); + Self { interned: InternedSlice::from_header_and_slice(flags, slice) } } -} -impl<'db> rustc_type_ir::inherent::Clauses<DbInterner<'db>> for Clauses<'db> {} + #[inline] + pub fn new_from_iter<I, T>(_interner: DbInterner<'db>, args: I) -> T::Output + where + I: IntoIterator<Item = T>, + T: CollectAndApply<Clause<'db>, Self>, + { + CollectAndApply::collect_and_apply(args.into_iter(), Self::new_from_slice) + } -impl<'db> rustc_type_ir::inherent::SliceLike for Clauses<'db> { - type Item = Clause<'db>; + #[inline] + pub fn as_slice(self) -> &'db [Clause<'db>] { + let slice = &self.interned.get().slice; + unsafe { ::std::mem::transmute::<&[Clause<'static>], &[Clause<'db>]>(slice) } + } - type IntoIter = <smallvec::SmallVec<[Clause<'db>; 2]> as IntoIterator>::IntoIter; + #[inline] + pub fn iter(self) -> ::std::iter::Copied<::std::slice::Iter<'db, Clause<'db>>> { + self.as_slice().iter().copied() + } - fn iter(self) -> Self::IntoIter { - self.inner().0.clone().into_iter() + #[inline] + pub fn len(self) -> usize { + self.as_slice().len() } - fn as_slice(&self) -> &[Self::Item] { - self.inner().0.as_slice() + #[inline] + pub fn is_empty(self) -> bool { + self.as_slice().is_empty() } } impl<'db> IntoIterator for Clauses<'db> { + type IntoIter = ::std::iter::Copied<::std::slice::Iter<'db, Clause<'db>>>; type Item = Clause<'db>; - type IntoIter = <Self as rustc_type_ir::inherent::SliceLike>::IntoIter; - + #[inline] fn into_iter(self) -> Self::IntoIter { - rustc_type_ir::inherent::SliceLike::iter(self) + self.iter() + } +} + +impl<'db> std::ops::Deref for Clauses<'db> { + type Target = [Clause<'db>]; + + #[inline] + fn deref(&self) -> &Self::Target { + (*self).as_slice() + } +} + +impl<'db> rustc_type_ir::inherent::SliceLike for Clauses<'db> { + type Item = Clause<'db>; + + type IntoIter = ::std::iter::Copied<::std::slice::Iter<'db, Clause<'db>>>; + + #[inline] + fn iter(self) -> Self::IntoIter { + self.iter() + } + + #[inline] + fn as_slice(&self) -> &[Self::Item] { + (*self).as_slice() } } impl<'db> Default for Clauses<'db> { + #[inline] fn default() -> Self { - Clauses::new_from_iter(DbInterner::conjure(), []) + Clauses::empty(DbInterner::conjure()) } } +impl<'db> rustc_type_ir::inherent::Clauses<DbInterner<'db>> for Clauses<'db> {} + impl<'db> rustc_type_ir::TypeSuperFoldable<DbInterner<'db>> for Clauses<'db> { fn try_super_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>( self, folder: &mut F, ) -> Result<Self, F::Error> { - let mut clauses: SmallVec<[_; 2]> = SmallVec::with_capacity(self.inner().0.len()); - for c in self { - clauses.push(c.try_fold_with(folder)?); - } - Ok(Clauses::new_from_iter(folder.cx(), clauses)) + Clauses::new_from_iter(folder.cx(), self.iter().map(|clause| clause.try_fold_with(folder))) } fn super_fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>( self, folder: &mut F, ) -> Self { - let mut clauses: SmallVec<[_; 2]> = SmallVec::with_capacity(self.inner().0.len()); - for c in self { - clauses.push(c.fold_with(folder)); - } - Clauses::new_from_iter(folder.cx(), clauses) + Clauses::new_from_iter(folder.cx(), self.iter().map(|clause| clause.fold_with(folder))) } } @@ -370,15 +385,10 @@ impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for Clauses<'db> { self, folder: &mut F, ) -> Result<Self, F::Error> { - use rustc_type_ir::inherent::SliceLike as _; - let inner: smallvec::SmallVec<[_; 2]> = - self.iter().map(|v| v.try_fold_with(folder)).collect::<Result<_, _>>()?; - Ok(Clauses::new_from_iter(folder.cx(), inner)) + self.try_super_fold_with(folder) } fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self { - use rustc_type_ir::inherent::SliceLike as _; - let inner: smallvec::SmallVec<[_; 2]> = self.iter().map(|v| v.fold_with(folder)).collect(); - Clauses::new_from_iter(folder.cx(), inner) + self.super_fold_with(folder) } } @@ -388,19 +398,28 @@ impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for Clauses<'db> { visitor: &mut V, ) -> V::Result { use rustc_ast_ir::visit::VisitorResult; - use rustc_type_ir::inherent::SliceLike as _; - rustc_ast_ir::walk_visitable_list!(visitor, self.as_slice().iter()); + rustc_ast_ir::walk_visitable_list!(visitor, self.iter()); V::Result::output() } } +impl<'db, V: super::WorldExposer> rustc_type_ir::GenericTypeVisitable<V> for Clauses<'db> { + fn generic_visit_with(&self, visitor: &mut V) { + if visitor.on_interned_slice(self.interned).is_continue() { + self.as_slice().iter().for_each(|it| it.generic_visit_with(visitor)); + } + } +} + impl<'db> rustc_type_ir::Flags for Clauses<'db> { + #[inline] fn flags(&self) -> rustc_type_ir::TypeFlags { - self.inner().1 + self.interned.header.header.0.flags } + #[inline] fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex { - self.inner().2 + self.interned.header.header.0.outer_exclusive_binder } } @@ -413,18 +432,24 @@ impl<'db> rustc_type_ir::TypeSuperVisitable<DbInterner<'db>> for Clauses<'db> { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] // TODO implement Debug by hand +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, GenericTypeVisitable)] // TODO implement Debug by hand pub struct Clause<'db>(pub(crate) Predicate<'db>); // We could cram the reveal into the clauses like rustc does, probably -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, TypeVisitable, TypeFoldable)] +#[derive( + Copy, Clone, Debug, Hash, PartialEq, Eq, TypeVisitable, TypeFoldable, GenericTypeVisitable, +)] pub struct ParamEnv<'db> { pub(crate) clauses: Clauses<'db>, } impl<'db> ParamEnv<'db> { pub fn empty() -> Self { - ParamEnv { clauses: Clauses::new_from_iter(DbInterner::conjure(), []) } + ParamEnv { clauses: Clauses::empty(DbInterner::conjure()) } + } + + pub fn clauses(self) -> Clauses<'db> { + self.clauses } } @@ -455,6 +480,14 @@ impl<'db> TypeVisitable<DbInterner<'db>> for Predicate<'db> { } } +impl<'db, V: super::WorldExposer> GenericTypeVisitable<V> for Predicate<'db> { + fn generic_visit_with(&self, visitor: &mut V) { + if visitor.on_interned(self.interned).is_continue() { + self.kind().generic_visit_with(visitor); + } + } +} + impl<'db> TypeSuperVisitable<DbInterner<'db>> for Predicate<'db> { fn super_visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>( &self, |