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 | 903 |
1 files changed, 236 insertions, 667 deletions
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index e787fd9b1e..25579e04ed 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -3,35 +3,32 @@ #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] -#[cfg(feature = "in-rust-tree")] -extern crate rustc_index; +// FIXME: We used to import `rustc_*` deps from `rustc_private` with `feature = "in-rust-tree" but +// temporarily switched to crates.io versions due to hardships that working on them from rustc +// demands corresponding changes on rust-analyzer at the same time. +// For details, see the zulip discussion below: +// https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/relying.20on.20in-tree.20.60rustc_type_ir.60.2F.60rustc_next_trait_solver.60/with/541055689 -#[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_index as rustc_index; -#[cfg(feature = "in-rust-tree")] -extern crate rustc_abi; - -#[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_abi as rustc_abi; -#[cfg(feature = "in-rust-tree")] -extern crate rustc_pattern_analysis; - -#[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis; -mod builder; -mod chalk_db; -mod chalk_ext; -mod drop; +extern crate ra_ap_rustc_ast_ir as rustc_ast_ir; + +extern crate ra_ap_rustc_type_ir as rustc_type_ir; + +extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver; + +extern crate self as hir_ty; + mod infer; mod inhabitedness; -mod interner; mod lower; -mod mapping; +pub mod next_solver; +mod specialization; mod target_feature; -mod tls; mod utils; pub mod autoderef; @@ -39,6 +36,7 @@ pub mod consteval; pub mod db; pub mod diagnostics; pub mod display; +pub mod drop; pub mod dyn_compatibility; pub mod generics; pub mod lang_items; @@ -56,160 +54,70 @@ mod variance; use std::hash::Hash; -use chalk_ir::{ - NoSolution, - 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::{ + 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::{ + 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, cast::CastError, - closure::{CaptureKind, CapturedItem}, + closure::analysis::{CaptureKind, CapturedItem}, could_coerce, could_unify, could_unify_deeply, }; -pub use interner::Interner; pub use lower::{ - ImplTraitLoweringMode, LifetimeElisionKind, ParamLoweringMode, TyDefId, TyLoweringContext, - ValueTyDefId, associated_type_shorthand_candidates, diagnostics::*, -}; -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, + LifetimeElisionKind, TyDefId, TyLoweringContext, ValueTyDefId, + associated_type_shorthand_candidates, diagnostics::*, }; 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 utils::{Unsafety, all_super_traits, direct_super_traits, is_fn_unsafe_to_call}; -pub use variance::Variance; - -pub use chalk_ir::{ - AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind, - cast::Cast, - visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, +pub use utils::{ + TargetFeatureIsSafeInTarget, Unsafety, all_super_traits, direct_super_traits, + is_fn_unsafe_to_call, target_feature_is_safe_in_target, }; -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 VariableKind = chalk_ir::VariableKind<Interner>; -pub type VariableKinds = chalk_ir::VariableKinds<Interner>; -pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<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 type DynTy = chalk_ir::DynTy<Interner>; -pub type FnPointer = chalk_ir::FnPointer<Interner>; -// pub type FnSubst = chalk_ir::FnSubst<Interner>; // a re-export so we don't lose the tuple constructor -pub use chalk_ir::FnSubst; -pub type ProjectionTy = chalk_ir::ProjectionTy<Interner>; -pub type AliasTy = chalk_ir::AliasTy<Interner>; -pub type OpaqueTy = chalk_ir::OpaqueTy<Interner>; -pub type InferenceVar = chalk_ir::InferenceVar; - -pub type Lifetime = chalk_ir::Lifetime<Interner>; -pub type LifetimeData = chalk_ir::LifetimeData<Interner>; -pub type LifetimeOutlives = chalk_ir::LifetimeOutlives<Interner>; - -pub type Const = chalk_ir::Const<Interner>; -pub type ConstData = chalk_ir::ConstData<Interner>; -pub type ConstValue = chalk_ir::ConstValue<Interner>; -pub type ConcreteConst = chalk_ir::ConcreteConst<Interner>; - -pub type ChalkTraitId = chalk_ir::TraitId<Interner>; -pub type TraitRef = chalk_ir::TraitRef<Interner>; -pub type QuantifiedWhereClause = Binders<WhereClause>; -pub type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses<Interner>; -pub type Canonical<T> = chalk_ir::Canonical<T>; - -pub type FnSig = chalk_ir::FnSig<Interner>; - -pub type InEnvironment<T> = chalk_ir::InEnvironment<T>; -pub type Environment = chalk_ir::Environment<Interner>; -pub type DomainGoal = chalk_ir::DomainGoal<Interner>; -pub type Goal = chalk_ir::Goal<Interner>; -pub type AliasEq = chalk_ir::AliasEq<Interner>; -pub type Solution = chalk_solve::Solution<Interner>; -pub type Constraint = chalk_ir::Constraint<Interner>; -pub type Constraints = chalk_ir::Constraints<Interner>; -pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>; -pub type Guidance = chalk_solve::Guidance<Interner>; -pub type WhereClause = chalk_ir::WhereClause<Interner>; - -pub type CanonicalVarKind = chalk_ir::CanonicalVarKind<Interner>; -pub type GoalData = chalk_ir::GoalData<Interner>; -pub type Goals = chalk_ir::Goals<Interner>; -pub type ProgramClauseData = chalk_ir::ProgramClauseData<Interner>; -pub type ProgramClause = chalk_ir::ProgramClause<Interner>; -pub type ProgramClauses = chalk_ir::ProgramClauses<Interner>; -pub type TyData = chalk_ir::TyData<Interner>; -pub type Variances = chalk_ir::Variances<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 /// meaningful. #[derive(Debug, Default, Clone, PartialEq, Eq)] -pub enum MemoryMap { +pub enum MemoryMap<'db> { #[default] Empty, Simple(Box<[u8]>), - Complex(Box<ComplexMemoryMap>), + Complex(Box<ComplexMemoryMap<'db>>), } #[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct ComplexMemoryMap { +pub struct ComplexMemoryMap<'db> { memory: IndexMap<usize, Box<[u8]>, FxBuildHasher>, - vtable: VTableMap, + vtable: VTableMap<'db>, } -impl ComplexMemoryMap { +impl ComplexMemoryMap<'_> { fn insert(&mut self, addr: usize, val: Box<[u8]>) { match self.memory.entry(addr) { Entry::Occupied(mut e) => { @@ -224,8 +132,8 @@ impl ComplexMemoryMap { } } -impl MemoryMap { - pub fn vtable_ty(&self, id: usize) -> Result<&Ty, MirEvalError> { +impl<'db> MemoryMap<'db> { + 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), @@ -241,8 +149,8 @@ impl MemoryMap { /// 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) }; @@ -275,112 +183,11 @@ impl MemoryMap { } } -/// A concrete constant value -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ConstScalar { - Bytes(Box<[u8]>, MemoryMap), - // 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) - } - } -} - /// 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_type_and_const_binders<T: HasInterner<Interner = Interner>>( - which_is_const: impl Iterator<Item = Option<Ty>>, - value: T, -) -> Binders<T> { - Binders::new( - VariableKinds::from_iter( - Interner, - which_is_const.map(|x| { - if let Some(ty) = x { - chalk_ir::VariableKind::Const(ty) - } else { - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) - } - }), - ), - value, - ) -} - -pub(crate) fn make_single_type_binders<T: HasInterner<Interner = Interner>>( - value: T, -) -> Binders<T> { - Binders::new( - 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 { - 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, @@ -524,371 +331,151 @@ 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 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, + use rustc_type_ir::{FallibleTypeFolder, TypeSuperFoldable}; + struct ErrorReplacer<'db> { + interner: DbInterner<'db>, + vars: Vec<CanonicalVarKind<'db>>, + binder: rustc_type_ir::DebruijnIndex, } - 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) + 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)> { +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 krate = trait_env.krate; let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; let output_assoc_type = fn_once_trait @@ -896,57 +483,48 @@ pub fn callable_sig_from_fn_trait( .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 block = trait_env.block; - let trait_env = trait_env.env.clone(); - let obligation = - InEnvironment { goal: trait_ref.clone().cast(Interner), environment: trait_env.clone() }; - let canonical = table.canonicalize(obligation.clone()); - if db.trait_solve(krate, block, canonical.cast(Interner)).is_some() { - table.register_obligation(obligation.goal); - let return_ty = table.normalize_projection_ty(projection); + 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_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); - let obligation: chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> = InEnvironment { - goal: trait_ref.clone().cast(Interner), - environment: trait_env.clone(), - }; - let canonical = table.canonicalize(obligation.clone()); - if db.trait_solve(krate, block, canonical.cast(Interner)).is_some() { + 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, + }), )); } } @@ -956,74 +534,43 @@ pub fn callable_sig_from_fn_trait( } } -struct PlaceholderCollector<'db> { - db: &'db dyn HirDatabase, - placeholders: FxHashSet<TypeOrConstParamId>, -} - -impl PlaceholderCollector<'_> { - fn collect(&mut self, idx: PlaceholderIndex) { - let id = from_placeholder_idx(self.db, idx); - self.placeholders.insert(id); - } +struct ParamCollector { + params: FxHashSet<TypeOrConstParamId>, } -impl TypeVisitor<Interner> for PlaceholderCollector<'_> { - type BreakTy = (); - - fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> { - self - } - - fn interner(&self) -> Interner { - Interner - } - - 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 TyData { kind, flags } = ty.data(Interner); +impl<'db> rustc_type_ir::TypeVisitor<DbInterner<'db>> for ParamCollector { + type Result = (); - if let TyKind::Placeholder(idx) = kind { - self.collect(*idx); - } else if flags.intersects(has_placeholder_bits) { - return ty.super_visit_with(self, outer_binder); - } else { - // Fast path: don't visit inner types (e.g. generic arguments) when `flags` indicate - // that there are no placeholders. + fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result { + if let TyKind::Param(param) = ty.kind() { + self.params.insert(param.id.into()); } - std::ops::ControlFlow::Continue(()) + ty.super_visit_with(self); } - 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); + fn visit_const(&mut self, konst: Const<'db>) -> Self::Result { + if let ConstKind::Param(param) = konst.kind() { + self.params.insert(param.id.into()); } - std::ops::ControlFlow::Continue(()) + + konst.super_visit_with(self); } } -/// Returns unique placeholders for types and consts contained in `value`. -pub fn collect_placeholders<T>(value: &T, db: &dyn HirDatabase) -> Vec<TypeOrConstParamId> +/// Returns unique params for types and consts contained in `value`. +pub fn collect_params<'db, T>(value: &T) -> Vec<TypeOrConstParamId> 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 = ParamCollector { params: FxHashSet::default() }; + value.visit_with(&mut collector); + Vec::from_iter(collector.params) } -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())) @@ -1045,3 +592,25 @@ pub(crate) enum DeclOrigin { pub(crate) struct DeclContext { pub(crate) origin: DeclOrigin, } + +pub fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> { + use std::env; + use std::sync::LazyLock; + use tracing_subscriber::{Registry, layer::SubscriberExt}; + use tracing_tree::HierarchicalLayer; + + static ENABLE: LazyLock<bool> = LazyLock::new(|| env::var("CHALK_DEBUG").is_ok()); + if !*ENABLE { + return None; + } + + let filter: tracing_subscriber::filter::Targets = + env::var("CHALK_DEBUG").ok().and_then(|it| it.parse().ok()).unwrap_or_default(); + let layer = HierarchicalLayer::default() + .with_indent_lines(true) + .with_ansi(false) + .with_indent_amount(2) + .with_writer(std::io::stderr); + let subscriber = Registry::default().with(filter).with(layer); + Some(tracing::subscriber::set_default(subscriber)) +} |