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 | 283 |
1 files changed, 203 insertions, 80 deletions
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs index b72504a19c..3fd8e7b39d 100644 --- a/crates/hir-ty/src/next_solver/interner.rs +++ b/crates/hir-ty/src/next_solver/interner.rs @@ -1,75 +1,81 @@ //! Things related to the Interner in the next-trait-solver. -#![allow(unused)] +#![allow(unused)] // FIXME(next-solver): Remove this. + +use std::{fmt, ops::ControlFlow}; + +pub use tls_db::{attach_db, attach_db_allow_change, with_attached_db}; 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 hir_def::{ + AdtId, AttrDefId, BlockId, CallableDefId, EnumVariantId, GenericDefId, ItemContainerId, Lookup, + StructId, TypeAliasId, UnionId, VariantId, + lang_item::LangItem, + signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags}, +}; use intern::sym::non_exhaustive; use intern::{Interned, impl_internable, sym}; use la_arena::Idx; use rustc_abi::{Align, ReprFlags, ReprOptions}; +use rustc_ast_ir::visit::VisitorResult; 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_index::{IndexVec, bit_set::DenseBitSet}; use rustc_type_ir::{ - AliasTerm, AliasTermKind, AliasTy, AliasTyKind, EarlyBinder, FlagComputation, Flags, - ImplPolarity, InferTy, ProjectionPredicate, TraitPredicate, TraitRef, Upcast, + AliasTerm, AliasTermKind, AliasTy, AliasTyKind, BoundVar, CollectAndApply, DebruijnIndex, + EarlyBinder, FlagComputation, Flags, GenericArgKind, ImplPolarity, InferTy, + ProjectionPredicate, RegionKind, TermKind, TraitPredicate, TraitRef, TypeVisitableExt, + UniverseIndex, Upcast, Variance, WithCachedTypeInfo, + elaborate::{self, elaborate}, + error::TypeError, + inherent::{ + self, AdtDef as _, Const as _, GenericArgs as _, GenericsOf, IntoKind, ParamEnv as _, + Region as _, SliceLike as _, Span as _, Ty as _, + }, + ir_print, + lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}, + relate, + solve::SizedTraitKind, }; use salsa::plumbing::AsId; use smallvec::{SmallVec, smallvec}; -use std::fmt; -use std::ops::ControlFlow; use syntax::ast::SelfParamKind; +use tracing::debug; 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, + lower_nextsolver::{self, TyLoweringContext}, + method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TyFingerprint}, + next_solver::{ + AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper, + CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, InternedWrapperNoDebug, + RegionAssumptions, SolverContext, SolverDefIds, TraitIdWrapper, TypeAliasIdWrapper, + TypingMode, + infer::{ + DbInternerInferExt, InferCtxt, + traits::{Obligation, ObligationCause}, + }, + obligation_ctxt::ObligationCtxt, + util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls}, + }, }; -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, + ClauseKind, Clauses, Const, ConstKind, ErrorGuaranteed, ExprConst, ExternalConstraints, ExternalConstraintsData, GenericArg, GenericArgs, InternedClausesWrapper, ParamConst, ParamEnv, ParamTy, PlaceholderConst, PlaceholderTy, PredefinedOpaques, PredefinedOpaquesData, Predicate, - PredicateKind, Term, Ty, TyKind, Tys, ValueConst, + PredicateKind, SolverDefId, Term, Ty, TyKind, Tys, Valtree, ValueConst, abi::Safety, fold::{BoundVarReplacer, BoundVarReplacerDelegate, FnMutDelegate}, - generics::Generics, + generics::{Generics, generics}, mapping::ChalkToNextSolver, region::{ BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, PlaceholderRegion, Region, }, + util::sizedness_constraint_for_ty, }; -use super::{ClauseKind, SolverDefId, Valtree}; #[macro_export] #[doc(hidden)] @@ -127,11 +133,10 @@ macro_rules! _interned_vec_nolifetime_salsa { pub fn inner(&self) -> &smallvec::SmallVec<[$ty; 2]> { // SAFETY: ¯\_(ツ)_/¯ - salsa::with_attached_database(|db| { + $crate::with_attached_db(|db| { let inner = self.inner_(db); unsafe { std::mem::transmute(inner) } }) - .unwrap() } } @@ -230,11 +235,10 @@ macro_rules! _interned_vec_db { pub fn inner(&self) -> &smallvec::SmallVec<[$ty<'db>; 2]> { // SAFETY: ¯\_(ツ)_/¯ - salsa::with_attached_database(|db| { + $crate::with_attached_db(|db| { let inner = self.inner_(db); unsafe { std::mem::transmute(inner) } }) - .unwrap() } } @@ -285,14 +289,11 @@ 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()) - }, + crate::with_attached_db(|db| DbInterner { + db: unsafe { std::mem::transmute::<&dyn HirDatabase, &'db dyn HirDatabase>(db) }, krate: None, block: None, }) - .expect("db is expected to be attached") } pub fn new_with( @@ -303,6 +304,7 @@ impl<'db> DbInterner<'db> { DbInterner { db, krate, block } } + #[inline] pub fn db(&self) -> &'db dyn HirDatabase { self.db } @@ -585,12 +587,11 @@ impl AdtDef { } pub fn inner(&self) -> &AdtDefInner { - salsa::with_attached_database(|db| { + crate::with_attached_db(|db| { let inner = self.data_(db); // SAFETY: ¯\_(ツ)_/¯ unsafe { std::mem::transmute(inner) } }) - .unwrap() } pub fn is_enum(&self) -> bool { @@ -708,21 +709,20 @@ impl<'db> inherent::AdtDef<DbInterner<'db>> for AdtDef { impl fmt::Debug for AdtDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - salsa::with_attached_database(|db| match self.inner().id { + crate::with_attached_db(|db| match self.inner().id { AdtId::StructId(struct_id) => { - let data = db.as_view::<dyn HirDatabase>().struct_signature(struct_id); + let data = db.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); + let data = db.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); + let data = db.enum_signature(enum_id); f.write_str(data.name.as_str()) } }) - .unwrap_or_else(|| f.write_str(&format!("AdtDef({:?})", self.inner().id))) } } @@ -778,13 +778,12 @@ impl<'db> Pattern<'db> { } pub fn inner(&self) -> &PatternKind<'db> { - salsa::with_attached_database(|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) } }) - .unwrap() } } @@ -1020,17 +1019,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { 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() + tls_cache::with_cache(self.db, f) } fn canonical_param_env_cache_get_or_insert<R>( @@ -1118,7 +1107,15 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn alias_ty_kind(self, alias: rustc_type_ir::AliasTy<Self>) -> AliasTyKind { match alias.def_id { SolverDefId::InternedOpaqueTyId(_) => AliasTyKind::Opaque, - SolverDefId::TypeAliasId(_) => AliasTyKind::Projection, + SolverDefId::TypeAliasId(type_alias) => match type_alias.loc(self.db).container { + ItemContainerId::ImplId(impl_) + if self.db.impl_signature(impl_).target_trait.is_none() => + { + AliasTyKind::Inherent + } + ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => AliasTyKind::Projection, + _ => AliasTyKind::Free, + }, _ => unimplemented!("Unexpected alias: {:?}", alias.def_id), } } @@ -1129,7 +1126,19 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { ) -> rustc_type_ir::AliasTermKind { match alias.def_id { SolverDefId::InternedOpaqueTyId(_) => AliasTermKind::OpaqueTy, - SolverDefId::TypeAliasId(_) => AliasTermKind::ProjectionTy, + SolverDefId::TypeAliasId(type_alias) => match type_alias.loc(self.db).container { + ItemContainerId::ImplId(impl_) + if self.db.impl_signature(impl_).target_trait.is_none() => + { + AliasTermKind::InherentTy + } + ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => { + AliasTermKind::ProjectionTy + } + _ => AliasTermKind::FreeTy, + }, + // rustc creates an `AnonConst` for consts, and evaluates them with CTFE (normalizing projections + // via selection, similar to ours `find_matching_impl()`, and not with the trait solver), so mimic it. SolverDefId::ConstId(_) => AliasTermKind::UnevaluatedConst, _ => unimplemented!("Unexpected alias: {:?}", alias.def_id), } @@ -1616,7 +1625,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { mut f: impl FnMut(Self::ImplId), ) { let trait_ = trait_.0; - let self_ty_fp = TyFingerprint::for_trait_impl_ns(&self_ty); + 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, @@ -1692,8 +1701,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } fn impl_is_default(self, impl_def_id: Self::ImplId) -> bool { - // FIXME - false + self.db.impl_signature(impl_def_id.0).is_default() } #[tracing::instrument(skip(self), ret)] @@ -1747,7 +1755,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed { - panic!("Bug encountered in next-trait-solver.") + panic!("Bug encountered in next-trait-solver: {}", msg.to_string()) } fn is_general_coroutine(self, coroutine_def_id: Self::CoroutineId) -> bool { @@ -1907,7 +1915,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { 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)) + EarlyBinder::bind(infer.type_of_rpit[idx.to_nextsolver(self)]) } crate::ImplTraitId::TypeAliasImplTrait(..) | crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { @@ -1945,7 +1953,11 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { false } - fn impl_specializes(self, impl_def_id: Self::ImplId, victim_def_id: Self::ImplId) -> bool { + fn impl_specializes( + self, + specializing_impl_def_id: Self::ImplId, + parent_impl_def_id: Self::ImplId, + ) -> bool { false } @@ -2106,6 +2118,117 @@ TrivialTypeTraversalImpls! { Placeholder<BoundVar>, } +mod tls_db { + use std::{cell::Cell, ptr::NonNull}; + + use crate::db::HirDatabase; + + struct Attached { + database: Cell<Option<NonNull<dyn HirDatabase>>>, + } + + impl Attached { + #[inline] + fn attach<R>(&self, db: &dyn HirDatabase, op: impl FnOnce() -> R) -> R { + struct DbGuard<'s> { + state: Option<&'s Attached>, + } + + impl<'s> DbGuard<'s> { + #[inline] + fn new(attached: &'s Attached, db: &dyn HirDatabase) -> Self { + match attached.database.get() { + Some(current_db) => { + let new_db = NonNull::from(db); + if !std::ptr::addr_eq(current_db.as_ptr(), new_db.as_ptr()) { + panic!( + "Cannot change attached database. This is likely a bug.\n\ + If this is not a bug, you can use `attach_db_allow_change()`." + ); + } + Self { state: None } + } + None => { + // Otherwise, set the database. + attached.database.set(Some(NonNull::from(db))); + Self { state: Some(attached) } + } + } + } + } + + impl Drop for DbGuard<'_> { + #[inline] + fn drop(&mut self) { + // Reset database to null if we did anything in `DbGuard::new`. + if let Some(attached) = self.state { + attached.database.set(None); + } + } + } + + let _guard = DbGuard::new(self, db); + op() + } + + #[inline] + fn attach_allow_change<R>(&self, db: &dyn HirDatabase, op: impl FnOnce() -> R) -> R { + struct DbGuard<'s> { + state: &'s Attached, + prev: Option<NonNull<dyn HirDatabase>>, + } + + impl<'s> DbGuard<'s> { + #[inline] + fn new(attached: &'s Attached, db: &dyn HirDatabase) -> Self { + let prev = attached.database.replace(Some(NonNull::from(db))); + Self { state: attached, prev } + } + } + + impl Drop for DbGuard<'_> { + #[inline] + fn drop(&mut self) { + self.state.database.set(self.prev); + } + } + + let _guard = DbGuard::new(self, db); + op() + } + + #[inline] + fn with<R>(&self, op: impl FnOnce(&dyn HirDatabase) -> R) -> R { + let db = self.database.get().expect("Try to use attached db, but not db is attached"); + + // SAFETY: The db is attached, so it must be valid. + op(unsafe { db.as_ref() }) + } + } + + thread_local! { + static GLOBAL_DB: Attached = const { Attached { database: Cell::new(None) } }; + } + + #[inline] + pub fn attach_db<R>(db: &dyn HirDatabase, op: impl FnOnce() -> R) -> R { + GLOBAL_DB.with(|global_db| global_db.attach(db, op)) + } + + #[inline] + pub fn attach_db_allow_change<R>(db: &dyn HirDatabase, op: impl FnOnce() -> R) -> R { + GLOBAL_DB.with(|global_db| global_db.attach_allow_change(db, op)) + } + + #[inline] + pub fn with_attached_db<R>(op: impl FnOnce(&dyn HirDatabase) -> R) -> R { + GLOBAL_DB.with( + #[inline] + |a| a.with(op), + ) + } +} + mod tls_cache { use crate::db::HirDatabase; |