Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lib.rs')
| -rw-r--r-- | crates/hir-ty/src/lib.rs | 895 |
1 files changed, 224 insertions, 671 deletions
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 2e59a488e6..6d3adec6a8 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -21,27 +21,24 @@ extern crate ra_ap_rustc_type_ir as rustc_type_ir; extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver; -mod builder; -mod chalk_db; -mod chalk_ext; -mod drop; +extern crate self as hir_ty; + mod infer; mod inhabitedness; -mod interner; mod lower; -mod lower_nextsolver; -mod mapping; pub mod next_solver; +mod opaques; +mod specialization; mod target_feature; -mod tls; mod utils; +mod variance; pub mod autoderef; pub mod consteval; -pub mod consteval_nextsolver; pub mod db; pub mod diagnostics; pub mod display; +pub mod drop; pub mod dyn_compatibility; pub mod generics; pub mod lang_items; @@ -55,44 +52,35 @@ pub mod traits; mod test_db; #[cfg(test)] mod tests; -mod variance; use std::hash::Hash; -use chalk_ir::{ - NoSolution, VariableKinds, - fold::{Shift, TypeFoldable}, - interner::HasInterner, -}; -use either::Either; -use hir_def::{CallableDefId, GeneralConstId, TypeOrConstParamId, hir::ExprId, type_ref::Rawness}; +use hir_def::{CallableDefId, TypeOrConstParamId, type_ref::Rawness}; use hir_expand::name::Name; use indexmap::{IndexMap, map::Entry}; use intern::{Symbol, sym}; -use la_arena::{Arena, Idx}; use mir::{MirEvalError, VTableMap}; use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet}; -use rustc_type_ir::inherent::SliceLike; +use rustc_type_ir::{ + BoundVarIndexKind, TypeSuperVisitable, TypeVisitableExt, UpcastFrom, + inherent::{IntoKind, SliceLike, Ty as _}, +}; use syntax::ast::{ConstArg, make}; use traits::FnTrait; use triomphe::Arc; use crate::{ - consteval::unknown_const, db::HirDatabase, display::{DisplayTarget, HirDisplay}, - generics::Generics, infer::unify::InferenceTable, next_solver::{ - DbInterner, - mapping::{ChalkToNextSolver, convert_ty_for_result}, + AliasTy, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, Canonical, + CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, FnSig, PolyFnSig, Predicate, + Region, RegionKind, TraitRef, Ty, TyKind, Tys, abi, }, }; pub use autoderef::autoderef; -pub use builder::{ParamKind, TyBuilder}; -pub use chalk_ext::*; -pub use drop::DropGlue; pub use infer::{ Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, InferenceResult, InferenceTyDiagnosticSource, OverloadedDeref, PointerCast, @@ -100,102 +88,17 @@ pub use infer::{ closure::analysis::{CaptureKind, CapturedItem}, could_coerce, could_unify, could_unify_deeply, }; -pub use interner::Interner; pub use lower::{ - ImplTraitLoweringMode, LifetimeElisionKind, ParamLoweringMode, TyDefId, TyLoweringContext, - ValueTyDefId, diagnostics::*, + GenericPredicates, ImplTraits, LifetimeElisionKind, TyDefId, TyLoweringContext, ValueTyDefId, + associated_type_shorthand_candidates, diagnostics::*, }; -pub use lower_nextsolver::associated_type_shorthand_candidates; -pub use mapping::{ - ToChalk, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, - lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, - to_foreign_def_id, to_placeholder_idx, to_placeholder_idx_no_index, -}; -pub use method_resolution::check_orphan_rules; +pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db}; pub use target_feature::TargetFeatures; -pub use traits::TraitEnvironment; +pub use traits::{TraitEnvironment, check_orphan_rules}; pub use utils::{ TargetFeatureIsSafeInTarget, Unsafety, all_super_traits, direct_super_traits, is_fn_unsafe_to_call, target_feature_is_safe_in_target, }; -pub use variance::Variance; - -pub use chalk_ir::{ - AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind, - cast::Cast, - visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, -}; - -pub type ForeignDefId = chalk_ir::ForeignDefId<Interner>; -pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>; -pub type FnDefId = chalk_ir::FnDefId<Interner>; -pub type ClosureId = chalk_ir::ClosureId<Interner>; -pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>; -pub type PlaceholderIndex = chalk_ir::PlaceholderIndex; - -pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>; - -pub(crate) type VariableKind = chalk_ir::VariableKind<Interner>; -/// Represents generic parameters and an item bound by them. When the item has parent, the binders -/// also contain the generic parameters for its parent. See chalk's documentation for details. -/// -/// One thing to keep in mind when working with `Binders` (and `Substitution`s, which represent -/// generic arguments) in rust-analyzer is that the ordering within *is* significant - the generic -/// parameters/arguments for an item MUST come before those for its parent. This is to facilitate -/// the integration with chalk-solve, which mildly puts constraints as such. See #13335 for its -/// motivation in detail. -pub type Binders<T> = chalk_ir::Binders<T>; -/// Interned list of generic arguments for an item. When an item has parent, the `Substitution` for -/// it contains generic arguments for both its parent and itself. See chalk's documentation for -/// details. -/// -/// See `Binders` for the constraint on the ordering. -pub type Substitution = chalk_ir::Substitution<Interner>; -pub type GenericArg = chalk_ir::GenericArg<Interner>; -pub type GenericArgData = chalk_ir::GenericArgData<Interner>; - -pub type Ty = chalk_ir::Ty<Interner>; -pub type TyKind = chalk_ir::TyKind<Interner>; -pub type TypeFlags = chalk_ir::TypeFlags; -pub(crate) type DynTy = chalk_ir::DynTy<Interner>; -pub type FnPointer = chalk_ir::FnPointer<Interner>; -pub(crate) use chalk_ir::FnSubst; // a re-export so we don't lose the tuple constructor - -pub type AliasTy = chalk_ir::AliasTy<Interner>; - -pub type ProjectionTy = chalk_ir::ProjectionTy<Interner>; -pub(crate) type OpaqueTy = chalk_ir::OpaqueTy<Interner>; -pub(crate) type InferenceVar = chalk_ir::InferenceVar; - -pub(crate) type Lifetime = chalk_ir::Lifetime<Interner>; -pub(crate) type LifetimeData = chalk_ir::LifetimeData<Interner>; -pub(crate) type LifetimeOutlives = chalk_ir::LifetimeOutlives<Interner>; - -pub type ConstValue = chalk_ir::ConstValue<Interner>; - -pub type Const = chalk_ir::Const<Interner>; -pub(crate) type ConstData = chalk_ir::ConstData<Interner>; -pub(crate) type ConcreteConst = chalk_ir::ConcreteConst<Interner>; - -pub type TraitRef = chalk_ir::TraitRef<Interner>; -pub type QuantifiedWhereClause = Binders<WhereClause>; -pub type Canonical<T> = chalk_ir::Canonical<T>; - -pub(crate) type ChalkTraitId = chalk_ir::TraitId<Interner>; -pub(crate) type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses<Interner>; - -pub(crate) type FnSig = chalk_ir::FnSig<Interner>; - -pub type InEnvironment<T> = chalk_ir::InEnvironment<T>; -pub type AliasEq = chalk_ir::AliasEq<Interner>; -pub type WhereClause = chalk_ir::WhereClause<Interner>; - -pub(crate) type DomainGoal = chalk_ir::DomainGoal<Interner>; -pub(crate) type Goal = chalk_ir::Goal<Interner>; - -pub(crate) type CanonicalVarKind = chalk_ir::CanonicalVarKind<Interner>; -pub(crate) type GoalData = chalk_ir::GoalData<Interner>; -pub(crate) type ProgramClause = chalk_ir::ProgramClause<Interner>; /// A constant can have reference to other things. Memory map job is holding /// the necessary bits of memory of the const eval session to keep the constant @@ -230,7 +133,7 @@ impl ComplexMemoryMap<'_> { } impl<'db> MemoryMap<'db> { - pub fn vtable_ty(&self, id: usize) -> Result<crate::next_solver::Ty<'db>, MirEvalError> { + pub fn vtable_ty(&self, id: usize) -> Result<Ty<'db>, MirEvalError<'db>> { match self { MemoryMap::Empty | MemoryMap::Simple(_) => Err(MirEvalError::InvalidVTableId(id)), MemoryMap::Complex(cm) => cm.vtable.ty(id), @@ -246,8 +149,8 @@ impl<'db> MemoryMap<'db> { /// allocator function as `f` and it will return a mapping of old addresses to new addresses. fn transform_addresses( &self, - mut f: impl FnMut(&[u8], usize) -> Result<usize, MirEvalError>, - ) -> Result<FxHashMap<usize, usize>, MirEvalError> { + mut f: impl FnMut(&[u8], usize) -> Result<usize, MirEvalError<'db>>, + ) -> Result<FxHashMap<usize, usize>, MirEvalError<'db>> { let mut transform = |(addr, val): (&usize, &[u8])| { let addr = *addr; let align = if addr == 0 { 64 } else { (addr - (addr & (addr - 1))).min(64) }; @@ -280,118 +183,11 @@ impl<'db> MemoryMap<'db> { } } -// FIXME(next-solver): add a lifetime to this -/// A concrete constant value -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ConstScalar { - Bytes(Box<[u8]>, MemoryMap<'static>), - // FIXME: this is a hack to get around chalk not being able to represent unevaluatable - // constants - UnevaluatedConst(GeneralConstId, Substitution), - /// Case of an unknown value that rustc might know but we don't - // FIXME: this is a hack to get around chalk not being able to represent unevaluatable - // constants - // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177 - // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348 - Unknown, -} - -impl Hash for ConstScalar { - fn hash<H: std::hash::Hasher>(&self, state: &mut H) { - core::mem::discriminant(self).hash(state); - if let ConstScalar::Bytes(b, _) = self { - b.hash(state) - } - } -} - -/// A concrete constant value -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ConstScalarNs<'db> { - Bytes(Box<[u8]>, MemoryMap<'db>), - // FIXME: this is a hack to get around chalk not being able to represent unevaluatable - // constants - UnevaluatedConst(GeneralConstId, Substitution), - /// Case of an unknown value that rustc might know but we don't - // FIXME: this is a hack to get around chalk not being able to represent unevaluatable - // constants - // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177 - // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348 - Unknown, -} - -impl Hash for ConstScalarNs<'_> { - fn hash<H: std::hash::Hasher>(&self, state: &mut H) { - core::mem::discriminant(self).hash(state); - if let ConstScalarNs::Bytes(b, _) = self { - b.hash(state) - } - } -} - /// Return an index of a parameter in the generic type parameter list by it's id. pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> { generics::generics(db, id.parent).type_or_const_param_idx(id) } -pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T> -where - T: TypeFoldable<Interner> + HasInterner<Interner = Interner>, -{ - Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE)) -} - -pub(crate) fn make_single_type_binders<T: HasInterner<Interner = Interner>>( - value: T, -) -> Binders<T> { - Binders::new( - chalk_ir::VariableKinds::from_iter( - Interner, - std::iter::once(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)), - ), - value, - ) -} - -pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>( - db: &dyn HirDatabase, - generics: &Generics, - value: T, -) -> Binders<T> { - Binders::new(variable_kinds_from_iter(db, generics.iter_id()), value) -} - -pub(crate) fn variable_kinds_from_iter( - db: &dyn HirDatabase, - iter: impl Iterator<Item = hir_def::GenericParamId>, -) -> VariableKinds<Interner> { - VariableKinds::from_iter( - Interner, - iter.map(|x| match x { - hir_def::GenericParamId::ConstParamId(id) => { - chalk_ir::VariableKind::Const(db.const_param_ty(id)) - } - hir_def::GenericParamId::TypeParamId(_) => { - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) - } - hir_def::GenericParamId::LifetimeParamId(_) => chalk_ir::VariableKind::Lifetime, - }), - ) -} - -// FIXME: get rid of this, just replace it by FnPointer -/// A function signature as seen by type inference: Several parameter types and -/// one return type. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct CallableSig { - params_and_return: Arc<[Ty]>, - is_varargs: bool, - safety: Safety, - abi: FnAbi, -} - -has_interner!(CallableSig); - #[derive(Debug, Copy, Clone, Eq)] pub enum FnAbi { Aapcs, @@ -535,442 +331,201 @@ impl FnAbi { } } -/// A polymorphic function signature. -pub type PolyFnSig = Binders<CallableSig>; - -impl CallableSig { - pub fn from_params_and_return( - params: impl Iterator<Item = Ty>, - ret: Ty, - is_varargs: bool, - safety: Safety, - abi: FnAbi, - ) -> CallableSig { - let mut params_and_return = Vec::with_capacity(params.size_hint().0 + 1); - params_and_return.extend(params); - params_and_return.push(ret); - CallableSig { params_and_return: params_and_return.into(), is_varargs, safety, abi } - } - - pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig { - let callable_def = ToChalk::from_chalk(db, def); - let sig = db.callable_item_signature(callable_def); - sig.substitute(Interner, substs) - } - pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig { - CallableSig { - // FIXME: what to do about lifetime params? -> return PolyFnSig - params_and_return: Arc::from_iter( - fn_ptr - .substitution - .clone() - .shifted_out_to(Interner, DebruijnIndex::ONE) - .expect("unexpected lifetime vars in fn ptr") - .0 - .as_slice(Interner) - .iter() - .map(|arg| arg.assert_ty_ref(Interner).clone()), - ), - is_varargs: fn_ptr.sig.variadic, - safety: fn_ptr.sig.safety, - abi: fn_ptr.sig.abi, - } - } - pub fn from_fn_sig_and_header<'db>( - interner: DbInterner<'db>, - sig: crate::next_solver::Binder<'db, rustc_type_ir::FnSigTys<DbInterner<'db>>>, - header: rustc_type_ir::FnHeader<DbInterner<'db>>, - ) -> CallableSig { - CallableSig { - // FIXME: what to do about lifetime params? -> return PolyFnSig - params_and_return: Arc::from_iter( - sig.skip_binder() - .inputs_and_output - .iter() - .map(|t| convert_ty_for_result(interner, t)), - ), - is_varargs: header.c_variadic, - safety: match header.safety { - next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe, - next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe, - }, - abi: header.abi, - } - } - - pub fn to_fn_ptr(&self) -> FnPointer { - FnPointer { - num_binders: 0, - sig: FnSig { abi: self.abi, safety: self.safety, variadic: self.is_varargs }, - substitution: FnSubst(Substitution::from_iter( - Interner, - self.params_and_return.iter().cloned(), - )), - } - } - - pub fn abi(&self) -> FnAbi { - self.abi - } - - pub fn params(&self) -> &[Ty] { - &self.params_and_return[0..self.params_and_return.len() - 1] - } - - pub fn ret(&self) -> &Ty { - &self.params_and_return[self.params_and_return.len() - 1] - } -} - -impl TypeFoldable<Interner> for CallableSig { - fn try_fold_with<E>( - self, - folder: &mut dyn chalk_ir::fold::FallibleTypeFolder<Interner, Error = E>, - outer_binder: DebruijnIndex, - ) -> Result<Self, E> { - let vec = self.params_and_return.to_vec(); - let folded = vec.try_fold_with(folder, outer_binder)?; - Ok(CallableSig { - params_and_return: folded.into(), - is_varargs: self.is_varargs, - safety: self.safety, - abi: self.abi, - }) - } -} - #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -pub enum ImplTraitId { - ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx), - TypeAliasImplTrait(hir_def::TypeAliasId, ImplTraitIdx), - AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId), -} - -#[derive(PartialEq, Eq, Debug, Hash)] -pub struct ImplTraits { - pub(crate) impl_traits: Arena<ImplTrait>, -} - -has_interner!(ImplTraits); - -#[derive(PartialEq, Eq, Debug, Hash)] -pub struct ImplTrait { - pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>, -} - -pub type ImplTraitIdx = Idx<ImplTrait>; - -pub fn static_lifetime() -> Lifetime { - LifetimeData::Static.intern(Interner) -} - -pub fn error_lifetime() -> Lifetime { - LifetimeData::Error.intern(Interner) -} - -pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>( - t: T, - for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty, - for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const, -) -> T { - use chalk_ir::fold::TypeFolder; - - #[derive(chalk_derive::FallibleTypeFolder)] - #[has_interner(Interner)] - struct FreeVarFolder< - F1: FnMut(BoundVar, DebruijnIndex) -> Ty, - F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const, - >(F1, F2); - impl<F1: FnMut(BoundVar, DebruijnIndex) -> Ty, F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const> - TypeFolder<Interner> for FreeVarFolder<F1, F2> - { - fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty { - self.0(bound_var, outer_binder) - } - - fn fold_free_var_const( - &mut self, - ty: Ty, - bound_var: BoundVar, - outer_binder: DebruijnIndex, - ) -> Const { - self.1(ty, bound_var, outer_binder) - } - } - t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST) -} - -pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>( - t: T, - mut for_ty: impl FnMut(Ty, DebruijnIndex) -> Ty, - binders: DebruijnIndex, -) -> T { - fold_tys_and_consts( - t, - |x, d| match x { - Either::Left(x) => Either::Left(for_ty(x, d)), - Either::Right(x) => Either::Right(x), - }, - binders, - ) -} - -pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>( - t: T, - f: impl FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>, - binders: DebruijnIndex, -) -> T { - use chalk_ir::fold::{TypeFolder, TypeSuperFoldable}; - #[derive(chalk_derive::FallibleTypeFolder)] - #[has_interner(Interner)] - struct TyFolder<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>>(F); - impl<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>> TypeFolder<Interner> - for TyFolder<F> - { - fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty { - let ty = ty.super_fold_with(self.as_dyn(), outer_binder); - self.0(Either::Left(ty), outer_binder).left().unwrap() - } - - fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const { - self.0(Either::Right(c), outer_binder).right().unwrap() - } - } - t.fold_with(&mut TyFolder(f), binders) -} - -pub(crate) fn fold_generic_args<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>( - t: T, - f: impl FnMut(GenericArgData, DebruijnIndex) -> GenericArgData, - binders: DebruijnIndex, -) -> T { - use chalk_ir::fold::{TypeFolder, TypeSuperFoldable}; - #[derive(chalk_derive::FallibleTypeFolder)] - #[has_interner(Interner)] - struct TyFolder<F: FnMut(GenericArgData, DebruijnIndex) -> GenericArgData>(F); - impl<F: FnMut(GenericArgData, DebruijnIndex) -> GenericArgData> TypeFolder<Interner> - for TyFolder<F> - { - fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty { - let ty = ty.super_fold_with(self.as_dyn(), outer_binder); - self.0(GenericArgData::Ty(ty), outer_binder) - .intern(Interner) - .ty(Interner) - .unwrap() - .clone() - } - - fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const { - self.0(GenericArgData::Const(c), outer_binder) - .intern(Interner) - .constant(Interner) - .unwrap() - .clone() - } - - fn fold_lifetime(&mut self, lt: Lifetime, outer_binder: DebruijnIndex) -> Lifetime { - let lt = lt.super_fold_with(self.as_dyn(), outer_binder); - self.0(GenericArgData::Lifetime(lt), outer_binder) - .intern(Interner) - .lifetime(Interner) - .unwrap() - .clone() - } - } - t.fold_with(&mut TyFolder(f), binders) +pub enum ImplTraitId<'db> { + ReturnTypeImplTrait(hir_def::FunctionId, next_solver::ImplTraitIdx<'db>), + TypeAliasImplTrait(hir_def::TypeAliasId, next_solver::ImplTraitIdx<'db>), } /// 'Canonicalizes' the `t` by replacing any errors with new variables. Also /// ensures there are no unbound variables or inference variables anywhere in /// the `t`. -pub fn replace_errors_with_variables<T>(t: &T) -> Canonical<T> +pub fn replace_errors_with_variables<'db, T>(interner: DbInterner<'db>, t: &T) -> Canonical<'db, T> where - T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + Clone, + T: rustc_type_ir::TypeFoldable<DbInterner<'db>> + Clone, { - use chalk_ir::{ - Fallible, - fold::{FallibleTypeFolder, TypeSuperFoldable}, - }; - struct ErrorReplacer { - vars: usize, - } - impl FallibleTypeFolder<Interner> for ErrorReplacer { - type Error = NoSolution; - - fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = Self::Error> { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn try_fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> { - if let TyKind::Error = ty.kind(Interner) { - let index = self.vars; - self.vars += 1; - Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(Interner)) - } else { - ty.try_super_fold_with(self.as_dyn(), outer_binder) + use rustc_type_ir::{FallibleTypeFolder, TypeSuperFoldable}; + struct ErrorReplacer<'db> { + interner: DbInterner<'db>, + vars: Vec<CanonicalVarKind<'db>>, + binder: rustc_type_ir::DebruijnIndex, + } + impl<'db> FallibleTypeFolder<DbInterner<'db>> for ErrorReplacer<'db> { + #[cfg(debug_assertions)] + type Error = (); + #[cfg(not(debug_assertions))] + type Error = std::convert::Infallible; + + fn cx(&self) -> DbInterner<'db> { + self.interner + } + + fn try_fold_binder<T>(&mut self, t: Binder<'db, T>) -> Result<Binder<'db, T>, Self::Error> + where + T: rustc_type_ir::TypeFoldable<DbInterner<'db>>, + { + self.binder.shift_in(1); + let result = t.try_super_fold_with(self); + self.binder.shift_out(1); + result + } + + fn try_fold_ty(&mut self, t: Ty<'db>) -> Result<Ty<'db>, Self::Error> { + if !t.has_type_flags( + rustc_type_ir::TypeFlags::HAS_ERROR + | rustc_type_ir::TypeFlags::HAS_TY_INFER + | rustc_type_ir::TypeFlags::HAS_CT_INFER + | rustc_type_ir::TypeFlags::HAS_RE_INFER, + ) { + return Ok(t); } - } - fn try_fold_inference_ty( - &mut self, - _var: InferenceVar, - _kind: TyVariableKind, - _outer_binder: DebruijnIndex, - ) -> Fallible<Ty> { - if cfg!(debug_assertions) { - // we don't want to just panic here, because then the error message - // won't contain the whole thing, which would not be very helpful - Err(NoSolution) - } else { - Ok(TyKind::Error.intern(Interner)) + #[cfg(debug_assertions)] + let error = || Err(()); + #[cfg(not(debug_assertions))] + let error = || Ok(Ty::new_error(self.interner, crate::next_solver::ErrorGuaranteed)); + + match t.kind() { + TyKind::Error(_) => { + let var = rustc_type_ir::BoundVar::from_usize(self.vars.len()); + self.vars.push(CanonicalVarKind::Ty { + ui: rustc_type_ir::UniverseIndex::ZERO, + sub_root: var, + }); + Ok(Ty::new_bound( + self.interner, + self.binder, + BoundTy { var, kind: BoundTyKind::Anon }, + )) + } + TyKind::Infer(_) => error(), + TyKind::Bound(BoundVarIndexKind::Bound(index), _) if index > self.binder => error(), + _ => t.try_super_fold_with(self), } } - fn try_fold_free_var_ty( - &mut self, - _bound_var: BoundVar, - _outer_binder: DebruijnIndex, - ) -> Fallible<Ty> { - if cfg!(debug_assertions) { - // we don't want to just panic here, because then the error message - // won't contain the whole thing, which would not be very helpful - Err(NoSolution) - } else { - Ok(TyKind::Error.intern(Interner)) + fn try_fold_const(&mut self, ct: Const<'db>) -> Result<Const<'db>, Self::Error> { + if !ct.has_type_flags( + rustc_type_ir::TypeFlags::HAS_ERROR + | rustc_type_ir::TypeFlags::HAS_TY_INFER + | rustc_type_ir::TypeFlags::HAS_CT_INFER + | rustc_type_ir::TypeFlags::HAS_RE_INFER, + ) { + return Ok(ct); } - } - fn try_fold_inference_const( - &mut self, - ty: Ty, - _var: InferenceVar, - _outer_binder: DebruijnIndex, - ) -> Fallible<Const> { - if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(unknown_const(ty)) } - } - - fn try_fold_free_var_const( - &mut self, - ty: Ty, - _bound_var: BoundVar, - _outer_binder: DebruijnIndex, - ) -> Fallible<Const> { - if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(unknown_const(ty)) } - } + #[cfg(debug_assertions)] + let error = || Err(()); + #[cfg(not(debug_assertions))] + let error = || Ok(Const::error(self.interner)); - fn try_fold_inference_lifetime( - &mut self, - _var: InferenceVar, - _outer_binder: DebruijnIndex, - ) -> Fallible<Lifetime> { - if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(error_lifetime()) } + match ct.kind() { + ConstKind::Error(_) => { + let var = rustc_type_ir::BoundVar::from_usize(self.vars.len()); + self.vars.push(CanonicalVarKind::Const(rustc_type_ir::UniverseIndex::ZERO)); + Ok(Const::new_bound(self.interner, self.binder, BoundConst { var })) + } + ConstKind::Infer(_) => error(), + ConstKind::Bound(BoundVarIndexKind::Bound(index), _) if index > self.binder => { + error() + } + _ => ct.try_super_fold_with(self), + } } - fn try_fold_free_var_lifetime( - &mut self, - _bound_var: BoundVar, - _outer_binder: DebruijnIndex, - ) -> Fallible<Lifetime> { - if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(error_lifetime()) } + fn try_fold_region(&mut self, region: Region<'db>) -> Result<Region<'db>, Self::Error> { + #[cfg(debug_assertions)] + let error = || Err(()); + #[cfg(not(debug_assertions))] + let error = || Ok(Region::error(self.interner)); + + match region.kind() { + RegionKind::ReError(_) => { + let var = rustc_type_ir::BoundVar::from_usize(self.vars.len()); + self.vars.push(CanonicalVarKind::Region(rustc_type_ir::UniverseIndex::ZERO)); + Ok(Region::new_bound( + self.interner, + self.binder, + BoundRegion { var, kind: BoundRegionKind::Anon }, + )) + } + RegionKind::ReVar(_) => error(), + RegionKind::ReBound(BoundVarIndexKind::Bound(index), _) if index > self.binder => { + error() + } + _ => Ok(region), + } } } - let mut error_replacer = ErrorReplacer { vars: 0 }; - let value = match t.clone().try_fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) { + + let mut error_replacer = + ErrorReplacer { vars: Vec::new(), binder: rustc_type_ir::DebruijnIndex::ZERO, interner }; + let value = match t.clone().try_fold_with(&mut error_replacer) { Ok(t) => t, Err(_) => panic!("Encountered unbound or inference vars in {t:?}"), }; - let kinds = (0..error_replacer.vars).map(|_| { - chalk_ir::CanonicalVarKind::new( - chalk_ir::VariableKind::Ty(TyVariableKind::General), - chalk_ir::UniverseIndex::ROOT, - ) - }); - Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) } + Canonical { + value, + max_universe: rustc_type_ir::UniverseIndex::ZERO, + variables: CanonicalVars::new_from_iter(interner, error_replacer.vars), + } } -pub fn callable_sig_from_fn_trait( - self_ty: &Ty, - trait_env: Arc<TraitEnvironment>, - db: &dyn HirDatabase, -) -> Option<(FnTrait, CallableSig)> { - let krate = trait_env.krate; - let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; +/// To be used from `hir` only. +pub fn callable_sig_from_fn_trait<'db>( + self_ty: Ty<'db>, + trait_env: Arc<TraitEnvironment<'db>>, + db: &'db dyn HirDatabase, +) -> Option<(FnTrait, PolyFnSig<'db>)> { + let mut table = InferenceTable::new(db, trait_env.clone(), None); + let lang_items = table.interner().lang_items(); + + let fn_once_trait = FnTrait::FnOnce.get_id(lang_items)?; let output_assoc_type = fn_once_trait .trait_items(db) .associated_type_by_name(&Name::new_symbol_root(sym::Output))?; - let mut table = InferenceTable::new(db, trait_env.clone()); - let b = TyBuilder::trait_ref(db, fn_once_trait); - if b.remaining() != 2 { - return None; - } - // Register two obligations: // - Self: FnOnce<?args_ty> // - <Self as FnOnce<?args_ty>>::Output == ?ret_ty - let args_ty = table.new_type_var(); - let mut trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build(); - let projection = TyBuilder::assoc_type_projection( - db, - output_assoc_type, - Some(trait_ref.substitution.clone()), - ) - .build(); - - let goal: Goal = trait_ref.clone().cast(Interner); - let pred = goal.to_nextsolver(table.interner); - if !table.try_obligation(goal).no_solution() { + let args_ty = table.next_ty_var(); + let args = [self_ty, args_ty]; + let trait_ref = TraitRef::new(table.interner(), fn_once_trait.into(), args); + let projection = Ty::new_alias( + table.interner(), + rustc_type_ir::AliasTyKind::Projection, + AliasTy::new(table.interner(), output_assoc_type.into(), args), + ); + + let pred = Predicate::upcast_from(trait_ref, table.interner()); + if !table.try_obligation(pred).no_solution() { table.register_obligation(pred); - let return_ty = table.normalize_projection_ty(projection); + let return_ty = table.normalize_alias_ty(projection); for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { - let fn_x_trait = fn_x.get_id(db, krate)?; - trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); - if !table.try_obligation(trait_ref.clone().cast(Interner)).no_solution() { + let fn_x_trait = fn_x.get_id(lang_items)?; + let trait_ref = TraitRef::new(table.interner(), fn_x_trait.into(), args); + if !table + .try_obligation(Predicate::upcast_from(trait_ref, table.interner())) + .no_solution() + { let ret_ty = table.resolve_completely(return_ty); let args_ty = table.resolve_completely(args_ty); - let params = args_ty - .as_tuple()? - .iter(Interner) - .map(|it| it.assert_ty_ref(Interner)) - .cloned(); + let TyKind::Tuple(params) = args_ty.kind() else { + return None; + }; + let inputs_and_output = Tys::new_from_iter( + table.interner(), + params.iter().chain(std::iter::once(ret_ty)), + ); return Some(( fn_x, - CallableSig::from_params_and_return( - params, - ret_ty, - false, - Safety::Safe, - FnAbi::RustCall, - ), + Binder::dummy(FnSig { + inputs_and_output, + c_variadic: false, + safety: abi::Safety::Safe, + abi: FnAbi::RustCall, + }), )); } } @@ -980,74 +535,72 @@ pub fn callable_sig_from_fn_trait( } } -struct PlaceholderCollector<'db> { - db: &'db dyn HirDatabase, - placeholders: FxHashSet<TypeOrConstParamId>, +struct ParamCollector { + params: FxHashSet<TypeOrConstParamId>, } -impl PlaceholderCollector<'_> { - fn collect(&mut self, idx: PlaceholderIndex) { - let id = from_placeholder_idx(self.db, idx).0; - self.placeholders.insert(id); - } -} +impl<'db> rustc_type_ir::TypeVisitor<DbInterner<'db>> for ParamCollector { + type Result = (); -impl TypeVisitor<Interner> for PlaceholderCollector<'_> { - type BreakTy = (); + fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result { + if let TyKind::Param(param) = ty.kind() { + self.params.insert(param.id.into()); + } - fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> { - self + ty.super_visit_with(self); } - fn interner(&self) -> Interner { - Interner + fn visit_const(&mut self, konst: Const<'db>) -> Self::Result { + if let ConstKind::Param(param) = konst.kind() { + self.params.insert(param.id.into()); + } + + konst.super_visit_with(self); } +} - fn visit_ty( - &mut self, - ty: &Ty, - outer_binder: DebruijnIndex, - ) -> std::ops::ControlFlow<Self::BreakTy> { - let has_placeholder_bits = TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER; - let chalk_ir::TyData { kind, flags } = ty.data(Interner); - - if let TyKind::Placeholder(idx) = kind { - self.collect(*idx); - } else if flags.intersects(has_placeholder_bits) { - return ty.super_visit_with(self, outer_binder); +/// Returns unique params for types and consts contained in `value`. +pub fn collect_params<'db, T>(value: &T) -> Vec<TypeOrConstParamId> +where + T: ?Sized + rustc_type_ir::TypeVisitable<DbInterner<'db>>, +{ + let mut collector = ParamCollector { params: FxHashSet::default() }; + value.visit_with(&mut collector); + Vec::from_iter(collector.params) +} + +struct TypeInferenceVarCollector<'db> { + type_inference_vars: Vec<Ty<'db>>, +} + +impl<'db> rustc_type_ir::TypeVisitor<DbInterner<'db>> for TypeInferenceVarCollector<'db> { + type Result = (); + + fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result { + use crate::rustc_type_ir::Flags; + if ty.is_ty_var() { + self.type_inference_vars.push(ty); + } else if ty.flags().intersects(rustc_type_ir::TypeFlags::HAS_TY_INFER) { + ty.super_visit_with(self); } else { // Fast path: don't visit inner types (e.g. generic arguments) when `flags` indicate // that there are no placeholders. } - - std::ops::ControlFlow::Continue(()) - } - - fn visit_const( - &mut self, - constant: &chalk_ir::Const<Interner>, - _outer_binder: DebruijnIndex, - ) -> std::ops::ControlFlow<Self::BreakTy> { - if let chalk_ir::ConstValue::Placeholder(idx) = constant.data(Interner).value { - self.collect(idx); - } - std::ops::ControlFlow::Continue(()) } } -/// Returns unique placeholders for types and consts contained in `value`. -pub fn collect_placeholders<T>(value: &T, db: &dyn HirDatabase) -> Vec<TypeOrConstParamId> +pub fn collect_type_inference_vars<'db, T>(value: &T) -> Vec<Ty<'db>> where - T: ?Sized + TypeVisitable<Interner>, + T: ?Sized + rustc_type_ir::TypeVisitable<DbInterner<'db>>, { - let mut collector = PlaceholderCollector { db, placeholders: FxHashSet::default() }; - _ = value.visit_with(&mut collector, DebruijnIndex::INNERMOST); - collector.placeholders.into_iter().collect() + let mut collector = TypeInferenceVarCollector { type_inference_vars: vec![] }; + value.visit_with(&mut collector); + collector.type_inference_vars } -pub fn known_const_to_ast( - konst: &Const, - db: &dyn HirDatabase, +pub fn known_const_to_ast<'db>( + konst: Const<'db>, + db: &'db dyn HirDatabase, display_target: DisplayTarget, ) -> Option<ConstArg> { Some(make::expr_const_value(konst.display(db, display_target).to_string().as_str())) |