| //! Things related to the Interner in the next-trait-solver. |
| #![allow(unused)] |
| |
| use base_db::Crate; |
| use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variances}; |
| use hir_def::lang_item::LangItem; |
| use hir_def::signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags}; |
| use hir_def::{AdtId, BlockId, GenericDefId, TypeAliasId, VariantId}; |
| use hir_def::{AttrDefId, Lookup}; |
| use hir_def::{CallableDefId, EnumVariantId, ItemContainerId, StructId, UnionId}; |
| use intern::sym::non_exhaustive; |
| use intern::{Interned, impl_internable, sym}; |
| use la_arena::Idx; |
| use rustc_abi::{Align, ReprFlags, ReprOptions}; |
| use rustc_hash::FxHashSet; |
| use rustc_index::bit_set::DenseBitSet; |
| use rustc_type_ir::elaborate::elaborate; |
| use rustc_type_ir::error::TypeError; |
| use rustc_type_ir::inherent::{ |
| AdtDef as _, GenericArgs as _, GenericsOf, IntoKind, SliceLike as _, Span as _, |
| }; |
| use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; |
| use rustc_type_ir::solve::SizedTraitKind; |
| use rustc_type_ir::{ |
| AliasTerm, AliasTermKind, AliasTy, AliasTyKind, EarlyBinder, FlagComputation, Flags, |
| ImplPolarity, InferTy, ProjectionPredicate, TraitPredicate, TraitRef, Upcast, |
| }; |
| use salsa::plumbing::AsId; |
| use smallvec::{SmallVec, smallvec}; |
| use std::fmt; |
| use std::ops::ControlFlow; |
| use syntax::ast::SelfParamKind; |
| use triomphe::Arc; |
| |
| use rustc_ast_ir::visit::VisitorResult; |
| use rustc_index::IndexVec; |
| use rustc_type_ir::TypeVisitableExt; |
| use rustc_type_ir::{ |
| BoundVar, CollectAndApply, DebruijnIndex, GenericArgKind, RegionKind, TermKind, UniverseIndex, |
| Variance, WithCachedTypeInfo, elaborate, |
| inherent::{self, Const as _, Region as _, Ty as _}, |
| ir_print, relate, |
| }; |
| |
| use crate::lower_nextsolver::{self, TyLoweringContext}; |
| use crate::method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TyFingerprint}; |
| use crate::next_solver::infer::InferCtxt; |
| use crate::next_solver::util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls}; |
| use crate::next_solver::{ |
| AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper, |
| CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, InternedWrapperNoDebug, |
| RegionAssumptions, SolverContext, SolverDefIds, TraitIdWrapper, TypeAliasIdWrapper, |
| }; |
| use crate::{ConstScalar, FnAbi, Interner, db::HirDatabase}; |
| |
| use super::generics::generics; |
| use super::util::sizedness_constraint_for_ty; |
| use super::{ |
| Binder, BoundExistentialPredicate, BoundExistentialPredicates, BoundTy, BoundTyKind, Clause, |
| Clauses, Const, ConstKind, ErrorGuaranteed, ExprConst, ExternalConstraints, |
| ExternalConstraintsData, GenericArg, GenericArgs, InternedClausesWrapper, ParamConst, ParamEnv, |
| ParamTy, PlaceholderConst, PlaceholderTy, PredefinedOpaques, PredefinedOpaquesData, Predicate, |
| PredicateKind, Term, Ty, TyKind, Tys, ValueConst, |
| abi::Safety, |
| fold::{BoundVarReplacer, BoundVarReplacerDelegate, FnMutDelegate}, |
| generics::Generics, |
| mapping::ChalkToNextSolver, |
| region::{ |
| BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, PlaceholderRegion, Region, |
| }, |
| }; |
| use super::{ClauseKind, SolverDefId, Valtree}; |
| |
| #[macro_export] |
| #[doc(hidden)] |
| macro_rules! _interned_vec_nolifetime_salsa { |
| ($name:ident, $ty:ty) => { |
| interned_vec_nolifetime_salsa!($name, $ty, nofold); |
| |
| impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for $name { |
| 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) |
| } |
| } |
| |
| impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for $name { |
| 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() |
| } |
| } |
| }; |
| ($name:ident, $ty:ty, nofold) => { |
| #[salsa::interned(no_lifetime, constructor = new_, debug)] |
| pub struct $name { |
| #[returns(ref)] |
| inner_: smallvec::SmallVec<[$ty; 2]>, |
| } |
| |
| impl $name { |
| pub fn new_from_iter<'db>( |
| interner: DbInterner<'db>, |
| data: impl IntoIterator<Item = $ty>, |
| ) -> Self { |
| $name::new_(interner.db(), data.into_iter().collect::<smallvec::SmallVec<[_; 2]>>()) |
| } |
| |
| pub fn inner(&self) -> &smallvec::SmallVec<[$ty; 2]> { |
| // SAFETY: ¯\_(ツ)_/¯ |
| salsa::with_attached_database(|db| { |
| let inner = self.inner_(db); |
| unsafe { std::mem::transmute(inner) } |
| }) |
| .unwrap() |
| } |
| } |
| |
| impl rustc_type_ir::inherent::SliceLike for $name { |
| type Item = $ty; |
| |
| type IntoIter = <smallvec::SmallVec<[$ty; 2]> as IntoIterator>::IntoIter; |
| |
| fn iter(self) -> Self::IntoIter { |
| self.inner().clone().into_iter() |
| } |
| |
| fn as_slice(&self) -> &[Self::Item] { |
| self.inner().as_slice() |
| } |
| } |
| |
| impl IntoIterator for $name { |
| 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 Default for $name { |
| fn default() -> Self { |
| $name::new_from_iter(DbInterner::conjure(), []) |
| } |
| } |
| }; |
| } |
| |
| pub use crate::_interned_vec_nolifetime_salsa as interned_vec_nolifetime_salsa; |
| |
| #[macro_export] |
| #[doc(hidden)] |
| macro_rules! _interned_vec_db { |
| ($name:ident, $ty:ident) => { |
| interned_vec_db!($name, $ty, nofold); |
| |
| 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) |
| } |
| } |
| |
| 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() |
| } |
| } |
| }; |
| ($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 new_from_iter( |
| interner: DbInterner<'db>, |
| data: impl IntoIterator<Item = $ty<'db>>, |
| ) -> Self { |
| $name::new_(interner.db(), data.into_iter().collect::<smallvec::SmallVec<[_; 2]>>()) |
| } |
| |
| pub fn inner(&self) -> &smallvec::SmallVec<[$ty<'db>; 2]> { |
| // SAFETY: ¯\_(ツ)_/¯ |
| salsa::with_attached_database(|db| { |
| let inner = self.inner_(db); |
| unsafe { std::mem::transmute(inner) } |
| }) |
| .unwrap() |
| } |
| } |
| |
| impl<'db> rustc_type_ir::inherent::SliceLike for $name<'db> { |
| type Item = $ty<'db>; |
| |
| type IntoIter = <smallvec::SmallVec<[$ty<'db>; 2]> as IntoIterator>::IntoIter; |
| |
| fn iter(self) -> Self::IntoIter { |
| self.inner().clone().into_iter() |
| } |
| |
| fn as_slice(&self) -> &[Self::Item] { |
| self.inner().as_slice() |
| } |
| } |
| |
| impl<'db> IntoIterator for $name<'db> { |
| type Item = $ty<'db>; |
| 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> { |
| fn default() -> Self { |
| $name::new_from_iter(DbInterner::conjure(), []) |
| } |
| } |
| }; |
| } |
| |
| pub use crate::_interned_vec_db as interned_vec_db; |
| |
| #[derive(Debug, Copy, Clone)] |
| pub struct DbInterner<'db> { |
| pub(crate) db: &'db dyn HirDatabase, |
| pub(crate) krate: Option<Crate>, |
| pub(crate) block: Option<BlockId>, |
| } |
| |
| // FIXME: very wrong, see https://github.com/rust-lang/rust/pull/144808 |
| unsafe impl Send for DbInterner<'_> {} |
| unsafe impl Sync for DbInterner<'_> {} |
| |
| impl<'db> DbInterner<'db> { |
| // FIXME(next-solver): remove this method |
| pub fn conjure() -> DbInterner<'db> { |
| salsa::with_attached_database(|db| DbInterner { |
| db: unsafe { |
| std::mem::transmute::<&dyn HirDatabase, &'db dyn HirDatabase>(db.as_view()) |
| }, |
| krate: None, |
| block: None, |
| }) |
| .expect("db is expected to be attached") |
| } |
| |
| pub fn new_with( |
| db: &'db dyn HirDatabase, |
| krate: Option<Crate>, |
| block: Option<BlockId>, |
| ) -> DbInterner<'db> { |
| DbInterner { db, krate, block } |
| } |
| |
| pub fn db(&self) -> &'db dyn HirDatabase { |
| self.db |
| } |
| } |
| |
| // This is intentionally left as `()` |
| #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] |
| pub struct Span(()); |
| |
| impl<'db> inherent::Span<DbInterner<'db>> for Span { |
| fn dummy() -> Self { |
| Span(()) |
| } |
| } |
| |
| interned_vec_nolifetime_salsa!(BoundVarKinds, BoundVarKind, nofold); |
| |
| #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] |
| pub enum BoundVarKind { |
| Ty(BoundTyKind), |
| Region(BoundRegionKind), |
| Const, |
| } |
| |
| impl BoundVarKind { |
| pub fn expect_region(self) -> BoundRegionKind { |
| match self { |
| BoundVarKind::Region(lt) => lt, |
| _ => panic!("expected a region, but found another kind"), |
| } |
| } |
| |
| pub fn expect_ty(self) -> BoundTyKind { |
| match self { |
| BoundVarKind::Ty(ty) => ty, |
| _ => panic!("expected a type, but found another kind"), |
| } |
| } |
| |
| pub fn expect_const(self) { |
| match self { |
| BoundVarKind::Const => (), |
| _ => panic!("expected a const, but found another kind"), |
| } |
| } |
| } |
| |
| interned_vec_db!(CanonicalVars, CanonicalVarKind, nofold); |
| |
| pub struct DepNodeIndex; |
| |
| #[derive(Debug)] |
| pub struct Tracked<T: fmt::Debug + Clone>(T); |
| |
| #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] |
| pub struct Placeholder<T> { |
| pub universe: UniverseIndex, |
| pub bound: T, |
| } |
| |
| impl<T: std::fmt::Debug> std::fmt::Debug for Placeholder<T> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { |
| if self.universe == UniverseIndex::ROOT { |
| write!(f, "!{:?}", self.bound) |
| } else { |
| write!(f, "!{}_{:?}", self.universe.index(), self.bound) |
| } |
| } |
| } |
| |
| #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] |
| pub struct AllocId; |
| |
| interned_vec_nolifetime_salsa!(VariancesOf, Variance, nofold); |
| |
| #[derive(Debug, Clone, Eq, PartialEq, Hash)] |
| pub struct VariantIdx(usize); |
| |
| // FIXME: could/should store actual data? |
| #[derive(Debug, Clone, Eq, PartialEq, Hash)] |
| pub enum VariantDef { |
| Struct(StructId), |
| Union(UnionId), |
| Enum(EnumVariantId), |
| } |
| |
| impl VariantDef { |
| pub fn id(&self) -> VariantId { |
| match self { |
| VariantDef::Struct(struct_id) => VariantId::StructId(*struct_id), |
| VariantDef::Union(union_id) => VariantId::UnionId(*union_id), |
| VariantDef::Enum(enum_variant_id) => VariantId::EnumVariantId(*enum_variant_id), |
| } |
| } |
| |
| pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Idx<FieldData>, FieldData)> { |
| let id: VariantId = match self { |
| VariantDef::Struct(it) => (*it).into(), |
| VariantDef::Union(it) => (*it).into(), |
| VariantDef::Enum(it) => (*it).into(), |
| }; |
| id.fields(db).fields().iter().map(|(id, data)| (id, data.clone())).collect() |
| } |
| } |
| |
| /* |
| /// Definition of a variant -- a struct's fields or an enum variant. |
| #[derive(Debug, HashStable, TyEncodable, TyDecodable)] |
| pub struct VariantDef { |
| /// `DefId` that identifies the variant itself. |
| /// If this variant belongs to a struct or union, then this is a copy of its `DefId`. |
| pub def_id: DefId, |
| /// `DefId` that identifies the variant's constructor. |
| /// If this variant is a struct variant, then this is `None`. |
| pub ctor: Option<(CtorKind, DefId)>, |
| /// Variant or struct name, maybe empty for anonymous adt (struct or union). |
| pub name: Symbol, |
| /// Discriminant of this variant. |
| pub discr: VariantDiscr, |
| /// Fields of this variant. |
| pub fields: IndexVec<FieldIdx, FieldDef>, |
| /// The error guarantees from parser, if any. |
| tainted: Option<ErrorGuaranteed>, |
| /// Flags of the variant (e.g. is field list non-exhaustive)? |
| flags: VariantFlags, |
| } |
| */ |
| |
| #[derive(Debug, Clone, Eq, PartialEq, Hash)] |
| pub struct AdtFlags { |
| is_enum: bool, |
| is_union: bool, |
| is_struct: bool, |
| is_phantom_data: bool, |
| is_fundamental: bool, |
| is_box: bool, |
| is_manually_drop: bool, |
| } |
| |
| #[derive(Debug, Clone, PartialEq, Eq)] |
| pub struct AdtDefInner { |
| pub id: AdtId, |
| variants: Vec<(VariantIdx, VariantDef)>, |
| flags: AdtFlags, |
| repr: ReprOptions, |
| } |
| |
| // We're gonna cheat a little bit and implement `Hash` on only the `DefId` and |
| // accept there might be collisions for def ids from different crates (or across |
| // different tests, oh my). |
| impl std::hash::Hash for AdtDefInner { |
| #[inline] |
| fn hash<H: std::hash::Hasher>(&self, s: &mut H) { |
| self.id.hash(s) |
| } |
| } |
| |
| #[salsa::interned(no_lifetime, constructor = new_)] |
| pub struct AdtDef { |
| #[returns(ref)] |
| data_: AdtDefInner, |
| } |
| |
| impl AdtDef { |
| pub fn new<'db>(def_id: AdtId, interner: DbInterner<'db>) -> Self { |
| let db = interner.db(); |
| let (flags, variants, repr) = match def_id { |
| AdtId::StructId(struct_id) => { |
| let data = db.struct_signature(struct_id); |
| |
| let flags = AdtFlags { |
| is_enum: false, |
| is_union: false, |
| is_struct: true, |
| is_phantom_data: data.flags.contains(StructFlags::IS_PHANTOM_DATA), |
| is_fundamental: data.flags.contains(StructFlags::FUNDAMENTAL), |
| is_box: data.flags.contains(StructFlags::IS_BOX), |
| is_manually_drop: data.flags.contains(StructFlags::IS_MANUALLY_DROP), |
| }; |
| |
| 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 mut repr_flags = ReprFlags::empty(); |
| if flags.is_box { |
| repr_flags.insert(ReprFlags::IS_LINEAR); |
| } |
| if data.repr.is_some_and(|r| r.c()) { |
| repr_flags.insert(ReprFlags::IS_C); |
| } |
| if data.repr.is_some_and(|r| r.simd()) { |
| repr_flags.insert(ReprFlags::IS_SIMD); |
| } |
| repr.flags = repr_flags; |
| |
| (flags, variants, repr) |
| } |
| AdtId::UnionId(union_id) => { |
| let data = db.union_signature(union_id); |
| |
| let flags = AdtFlags { |
| is_enum: false, |
| is_union: true, |
| is_struct: false, |
| is_phantom_data: false, |
| is_fundamental: false, |
| is_box: false, |
| is_manually_drop: false, |
| }; |
| |
| 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 mut repr_flags = ReprFlags::empty(); |
| if flags.is_box { |
| repr_flags.insert(ReprFlags::IS_LINEAR); |
| } |
| if data.repr.is_some_and(|r| r.c()) { |
| repr_flags.insert(ReprFlags::IS_C); |
| } |
| if data.repr.is_some_and(|r| r.simd()) { |
| repr_flags.insert(ReprFlags::IS_SIMD); |
| } |
| repr.flags = repr_flags; |
| |
| (flags, variants, repr) |
| } |
| AdtId::EnumId(enum_id) => { |
| let flags = AdtFlags { |
| is_enum: true, |
| is_union: false, |
| is_struct: false, |
| is_phantom_data: false, |
| is_fundamental: false, |
| is_box: false, |
| is_manually_drop: false, |
| }; |
| |
| let variants = enum_id |
| .enum_variants(db) |
| .variants |
| .iter() |
| .enumerate() |
| .map(|(idx, v)| (VariantIdx(idx), v)) |
| .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 mut repr_flags = ReprFlags::empty(); |
| if flags.is_box { |
| repr_flags.insert(ReprFlags::IS_LINEAR); |
| } |
| if data.repr.is_some_and(|r| r.c()) { |
| repr_flags.insert(ReprFlags::IS_C); |
| } |
| if data.repr.is_some_and(|r| r.simd()) { |
| repr_flags.insert(ReprFlags::IS_SIMD); |
| } |
| repr.flags = repr_flags; |
| |
| (flags, variants, repr) |
| } |
| }; |
| |
| AdtDef::new_(db, AdtDefInner { id: def_id, variants, flags, repr }) |
| } |
| |
| pub fn inner(&self) -> &AdtDefInner { |
| salsa::with_attached_database(|db| { |
| let inner = self.data_(db); |
| // SAFETY: ¯\_(ツ)_/¯ |
| unsafe { std::mem::transmute(inner) } |
| }) |
| .unwrap() |
| } |
| |
| pub fn is_enum(&self) -> bool { |
| self.inner().flags.is_enum |
| } |
| |
| #[inline] |
| pub fn repr(self) -> ReprOptions { |
| self.inner().repr |
| } |
| |
| /// Asserts this is a struct or union and returns its unique variant. |
| pub fn non_enum_variant(self) -> VariantDef { |
| assert!(self.inner().flags.is_struct || self.inner().flags.is_union); |
| self.inner().variants[0].1.clone() |
| } |
| } |
| |
| impl<'db> inherent::AdtDef<DbInterner<'db>> for AdtDef { |
| fn def_id(self) -> AdtIdWrapper { |
| self.inner().id.into() |
| } |
| |
| fn is_struct(self) -> bool { |
| self.inner().flags.is_struct |
| } |
| |
| fn is_phantom_data(self) -> bool { |
| self.inner().flags.is_phantom_data |
| } |
| |
| fn is_fundamental(self) -> bool { |
| self.inner().flags.is_fundamental |
| } |
| |
| fn struct_tail_ty( |
| self, |
| interner: DbInterner<'db>, |
| ) -> Option<EarlyBinder<DbInterner<'db>, Ty<'db>>> { |
| let db = interner.db(); |
| let hir_def::AdtId::StructId(struct_id) = self.inner().id else { |
| return None; |
| }; |
| let id: VariantId = struct_id.into(); |
| let field_types = interner.db().field_types_ns(id); |
| |
| field_types.iter().last().map(|f| *f.1) |
| } |
| |
| fn all_field_tys( |
| self, |
| interner: DbInterner<'db>, |
| ) -> EarlyBinder<DbInterner<'db>, impl IntoIterator<Item = Ty<'db>>> { |
| let db = interner.db(); |
| // FIXME: this is disabled just to match the behavior with chalk right now |
| let field_tys = |id: VariantId| { |
| let variant_data = id.fields(db); |
| let fields = if variant_data.fields().is_empty() { |
| vec![] |
| } else { |
| let field_types = db.field_types_ns(id); |
| variant_data |
| .fields() |
| .iter() |
| .map(|(idx, _)| { |
| let ty = field_types[idx]; |
| ty.skip_binder() |
| }) |
| .collect() |
| }; |
| }; |
| let field_tys = |id: VariantId| vec![]; |
| let tys: Vec<_> = match self.inner().id { |
| hir_def::AdtId::StructId(id) => field_tys(id.into()), |
| hir_def::AdtId::UnionId(id) => field_tys(id.into()), |
| hir_def::AdtId::EnumId(id) => id |
| .enum_variants(db) |
| .variants |
| .iter() |
| .flat_map(|&(variant_id, _, _)| field_tys(variant_id.into())) |
| .collect(), |
| }; |
| |
| EarlyBinder::bind(tys) |
| } |
| |
| fn sizedness_constraint( |
| self, |
| 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 |
| } |
| } |
| |
| fn destructor( |
| self, |
| interner: DbInterner<'db>, |
| ) -> Option<rustc_type_ir::solve::AdtDestructorKind> { |
| // FIXME(next-solver) |
| None |
| } |
| |
| fn is_manually_drop(self) -> bool { |
| self.inner().flags.is_manually_drop |
| } |
| } |
| |
| impl fmt::Debug for AdtDef { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| salsa::with_attached_database(|db| match self.inner().id { |
| AdtId::StructId(struct_id) => { |
| let data = db.as_view::<dyn HirDatabase>().struct_signature(struct_id); |
| f.write_str(data.name.as_str()) |
| } |
| AdtId::UnionId(union_id) => { |
| let data = db.as_view::<dyn HirDatabase>().union_signature(union_id); |
| f.write_str(data.name.as_str()) |
| } |
| AdtId::EnumId(enum_id) => { |
| let data = db.as_view::<dyn HirDatabase>().enum_signature(enum_id); |
| f.write_str(data.name.as_str()) |
| } |
| }) |
| .unwrap_or_else(|| f.write_str(&format!("AdtDef({:?})", self.inner().id))) |
| } |
| } |
| |
| #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] |
| pub struct Features; |
| |
| impl<'db> inherent::Features<DbInterner<'db>> for Features { |
| fn generic_const_exprs(self) -> bool { |
| false |
| } |
| |
| fn coroutine_clone(self) -> bool { |
| false |
| } |
| |
| fn associated_const_equality(self) -> bool { |
| false |
| } |
| |
| fn feature_bound_holds_in_crate(self, symbol: ()) -> bool { |
| false |
| } |
| } |
| |
| #[derive(Debug, Clone, Eq, PartialEq, Hash)] |
| pub struct UnsizingParams(pub(crate) DenseBitSet<u32>); |
| |
| impl std::ops::Deref for UnsizingParams { |
| type Target = DenseBitSet<u32>; |
| |
| fn deref(&self) -> &Self::Target { |
| &self.0 |
| } |
| } |
| |
| pub type PatternKind<'db> = rustc_type_ir::PatternKind<DbInterner<'db>>; |
| |
| #[salsa::interned(constructor = new_, debug)] |
| pub struct Pattern<'db> { |
| #[returns(ref)] |
| kind_: InternedWrapperNoDebug<PatternKind<'db>>, |
| } |
| |
| impl<'db> std::fmt::Debug for InternedWrapperNoDebug<PatternKind<'db>> { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| self.0.fmt(f) |
| } |
| } |
| |
| impl<'db> Pattern<'db> { |
| pub fn new(interner: DbInterner<'db>, kind: PatternKind<'db>) -> Self { |
| Pattern::new_(interner.db(), InternedWrapperNoDebug(kind)) |
| } |
| |
| pub fn inner(&self) -> &PatternKind<'db> { |
| salsa::with_attached_database(|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) } |
| }) |
| .unwrap() |
| } |
| } |
| |
| impl<'db> Flags for Pattern<'db> { |
| fn flags(&self) -> rustc_type_ir::TypeFlags { |
| match self.inner() { |
| PatternKind::Range { start, end } => { |
| FlagComputation::for_const_kind(&start.kind()).flags |
| | FlagComputation::for_const_kind(&end.kind()).flags |
| } |
| PatternKind::Or(pats) => { |
| let mut flags = pats.as_slice()[0].flags(); |
| for pat in pats.as_slice()[1..].iter() { |
| flags |= pat.flags(); |
| } |
| flags |
| } |
| } |
| } |
| |
| fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex { |
| match self.inner() { |
| PatternKind::Range { start, end } => { |
| start.outer_exclusive_binder().max(end.outer_exclusive_binder()) |
| } |
| PatternKind::Or(pats) => { |
| let mut idx = pats.as_slice()[0].outer_exclusive_binder(); |
| for pat in pats.as_slice()[1..].iter() { |
| idx = idx.max(pat.outer_exclusive_binder()); |
| } |
| idx |
| } |
| } |
| } |
| } |
| |
| impl<'db> rustc_type_ir::inherent::IntoKind for Pattern<'db> { |
| type Kind = rustc_type_ir::PatternKind<DbInterner<'db>>; |
| fn kind(self) -> Self::Kind { |
| *self.inner() |
| } |
| } |
| |
| 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, |
| a: Self, |
| b: Self, |
| ) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> { |
| let tcx = relation.cx(); |
| match (a.kind(), b.kind()) { |
| ( |
| PatternKind::Range { start: start_a, end: end_a }, |
| PatternKind::Range { start: start_b, end: end_b }, |
| ) => { |
| let start = relation.relate(start_a, start_b)?; |
| let end = relation.relate(end_a, end_b)?; |
| Ok(Pattern::new(tcx, PatternKind::Range { start, end })) |
| } |
| (PatternKind::Or(a), PatternKind::Or(b)) => { |
| if a.len() != b.len() { |
| return Err(TypeError::Mismatch); |
| } |
| let pats = CollectAndApply::collect_and_apply( |
| 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), |
| } |
| } |
| } |
| |
| interned_vec_db!(PatList, Pattern); |
| |
| macro_rules! as_lang_item { |
| ( |
| $solver_enum:ident, $var:ident; |
| |
| ignore = { |
| $( $ignore:ident ),* $(,)? |
| } |
| |
| $( $variant:ident ),* $(,)? |
| ) => {{ |
| // Ensure exhaustiveness. |
| if let Some(it) = None::<$solver_enum> { |
| match it { |
| $( $solver_enum::$variant => {} )* |
| $( $solver_enum::$ignore => {} )* |
| } |
| } |
| match $var { |
| $( LangItem::$variant => Some($solver_enum::$variant), )* |
| _ => None |
| } |
| }}; |
| } |
| |
| impl<'db> rustc_type_ir::Interner for DbInterner<'db> { |
| type DefId = SolverDefId; |
| type LocalDefId = SolverDefId; |
| type LocalDefIds = SolverDefIds; |
| type TraitId = TraitIdWrapper; |
| type ForeignId = TypeAliasIdWrapper; |
| type FunctionId = CallableIdWrapper; |
| type ClosureId = ClosureIdWrapper; |
| type CoroutineClosureId = CoroutineIdWrapper; |
| type CoroutineId = CoroutineIdWrapper; |
| type AdtId = AdtIdWrapper; |
| type ImplId = ImplIdWrapper; |
| type Span = Span; |
| |
| type GenericArgs = GenericArgs<'db>; |
| type GenericArgsSlice = GenericArgs<'db>; |
| type GenericArg = GenericArg<'db>; |
| |
| type Term = Term<'db>; |
| |
| type BoundVarKinds = BoundVarKinds; |
| type BoundVarKind = BoundVarKind; |
| |
| type PredefinedOpaques = PredefinedOpaques<'db>; |
| |
| fn mk_predefined_opaques_in_body( |
| self, |
| data: rustc_type_ir::solve::PredefinedOpaquesData<Self>, |
| ) -> Self::PredefinedOpaques { |
| PredefinedOpaques::new(self, data) |
| } |
| |
| type CanonicalVarKinds = CanonicalVars<'db>; |
| |
| fn mk_canonical_var_kinds( |
| self, |
| kinds: &[rustc_type_ir::CanonicalVarKind<Self>], |
| ) -> Self::CanonicalVarKinds { |
| CanonicalVars::new_from_iter(self, kinds.iter().cloned()) |
| } |
| |
| type ExternalConstraints = ExternalConstraints<'db>; |
| |
| fn mk_external_constraints( |
| self, |
| data: rustc_type_ir::solve::ExternalConstraintsData<Self>, |
| ) -> Self::ExternalConstraints { |
| ExternalConstraints::new(self, data) |
| } |
| |
| type DepNodeIndex = DepNodeIndex; |
| |
| type Tracked<T: fmt::Debug + Clone> = Tracked<T>; |
| |
| type Ty = Ty<'db>; |
| type Tys = Tys<'db>; |
| type FnInputTys = Tys<'db>; |
| type ParamTy = ParamTy; |
| type BoundTy = BoundTy; |
| type PlaceholderTy = PlaceholderTy; |
| type Symbol = (); |
| |
| type ErrorGuaranteed = ErrorGuaranteed; |
| type BoundExistentialPredicates = BoundExistentialPredicates<'db>; |
| type AllocId = AllocId; |
| type Pat = Pattern<'db>; |
| type PatList = PatList<'db>; |
| type Safety = Safety; |
| type Abi = FnAbi; |
| |
| type Const = Const<'db>; |
| type PlaceholderConst = PlaceholderConst; |
| type ParamConst = ParamConst; |
| type BoundConst = BoundConst; |
| type ValueConst = ValueConst<'db>; |
| type ValTree = Valtree<'db>; |
| type ExprConst = ExprConst; |
| |
| type Region = Region<'db>; |
| type EarlyParamRegion = EarlyParamRegion; |
| type LateParamRegion = LateParamRegion; |
| type BoundRegion = BoundRegion; |
| type PlaceholderRegion = PlaceholderRegion; |
| |
| type RegionAssumptions = RegionAssumptions<'db>; |
| |
| type ParamEnv = ParamEnv<'db>; |
| type Predicate = Predicate<'db>; |
| type Clause = Clause<'db>; |
| type Clauses = Clauses<'db>; |
| |
| type GenericsOf = Generics; |
| |
| type VariancesOf = VariancesOf; |
| |
| type AdtDef = AdtDef; |
| |
| type Features = Features; |
| |
| fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs { |
| GenericArgs::new_from_iter(self, args.iter().cloned()) |
| } |
| |
| fn mk_args_from_iter<I, T>(self, args: I) -> T::Output |
| where |
| 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()) |
| }) |
| } |
| |
| type UnsizingParams = UnsizingParams; |
| |
| fn mk_tracked<T: fmt::Debug + Clone>( |
| self, |
| data: T, |
| dep_node: Self::DepNodeIndex, |
| ) -> Self::Tracked<T> { |
| Tracked(data) |
| } |
| |
| fn get_tracked<T: fmt::Debug + Clone>(self, tracked: &Self::Tracked<T>) -> T { |
| tracked.0.clone() |
| } |
| |
| fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex) { |
| (task(), DepNodeIndex) |
| } |
| |
| fn with_global_cache<R>( |
| self, |
| f: impl FnOnce(&mut rustc_type_ir::search_graph::GlobalCache<Self>) -> R, |
| ) -> R { |
| salsa::with_attached_database(|db| { |
| tls_cache::with_cache( |
| unsafe { |
| std::mem::transmute::<&dyn HirDatabase, &'db dyn HirDatabase>( |
| db.as_view::<dyn HirDatabase>(), |
| ) |
| }, |
| f, |
| ) |
| }) |
| .unwrap() |
| } |
| |
| fn canonical_param_env_cache_get_or_insert<R>( |
| self, |
| param_env: Self::ParamEnv, |
| f: impl FnOnce() -> rustc_type_ir::CanonicalParamEnvCacheEntry<Self>, |
| from_entry: impl FnOnce(&rustc_type_ir::CanonicalParamEnvCacheEntry<Self>) -> R, |
| ) -> R { |
| from_entry(&f()) |
| } |
| |
| fn evaluation_is_concurrent(&self) -> bool { |
| false |
| } |
| |
| fn expand_abstract_consts<T: rustc_type_ir::TypeFoldable<Self>>(self, _: T) -> T { |
| unreachable!("only used by the old trait solver in rustc"); |
| } |
| |
| fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf { |
| generics(self.db(), def_id) |
| } |
| |
| fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf { |
| let generic_def = match def_id { |
| SolverDefId::FunctionId(def_id) => def_id.into(), |
| SolverDefId::AdtId(def_id) => def_id.into(), |
| SolverDefId::Ctor(Ctor::Struct(def_id)) => def_id.into(), |
| SolverDefId::Ctor(Ctor::Enum(def_id)) => def_id.loc(self.db).parent.into(), |
| SolverDefId::InternedOpaqueTyId(_def_id) => { |
| // FIXME(next-solver): track variances |
| // |
| // We compute them based on the only `Ty` level info in rustc, |
| // move `variances_of_opaque` into `rustc_next_trait_solver` for reuse. |
| return VariancesOf::new_from_iter( |
| self, |
| (0..self.generics_of(def_id).count()).map(|_| Variance::Invariant), |
| ); |
| } |
| _ => return VariancesOf::new_from_iter(self, []), |
| }; |
| VariancesOf::new_from_iter( |
| self, |
| self.db() |
| .variances_of(generic_def) |
| .as_deref() |
| .unwrap_or_default() |
| .iter() |
| .map(|v| v.to_nextsolver(self)), |
| ) |
| } |
| |
| 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_ns(id.into()) |
| } |
| SolverDefId::AdtId(id) => self.db().ty_ns(id.into()), |
| // FIXME(next-solver): This uses the types of `query mir_borrowck` in rustc. |
| // |
| // We currently always use the type from HIR typeck which ignores regions. This |
| // should be fine. |
| SolverDefId::InternedOpaqueTyId(_) => self.type_of_opaque_hir_typeck(def_id), |
| SolverDefId::FunctionId(id) => self.db.value_ty_ns(id.into()).unwrap(), |
| SolverDefId::Ctor(id) => { |
| let id = match id { |
| Ctor::Struct(id) => id.into(), |
| Ctor::Enum(id) => id.into(), |
| }; |
| self.db |
| .value_ty_ns(id) |
| .expect("`SolverDefId::Ctor` should have a function-like ctor") |
| } |
| _ => panic!("Unexpected def_id `{def_id:?}` provided for `type_of`"), |
| } |
| } |
| |
| fn adt_def(self, def_id: Self::AdtId) -> Self::AdtDef { |
| AdtDef::new(def_id.0, self) |
| } |
| |
| fn alias_ty_kind(self, alias: rustc_type_ir::AliasTy<Self>) -> AliasTyKind { |
| match alias.def_id { |
| SolverDefId::InternedOpaqueTyId(_) => AliasTyKind::Opaque, |
| SolverDefId::TypeAliasId(_) => AliasTyKind::Projection, |
| _ => unimplemented!("Unexpected alias: {:?}", alias.def_id), |
| } |
| } |
| |
| fn alias_term_kind( |
| self, |
| alias: rustc_type_ir::AliasTerm<Self>, |
| ) -> rustc_type_ir::AliasTermKind { |
| match alias.def_id { |
| SolverDefId::InternedOpaqueTyId(_) => AliasTermKind::OpaqueTy, |
| SolverDefId::TypeAliasId(_) => AliasTermKind::ProjectionTy, |
| SolverDefId::ConstId(_) => AliasTermKind::UnevaluatedConst, |
| _ => unimplemented!("Unexpected alias: {:?}", alias.def_id), |
| } |
| } |
| |
| fn trait_ref_and_own_args_for_alias( |
| self, |
| def_id: Self::DefId, |
| args: Self::GenericArgs, |
| ) -> (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())); |
| (TraitRef::new_from_args(self, trait_def_id.try_into().unwrap(), trait_args), alias_args) |
| } |
| |
| fn check_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) -> bool { |
| // FIXME |
| true |
| } |
| |
| fn debug_assert_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) {} |
| |
| fn debug_assert_existential_args_compatible( |
| self, |
| def_id: Self::DefId, |
| args: Self::GenericArgs, |
| ) { |
| } |
| |
| fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output |
| where |
| 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())) |
| } |
| |
| fn parent(self, def_id: Self::DefId) -> Self::DefId { |
| use hir_def::Lookup; |
| |
| let container = match def_id { |
| SolverDefId::FunctionId(it) => it.lookup(self.db()).container, |
| SolverDefId::TypeAliasId(it) => it.lookup(self.db()).container, |
| SolverDefId::ConstId(it) => it.lookup(self.db()).container, |
| SolverDefId::InternedClosureId(it) => { |
| return self |
| .db() |
| .lookup_intern_closure(it) |
| .0 |
| .as_generic_def_id(self.db()) |
| .unwrap() |
| .into(); |
| } |
| SolverDefId::InternedCoroutineId(it) => { |
| return self |
| .db() |
| .lookup_intern_coroutine(it) |
| .0 |
| .as_generic_def_id(self.db()) |
| .unwrap() |
| .into(); |
| } |
| SolverDefId::StaticId(_) |
| | SolverDefId::AdtId(_) |
| | SolverDefId::TraitId(_) |
| | SolverDefId::ImplId(_) |
| | SolverDefId::Ctor(..) |
| | SolverDefId::InternedOpaqueTyId(..) => panic!(), |
| }; |
| |
| match container { |
| ItemContainerId::ImplId(it) => it.into(), |
| ItemContainerId::TraitId(it) => it.into(), |
| ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => panic!(), |
| } |
| } |
| |
| fn recursion_limit(self) -> usize { |
| 50 |
| } |
| |
| fn features(self) -> Self::Features { |
| Features |
| } |
| |
| fn fn_sig( |
| self, |
| def_id: Self::FunctionId, |
| ) -> EarlyBinder<Self, rustc_type_ir::Binder<Self, rustc_type_ir::FnSig<Self>>> { |
| self.db().callable_item_signature_ns(def_id.0) |
| } |
| |
| fn coroutine_movability(self, def_id: Self::CoroutineId) -> rustc_ast_ir::Movability { |
| unimplemented!() |
| } |
| |
| fn coroutine_for_closure(self, def_id: Self::CoroutineId) -> Self::CoroutineId { |
| unimplemented!() |
| } |
| |
| 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 Some(sized_id) = sized_trait else { |
| return false; /* No Sized trait, can't require it! */ |
| }; |
| let sized_def_id = sized_id.into(); |
| |
| // Search for a predicate like `Self : Sized` amongst the trait bounds. |
| let predicates = self.predicates_of(def_id); |
| elaborate(self, predicates.iter_identity()).any(|pred| match pred.kind().skip_binder() { |
| ClauseKind::Trait(ref trait_pred) => { |
| trait_pred.def_id() == sized_def_id |
| && matches!( |
| trait_pred.self_ty().kind(), |
| TyKind::Param(ParamTy { index: 0, .. }) |
| ) |
| } |
| ClauseKind::RegionOutlives(_) |
| | ClauseKind::TypeOutlives(_) |
| | ClauseKind::Projection(_) |
| | ClauseKind::ConstArgHasType(_, _) |
| | ClauseKind::WellFormed(_) |
| | ClauseKind::ConstEvaluatable(_) |
| | ClauseKind::HostEffect(..) |
| | ClauseKind::UnstableFeature(_) => false, |
| }) |
| } |
| |
| #[tracing::instrument(skip(self), ret)] |
| 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<_>>()) |
| }) |
| } |
| |
| #[tracing::instrument(skip(self), ret)] |
| 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<_>>(), |
| ) |
| }) |
| } |
| |
| fn item_non_self_bounds( |
| self, |
| def_id: Self::DefId, |
| ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> { |
| let all_bounds: FxHashSet<_> = self.item_bounds(def_id).skip_binder().into_iter().collect(); |
| 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, [])) |
| } else { |
| EarlyBinder::bind(Clauses::new_from_iter( |
| self, |
| all_bounds.difference(&own_bounds).cloned(), |
| )) |
| } |
| } |
| |
| #[tracing::instrument(level = "debug", skip(self), ret)] |
| fn predicates_of( |
| self, |
| def_id: Self::DefId, |
| ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> { |
| let predicates = self.db().generic_predicates_ns(def_id.try_into().unwrap()); |
| let predicates: Vec<_> = predicates.iter().cloned().collect(); |
| EarlyBinder::bind(predicates.into_iter()) |
| } |
| |
| #[tracing::instrument(level = "debug", skip(self), ret)] |
| fn own_predicates_of( |
| self, |
| def_id: Self::DefId, |
| ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> { |
| let predicates = self.db().generic_predicates_without_parent_ns(def_id.try_into().unwrap()); |
| let predicates: Vec<_> = predicates.iter().cloned().collect(); |
| EarlyBinder::bind(predicates.into_iter()) |
| } |
| |
| #[tracing::instrument(skip(self), ret)] |
| fn explicit_super_predicates_of( |
| self, |
| def_id: Self::TraitId, |
| ) -> EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>> { |
| let is_self = |ty: Ty<'db>| match ty.kind() { |
| rustc_type_ir::TyKind::Param(param) => param.index == 0, |
| _ => false, |
| }; |
| |
| let predicates: Vec<(Clause<'db>, Span)> = self |
| .db() |
| .generic_predicates_ns(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) |
| } |
| |
| #[tracing::instrument(skip(self), ret)] |
| fn explicit_implied_predicates_of( |
| self, |
| def_id: Self::DefId, |
| ) -> EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>> { |
| fn is_self_or_assoc(ty: Ty<'_>) -> bool { |
| match ty.kind() { |
| rustc_type_ir::TyKind::Param(param) => param.index == 0, |
| rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Projection, alias) => { |
| is_self_or_assoc(alias.self_ty()) |
| } |
| _ => false, |
| } |
| } |
| |
| let predicates: Vec<(Clause<'db>, Span)> = self |
| .db() |
| .generic_predicates_ns(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) |
| } |
| |
| fn impl_super_outlives( |
| self, |
| impl_id: Self::ImplId, |
| ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> { |
| let trait_ref = self.db().impl_trait_ns(impl_id.0).expect("expected an impl of trait"); |
| 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(_) |
| ) |
| }), |
| ) |
| }) |
| } |
| |
| fn const_conditions( |
| self, |
| def_id: Self::DefId, |
| ) -> EarlyBinder< |
| Self, |
| impl IntoIterator<Item = rustc_type_ir::Binder<Self, rustc_type_ir::TraitRef<Self>>>, |
| > { |
| EarlyBinder::bind([unimplemented!()]) |
| } |
| |
| fn has_target_features(self, def_id: Self::FunctionId) -> bool { |
| false |
| } |
| |
| fn require_lang_item(self, lang_item: SolverLangItem) -> Self::DefId { |
| 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, |
| }; |
| 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(enum_variant_id) => unimplemented!(), |
| } |
| } |
| |
| fn require_trait_lang_item(self, lang_item: SolverTraitLangItem) -> TraitIdWrapper { |
| let lang_item = match lang_item { |
| SolverTraitLangItem::AsyncFn => LangItem::AsyncFn, |
| SolverTraitLangItem::AsyncFnKindHelper => unimplemented!(), |
| SolverTraitLangItem::AsyncFnMut => LangItem::AsyncFnMut, |
| SolverTraitLangItem::AsyncFnOnce => LangItem::AsyncFnOnce, |
| SolverTraitLangItem::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput, |
| 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::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::BikeshedGuaranteedNoDrop => { |
| unimplemented!() |
| } |
| }; |
| 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() |
| } |
| |
| fn require_adt_lang_item(self, lang_item: SolverAdtLangItem) -> AdtIdWrapper { |
| let lang_item = match lang_item { |
| SolverAdtLangItem::Option => LangItem::Option, |
| SolverAdtLangItem::Poll => LangItem::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() |
| } |
| |
| fn is_lang_item(self, def_id: Self::DefId, lang_item: SolverLangItem) -> bool { |
| self.as_lang_item(def_id) |
| .map_or(false, |l| std::mem::discriminant(&l) == std::mem::discriminant(&lang_item)) |
| } |
| |
| 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)) |
| } |
| |
| fn is_adt_lang_item(self, def_id: Self::AdtId, lang_item: SolverAdtLangItem) -> bool { |
| // FIXME: derive PartialEq on SolverTraitLangItem |
| self.as_adt_lang_item(def_id) |
| .map_or(false, |l| std::mem::discriminant(&l) == std::mem::discriminant(&lang_item)) |
| } |
| |
| 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; |
| |
| ignore = { |
| AsyncFnKindUpvars, |
| } |
| |
| Metadata, |
| DynMetadata, |
| CoroutineReturn, |
| CoroutineYield, |
| FutureOutput, |
| AsyncFnOnceOutput, |
| CallRefFuture, |
| CallOnceFuture, |
| AsyncFnOnceOutput, |
| ) |
| } |
| |
| 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; |
| |
| ignore = { |
| AsyncFnKindHelper, |
| AsyncIterator, |
| BikeshedGuaranteedNoDrop, |
| FusedIterator, |
| } |
| |
| Sized, |
| MetaSized, |
| PointeeSized, |
| Unsize, |
| Copy, |
| Clone, |
| DiscriminantKind, |
| PointeeTrait, |
| FnPtrTrait, |
| Drop, |
| Destruct, |
| TransmuteTrait, |
| Fn, |
| FnMut, |
| FnOnce, |
| Future, |
| Coroutine, |
| Unpin, |
| Tuple, |
| Iterator, |
| AsyncFn, |
| AsyncFnMut, |
| AsyncFnOnce, |
| AsyncFnOnceOutput, |
| AsyncFnOnceOutput, |
| ) |
| } |
| |
| 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)?; |
| as_lang_item!( |
| SolverAdtLangItem, lang_item; |
| |
| ignore = {} |
| |
| Option, |
| Poll, |
| ) |
| } |
| |
| 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 for_each_relevant_impl( |
| self, |
| trait_: Self::TraitId, |
| self_ty: Self::Ty, |
| mut f: impl FnMut(Self::ImplId), |
| ) { |
| let trait_ = trait_.0; |
| let self_ty_fp = TyFingerprint::for_trait_impl_ns(&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_ns(i).map_or(false, |b| { |
| b.skip_binder().visit_with(&mut ContainsTypeErrors).is_break() |
| }); |
| if contains_errors { |
| continue; |
| } |
| |
| f(i.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_ns(i).map_or(false, |b| { |
| b.skip_binder().visit_with(&mut ContainsTypeErrors).is_break() |
| }); |
| if contains_errors { |
| continue; |
| } |
| |
| f(i.into()); |
| } |
| } |
| ControlFlow::Continue(()) |
| }, |
| ); |
| } |
| } |
| |
| fn for_each_blanket_impl(self, trait_def_id: Self::TraitId, mut f: impl FnMut(Self::ImplId)) { |
| let Some(krate) = self.krate else { return }; |
| |
| 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()); |
| } |
| } |
| } |
| } |
| |
| fn has_item_definition(self, def_id: Self::DefId) -> bool { |
| // FIXME(next-solver): should check if the associated item has a value. |
| true |
| } |
| |
| fn impl_is_default(self, impl_def_id: Self::ImplId) -> bool { |
| // FIXME |
| false |
| } |
| |
| #[tracing::instrument(skip(self), ret)] |
| fn impl_trait_ref( |
| self, |
| impl_id: Self::ImplId, |
| ) -> EarlyBinder<Self, rustc_type_ir::TraitRef<Self>> { |
| let db = self.db(); |
| db.impl_trait_ns(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") |
| } |
| |
| fn impl_polarity(self, impl_id: Self::ImplId) -> rustc_type_ir::ImplPolarity { |
| let impl_data = self.db().impl_signature(impl_id.0); |
| if impl_data.flags.contains(ImplFlags::NEGATIVE) { |
| ImplPolarity::Negative |
| } else { |
| ImplPolarity::Positive |
| } |
| } |
| |
| fn trait_is_auto(self, trait_: Self::TraitId) -> bool { |
| let trait_data = self.db().trait_signature(trait_.0); |
| trait_data.flags.contains(TraitFlags::AUTO) |
| } |
| |
| fn trait_is_alias(self, trait_: Self::TraitId) -> bool { |
| let trait_data = self.db().trait_signature(trait_.0); |
| trait_data.flags.contains(TraitFlags::ALIAS) |
| } |
| |
| fn trait_is_dyn_compatible(self, trait_: Self::TraitId) -> bool { |
| crate::dyn_compatibility::dyn_compatibility(self.db(), trait_.0).is_none() |
| } |
| |
| fn trait_is_fundamental(self, trait_: Self::TraitId) -> bool { |
| let trait_data = self.db().trait_signature(trait_.0); |
| trait_data.flags.contains(TraitFlags::FUNDAMENTAL) |
| } |
| |
| fn trait_may_be_implemented_via_object(self, trait_def_id: Self::TraitId) -> bool { |
| // FIXME(next-solver): should check the `TraitFlags` for |
| // the `#[rustc_do_not_implement_via_object]` flag |
| true |
| } |
| |
| fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool { |
| // FIXME(next-solver) |
| false |
| } |
| |
| fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed { |
| panic!("Bug encountered in next-trait-solver.") |
| } |
| |
| fn is_general_coroutine(self, coroutine_def_id: Self::CoroutineId) -> bool { |
| // FIXME(next-solver) |
| true |
| } |
| |
| fn coroutine_is_async(self, coroutine_def_id: Self::CoroutineId) -> bool { |
| // FIXME(next-solver) |
| true |
| } |
| |
| fn coroutine_is_gen(self, coroutine_def_id: Self::CoroutineId) -> bool { |
| // FIXME(next-solver) |
| false |
| } |
| |
| fn coroutine_is_async_gen(self, coroutine_def_id: Self::CoroutineId) -> bool { |
| // FIXME(next-solver) |
| false |
| } |
| |
| fn unsizing_params_for_adt(self, id: Self::AdtId) -> Self::UnsizingParams { |
| let def = AdtDef::new(id.0, self); |
| let num_params = self.generics_of(id.into()).count(); |
| |
| let maybe_unsizing_param_idx = |arg: GenericArg<'db>| match arg.kind() { |
| GenericArgKind::Type(ty) => match ty.kind() { |
| rustc_type_ir::TyKind::Param(p) => Some(p.index), |
| _ => None, |
| }, |
| GenericArgKind::Lifetime(_) => None, |
| GenericArgKind::Const(ct) => match ct.kind() { |
| rustc_type_ir::ConstKind::Param(p) => Some(p.index), |
| _ => None, |
| }, |
| }; |
| |
| // The last field of the structure has to exist and contain type/const parameters. |
| let variant = def.non_enum_variant(); |
| let fields = variant.fields(self.db()); |
| let Some((tail_field, prefix_fields)) = fields.split_last() else { |
| return UnsizingParams(DenseBitSet::new_empty(num_params)); |
| }; |
| |
| let field_types = self.db().field_types_ns(variant.id()); |
| let mut unsizing_params = DenseBitSet::new_empty(num_params); |
| let ty = field_types[tail_field.0]; |
| for arg in ty.instantiate_identity().walk() { |
| if let Some(i) = maybe_unsizing_param_idx(arg) { |
| unsizing_params.insert(i); |
| } |
| } |
| |
| // 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() { |
| if let Some(i) = maybe_unsizing_param_idx(arg) { |
| unsizing_params.remove(i); |
| } |
| } |
| } |
| |
| UnsizingParams(unsizing_params) |
| } |
| |
| fn anonymize_bound_vars<T: rustc_type_ir::TypeFoldable<Self>>( |
| self, |
| value: rustc_type_ir::Binder<Self, T>, |
| ) -> rustc_type_ir::Binder<Self, T> { |
| struct Anonymize<'a, 'db> { |
| interner: DbInterner<'db>, |
| map: &'a mut FxIndexMap<BoundVar, BoundVarKind>, |
| } |
| impl<'db> BoundVarReplacerDelegate<'db> for Anonymize<'_, 'db> { |
| fn replace_region(&mut self, br: BoundRegion) -> Region<'db> { |
| let entry = self.map.entry(br.var); |
| let index = entry.index(); |
| let var = BoundVar::from_usize(index); |
| let kind = (*entry.or_insert_with(|| BoundVarKind::Region(BoundRegionKind::Anon))) |
| .expect_region(); |
| let br = BoundRegion { var, kind }; |
| Region::new_bound(self.interner, DebruijnIndex::ZERO, br) |
| } |
| fn replace_ty(&mut self, bt: BoundTy) -> Ty<'db> { |
| let entry = self.map.entry(bt.var); |
| let index = entry.index(); |
| let var = BoundVar::from_usize(index); |
| let kind = |
| (*entry.or_insert_with(|| BoundVarKind::Ty(BoundTyKind::Anon))).expect_ty(); |
| Ty::new_bound(self.interner, DebruijnIndex::ZERO, BoundTy { var, kind }) |
| } |
| fn replace_const(&mut self, bv: BoundConst) -> Const<'db> { |
| let entry = self.map.entry(bv.var); |
| let index = entry.index(); |
| let var = BoundVar::from_usize(index); |
| let () = (*entry.or_insert_with(|| BoundVarKind::Const)).expect_const(); |
| Const::new_bound(self.interner, DebruijnIndex::ZERO, BoundConst { var }) |
| } |
| } |
| |
| 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()) |
| }); |
| Binder::bind_with_vars(inner, bound_vars) |
| } |
| |
| fn opaque_types_defined_by(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds { |
| // FIXME(next-solver) |
| SolverDefIds::new_from_iter(self, []) |
| } |
| |
| fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool { |
| // FIXME(next-solver) |
| false |
| } |
| |
| fn explicit_implied_const_bounds( |
| self, |
| def_id: Self::DefId, |
| ) -> EarlyBinder< |
| Self, |
| impl IntoIterator<Item = rustc_type_ir::Binder<Self, rustc_type_ir::TraitRef<Self>>>, |
| > { |
| // FIXME(next-solver) |
| EarlyBinder::bind([]) |
| } |
| |
| fn fn_is_const(self, id: Self::FunctionId) -> bool { |
| let id = match id.0 { |
| CallableDefId::FunctionId(id) => id, |
| _ => return false, |
| }; |
| self.db().function_signature(id).flags.contains(FnFlags::CONST) |
| } |
| |
| fn impl_is_const(self, def_id: Self::ImplId) -> bool { |
| false |
| } |
| |
| fn opt_alias_variances( |
| self, |
| kind: impl Into<rustc_type_ir::AliasTermKind>, |
| def_id: Self::DefId, |
| ) -> Option<Self::VariancesOf> { |
| None |
| } |
| |
| fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId) -> EarlyBinder<Self, Self::Ty> { |
| match def_id { |
| SolverDefId::InternedOpaqueTyId(opaque) => { |
| let impl_trait_id = self.db().lookup_intern_impl_trait_id(opaque); |
| match impl_trait_id { |
| crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { |
| let infer = self.db().infer(func.into()); |
| EarlyBinder::bind(infer.type_of_rpit[idx].to_nextsolver(self)) |
| } |
| crate::ImplTraitId::TypeAliasImplTrait(..) |
| | crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { |
| // FIXME(next-solver) |
| EarlyBinder::bind(Ty::new_error(self, ErrorGuaranteed)) |
| } |
| } |
| } |
| _ => panic!("Unexpected SolverDefId in type_of_opaque_hir_typeck"), |
| } |
| } |
| |
| fn coroutine_hidden_types( |
| self, |
| def_id: Self::CoroutineId, |
| ) -> EarlyBinder<Self, rustc_type_ir::Binder<Self, rustc_type_ir::CoroutineWitnessTypes<Self>>> |
| { |
| // FIXME(next-solver) |
| unimplemented!() |
| } |
| |
| fn is_default_trait(self, def_id: Self::TraitId) -> bool { |
| self.as_trait_lang_item(def_id).map_or(false, |l| matches!(l, SolverTraitLangItem::Sized)) |
| } |
| |
| fn trait_is_coinductive(self, trait_: Self::TraitId) -> bool { |
| self.db().trait_signature(trait_.0).flags.contains(TraitFlags::COINDUCTIVE) |
| } |
| |
| fn trait_is_unsafe(self, trait_: Self::TraitId) -> bool { |
| self.db().trait_signature(trait_.0).flags.contains(TraitFlags::UNSAFE) |
| } |
| |
| fn impl_self_is_guaranteed_unsized(self, def_id: Self::ImplId) -> bool { |
| false |
| } |
| |
| fn impl_specializes(self, impl_def_id: Self::ImplId, victim_def_id: Self::ImplId) -> bool { |
| false |
| } |
| |
| fn next_trait_solver_globally(self) -> bool { |
| true |
| } |
| |
| fn opaque_types_and_coroutines_defined_by( |
| self, |
| defining_anchor: Self::LocalDefId, |
| ) -> Self::LocalDefIds { |
| // FIXME(next-solver) |
| unimplemented!() |
| } |
| |
| type Probe = rustc_type_ir::solve::inspect::Probe<DbInterner<'db>>; |
| fn mk_probe(self, probe: rustc_type_ir::solve::inspect::Probe<Self>) -> Self::Probe { |
| probe |
| } |
| fn evaluate_root_goal_for_proof_tree_raw( |
| self, |
| canonical_goal: rustc_type_ir::solve::CanonicalInput<Self>, |
| ) -> (rustc_type_ir::solve::QueryResult<Self>, Self::Probe) { |
| rustc_next_trait_solver::solve::evaluate_root_goal_for_proof_tree_raw_provider::< |
| SolverContext<'db>, |
| Self, |
| >(self, canonical_goal) |
| } |
| } |
| |
| impl<'db> DbInterner<'db> { |
| pub fn shift_bound_var_indices<T>(self, bound_vars: usize, value: T) -> T |
| where |
| T: rustc_type_ir::TypeFoldable<Self>, |
| { |
| let shift_bv = |bv: BoundVar| BoundVar::from_usize(bv.as_usize() + bound_vars); |
| self.replace_escaping_bound_vars_uncached( |
| value, |
| FnMutDelegate { |
| regions: &mut |r: BoundRegion| { |
| Region::new_bound( |
| self, |
| DebruijnIndex::ZERO, |
| BoundRegion { var: shift_bv(r.var), kind: r.kind }, |
| ) |
| }, |
| types: &mut |t: BoundTy| { |
| Ty::new_bound( |
| self, |
| DebruijnIndex::ZERO, |
| BoundTy { var: shift_bv(t.var), kind: t.kind }, |
| ) |
| }, |
| consts: &mut |c| { |
| Const::new_bound(self, DebruijnIndex::ZERO, BoundConst { var: shift_bv(c.var) }) |
| }, |
| }, |
| ) |
| } |
| |
| pub fn replace_escaping_bound_vars_uncached<T: rustc_type_ir::TypeFoldable<DbInterner<'db>>>( |
| self, |
| value: T, |
| delegate: impl BoundVarReplacerDelegate<'db>, |
| ) -> T { |
| if !value.has_escaping_bound_vars() { |
| value |
| } else { |
| let mut replacer = BoundVarReplacer::new(self, delegate); |
| value.fold_with(&mut replacer) |
| } |
| } |
| |
| pub fn replace_bound_vars_uncached<T: rustc_type_ir::TypeFoldable<DbInterner<'db>>>( |
| self, |
| value: Binder<'db, T>, |
| delegate: impl BoundVarReplacerDelegate<'db>, |
| ) -> T { |
| self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate) |
| } |
| |
| pub fn mk_fn_sig<I>( |
| self, |
| inputs: I, |
| output: Ty<'db>, |
| c_variadic: bool, |
| safety: Safety, |
| abi: FnAbi, |
| ) -> FnSig<'db> |
| where |
| I: IntoIterator<Item = Ty<'db>>, |
| { |
| FnSig { |
| inputs_and_output: Tys::new_from_iter( |
| self, |
| inputs.into_iter().chain(std::iter::once(output)), |
| ), |
| c_variadic, |
| safety, |
| abi, |
| } |
| } |
| } |
| |
| macro_rules! TrivialTypeTraversalImpls { |
| ($($ty:ty,)+) => { |
| $( |
| impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for $ty { |
| fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>( |
| self, |
| _: &mut F, |
| ) -> ::std::result::Result<Self, F::Error> { |
| Ok(self) |
| } |
| |
| #[inline] |
| fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>( |
| self, |
| _: &mut F, |
| ) -> Self { |
| self |
| } |
| } |
| |
| impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for $ty { |
| #[inline] |
| fn visit_with<F: rustc_type_ir::TypeVisitor<DbInterner<'db>>>( |
| &self, |
| _: &mut F) |
| -> F::Result |
| { |
| <F::Result as rustc_ast_ir::visit::VisitorResult>::output() |
| } |
| } |
| )+ |
| }; |
| } |
| |
| TrivialTypeTraversalImpls! { |
| SolverDefId, |
| TraitIdWrapper, |
| TypeAliasIdWrapper, |
| CallableIdWrapper, |
| ClosureIdWrapper, |
| CoroutineIdWrapper, |
| AdtIdWrapper, |
| ImplIdWrapper, |
| Pattern<'db>, |
| Safety, |
| FnAbi, |
| Span, |
| ParamConst, |
| ParamTy, |
| BoundRegion, |
| BoundVar, |
| Placeholder<BoundRegion>, |
| Placeholder<BoundTy>, |
| Placeholder<BoundVar>, |
| } |
| |
| mod tls_cache { |
| use crate::db::HirDatabase; |
| |
| use super::DbInterner; |
| use base_db::Nonce; |
| use rustc_type_ir::search_graph::GlobalCache; |
| use salsa::Revision; |
| use std::cell::RefCell; |
| |
| struct Cache { |
| cache: GlobalCache<DbInterner<'static>>, |
| revision: Revision, |
| db_nonce: Nonce, |
| } |
| |
| thread_local! { |
| static GLOBAL_CACHE: RefCell<Option<Cache>> = const { RefCell::new(None) }; |
| } |
| |
| pub(super) fn with_cache<'db, T>( |
| db: &'db dyn HirDatabase, |
| f: impl FnOnce(&mut GlobalCache<DbInterner<'db>>) -> T, |
| ) -> T { |
| GLOBAL_CACHE.with_borrow_mut(|handle| { |
| let (db_nonce, revision) = db.nonce_and_revision(); |
| let handle = match handle { |
| Some(handle) => { |
| if handle.revision != revision || db_nonce != handle.db_nonce { |
| *handle = Cache { cache: GlobalCache::default(), revision, db_nonce }; |
| } |
| handle |
| } |
| None => handle.insert(Cache { cache: GlobalCache::default(), revision, db_nonce }), |
| }; |
| |
| // SAFETY: No idea |
| f(unsafe { |
| std::mem::transmute::< |
| &mut GlobalCache<DbInterner<'static>>, |
| &mut GlobalCache<DbInterner<'db>>, |
| >(&mut handle.cache) |
| }) |
| }) |
| } |
| } |