Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/next_solver/interner.rs')
-rw-r--r--crates/hir-ty/src/next_solver/interner.rs621
1 files changed, 422 insertions, 199 deletions
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index 8b24a20a5b..2ebc5b81ba 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -1,7 +1,9 @@
//! Things related to the Interner in the next-trait-solver.
-use std::fmt;
+use std::{fmt, ops::ControlFlow};
+use intern::{Interned, InternedRef, InternedSliceRef, impl_internable};
+use macros::GenericTypeVisitable;
use rustc_ast_ir::{FloatTy, IntTy, UintTy};
pub use tls_cache::clear_tls_solver_cache;
pub use tls_db::{attach_db, attach_db_allow_change, with_attached_db};
@@ -19,13 +21,13 @@ use rustc_abi::{ReprFlags, ReprOptions};
use rustc_hash::FxHashSet;
use rustc_index::bit_set::DenseBitSet;
use rustc_type_ir::{
- AliasTermKind, AliasTyKind, BoundVar, CollectAndApply, CoroutineWitnessTypes, DebruijnIndex,
- EarlyBinder, FlagComputation, Flags, GenericArgKind, ImplPolarity, InferTy, Interner, TraitRef,
- TypeFlags, TypeVisitableExt, UniverseIndex, Upcast, Variance,
+ AliasTermKind, AliasTyKind, BoundVar, CoroutineWitnessTypes, DebruijnIndex, EarlyBinder,
+ FlagComputation, Flags, GenericArgKind, GenericTypeVisitable, ImplPolarity, InferTy, Interner,
+ TraitRef, TypeFlags, TypeVisitableExt, UniverseIndex, Upcast, Variance,
elaborate::elaborate,
error::TypeError,
fast_reject,
- inherent::{self, GenericsOf, IntoKind, SliceLike as _, Span as _, Ty as _},
+ inherent::{self, Const as _, GenericsOf, IntoKind, SliceLike as _, Span as _, Ty as _},
lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem},
solve::SizedTraitKind,
};
@@ -39,7 +41,7 @@ use crate::{
AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper,
CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, GeneralConstIdWrapper, ImplIdWrapper,
OpaqueTypeKey, RegionAssumptions, SimplifiedType, SolverContext, SolverDefIds,
- TraitIdWrapper, TypeAliasIdWrapper, util::explicit_item_bounds,
+ TraitIdWrapper, TypeAliasIdWrapper, UnevaluatedConst, util::explicit_item_bounds,
},
};
@@ -57,216 +59,256 @@ use super::{
util::sizedness_constraint_for_ty,
};
-#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
-pub struct InternedWrapperNoDebug<T>(pub(crate) T);
+macro_rules! interned_slice {
+ ($storage:ident, $name:ident, $stored_name:ident, $default_types_field:ident, $ty_db:ty, $ty_static:ty $(,)?) => {
+ const _: () = {
+ #[allow(unused_lifetimes)]
+ fn _ensure_correct_types<'db: 'static>(v: $ty_db) -> $ty_static { v }
+ };
-#[macro_export]
-#[doc(hidden)]
-macro_rules! _interned_vec_nolifetime_salsa {
- ($name:ident, $ty:ty) => {
- interned_vec_nolifetime_salsa!($name, $ty, nofold);
+ ::intern::impl_slice_internable!(gc; $storage, (), $ty_static);
- impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for $name<'db> {
- fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'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($name::new_(folder.cx().db(), inner))
- }
- 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();
- $name::new_(folder.cx().db(), inner)
- }
+ #[derive(Clone, Copy, PartialEq, Eq, Hash)]
+ pub struct $name<'db> {
+ interned: ::intern::InternedSliceRef<'db, $storage>,
}
- impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for $name<'db> {
- fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
- &self,
- 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());
- V::Result::output()
+ impl<'db> std::fmt::Debug for $name<'db> {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.as_slice().fmt(fmt)
}
}
- };
- ($name:ident, $ty:ty, nofold) => {
- #[salsa::interned(constructor = new_)]
- pub struct $name {
- #[returns(ref)]
- inner_: smallvec::SmallVec<[$ty; 2]>,
- }
impl<'db> $name<'db> {
- pub fn new_from_iter(
- interner: DbInterner<'db>,
- data: impl IntoIterator<Item = $ty>,
- ) -> Self {
- $name::new_(interner.db(), data.into_iter().collect::<smallvec::SmallVec<[_; 2]>>())
+ #[inline]
+ pub fn empty(interner: DbInterner<'db>) -> Self {
+ interner.default_types().empty.$default_types_field
+ }
+
+ #[inline]
+ pub fn new_from_slice(slice: &[$ty_db]) -> Self {
+ let slice = unsafe { ::std::mem::transmute::<&[$ty_db], &[$ty_static]>(slice) };
+ Self { interned: ::intern::InternedSlice::from_header_and_slice((), slice) }
}
- pub fn inner(&self) -> &smallvec::SmallVec<[$ty; 2]> {
- // SAFETY: ¯\_(ツ)_/¯
- $crate::with_attached_db(|db| {
- let inner = self.inner_(db);
- unsafe { std::mem::transmute(inner) }
+ #[inline]
+ pub fn new_from_iter<I, T>(_interner: DbInterner<'db>, args: I) -> T::Output
+ where
+ I: IntoIterator<Item = T>,
+ T: ::rustc_type_ir::CollectAndApply<$ty_db, Self>,
+ {
+ ::rustc_type_ir::CollectAndApply::collect_and_apply(args.into_iter(), |g| {
+ Self::new_from_slice(g)
})
}
+
+ #[inline]
+ pub fn as_slice(self) -> &'db [$ty_db] {
+ let slice = &self.interned.get().slice;
+ unsafe { ::std::mem::transmute::<&[$ty_static], &[$ty_db]>(slice) }
+ }
+
+ #[inline]
+ pub fn iter(self) -> ::std::iter::Copied<::std::slice::Iter<'db, $ty_db>> {
+ self.as_slice().iter().copied()
+ }
+
+ #[inline]
+ pub fn len(self) -> usize {
+ self.as_slice().len()
+ }
+
+ #[inline]
+ pub fn is_empty(self) -> bool {
+ self.as_slice().is_empty()
+ }
}
- impl<'db> std::fmt::Debug for $name<'db> {
- fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- self.as_slice().fmt(fmt)
+ impl<'db> IntoIterator for $name<'db> {
+ type IntoIter = ::std::iter::Copied<::std::slice::Iter<'db, $ty_db>>;
+ type Item = $ty_db;
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter { self.iter() }
+ }
+
+ impl<'db> ::std::ops::Deref for $name<'db> {
+ type Target = [$ty_db];
+
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ (*self).as_slice()
}
}
impl<'db> rustc_type_ir::inherent::SliceLike for $name<'db> {
- type Item = $ty;
+ type Item = $ty_db;
- type IntoIter = <smallvec::SmallVec<[$ty; 2]> as IntoIterator>::IntoIter;
+ type IntoIter = ::std::iter::Copied<::std::slice::Iter<'db, $ty_db>>;
+ #[inline]
fn iter(self) -> Self::IntoIter {
- self.inner().clone().into_iter()
+ self.iter()
}
+ #[inline]
fn as_slice(&self) -> &[Self::Item] {
- self.inner().as_slice()
+ (*self).as_slice()
}
}
- impl<'db> IntoIterator for $name<'db> {
- type Item = $ty;
- type IntoIter = <Self as rustc_type_ir::inherent::SliceLike>::IntoIter;
-
- fn into_iter(self) -> Self::IntoIter {
- rustc_type_ir::inherent::SliceLike::iter(self)
+ impl<'db> Default for $name<'db> {
+ #[inline]
+ fn default() -> Self {
+ $name::empty(DbInterner::conjure())
}
}
- impl<'db> Default for $name<'db> {
- fn default() -> Self {
- $name::new_from_iter(DbInterner::conjure(), [])
+
+ impl<'db, V: $crate::next_solver::interner::WorldExposer>
+ rustc_type_ir::GenericTypeVisitable<V> for $name<'db>
+ {
+ #[inline]
+ 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));
+ }
}
}
+
+ $crate::next_solver::interner::impl_stored_interned_slice!($storage, $name, $stored_name);
};
}
+pub(crate) use interned_slice;
-pub use crate::_interned_vec_nolifetime_salsa as interned_vec_nolifetime_salsa;
+macro_rules! impl_stored_interned_slice {
+ ( $storage:ident, $name:ident, $stored_name:ident $(,)? ) => {
+ #[derive(Clone, PartialEq, Eq, Hash)]
+ pub struct $stored_name {
+ interned: ::intern::InternedSlice<$storage>,
+ }
-#[macro_export]
-#[doc(hidden)]
-macro_rules! _interned_vec_db {
- ($name:ident, $ty:ident) => {
- interned_vec_db!($name, $ty, nofold);
+ impl $stored_name {
+ #[inline]
+ fn new(it: $name<'_>) -> Self {
+ Self { interned: it.interned.to_owned() }
+ }
- impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for $name<'db> {
- fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'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($name::new_(folder.cx().db(), inner))
+ #[inline]
+ pub fn as_ref<'a, 'db>(&'a self) -> $name<'db> {
+ let it = $name { interned: self.interned.as_ref() };
+ unsafe { std::mem::transmute::<$name<'a>, $name<'db>>(it) }
}
- 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();
- $name::new_(folder.cx().db(), inner)
+ }
+
+ // SAFETY: It is safe to store this type in queries (but not `$name`).
+ unsafe impl salsa::Update for $stored_name {
+ unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
+ // SAFETY: Comparing by (pointer) equality is safe.
+ unsafe { crate::utils::unsafe_update_eq(old_pointer, new_value) }
+ }
+ }
+
+ impl std::fmt::Debug for $stored_name {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.as_ref().fmt(f)
+ }
+ }
+
+ impl $name<'_> {
+ #[inline]
+ pub fn store(self) -> $stored_name {
+ $stored_name::new(self)
}
}
+ };
+}
+pub(crate) use impl_stored_interned_slice;
- impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for $name<'db> {
+macro_rules! impl_foldable_for_interned_slice {
+ ($name:ident) => {
+ impl<'db> ::rustc_type_ir::TypeVisitable<DbInterner<'db>> for $name<'db> {
fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
&self,
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()
}
}
- };
- ($name:ident, $ty:ident, nofold) => {
- #[salsa::interned(constructor = new_)]
- pub struct $name<'db> {
- #[returns(ref)]
- inner_: smallvec::SmallVec<[$ty<'db>; 2]>,
- }
-
- impl<'db> std::fmt::Debug for $name<'db> {
- fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- self.as_slice().fmt(fmt)
- }
- }
- impl<'db> $name<'db> {
- pub fn empty(interner: DbInterner<'db>) -> Self {
- $name::new_(interner.db(), smallvec::SmallVec::new())
+ impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for $name<'db> {
+ fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Self::new_from_iter(folder.cx(), self.iter().map(|it| it.try_fold_with(folder)))
}
-
- pub fn new_from_iter(
- interner: DbInterner<'db>,
- data: impl IntoIterator<Item = $ty<'db>>,
+ fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(
+ self,
+ folder: &mut F,
) -> Self {
- $name::new_(interner.db(), data.into_iter().collect::<smallvec::SmallVec<[_; 2]>>())
- }
-
- pub fn inner(&self) -> &smallvec::SmallVec<[$ty<'db>; 2]> {
- // SAFETY: ¯\_(ツ)_/¯
- $crate::with_attached_db(|db| {
- let inner = self.inner_(db);
- unsafe { std::mem::transmute(inner) }
- })
+ Self::new_from_iter(folder.cx(), self.iter().map(|it| it.fold_with(folder)))
}
}
+ };
+}
+pub(crate) use impl_foldable_for_interned_slice;
- impl<'db> rustc_type_ir::inherent::SliceLike for $name<'db> {
- type Item = $ty<'db>;
-
- type IntoIter = <smallvec::SmallVec<[$ty<'db>; 2]> as IntoIterator>::IntoIter;
+macro_rules! impl_stored_interned {
+ ( $storage:ident, $name:ident, $stored_name:ident $(,)? ) => {
+ #[derive(Clone, PartialEq, Eq, Hash)]
+ pub struct $stored_name {
+ interned: ::intern::Interned<$storage>,
+ }
- fn iter(self) -> Self::IntoIter {
- self.inner().clone().into_iter()
+ impl $stored_name {
+ #[inline]
+ fn new(it: $name<'_>) -> Self {
+ Self { interned: it.interned.to_owned() }
}
- fn as_slice(&self) -> &[Self::Item] {
- self.inner().as_slice()
+ #[inline]
+ pub fn as_ref<'a, 'db>(&'a self) -> $name<'db> {
+ let it = $name { interned: self.interned.as_ref() };
+ unsafe { std::mem::transmute::<$name<'a>, $name<'db>>(it) }
}
}
- impl<'db> IntoIterator for $name<'db> {
- type Item = $ty<'db>;
- type IntoIter = <Self as rustc_type_ir::inherent::SliceLike>::IntoIter;
+ unsafe impl salsa::Update for $stored_name {
+ unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
+ unsafe { crate::utils::unsafe_update_eq(old_pointer, new_value) }
+ }
+ }
- fn into_iter(self) -> Self::IntoIter {
- rustc_type_ir::inherent::SliceLike::iter(self)
+ impl std::fmt::Debug for $stored_name {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.as_ref().fmt(f)
}
}
- impl<'db> Default for $name<'db> {
- fn default() -> Self {
- $name::new_from_iter(DbInterner::conjure(), [])
+ impl $name<'_> {
+ #[inline]
+ pub fn store(self) -> $stored_name {
+ $stored_name::new(self)
}
}
};
}
-
-pub use crate::_interned_vec_db as interned_vec_db;
+pub(crate) use impl_stored_interned;
+
+/// This is a visitor trait that treats any interned thing specifically. Visitables are expected to call
+/// the trait's methods when encountering an interned. This is used to implement marking in GC.
+pub trait WorldExposer {
+ fn on_interned<T: intern::Internable>(
+ &mut self,
+ interned: InternedRef<'_, T>,
+ ) -> ControlFlow<()>;
+ fn on_interned_slice<T: intern::SliceInternable>(
+ &mut self,
+ interned: InternedSliceRef<'_, T>,
+ ) -> ControlFlow<()>;
+}
#[derive(Debug, Copy, Clone)]
pub struct DbInterner<'db> {
@@ -321,6 +363,11 @@ impl<'db> DbInterner<'db> {
where you should've called `DbInterner::new_with()`",
)
}
+
+ #[inline]
+ pub fn default_types<'a>(&self) -> &'a crate::next_solver::DefaultAny<'db> {
+ crate::next_solver::default_types(self.db)
+ }
}
// This is intentionally left as `()`
@@ -333,7 +380,14 @@ impl<'db> inherent::Span<DbInterner<'db>> for Span {
}
}
-interned_vec_nolifetime_salsa!(BoundVarKinds, BoundVarKind, nofold);
+interned_slice!(
+ BoundVarKindsStorage,
+ BoundVarKinds,
+ StoredBoundVarKinds,
+ bound_var_kinds,
+ BoundVarKind,
+ BoundVarKind,
+);
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum BoundVarKind {
@@ -365,7 +419,14 @@ impl BoundVarKind {
}
}
-interned_vec_db!(CanonicalVars, CanonicalVarKind, nofold);
+interned_slice!(
+ CanonicalVarsStorage,
+ CanonicalVars,
+ StoredCanonicalVars,
+ canonical_vars,
+ CanonicalVarKind<'db>,
+ CanonicalVarKind<'static>
+);
pub struct DepNodeIndex;
@@ -391,7 +452,7 @@ impl<T: std::fmt::Debug> std::fmt::Debug for Placeholder<T> {
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct AllocId;
-interned_vec_nolifetime_salsa!(VariancesOf, Variance, nofold);
+interned_slice!(VariancesOfStorage, VariancesOf, StoredVariancesOf, variances, Variance, Variance);
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct VariantIdx(usize);
@@ -658,7 +719,7 @@ impl<'db> inherent::AdtDef<DbInterner<'db>> for AdtDef {
let id: VariantId = struct_id.into();
let field_types = interner.db().field_types(id);
- field_types.iter().last().map(|f| *f.1)
+ field_types.iter().last().map(|f| f.1.get())
}
fn all_field_tys(
@@ -668,7 +729,7 @@ impl<'db> inherent::AdtDef<DbInterner<'db>> for AdtDef {
let db = interner.db();
// FIXME: this is disabled just to match the behavior with chalk right now
let _field_tys = |id: VariantId| {
- db.field_types(id).iter().map(|(_, ty)| ty.skip_binder()).collect::<Vec<_>>()
+ db.field_types(id).iter().map(|(_, ty)| ty.get().skip_binder()).collect::<Vec<_>>()
};
let field_tys = |_id: VariantId| vec![];
let tys: Vec<_> = match self.inner().id {
@@ -762,30 +823,36 @@ impl std::ops::Deref for UnsizingParams {
pub type PatternKind<'db> = rustc_type_ir::PatternKind<DbInterner<'db>>;
-#[salsa::interned(constructor = new_, debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct Pattern<'db> {
- #[returns(ref)]
- kind_: InternedWrapperNoDebug<PatternKind<'db>>,
+ interned: InternedRef<'db, PatternInterned>,
}
-impl<'db> std::fmt::Debug for InternedWrapperNoDebug<PatternKind<'db>> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- self.0.fmt(f)
- }
-}
+#[derive(PartialEq, Eq, Hash, GenericTypeVisitable)]
+struct PatternInterned(PatternKind<'static>);
+
+impl_internable!(gc; PatternInterned);
+
+const _: () = {
+ const fn is_copy<T: Copy>() {}
+ is_copy::<Pattern<'static>>();
+};
impl<'db> Pattern<'db> {
- pub fn new(interner: DbInterner<'db>, kind: PatternKind<'db>) -> Self {
- Pattern::new_(interner.db(), InternedWrapperNoDebug(kind))
+ pub fn new(_interner: DbInterner<'db>, kind: PatternKind<'db>) -> Self {
+ let kind = unsafe { std::mem::transmute::<PatternKind<'db>, PatternKind<'static>>(kind) };
+ Self { interned: Interned::new_gc(PatternInterned(kind)) }
}
pub fn inner(&self) -> &PatternKind<'db> {
- crate::with_attached_db(|db| {
- let inner = &self.kind_(db).0;
- // SAFETY: The caller already has access to a `Ty<'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::<&PatternKind<'static>, &PatternKind<'db>>(inner) }
+ }
+}
+
+impl<'db> std::fmt::Debug for Pattern<'db> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.kind().fmt(f)
}
}
@@ -831,6 +898,36 @@ impl<'db> rustc_type_ir::inherent::IntoKind for Pattern<'db> {
}
}
+impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for Pattern<'db> {
+ fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
+ &self,
+ visitor: &mut V,
+ ) -> V::Result {
+ self.kind().visit_with(visitor)
+ }
+}
+
+impl<'db, V: WorldExposer> rustc_type_ir::GenericTypeVisitable<V> for Pattern<'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> rustc_type_ir::TypeFoldable<DbInterner<'db>> for Pattern<'db> {
+ fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(Pattern::new(folder.cx(), self.kind().try_fold_with(folder)?))
+ }
+
+ fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
+ Pattern::new(folder.cx(), self.kind().fold_with(folder))
+ }
+}
+
impl<'db> rustc_type_ir::relate::Relate<DbInterner<'db>> for Pattern<'db> {
fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
relation: &mut R,
@@ -851,9 +948,9 @@ impl<'db> rustc_type_ir::relate::Relate<DbInterner<'db>> for Pattern<'db> {
if a.len() != b.len() {
return Err(TypeError::Mismatch);
}
- let pats = CollectAndApply::collect_and_apply(
+ let pats = PatList::new_from_iter(
+ relation.cx(),
std::iter::zip(a.iter(), b.iter()).map(|(a, b)| relation.relate(a, b)),
- |g| PatList::new_from_iter(tcx, g.iter().cloned()),
)?;
Ok(Pattern::new(tcx, PatternKind::Or(pats)))
}
@@ -865,7 +962,8 @@ impl<'db> rustc_type_ir::relate::Relate<DbInterner<'db>> for Pattern<'db> {
}
}
-interned_vec_db!(PatList, Pattern);
+interned_slice!(PatListStorage, PatList, StoredPatList, pat_list, Pattern<'db>, Pattern<'static>);
+impl_foldable_for_interned_slice!(PatList);
macro_rules! as_lang_item {
(
@@ -927,7 +1025,7 @@ impl<'db> Interner for DbInterner<'db> {
type Span = Span;
type GenericArgs = GenericArgs<'db>;
- type GenericArgsSlice = GenericArgs<'db>;
+ type GenericArgsSlice = &'db [GenericArg<'db>];
type GenericArg = GenericArg<'db>;
type Term = Term<'db>;
@@ -941,7 +1039,7 @@ impl<'db> Interner for DbInterner<'db> {
self,
data: &[(OpaqueTypeKey<'db>, Self::Ty)],
) -> Self::PredefinedOpaques {
- PredefinedOpaques::new_from_iter(self, data.iter().cloned())
+ PredefinedOpaques::new_from_slice(data)
}
type CanonicalVarKinds = CanonicalVars<'db>;
@@ -950,7 +1048,7 @@ impl<'db> Interner for DbInterner<'db> {
self,
kinds: &[rustc_type_ir::CanonicalVarKind<Self>],
) -> Self::CanonicalVarKinds {
- CanonicalVars::new_from_iter(self, kinds.iter().cloned())
+ CanonicalVars::new_from_slice(kinds)
}
type ExternalConstraints = ExternalConstraints<'db>;
@@ -968,7 +1066,7 @@ impl<'db> Interner for DbInterner<'db> {
type Ty = Ty<'db>;
type Tys = Tys<'db>;
- type FnInputTys = Tys<'db>;
+ type FnInputTys = &'db [Ty<'db>];
type ParamTy = ParamTy;
type BoundTy = BoundTy;
type PlaceholderTy = PlaceholderTy;
@@ -1012,7 +1110,7 @@ impl<'db> Interner for DbInterner<'db> {
type Features = Features;
fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs {
- GenericArgs::new_from_iter(self, args.iter().cloned())
+ GenericArgs::new_from_slice(args)
}
fn mk_args_from_iter<I, T>(self, args: I) -> T::Output
@@ -1020,9 +1118,7 @@ impl<'db> Interner for DbInterner<'db> {
I: Iterator<Item = T>,
T: rustc_type_ir::CollectAndApply<Self::GenericArg, Self::GenericArgs>,
{
- CollectAndApply::collect_and_apply(args, |g| {
- GenericArgs::new_from_iter(self, g.iter().cloned())
- })
+ GenericArgs::new_from_iter(self, args)
}
type UnsizingParams = UnsizingParams;
@@ -1096,7 +1192,7 @@ impl<'db> Interner for DbInterner<'db> {
| SolverDefId::ImplId(_)
| SolverDefId::InternedClosureId(_)
| SolverDefId::InternedCoroutineId(_) => {
- return VariancesOf::new_from_iter(self, []);
+ return VariancesOf::empty(self);
}
};
self.db.variances_of(generic_def)
@@ -1174,12 +1270,9 @@ impl<'db> Interner for DbInterner<'db> {
) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) {
let trait_def_id = self.parent(def_id);
let trait_generics = self.generics_of(trait_def_id);
- let trait_args = GenericArgs::new_from_iter(
- self,
- args.as_slice()[0..trait_generics.own_params.len()].iter().cloned(),
- );
- let alias_args =
- GenericArgs::new_from_iter(self, args.iter().skip(trait_generics.own_params.len()));
+ let trait_args =
+ GenericArgs::new_from_slice(&args.as_slice()[0..trait_generics.own_params.len()]);
+ let alias_args = &args.as_slice()[trait_generics.own_params.len()..];
(TraitRef::new_from_args(self, trait_def_id.try_into().unwrap(), trait_args), alias_args)
}
@@ -1202,7 +1295,7 @@ impl<'db> Interner for DbInterner<'db> {
I: Iterator<Item = T>,
T: rustc_type_ir::CollectAndApply<Self::Ty, Self::Tys>,
{
- CollectAndApply::collect_and_apply(args, |g| Tys::new_from_iter(self, g.iter().cloned()))
+ Tys::new_from_iter(self, args)
}
fn parent(self, def_id: Self::DefId) -> Self::DefId {
@@ -1338,7 +1431,7 @@ impl<'db> Interner for DbInterner<'db> {
let own_bounds: FxHashSet<_> =
self.item_self_bounds(def_id).skip_binder().into_iter().collect();
if all_bounds.len() == own_bounds.len() {
- EarlyBinder::bind(Clauses::new_from_iter(self, []))
+ EarlyBinder::bind(Clauses::empty(self))
} else {
EarlyBinder::bind(Clauses::new_from_iter(
self,
@@ -1512,6 +1605,7 @@ impl<'db> Interner for DbInterner<'db> {
SolverTraitLangItem::BikeshedGuaranteedNoDrop => {
unimplemented!()
}
+ SolverTraitLangItem::TrivialClone => lang_items.TrivialClone,
};
lang_item.expect("Lang item required but not found.").into()
}
@@ -1565,6 +1659,7 @@ impl<'db> Interner for DbInterner<'db> {
AsyncFn,
AsyncFnMut,
AsyncFnOnce,
+ TrivialClone,
)
}
@@ -1651,6 +1746,7 @@ impl<'db> Interner for DbInterner<'db> {
AsyncFn,
AsyncFnMut,
AsyncFnOnce,
+ TrivialClone,
)
}
@@ -1949,7 +2045,7 @@ impl<'db> Interner for DbInterner<'db> {
let field_types = self.db().field_types(variant.id());
let mut unsizing_params = DenseBitSet::new_empty(num_params);
- let ty = field_types[tail_field.0];
+ let ty = field_types[tail_field.0].get();
for arg in ty.instantiate_identity().walk() {
if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.insert(i);
@@ -1959,7 +2055,7 @@ impl<'db> Interner for DbInterner<'db> {
// Ensure none of the other fields mention the parameters used
// in unsizing.
for field in prefix_fields {
- for arg in field_types[field.0].instantiate_identity().walk() {
+ for arg in field_types[field.0].get().instantiate_identity().walk() {
if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.remove(i);
}
@@ -2007,9 +2103,7 @@ impl<'db> Interner for DbInterner<'db> {
let mut map = Default::default();
let delegate = Anonymize { interner: self, map: &mut map };
let inner = self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate);
- let bound_vars = CollectAndApply::collect_and_apply(map.into_values(), |xs| {
- BoundVarKinds::new_from_iter(self, xs.iter().cloned())
- });
+ let bound_vars = BoundVarKinds::new_from_iter(self, map.into_values());
Binder::bind_with_vars(inner, bound_vars)
}
@@ -2019,7 +2113,7 @@ impl<'db> Interner for DbInterner<'db> {
};
let mut result = Vec::new();
crate::opaques::opaque_types_defined_by(self.db, def_id, &mut result);
- SolverDefIds::new_from_iter(self, result)
+ SolverDefIds::new_from_slice(&result)
}
fn opaque_types_and_coroutines_defined_by(self, def_id: Self::LocalDefId) -> Self::LocalDefIds {
@@ -2048,7 +2142,7 @@ impl<'db> Interner for DbInterner<'db> {
}
});
- SolverDefIds::new_from_iter(self, result)
+ SolverDefIds::new_from_slice(&result)
}
fn alias_has_const_conditions(self, _def_id: Self::DefId) -> bool {
@@ -2093,10 +2187,10 @@ impl<'db> Interner for DbInterner<'db> {
let impl_trait_id = self.db().lookup_intern_impl_trait_id(opaque);
match impl_trait_id {
crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
- crate::opaques::rpit_hidden_types(self.db, func)[idx]
+ crate::opaques::rpit_hidden_types(self.db, func)[idx].get()
}
crate::ImplTraitId::TypeAliasImplTrait(type_alias, idx) => {
- crate::opaques::tait_hidden_types(self.db, type_alias)[idx]
+ crate::opaques::tait_hidden_types(self.db, type_alias)[idx].get()
}
}
}
@@ -2167,6 +2261,18 @@ impl<'db> Interner for DbInterner<'db> {
Some(SolverTraitLangItem::Sized | SolverTraitLangItem::MetaSized)
)
}
+
+ fn const_of_item(self, def_id: Self::DefId) -> rustc_type_ir::EarlyBinder<Self, Self::Const> {
+ let id = match def_id {
+ SolverDefId::StaticId(id) => id.into(),
+ SolverDefId::ConstId(id) => id.into(),
+ _ => unreachable!(),
+ };
+ EarlyBinder::bind(Const::new_unevaluated(
+ self,
+ UnevaluatedConst { def: GeneralConstIdWrapper(id), args: GenericArgs::empty(self) },
+ ))
+ }
}
impl<'db> DbInterner<'db> {
@@ -2273,6 +2379,11 @@ macro_rules! TrivialTypeTraversalImpls {
<F::Result as rustc_ast_ir::visit::VisitorResult>::output()
}
}
+
+ impl<V> rustc_type_ir::GenericTypeVisitable<V> for $ty {
+ #[inline]
+ fn generic_visit_with(&self, _visitor: &mut V) {}
+ }
)+
};
}
@@ -2287,17 +2398,22 @@ TrivialTypeTraversalImpls! {
AdtIdWrapper,
ImplIdWrapper,
GeneralConstIdWrapper,
- Pattern<'db>,
Safety,
FnAbi,
Span,
ParamConst,
ParamTy,
BoundRegion,
- BoundVar,
Placeholder<BoundRegion>,
Placeholder<BoundTy>,
Placeholder<BoundVar>,
+ Placeholder<BoundConst>,
+ BoundVarKind,
+ EarlyParamRegion,
+ LateParamRegion,
+ AdtDef,
+ BoundTy,
+ BoundConst,
}
mod tls_db {
@@ -2464,3 +2580,110 @@ mod tls_cache {
GLOBAL_CACHE.with_borrow_mut(|handle| *handle = None);
}
}
+
+impl WorldExposer for intern::GarbageCollector {
+ fn on_interned<T: intern::Internable>(
+ &mut self,
+ interned: InternedRef<'_, T>,
+ ) -> ControlFlow<()> {
+ self.mark_interned_alive(interned)
+ }
+
+ fn on_interned_slice<T: intern::SliceInternable>(
+ &mut self,
+ interned: InternedSliceRef<'_, T>,
+ ) -> ControlFlow<()> {
+ self.mark_interned_slice_alive(interned)
+ }
+}
+
+/// # Safety
+///
+/// This cannot be called if there are some not-yet-recorded type values. Generally, if you have a mutable
+/// reference to the database, and there are no other database - then you can call this safely, but you
+/// also need to make sure to maintain the mutable reference while this is running.
+pub unsafe fn collect_ty_garbage() {
+ let mut gc = intern::GarbageCollector::default();
+
+ gc.add_storage::<super::consts::ConstInterned>();
+ gc.add_storage::<super::consts::ValtreeInterned>();
+ gc.add_storage::<PatternInterned>();
+ gc.add_storage::<super::opaques::ExternalConstraintsInterned>();
+ gc.add_storage::<super::predicate::PredicateInterned>();
+ gc.add_storage::<super::region::RegionInterned>();
+ gc.add_storage::<super::ty::TyInterned>();
+
+ gc.add_slice_storage::<super::predicate::ClausesStorage>();
+ gc.add_slice_storage::<super::generic_arg::GenericArgsStorage>();
+ gc.add_slice_storage::<BoundVarKindsStorage>();
+ gc.add_slice_storage::<VariancesOfStorage>();
+ gc.add_slice_storage::<CanonicalVarsStorage>();
+ gc.add_slice_storage::<PatListStorage>();
+ gc.add_slice_storage::<super::opaques::PredefinedOpaquesStorage>();
+ gc.add_slice_storage::<super::opaques::SolverDefIdsStorage>();
+ gc.add_slice_storage::<super::predicate::BoundExistentialPredicatesStorage>();
+ gc.add_slice_storage::<super::region::RegionAssumptionsStorage>();
+ gc.add_slice_storage::<super::ty::TysStorage>();
+
+ // SAFETY:
+ // - By our precondition, there are no unrecorded types.
+ // - We implement `GcInternedVisit` and `GcInternedSliceVisit` correctly for all types.
+ // - We added all storages (FIXME: it's too easy to forget to add a new storage here).
+ unsafe { gc.collect() };
+}
+
+macro_rules! impl_gc_visit {
+ ( $($ty:ty),* $(,)? ) => {
+ $(
+ impl ::intern::GcInternedVisit for $ty {
+ #[inline]
+ fn visit_with(&self, gc: &mut ::intern::GarbageCollector) {
+ self.generic_visit_with(gc);
+ }
+ }
+ )*
+ };
+}
+
+impl_gc_visit!(
+ super::consts::ConstInterned,
+ super::consts::ValtreeInterned,
+ PatternInterned,
+ super::opaques::ExternalConstraintsInterned,
+ super::predicate::PredicateInterned,
+ super::region::RegionInterned,
+ super::ty::TyInterned,
+ super::predicate::ClausesCachedTypeInfo,
+);
+
+macro_rules! impl_gc_visit_slice {
+ ( $($ty:ty),* $(,)? ) => {
+ $(
+ impl ::intern::GcInternedSliceVisit for $ty {
+ #[inline]
+ fn visit_header(header: &<Self as ::intern::SliceInternable>::Header, gc: &mut ::intern::GarbageCollector) {
+ header.generic_visit_with(gc);
+ }
+
+ #[inline]
+ fn visit_slice(header: &[<Self as ::intern::SliceInternable>::SliceType], gc: &mut ::intern::GarbageCollector) {
+ header.generic_visit_with(gc);
+ }
+ }
+ )*
+ };
+}
+
+impl_gc_visit_slice!(
+ super::predicate::ClausesStorage,
+ super::generic_arg::GenericArgsStorage,
+ BoundVarKindsStorage,
+ VariancesOfStorage,
+ CanonicalVarsStorage,
+ PatListStorage,
+ super::opaques::PredefinedOpaquesStorage,
+ super::opaques::SolverDefIdsStorage,
+ super::predicate::BoundExistentialPredicatesStorage,
+ super::region::RegionAssumptionsStorage,
+ super::ty::TysStorage,
+);