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.rs | 1374 |
1 files changed, 883 insertions, 491 deletions
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs index b18e08bea4..2a3df1d32a 100644 --- a/crates/hir-ty/src/next_solver/interner.rs +++ b/crates/hir-ty/src/next_solver/interner.rs @@ -2,14 +2,18 @@ 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}; use base_db::Crate; use hir_def::{ - AdtId, AttrDefId, BlockId, CallableDefId, DefWithBodyId, EnumVariantId, ItemContainerId, - StructId, UnionId, VariantId, - lang_item::LangItem, + AdtId, CallableDefId, DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, StructId, + UnionId, VariantId, + attrs::AttrFlags, + lang_item::LangItems, signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags}, }; use la_arena::Idx; @@ -17,12 +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, - 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, - inherent::{self, GenericsOf, IntoKind, SliceLike as _, Span as _, Ty as _}, + fast_reject, + inherent::{self, Const as _, GenericsOf, IntoKind, SliceLike as _, Span as _, Ty as _}, lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}, solve::SizedTraitKind, }; @@ -30,12 +35,13 @@ use rustc_type_ir::{ use crate::{ FnAbi, db::{HirDatabase, InternedCoroutine, InternedCoroutineId}, - method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TyFingerprint}, + lower::GenericPredicates, + method_resolution::TraitImpls, next_solver::{ - AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper, - CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, OpaqueTypeKey, - RegionAssumptions, SolverContext, SolverDefIds, TraitIdWrapper, TypeAliasIdWrapper, - util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls}, + AdtIdWrapper, AnyImplId, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper, + CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, GeneralConstIdWrapper, OpaqueTypeKey, + RegionAssumptions, SimplifiedType, SolverContext, SolverDefIds, TraitIdWrapper, + TypeAliasIdWrapper, UnevaluatedConst, util::explicit_item_bounds, }, }; @@ -53,218 +59,262 @@ 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 } - 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_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) } + } + + #[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<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for $name<'db> { + impl $name<'_> { + #[inline] + pub fn store(self) -> $stored_name { + $stored_name::new(self) + } + } + }; +} +pub(crate) use impl_stored_interned_slice; + +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> 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))) } - } - - impl<'db> $name<'db> { - 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> { pub(crate) db: &'db dyn HirDatabase, - pub(crate) krate: Option<Crate>, - pub(crate) block: Option<BlockId>, + krate: Option<Crate>, + lang_items: Option<&'db LangItems>, } // FIXME: very wrong, see https://github.com/rust-lang/rust/pull/144808 @@ -277,22 +327,47 @@ impl<'db> DbInterner<'db> { crate::with_attached_db(|db| DbInterner { db: unsafe { std::mem::transmute::<&dyn HirDatabase, &'db dyn HirDatabase>(db) }, krate: None, - block: None, + lang_items: None, }) } - pub fn new_with( - db: &'db dyn HirDatabase, - krate: Option<Crate>, - block: Option<BlockId>, - ) -> DbInterner<'db> { - DbInterner { db, krate, block } + /// Creates a new interner without an active crate. Good only for interning things, not for trait solving etc.. + /// As a rule of thumb, when you create an `InferCtxt`, you need to provide the crate (and the block). + /// + /// Elaboration is a special kind: it needs lang items (for `Sized`), therefore it needs `new_with()`. + pub fn new_no_crate(db: &'db dyn HirDatabase) -> Self { + DbInterner { db, krate: None, lang_items: None } + } + + pub fn new_with(db: &'db dyn HirDatabase, krate: Crate) -> DbInterner<'db> { + DbInterner { + db, + krate: Some(krate), + // As an approximation, when we call `new_with` we're trait solving, therefore we need the lang items. + // This is also convenient since here we have a starting crate but not in `new_no_crate`. + lang_items: Some(hir_def::lang_item::lang_items(db, krate)), + } } #[inline] pub fn db(&self) -> &'db dyn HirDatabase { self.db } + + #[inline] + #[track_caller] + pub fn lang_items(&self) -> &'db LangItems { + self.lang_items.expect( + "Must have `DbInterner::lang_items`.\n\n\ + Note: you might have called `DbInterner::new_no_crate()` \ + 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 `()` @@ -305,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 { @@ -337,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; @@ -363,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); @@ -472,28 +561,28 @@ impl AdtDef { let variants = vec![(VariantIdx(0), VariantDef::Struct(struct_id))]; - let mut repr = ReprOptions::default(); - repr.align = data.repr.and_then(|r| r.align); - repr.pack = data.repr.and_then(|r| r.pack); - repr.int = data.repr.and_then(|r| r.int); - + let data_repr = data.repr(db, struct_id); let mut repr_flags = ReprFlags::empty(); if flags.is_box { repr_flags.insert(ReprFlags::IS_LINEAR); } - if data.repr.is_some_and(|r| r.c()) { + if data_repr.is_some_and(|r| r.c()) { repr_flags.insert(ReprFlags::IS_C); } - if data.repr.is_some_and(|r| r.simd()) { + if data_repr.is_some_and(|r| r.simd()) { repr_flags.insert(ReprFlags::IS_SIMD); } - repr.flags = repr_flags; + let repr = ReprOptions { + align: data_repr.and_then(|r| r.align), + pack: data_repr.and_then(|r| r.pack), + int: data_repr.and_then(|r| r.int), + flags: repr_flags, + ..ReprOptions::default() + }; (flags, variants, repr) } AdtId::UnionId(union_id) => { - let data = db.union_signature(union_id); - let flags = AdtFlags { is_enum: false, is_union: true, @@ -506,22 +595,24 @@ impl AdtDef { let variants = vec![(VariantIdx(0), VariantDef::Union(union_id))]; - let mut repr = ReprOptions::default(); - repr.align = data.repr.and_then(|r| r.align); - repr.pack = data.repr.and_then(|r| r.pack); - repr.int = data.repr.and_then(|r| r.int); - + let data_repr = AttrFlags::repr(db, union_id.into()); let mut repr_flags = ReprFlags::empty(); if flags.is_box { repr_flags.insert(ReprFlags::IS_LINEAR); } - if data.repr.is_some_and(|r| r.c()) { + if data_repr.is_some_and(|r| r.c()) { repr_flags.insert(ReprFlags::IS_C); } - if data.repr.is_some_and(|r| r.simd()) { + if data_repr.is_some_and(|r| r.simd()) { repr_flags.insert(ReprFlags::IS_SIMD); } - repr.flags = repr_flags; + let repr = ReprOptions { + align: data_repr.and_then(|r| r.align), + pack: data_repr.and_then(|r| r.pack), + int: data_repr.and_then(|r| r.int), + flags: repr_flags, + ..ReprOptions::default() + }; (flags, variants, repr) } @@ -545,24 +636,26 @@ impl AdtDef { .map(|(idx, v)| (idx, VariantDef::Enum(v.0))) .collect(); - let data = db.enum_signature(enum_id); - - let mut repr = ReprOptions::default(); - repr.align = data.repr.and_then(|r| r.align); - repr.pack = data.repr.and_then(|r| r.pack); - repr.int = data.repr.and_then(|r| r.int); + let data_repr = AttrFlags::repr(db, enum_id.into()); let mut repr_flags = ReprFlags::empty(); if flags.is_box { repr_flags.insert(ReprFlags::IS_LINEAR); } - if data.repr.is_some_and(|r| r.c()) { + if data_repr.is_some_and(|r| r.c()) { repr_flags.insert(ReprFlags::IS_C); } - if data.repr.is_some_and(|r| r.simd()) { + if data_repr.is_some_and(|r| r.simd()) { repr_flags.insert(ReprFlags::IS_SIMD); } - repr.flags = repr_flags; + + let repr = ReprOptions { + align: data_repr.and_then(|r| r.align), + pack: data_repr.and_then(|r| r.pack), + int: data_repr.and_then(|r| r.int), + flags: repr_flags, + ..ReprOptions::default() + }; (flags, variants, repr) } @@ -583,6 +676,10 @@ impl AdtDef { self.inner().flags.is_enum } + pub fn is_box(&self) -> bool { + self.inner().flags.is_box + } + #[inline] pub fn repr(self) -> ReprOptions { self.inner().repr @@ -622,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( @@ -632,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 { @@ -654,15 +751,10 @@ impl<'db> inherent::AdtDef<DbInterner<'db>> for AdtDef { interner: DbInterner<'db>, sizedness: SizedTraitKind, ) -> Option<EarlyBinder<DbInterner<'db>, Ty<'db>>> { - if self.is_struct() { - let tail_ty = self.all_field_tys(interner).skip_binder().into_iter().last()?; - - let constraint_ty = sizedness_constraint_for_ty(interner, sizedness, tail_ty)?; - - Some(EarlyBinder::bind(constraint_ty)) - } else { - None - } + let tail_ty = self.struct_tail_ty(interner)?; + tail_ty + .map_bound(|tail_ty| sizedness_constraint_for_ty(interner, sizedness, tail_ty)) + .transpose() } fn destructor( @@ -731,35 +823,41 @@ 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) } } impl<'db> Flags for Pattern<'db> { - fn flags(&self) -> rustc_type_ir::TypeFlags { + fn flags(&self) -> TypeFlags { match self.inner() { PatternKind::Range { start, end } => { FlagComputation::for_const_kind(&start.kind()).flags @@ -772,6 +870,7 @@ impl<'db> Flags for Pattern<'db> { } flags } + PatternKind::NotNull => TypeFlags::empty(), } } @@ -787,6 +886,7 @@ impl<'db> Flags for Pattern<'db> { } idx } + PatternKind::NotNull => rustc_type_ir::INNERMOST, } } } @@ -798,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, @@ -818,22 +948,26 @@ 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))) } - (PatternKind::Range { .. } | PatternKind::Or(_), _) => Err(TypeError::Mismatch), + (PatternKind::NotNull, PatternKind::NotNull) => Ok(a), + (PatternKind::Range { .. } | PatternKind::Or(_) | PatternKind::NotNull, _) => { + Err(TypeError::Mismatch) + } } } } -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 { ( - $solver_enum:ident, $var:ident; + $solver_enum:ident, $self:ident, $def_id:expr; ignore = { $( $ignore:ident ),* $(,)? @@ -841,6 +975,7 @@ macro_rules! as_lang_item { $( $variant:ident ),* $(,)? ) => {{ + let lang_items = $self.lang_items(); // Ensure exhaustiveness. if let Some(it) = None::<$solver_enum> { match it { @@ -848,13 +983,32 @@ macro_rules! as_lang_item { $( $solver_enum::$ignore => {} )* } } - match $var { - $( LangItem::$variant => Some($solver_enum::$variant), )* + match $def_id { + $( def_id if lang_items.$variant.is_some_and(|it| it == def_id) => Some($solver_enum::$variant), )* _ => None } }}; } +macro_rules! is_lang_item { + ( + $solver_enum:ident, $self:ident, $def_id:expr, $expected_variant:ident; + + ignore = { + $( $ignore:ident ),* $(,)? + } + + $( $variant:ident ),* $(,)? + ) => {{ + let lang_items = $self.lang_items(); + let def_id = $def_id; + match $expected_variant { + $( $solver_enum::$variant => lang_items.$variant.is_some_and(|it| it == def_id), )* + $( $solver_enum::$ignore => false, )* + } + }}; +} + impl<'db> Interner for DbInterner<'db> { type DefId = SolverDefId; type LocalDefId = SolverDefId; @@ -866,11 +1020,12 @@ impl<'db> Interner for DbInterner<'db> { type CoroutineClosureId = CoroutineIdWrapper; type CoroutineId = CoroutineIdWrapper; type AdtId = AdtIdWrapper; - type ImplId = ImplIdWrapper; + type ImplId = AnyImplId; + type UnevaluatedConstId = GeneralConstIdWrapper; type Span = Span; type GenericArgs = GenericArgs<'db>; - type GenericArgsSlice = GenericArgs<'db>; + type GenericArgsSlice = &'db [GenericArg<'db>]; type GenericArg = GenericArg<'db>; type Term = Term<'db>; @@ -884,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>; @@ -893,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>; @@ -911,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; @@ -955,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 @@ -963,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; @@ -1011,7 +1164,7 @@ impl<'db> Interner for DbInterner<'db> { } fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf { - generics(self.db(), def_id) + generics(self, def_id) } fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf { @@ -1037,9 +1190,10 @@ impl<'db> Interner for DbInterner<'db> { | SolverDefId::TraitId(_) | SolverDefId::TypeAliasId(_) | SolverDefId::ImplId(_) + | SolverDefId::BuiltinDeriveImplId(_) | SolverDefId::InternedClosureId(_) | SolverDefId::InternedCoroutineId(_) => { - return VariancesOf::new_from_iter(self, []); + return VariancesOf::empty(self); } }; self.db.variances_of(generic_def) @@ -1047,14 +1201,7 @@ impl<'db> Interner for DbInterner<'db> { fn type_of(self, def_id: Self::DefId) -> EarlyBinder<Self, Self::Ty> { match def_id { - SolverDefId::TypeAliasId(id) => { - use hir_def::Lookup; - match id.lookup(self.db()).container { - ItemContainerId::ImplId(it) => it, - _ => panic!("assoc ty value should be in impl"), - }; - self.db().ty(id.into()) - } + SolverDefId::TypeAliasId(id) => self.db().ty(id.into()), SolverDefId::AdtId(id) => self.db().ty(id.into()), // FIXME(next-solver): This uses the types of `query mir_borrowck` in rustc. // @@ -1124,12 +1271,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) } @@ -1152,7 +1296,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 { @@ -1184,6 +1328,7 @@ impl<'db> Interner for DbInterner<'db> { | SolverDefId::AdtId(_) | SolverDefId::TraitId(_) | SolverDefId::ImplId(_) + | SolverDefId::BuiltinDeriveImplId(_) | SolverDefId::EnumVariantId(..) | SolverDefId::Ctor(..) | SolverDefId::InternedOpaqueTyId(..) => panic!(), @@ -1236,8 +1381,7 @@ impl<'db> Interner for DbInterner<'db> { } fn generics_require_sized_self(self, def_id: Self::DefId) -> bool { - let sized_trait = - LangItem::Sized.resolve_trait(self.db(), self.krate.expect("Must have self.krate")); + let sized_trait = self.lang_items().Sized; let Some(sized_id) = sized_trait else { return false; /* No Sized trait, can't require it! */ }; @@ -1264,27 +1408,21 @@ impl<'db> Interner for DbInterner<'db> { }) } - #[tracing::instrument(skip(self), ret)] + #[tracing::instrument(skip(self))] fn item_bounds( self, def_id: Self::DefId, ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> { - explicit_item_bounds(self, def_id).map_bound(|bounds| { - Clauses::new_from_iter(self, elaborate(self, bounds).collect::<Vec<_>>()) - }) + explicit_item_bounds(self, def_id).map_bound(|bounds| elaborate(self, bounds)) } - #[tracing::instrument(skip(self), ret)] + #[tracing::instrument(skip(self))] fn item_self_bounds( self, def_id: Self::DefId, ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> { - explicit_item_bounds(self, def_id).map_bound(|bounds| { - Clauses::new_from_iter( - self, - elaborate(self, bounds).filter_only_self().collect::<Vec<_>>(), - ) - }) + explicit_item_bounds(self, def_id) + .map_bound(|bounds| elaborate(self, bounds).filter_only_self()) } fn item_non_self_bounds( @@ -1295,7 +1433,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, @@ -1309,9 +1447,7 @@ impl<'db> Interner for DbInterner<'db> { self, def_id: Self::DefId, ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> { - let predicates = self.db().generic_predicates(def_id.try_into().unwrap()); - let predicates: Vec<_> = predicates.iter().cloned().collect(); - EarlyBinder::bind(predicates.into_iter()) + predicates_of(self.db, def_id).all_predicates().map_bound(|it| it.iter().copied()) } #[tracing::instrument(level = "debug", skip(self), ret)] @@ -1319,9 +1455,7 @@ impl<'db> Interner for DbInterner<'db> { self, def_id: Self::DefId, ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> { - let predicates = self.db().generic_predicates_without_parent(def_id.try_into().unwrap()); - let predicates: Vec<_> = predicates.iter().cloned().collect(); - EarlyBinder::bind(predicates.into_iter()) + predicates_of(self.db, def_id).own_predicates().map_bound(|it| it.iter().copied()) } #[tracing::instrument(skip(self), ret)] @@ -1334,23 +1468,21 @@ impl<'db> Interner for DbInterner<'db> { _ => false, }; - let predicates: Vec<(Clause<'db>, Span)> = self - .db() - .generic_predicates(def_id.0.into()) - .iter() - .filter(|p| match p.kind().skip_binder() { - // rustc has the following assertion: - // https://github.com/rust-lang/rust/blob/52618eb338609df44978b0ca4451ab7941fd1c7a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs#L525-L608 - rustc_type_ir::ClauseKind::Trait(it) => is_self(it.self_ty()), - rustc_type_ir::ClauseKind::TypeOutlives(it) => is_self(it.0), - rustc_type_ir::ClauseKind::Projection(it) => is_self(it.self_ty()), - rustc_type_ir::ClauseKind::HostEffect(it) => is_self(it.self_ty()), - _ => false, - }) - .cloned() - .map(|p| (p, Span::dummy())) - .collect(); - EarlyBinder::bind(predicates) + GenericPredicates::query_explicit(self.db, def_id.0.into()).map_bound(move |predicates| { + predicates + .iter() + .copied() + .filter(move |p| match p.kind().skip_binder() { + // rustc has the following assertion: + // https://github.com/rust-lang/rust/blob/52618eb338609df44978b0ca4451ab7941fd1c7a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs#L525-L608 + ClauseKind::Trait(it) => is_self(it.self_ty()), + ClauseKind::TypeOutlives(it) => is_self(it.0), + ClauseKind::Projection(it) => is_self(it.self_ty()), + ClauseKind::HostEffect(it) => is_self(it.self_ty()), + _ => false, + }) + .map(|p| (p, Span::dummy())) + }) } #[tracing::instrument(skip(self), ret)] @@ -1368,43 +1500,38 @@ impl<'db> Interner for DbInterner<'db> { } } - let predicates: Vec<(Clause<'db>, Span)> = self - .db() - .generic_predicates(def_id.try_into().unwrap()) - .iter() - .filter(|p| match p.kind().skip_binder() { - rustc_type_ir::ClauseKind::Trait(it) => is_self_or_assoc(it.self_ty()), - rustc_type_ir::ClauseKind::TypeOutlives(it) => is_self_or_assoc(it.0), - rustc_type_ir::ClauseKind::Projection(it) => is_self_or_assoc(it.self_ty()), - rustc_type_ir::ClauseKind::HostEffect(it) => is_self_or_assoc(it.self_ty()), - // FIXME: Not sure is this correct to allow other clauses but we might replace - // `generic_predicates_ns` query here with something closer to rustc's - // `implied_bounds_with_filter`, which is more granular lowering than this - // "lower at once and then filter" implementation. - _ => true, - }) - .cloned() - .map(|p| (p, Span::dummy())) - .collect(); - EarlyBinder::bind(predicates) + predicates_of(self.db, def_id).explicit_predicates().map_bound(|predicates| { + predicates + .iter() + .copied() + .filter(|p| match p.kind().skip_binder() { + ClauseKind::Trait(it) => is_self_or_assoc(it.self_ty()), + ClauseKind::TypeOutlives(it) => is_self_or_assoc(it.0), + ClauseKind::Projection(it) => is_self_or_assoc(it.self_ty()), + ClauseKind::HostEffect(it) => is_self_or_assoc(it.self_ty()), + // FIXME: Not sure is this correct to allow other clauses but we might replace + // `generic_predicates_ns` query here with something closer to rustc's + // `implied_bounds_with_filter`, which is more granular lowering than this + // "lower at once and then filter" implementation. + _ => true, + }) + .map(|p| (p, Span::dummy())) + }) } fn impl_super_outlives( self, impl_id: Self::ImplId, ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> { - let trait_ref = self.db().impl_trait(impl_id.0).expect("expected an impl of trait"); + let trait_ref = self.impl_trait_ref(impl_id); trait_ref.map_bound(|trait_ref| { let clause: Clause<'_> = trait_ref.upcast(self); - Clauses::new_from_iter( - self, - rustc_type_ir::elaborate::elaborate(self, [clause]).filter(|clause| { - matches!( - clause.kind().skip_binder(), - ClauseKind::TypeOutlives(_) | ClauseKind::RegionOutlives(_) - ) - }), - ) + elaborate(self, [clause]).filter(|clause| { + matches!( + clause.kind().skip_binder(), + ClauseKind::TypeOutlives(_) | ClauseKind::RegionOutlives(_) + ) + }) }) } @@ -1424,84 +1551,70 @@ impl<'db> Interner for DbInterner<'db> { } fn require_lang_item(self, lang_item: SolverLangItem) -> Self::DefId { + let lang_items = self.lang_items(); let lang_item = match lang_item { SolverLangItem::AsyncFnKindUpvars => unimplemented!(), - SolverLangItem::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput, - SolverLangItem::CallOnceFuture => LangItem::CallOnceFuture, - SolverLangItem::CallRefFuture => LangItem::CallRefFuture, - SolverLangItem::CoroutineReturn => LangItem::CoroutineReturn, - SolverLangItem::CoroutineYield => LangItem::CoroutineYield, - SolverLangItem::DynMetadata => LangItem::DynMetadata, - SolverLangItem::FutureOutput => LangItem::FutureOutput, - SolverLangItem::Metadata => LangItem::Metadata, + SolverLangItem::AsyncFnOnceOutput => lang_items.AsyncFnOnceOutput, + SolverLangItem::CallOnceFuture => lang_items.CallOnceFuture, + SolverLangItem::CallRefFuture => lang_items.CallRefFuture, + SolverLangItem::CoroutineReturn => lang_items.CoroutineReturn, + SolverLangItem::CoroutineYield => lang_items.CoroutineYield, + SolverLangItem::FutureOutput => lang_items.FutureOutput, + SolverLangItem::Metadata => lang_items.Metadata, + SolverLangItem::DynMetadata => { + return lang_items.DynMetadata.expect("Lang item required but not found.").into(); + } }; - let target = hir_def::lang_item::lang_item( - self.db(), - self.krate.expect("Must have self.krate"), - lang_item, - ) - .unwrap_or_else(|| panic!("Lang item {lang_item:?} required but not found.")); - match target { - hir_def::lang_item::LangItemTarget::EnumId(enum_id) => enum_id.into(), - hir_def::lang_item::LangItemTarget::Function(function_id) => function_id.into(), - hir_def::lang_item::LangItemTarget::ImplDef(impl_id) => impl_id.into(), - hir_def::lang_item::LangItemTarget::Static(static_id) => static_id.into(), - hir_def::lang_item::LangItemTarget::Struct(struct_id) => struct_id.into(), - hir_def::lang_item::LangItemTarget::Union(union_id) => union_id.into(), - hir_def::lang_item::LangItemTarget::TypeAlias(type_alias_id) => type_alias_id.into(), - hir_def::lang_item::LangItemTarget::Trait(trait_id) => trait_id.into(), - hir_def::lang_item::LangItemTarget::EnumVariant(_) => unimplemented!(), - } + lang_item.expect("Lang item required but not found.").into() } fn require_trait_lang_item(self, lang_item: SolverTraitLangItem) -> TraitIdWrapper { + let lang_items = self.lang_items(); let lang_item = match lang_item { - SolverTraitLangItem::AsyncFn => LangItem::AsyncFn, + SolverTraitLangItem::AsyncFn => lang_items.AsyncFn, SolverTraitLangItem::AsyncFnKindHelper => unimplemented!(), - SolverTraitLangItem::AsyncFnMut => LangItem::AsyncFnMut, - SolverTraitLangItem::AsyncFnOnce => LangItem::AsyncFnOnce, - SolverTraitLangItem::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput, + SolverTraitLangItem::AsyncFnMut => lang_items.AsyncFnMut, + SolverTraitLangItem::AsyncFnOnce => lang_items.AsyncFnOnce, + SolverTraitLangItem::AsyncFnOnceOutput => unimplemented!( + "This is incorrectly marked as `SolverTraitLangItem`, and is not used by the solver." + ), SolverTraitLangItem::AsyncIterator => unimplemented!(), - SolverTraitLangItem::Clone => LangItem::Clone, - SolverTraitLangItem::Copy => LangItem::Copy, - SolverTraitLangItem::Coroutine => LangItem::Coroutine, - SolverTraitLangItem::Destruct => LangItem::Destruct, - SolverTraitLangItem::DiscriminantKind => LangItem::DiscriminantKind, - SolverTraitLangItem::Drop => LangItem::Drop, - SolverTraitLangItem::Fn => LangItem::Fn, - SolverTraitLangItem::FnMut => LangItem::FnMut, - SolverTraitLangItem::FnOnce => LangItem::FnOnce, - SolverTraitLangItem::FnPtrTrait => LangItem::FnPtrTrait, + SolverTraitLangItem::Clone => lang_items.Clone, + SolverTraitLangItem::Copy => lang_items.Copy, + SolverTraitLangItem::Coroutine => lang_items.Coroutine, + SolverTraitLangItem::Destruct => lang_items.Destruct, + SolverTraitLangItem::DiscriminantKind => lang_items.DiscriminantKind, + SolverTraitLangItem::Drop => lang_items.Drop, + SolverTraitLangItem::Fn => lang_items.Fn, + SolverTraitLangItem::FnMut => lang_items.FnMut, + SolverTraitLangItem::FnOnce => lang_items.FnOnce, + SolverTraitLangItem::FnPtrTrait => lang_items.FnPtrTrait, SolverTraitLangItem::FusedIterator => unimplemented!(), - SolverTraitLangItem::Future => LangItem::Future, - SolverTraitLangItem::Iterator => LangItem::Iterator, - SolverTraitLangItem::PointeeTrait => LangItem::PointeeTrait, - SolverTraitLangItem::Sized => LangItem::Sized, - SolverTraitLangItem::MetaSized => LangItem::MetaSized, - SolverTraitLangItem::PointeeSized => LangItem::PointeeSized, - SolverTraitLangItem::TransmuteTrait => LangItem::TransmuteTrait, - SolverTraitLangItem::Tuple => LangItem::Tuple, - SolverTraitLangItem::Unpin => LangItem::Unpin, - SolverTraitLangItem::Unsize => LangItem::Unsize, + SolverTraitLangItem::Future => lang_items.Future, + SolverTraitLangItem::Iterator => lang_items.Iterator, + SolverTraitLangItem::PointeeTrait => lang_items.PointeeTrait, + SolverTraitLangItem::Sized => lang_items.Sized, + SolverTraitLangItem::MetaSized => lang_items.MetaSized, + SolverTraitLangItem::PointeeSized => lang_items.PointeeSized, + SolverTraitLangItem::TransmuteTrait => lang_items.TransmuteTrait, + SolverTraitLangItem::Tuple => lang_items.Tuple, + SolverTraitLangItem::Unpin => lang_items.Unpin, + SolverTraitLangItem::Unsize => lang_items.Unsize, SolverTraitLangItem::BikeshedGuaranteedNoDrop => { unimplemented!() } + SolverTraitLangItem::TrivialClone => lang_items.TrivialClone, }; - lang_item - .resolve_trait(self.db(), self.krate.expect("Must have self.krate")) - .unwrap_or_else(|| panic!("Lang item {lang_item:?} required but not found.")) - .into() + lang_item.expect("Lang item required but not found.").into() } fn require_adt_lang_item(self, lang_item: SolverAdtLangItem) -> AdtIdWrapper { + let lang_items = self.lang_items(); let lang_item = match lang_item { - SolverAdtLangItem::Option => LangItem::Option, - SolverAdtLangItem::Poll => LangItem::Poll, + SolverAdtLangItem::Option => lang_items.Option, + SolverAdtLangItem::Poll => lang_items.Poll, }; - lang_item - .resolve_adt(self.db(), self.krate.expect("Must have self.krate")) - .unwrap_or_else(|| panic!("Lang item {lang_item:?} required but not found.")) - .into() + AdtIdWrapper(lang_item.expect("Lang item required but not found.").into()) } fn is_lang_item(self, def_id: Self::DefId, lang_item: SolverLangItem) -> bool { @@ -1510,8 +1623,42 @@ impl<'db> Interner for DbInterner<'db> { } fn is_trait_lang_item(self, def_id: Self::TraitId, lang_item: SolverTraitLangItem) -> bool { - self.as_trait_lang_item(def_id) - .map_or(false, |l| std::mem::discriminant(&l) == std::mem::discriminant(&lang_item)) + is_lang_item!( + SolverTraitLangItem, self, def_id.0, lang_item; + + ignore = { + AsyncFnKindHelper, + AsyncIterator, + BikeshedGuaranteedNoDrop, + FusedIterator, + AsyncFnOnceOutput, // This is incorrectly marked as `SolverTraitLangItem`, and is not used by the solver. + } + + Sized, + MetaSized, + PointeeSized, + Unsize, + Copy, + Clone, + DiscriminantKind, + PointeeTrait, + FnPtrTrait, + Drop, + Destruct, + TransmuteTrait, + Fn, + FnMut, + FnOnce, + Future, + Coroutine, + Unpin, + Tuple, + Iterator, + AsyncFn, + AsyncFnMut, + AsyncFnOnce, + TrivialClone, + ) } fn is_adt_lang_item(self, def_id: Self::AdtId, lang_item: SolverAdtLangItem) -> bool { @@ -1521,42 +1668,57 @@ impl<'db> Interner for DbInterner<'db> { } fn as_lang_item(self, def_id: Self::DefId) -> Option<SolverLangItem> { - let def_id: AttrDefId = match def_id { - SolverDefId::TraitId(id) => id.into(), - SolverDefId::TypeAliasId(id) => id.into(), - SolverDefId::AdtId(id) => id.into(), - _ => panic!("Unexpected SolverDefId in as_lang_item"), - }; - let lang_item = self.db().lang_attr(def_id)?; - as_lang_item!( - SolverLangItem, lang_item; + match def_id { + SolverDefId::TypeAliasId(id) => { + as_lang_item!( + SolverLangItem, self, id; - ignore = { - AsyncFnKindUpvars, + ignore = { + AsyncFnKindUpvars, + DynMetadata, + } + + Metadata, + CoroutineReturn, + CoroutineYield, + FutureOutput, + CallRefFuture, + CallOnceFuture, + AsyncFnOnceOutput, + ) } + SolverDefId::AdtId(AdtId::StructId(id)) => { + as_lang_item!( + SolverLangItem, self, id; + + ignore = { + AsyncFnKindUpvars, + Metadata, + CoroutineReturn, + CoroutineYield, + FutureOutput, + CallRefFuture, + CallOnceFuture, + AsyncFnOnceOutput, + } - Metadata, - DynMetadata, - CoroutineReturn, - CoroutineYield, - FutureOutput, - CallRefFuture, - CallOnceFuture, - AsyncFnOnceOutput, - ) + DynMetadata, + ) + } + _ => panic!("Unexpected SolverDefId in as_lang_item"), + } } fn as_trait_lang_item(self, def_id: Self::TraitId) -> Option<SolverTraitLangItem> { - let def_id: AttrDefId = def_id.0.into(); - let lang_item = self.db().lang_attr(def_id)?; as_lang_item!( - SolverTraitLangItem, lang_item; + SolverTraitLangItem, self, def_id.0; ignore = { AsyncFnKindHelper, AsyncIterator, BikeshedGuaranteedNoDrop, FusedIterator, + AsyncFnOnceOutput, // This is incorrectly marked as `SolverTraitLangItem`, and is not used by the solver. } Sized, @@ -1582,15 +1744,16 @@ impl<'db> Interner for DbInterner<'db> { AsyncFn, AsyncFnMut, AsyncFnOnce, - AsyncFnOnceOutput, + TrivialClone, ) } fn as_adt_lang_item(self, def_id: Self::AdtId) -> Option<SolverAdtLangItem> { - let def_id: AttrDefId = def_id.0.into(); - let lang_item = self.db().lang_attr(def_id)?; + let AdtId::EnumId(def_id) = def_id.0 else { + panic!("Unexpected SolverDefId in as_adt_lang_item"); + }; as_lang_item!( - SolverAdtLangItem, lang_item; + SolverAdtLangItem, self, def_id; ignore = {} @@ -1599,89 +1762,167 @@ impl<'db> Interner for DbInterner<'db> { ) } - fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId> { - let trait_ = match def_id { - SolverDefId::TraitId(id) => id, - _ => unreachable!(), - }; - trait_.trait_items(self.db()).associated_types().map(|id| id.into()) + fn associated_type_def_ids( + self, + def_id: Self::TraitId, + ) -> impl IntoIterator<Item = Self::DefId> { + def_id.0.trait_items(self.db()).associated_types().map(|id| id.into()) } fn for_each_relevant_impl( self, - trait_: Self::TraitId, + trait_def_id: Self::TraitId, self_ty: Self::Ty, mut f: impl FnMut(Self::ImplId), ) { - let trait_ = trait_.0; - let self_ty_fp = TyFingerprint::for_trait_impl(self_ty); - let fps: &[TyFingerprint] = match self_ty.kind() { - TyKind::Infer(InferTy::IntVar(..)) => &ALL_INT_FPS, - TyKind::Infer(InferTy::FloatVar(..)) => &ALL_FLOAT_FPS, - _ => self_ty_fp.as_slice(), - }; - - if fps.is_empty() { - _ = for_trait_impls( - self.db(), - self.krate.expect("Must have self.krate"), - self.block, - trait_, - self_ty_fp, - |impls| { - for i in impls.for_trait(trait_) { - use rustc_type_ir::TypeVisitable; - let contains_errors = self.db().impl_trait(i).map_or(false, |b| { - b.skip_binder().visit_with(&mut ContainsTypeErrors).is_break() - }); - if contains_errors { - continue; - } - - f(i.into()); + let krate = self.krate.expect("trait solving requires setting `DbInterner::krate`"); + let trait_block = trait_def_id.0.loc(self.db).container.block(self.db); + let mut consider_impls_for_simplified_type = |simp: SimplifiedType| { + let type_block = simp.def().and_then(|def_id| { + let module = match def_id { + SolverDefId::AdtId(AdtId::StructId(id)) => id.module(self.db), + SolverDefId::AdtId(AdtId::EnumId(id)) => id.module(self.db), + SolverDefId::AdtId(AdtId::UnionId(id)) => id.module(self.db), + SolverDefId::TraitId(id) => id.module(self.db), + SolverDefId::TypeAliasId(id) => id.module(self.db), + SolverDefId::ConstId(_) + | SolverDefId::FunctionId(_) + | SolverDefId::ImplId(_) + | SolverDefId::BuiltinDeriveImplId(_) + | SolverDefId::StaticId(_) + | SolverDefId::InternedClosureId(_) + | SolverDefId::InternedCoroutineId(_) + | SolverDefId::InternedOpaqueTyId(_) + | SolverDefId::EnumVariantId(_) + | SolverDefId::Ctor(_) => return None, + }; + module.block(self.db) + }); + TraitImpls::for_each_crate_and_block_trait_and_type( + self.db, + krate, + type_block, + trait_block, + &mut |impls| { + let (regular_impls, builtin_derive_impls) = + impls.for_trait_and_self_ty(trait_def_id.0, &simp); + for &impl_ in regular_impls { + f(impl_.into()); } - ControlFlow::Continue(()) - }, - ); - } else { - _ = for_trait_impls( - self.db(), - self.krate.expect("Must have self.krate"), - self.block, - trait_, - self_ty_fp, - |impls| { - for fp in fps { - for i in impls.for_trait_and_self_ty(trait_, *fp) { - use rustc_type_ir::TypeVisitable; - let contains_errors = self.db().impl_trait(i).map_or(false, |b| { - b.skip_binder().visit_with(&mut ContainsTypeErrors).is_break() - }); - if contains_errors { - continue; - } - - f(i.into()); - } + for &impl_ in builtin_derive_impls { + f(impl_.into()); } - ControlFlow::Continue(()) }, ); + }; + + match self_ty.kind() { + TyKind::Bool + | TyKind::Char + | TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::Adt(_, _) + | TyKind::Foreign(_) + | TyKind::Str + | TyKind::Array(_, _) + | TyKind::Pat(_, _) + | TyKind::Slice(_) + | TyKind::RawPtr(_, _) + | TyKind::Ref(_, _, _) + | TyKind::FnDef(_, _) + | TyKind::FnPtr(..) + | TyKind::Dynamic(_, _) + | TyKind::Closure(..) + | TyKind::CoroutineClosure(..) + | TyKind::Coroutine(_, _) + | TyKind::Never + | TyKind::Tuple(_) + | TyKind::UnsafeBinder(_) => { + let simp = + fast_reject::simplify_type(self, self_ty, fast_reject::TreatParams::AsRigid) + .unwrap(); + consider_impls_for_simplified_type(simp); + } + + // HACK: For integer and float variables we have to manually look at all impls + // which have some integer or float as a self type. + TyKind::Infer(InferTy::IntVar(_)) => { + use IntTy::*; + use UintTy::*; + // This causes a compiler error if any new integer kinds are added. + let (I8 | I16 | I32 | I64 | I128 | Isize): IntTy; + let (U8 | U16 | U32 | U64 | U128 | Usize): UintTy; + let possible_integers = [ + // signed integers + SimplifiedType::Int(I8), + SimplifiedType::Int(I16), + SimplifiedType::Int(I32), + SimplifiedType::Int(I64), + SimplifiedType::Int(I128), + SimplifiedType::Int(Isize), + // unsigned integers + SimplifiedType::Uint(U8), + SimplifiedType::Uint(U16), + SimplifiedType::Uint(U32), + SimplifiedType::Uint(U64), + SimplifiedType::Uint(U128), + SimplifiedType::Uint(Usize), + ]; + for simp in possible_integers { + consider_impls_for_simplified_type(simp); + } + } + + TyKind::Infer(InferTy::FloatVar(_)) => { + // This causes a compiler error if any new float kinds are added. + let (FloatTy::F16 | FloatTy::F32 | FloatTy::F64 | FloatTy::F128); + let possible_floats = [ + SimplifiedType::Float(FloatTy::F16), + SimplifiedType::Float(FloatTy::F32), + SimplifiedType::Float(FloatTy::F64), + SimplifiedType::Float(FloatTy::F128), + ]; + + for simp in possible_floats { + consider_impls_for_simplified_type(simp); + } + } + + // The only traits applying to aliases and placeholders are blanket impls. + // + // Impls which apply to an alias after normalization are handled by + // `assemble_candidates_after_normalizing_self_ty`. + TyKind::Alias(_, _) | TyKind::Placeholder(..) | TyKind::Error(_) => (), + + // FIXME: These should ideally not exist as a self type. It would be nice for + // the builtin auto trait impls of coroutines to instead directly recurse + // into the witness. + TyKind::CoroutineWitness(..) => (), + + // These variants should not exist as a self type. + TyKind::Infer( + InferTy::TyVar(_) + | InferTy::FreshTy(_) + | InferTy::FreshIntTy(_) + | InferTy::FreshFloatTy(_), + ) + | TyKind::Param(_) + | TyKind::Bound(_, _) => panic!("unexpected self type: {self_ty:?}"), } + + self.for_each_blanket_impl(trait_def_id, f) } fn for_each_blanket_impl(self, trait_def_id: Self::TraitId, mut f: impl FnMut(Self::ImplId)) { let Some(krate) = self.krate else { return }; + let block = trait_def_id.0.loc(self.db).container.block(self.db); - for impls in self.db.trait_impls_in_deps(krate).iter() { - for impl_id in impls.for_trait(trait_def_id.0) { - let impl_data = self.db.impl_signature(impl_id); - let self_ty_ref = &impl_data.store[impl_data.self_ty]; - if matches!(self_ty_ref, hir_def::type_ref::TypeRef::TypeParam(_)) { - f(impl_id.into()); - } + TraitImpls::for_each_crate_and_block(self.db, krate, block, &mut |impls| { + for &impl_ in impls.blanket_impls(trait_def_id.0) { + f(impl_.into()); } - } + }); } fn has_item_definition(self, _def_id: Self::DefId) -> bool { @@ -1690,7 +1931,10 @@ impl<'db> Interner for DbInterner<'db> { } fn impl_is_default(self, impl_def_id: Self::ImplId) -> bool { - self.db.impl_signature(impl_def_id.0).is_default() + match impl_def_id { + AnyImplId::ImplId(impl_id) => self.db.impl_signature(impl_id).is_default(), + AnyImplId::BuiltinDeriveImplId(_) => false, + } } #[tracing::instrument(skip(self), ret)] @@ -1698,14 +1942,24 @@ impl<'db> Interner for DbInterner<'db> { self, impl_id: Self::ImplId, ) -> EarlyBinder<Self, rustc_type_ir::TraitRef<Self>> { - let db = self.db(); - db.impl_trait(impl_id.0) - // ImplIds for impls where the trait ref can't be resolved should never reach trait solving - .expect("invalid impl passed to trait solver") + match impl_id { + AnyImplId::ImplId(impl_id) => { + let db = self.db(); + db.impl_trait(impl_id) + // ImplIds for impls where the trait ref can't be resolved should never reach trait solving + .expect("invalid impl passed to trait solver") + } + AnyImplId::BuiltinDeriveImplId(impl_id) => { + crate::builtin_derive::impl_trait(self, impl_id) + } + } } fn impl_polarity(self, impl_id: Self::ImplId) -> rustc_type_ir::ImplPolarity { - let impl_data = self.db().impl_signature(impl_id.0); + let AnyImplId::ImplId(impl_id) = impl_id else { + return ImplPolarity::Positive; + }; + let impl_data = self.db().impl_signature(impl_id); if impl_data.flags.contains(ImplFlags::NEGATIVE) { ImplPolarity::Negative } else { @@ -1808,7 +2062,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); @@ -1818,7 +2072,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); } @@ -1866,9 +2120,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) } @@ -1878,7 +2130,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 { @@ -1907,7 +2159,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 { @@ -1952,10 +2204,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() } } } @@ -1995,11 +2247,13 @@ impl<'db> Interner for DbInterner<'db> { specializing_impl_def_id: Self::ImplId, parent_impl_def_id: Self::ImplId, ) -> bool { - crate::specialization::specializes( - self.db, - specializing_impl_def_id.0, - parent_impl_def_id.0, - ) + let (AnyImplId::ImplId(specializing_impl_def_id), AnyImplId::ImplId(parent_impl_def_id)) = + (specializing_impl_def_id, parent_impl_def_id) + else { + // No builtin derive allow specialization currently. + return false; + }; + crate::specialization::specializes(self.db, specializing_impl_def_id, parent_impl_def_id) } fn next_trait_solver_globally(self) -> bool { @@ -2026,6 +2280,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> { @@ -2102,6 +2368,14 @@ impl<'db> DbInterner<'db> { } } +fn predicates_of(db: &dyn HirDatabase, def_id: SolverDefId) -> &GenericPredicates { + if let SolverDefId::BuiltinDeriveImplId(impl_) = def_id { + crate::builtin_derive::predicates(db, impl_) + } else { + GenericPredicates::query(db, def_id.try_into().unwrap()) + } +} + macro_rules! TrivialTypeTraversalImpls { ($($ty:ty,)+) => { $( @@ -2132,6 +2406,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) {} + } )+ }; } @@ -2144,18 +2423,24 @@ TrivialTypeTraversalImpls! { ClosureIdWrapper, CoroutineIdWrapper, AdtIdWrapper, - ImplIdWrapper, - Pattern<'db>, + AnyImplId, + GeneralConstIdWrapper, Safety, FnAbi, Span, ParamConst, ParamTy, BoundRegion, - BoundVar, Placeholder<BoundRegion>, Placeholder<BoundTy>, Placeholder<BoundVar>, + Placeholder<BoundConst>, + BoundVarKind, + EarlyParamRegion, + LateParamRegion, + AdtDef, + BoundTy, + BoundConst, } mod tls_db { @@ -2322,3 +2607,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, +); |