//! The type system. We currently use this to infer types for completion, hover //! information and various assists. #[allow(unused)] macro_rules! eprintln { ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; } mod autoderef; mod builder; mod chalk_db; mod chalk_ext; pub mod consteval; mod infer; mod interner; mod lower; mod mapping; mod tls; mod utils; mod walk; pub mod db; pub mod diagnostics; pub mod display; pub mod method_resolution; pub mod primitive; pub mod traits; #[cfg(test)] mod tests; #[cfg(test)] mod test_db; use std::sync::Arc; use chalk_ir::{ fold::{Shift, TypeFoldable}, interner::HasInterner, NoSolution, }; use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId}; use itertools::Either; use utils::Generics; use crate::{consteval::unknown_const, db::HirDatabase, utils::generics}; pub use autoderef::autoderef; pub use builder::{ParamKind, TyBuilder}; pub use chalk_ext::*; pub use infer::{ could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, InferenceResult, }; pub use interner::Interner; pub use lower::{ associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId, }; pub use mapping::{ from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id, to_placeholder_idx, }; pub use traits::TraitEnvironment; pub use utils::{all_super_traits, is_fn_unsafe_to_call}; pub use walk::TypeWalk; pub use chalk_ir::{ cast::Cast, AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind, }; pub type ForeignDefId = chalk_ir::ForeignDefId; pub type AssocTypeId = chalk_ir::AssocTypeId; pub type FnDefId = chalk_ir::FnDefId; pub type ClosureId = chalk_ir::ClosureId; pub type OpaqueTyId = chalk_ir::OpaqueTyId; pub type PlaceholderIndex = chalk_ir::PlaceholderIndex; pub type VariableKind = chalk_ir::VariableKind; pub type VariableKinds = chalk_ir::VariableKinds; pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds; pub type Binders = chalk_ir::Binders; pub type Substitution = chalk_ir::Substitution; pub type GenericArg = chalk_ir::GenericArg; pub type GenericArgData = chalk_ir::GenericArgData; pub type Ty = chalk_ir::Ty; pub type TyKind = chalk_ir::TyKind; pub type DynTy = chalk_ir::DynTy; pub type FnPointer = chalk_ir::FnPointer; // pub type FnSubst = chalk_ir::FnSubst; pub use chalk_ir::FnSubst; pub type ProjectionTy = chalk_ir::ProjectionTy; pub type AliasTy = chalk_ir::AliasTy; pub type OpaqueTy = chalk_ir::OpaqueTy; pub type InferenceVar = chalk_ir::InferenceVar; pub type Lifetime = chalk_ir::Lifetime; pub type LifetimeData = chalk_ir::LifetimeData; pub type LifetimeOutlives = chalk_ir::LifetimeOutlives; pub type Const = chalk_ir::Const; pub type ConstData = chalk_ir::ConstData; pub type ConstValue = chalk_ir::ConstValue; pub type ConcreteConst = chalk_ir::ConcreteConst; pub type ChalkTraitId = chalk_ir::TraitId; pub type TraitRef = chalk_ir::TraitRef; pub type QuantifiedWhereClause = Binders; pub type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses; pub type Canonical = chalk_ir::Canonical; pub type FnSig = chalk_ir::FnSig; pub type InEnvironment = chalk_ir::InEnvironment; pub type Environment = chalk_ir::Environment; pub type DomainGoal = chalk_ir::DomainGoal; pub type Goal = chalk_ir::Goal; pub type AliasEq = chalk_ir::AliasEq; pub type Solution = chalk_solve::Solution; pub type ConstrainedSubst = chalk_ir::ConstrainedSubst; pub type Guidance = chalk_solve::Guidance; pub type WhereClause = chalk_ir::WhereClause; // FIXME: get rid of this pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution { Substitution::from_iter( Interner, s.as_slice(Interner)[..std::cmp::min(s.len(Interner), n)].iter().cloned(), ) } /// 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 { generics(db.upcast(), id.parent).param_idx(id) } pub(crate) fn wrap_empty_binders(value: T) -> Binders where T: TypeFoldable + HasInterner, { Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE)) } pub(crate) fn make_type_and_const_binders>( which_is_const: impl Iterator>, value: T, ) -> Binders { 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>( value: T, ) -> Binders { Binders::new( VariableKinds::from_iter( Interner, std::iter::once(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)), ), value, ) } pub(crate) fn make_binders_with_count>( db: &dyn HirDatabase, count: usize, generics: &Generics, value: T, ) -> Binders { let it = generics.iter_id().take(count).map(|id| match id { Either::Left(_) => None, Either::Right(id) => Some(db.const_param_ty(id)), }); crate::make_type_and_const_binders(it, value) } pub(crate) fn make_binders>( db: &dyn HirDatabase, generics: &Generics, value: T, ) -> Binders { make_binders_with_count(db, usize::MAX, generics, value) } // FIXME: get rid of this pub fn make_canonical>( value: T, kinds: impl IntoIterator, ) -> Canonical { let kinds = kinds.into_iter().map(|tk| { chalk_ir::CanonicalVarKind::new( chalk_ir::VariableKind::Ty(tk), chalk_ir::UniverseIndex::ROOT, ) }); Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) } } // 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, } has_interner!(CallableSig); /// A polymorphic function signature. pub type PolyFnSig = Binders; impl CallableSig { pub fn from_params_and_return(mut params: Vec, ret: Ty, is_varargs: bool) -> CallableSig { params.push(ret); CallableSig { params_and_return: params.into(), is_varargs } } pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig { CallableSig { // FIXME: what to do about lifetime params? -> return PolyFnSig params_and_return: 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()) .collect(), is_varargs: fn_ptr.sig.variadic, } } pub fn to_fn_ptr(&self) -> FnPointer { FnPointer { num_binders: 0, sig: FnSig { abi: (), safety: Safety::Safe, variadic: self.is_varargs }, substitution: FnSubst(Substitution::from_iter( Interner, self.params_and_return.iter().cloned(), )), } } 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 for CallableSig { fn fold_with( self, folder: &mut dyn chalk_ir::fold::TypeFolder, outer_binder: DebruijnIndex, ) -> Result { let vec = self.params_and_return.to_vec(); let folded = vec.fold_with(folder, outer_binder)?; Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs }) } } #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum ImplTraitId { ReturnTypeImplTrait(hir_def::FunctionId, u16), AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId), } #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct ReturnTypeImplTraits { pub(crate) impl_traits: Vec, } has_interner!(ReturnTypeImplTraits); #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) struct ReturnTypeImplTrait { pub(crate) bounds: Binders>, } pub fn static_lifetime() -> Lifetime { LifetimeData::Static.intern(Interner) } pub(crate) fn fold_free_vars + TypeFoldable>( t: T, for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty, for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const, ) -> T { use chalk_ir::{fold::TypeFolder, Fallible}; struct FreeVarFolder(F1, F2); impl< 'i, F1: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i, F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const + 'i, > TypeFolder for FreeVarFolder { type Error = NoSolution; fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } fn interner(&self) -> Interner { Interner } fn fold_free_var_ty( &mut self, bound_var: BoundVar, outer_binder: DebruijnIndex, ) -> Fallible { Ok(self.0(bound_var, outer_binder)) } fn fold_free_var_const( &mut self, ty: Ty, bound_var: BoundVar, outer_binder: DebruijnIndex, ) -> Fallible { Ok(self.1(ty, bound_var, outer_binder)) } } t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST) .expect("fold failed unexpectedly") } pub(crate) fn fold_tys + TypeFoldable>( 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 + TypeFoldable>( t: T, f: impl FnMut(Either, DebruijnIndex) -> Either, binders: DebruijnIndex, ) -> T { use chalk_ir::{ fold::{TypeFolder, TypeSuperFoldable}, Fallible, }; struct TyFolder(F); impl<'i, F: FnMut(Either, DebruijnIndex) -> Either + 'i> TypeFolder for TyFolder { type Error = NoSolution; fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } fn interner(&self) -> Interner { Interner } fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible { let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?; Ok(self.0(Either::Left(ty), outer_binder).left().unwrap()) } fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Fallible { Ok(self.0(Either::Right(c), outer_binder).right().unwrap()) } } t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly") } /// '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) -> Canonical where T: HasInterner + TypeFoldable + Clone, T: HasInterner, { use chalk_ir::{ fold::{TypeFolder, TypeSuperFoldable}, Fallible, }; struct ErrorReplacer { vars: usize, } impl TypeFolder for ErrorReplacer { type Error = NoSolution; fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } fn interner(&self) -> Interner { Interner } fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible { 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 { let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?; Ok(ty) } } fn fold_inference_ty( &mut self, _var: InferenceVar, _kind: TyVariableKind, _outer_binder: DebruijnIndex, ) -> Fallible { 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 fold_free_var_ty( &mut self, _bound_var: BoundVar, _outer_binder: DebruijnIndex, ) -> Fallible { 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 fold_inference_const( &mut self, ty: Ty, _var: InferenceVar, _outer_binder: DebruijnIndex, ) -> Fallible { if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(unknown_const(ty)) } } fn fold_free_var_const( &mut self, ty: Ty, _bound_var: BoundVar, _outer_binder: DebruijnIndex, ) -> Fallible { if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(unknown_const(ty)) } } fn fold_inference_lifetime( &mut self, _var: InferenceVar, _outer_binder: DebruijnIndex, ) -> Fallible { if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(static_lifetime()) } } fn fold_free_var_lifetime( &mut self, _bound_var: BoundVar, _outer_binder: DebruijnIndex, ) -> Fallible { if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(static_lifetime()) } } } let mut error_replacer = ErrorReplacer { vars: 0 }; let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) { 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) } }