//! 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 op; 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::{Fold, Shift}, interner::HasInterner, UintTy, }; use hir_def::{ expr::ExprId, type_ref::{ConstScalar, Rawness}, TypeParamId, }; use crate::{db::HirDatabase, utils::generics}; pub use autoderef::autoderef; pub use builder::TyBuilder; pub use chalk_ext::*; pub use infer::{could_unify, InferenceDiagnostic, InferenceResult}; pub use interner::Interner; pub use lower::{ associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId, }; pub use mapping::{ const_from_placeholder_idx, 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; 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 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: TypeParamId) -> Option { generics(db.upcast(), id.parent).param_idx(id) } pub(crate) fn wrap_empty_binders(value: T) -> Binders where T: Fold + HasInterner, { Binders::empty(&Interner, value.shifted_in_from(&Interner, DebruijnIndex::ONE)) } pub(crate) fn make_only_type_binders>( num_vars: usize, value: T, ) -> Binders { Binders::new( VariableKinds::from_iter( &Interner, std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)) .take(num_vars), ), 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 Fold for CallableSig { type Result = CallableSig; fn fold_with<'i>( self, folder: &mut dyn chalk_ir::fold::Folder<'i, Interner>, outer_binder: DebruijnIndex, ) -> chalk_ir::Fallible where Interner: 'i, { 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 fn dummy_usize_const() -> Const { let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner); chalk_ir::ConstData { ty: usize_ty, value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: ConstScalar::Unknown, }), } .intern(&Interner) } pub(crate) fn fold_free_vars + Fold>( t: T, f: impl FnMut(BoundVar, DebruijnIndex) -> Ty, ) -> T::Result { use chalk_ir::{fold::Folder, Fallible}; struct FreeVarFolder(F); impl<'i, F: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i> Folder<'i, Interner> for FreeVarFolder { fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> { self } fn interner(&self) -> &'i Interner { &Interner } fn fold_free_var_ty( &mut self, bound_var: BoundVar, outer_binder: DebruijnIndex, ) -> Fallible { Ok(self.0(bound_var, outer_binder)) } } t.fold_with(&mut FreeVarFolder(f), DebruijnIndex::INNERMOST).expect("fold failed unexpectedly") } pub(crate) fn fold_tys + Fold>( t: T, f: impl FnMut(Ty, DebruijnIndex) -> Ty, binders: DebruijnIndex, ) -> T::Result { use chalk_ir::{ fold::{Folder, SuperFold}, Fallible, }; struct TyFolder(F); impl<'i, F: FnMut(Ty, DebruijnIndex) -> Ty + 'i> Folder<'i, Interner> for TyFolder { fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> { self } fn interner(&self) -> &'i 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(ty, outer_binder)) } } 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 + Fold + Clone, T::Result: HasInterner, { use chalk_ir::{ fold::{Folder, SuperFold}, Fallible, NoSolution, }; struct ErrorReplacer { vars: usize, } impl<'i> Folder<'i, Interner> for ErrorReplacer { fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> { self } fn interner(&self) -> &'i 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(dummy_usize_const()) } } fn fold_free_var_const( &mut self, _ty: Ty, _bound_var: BoundVar, _outer_binder: DebruijnIndex, ) -> Fallible { if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(dummy_usize_const()) } } 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) } }