//! This gets rid of free variables in a type by replacing them by fresh bound //! ones. We use this when building clauses that contain types passed to //! `program_clauses`; these may contain variables, and just copying those //! variables verbatim leads to problems. Instead, we return a slightly more //! general program clause, with new variables in those places. This can only //! happen with `dyn Trait` currently; that's the only case where we use the //! types passed to `program_clauses` in the clauses we generate. use chalk_derive::FallibleTypeFolder; use chalk_ir::{ fold::{TypeFoldable, TypeFolder}, interner::{HasInterner, Interner}, Binders, BoundVar, Const, ConstData, ConstValue, DebruijnIndex, Lifetime, LifetimeData, Ty, TyKind, TyVariableKind, VariableKind, VariableKinds, }; use rustc_hash::FxHashMap; #[derive(FallibleTypeFolder)] pub struct Generalize { binders: Vec>, mapping: FxHashMap, interner: I, } impl Generalize { pub fn apply(interner: I, value: T) -> Binders where T: HasInterner + TypeFoldable, { let mut generalize = Generalize { binders: Vec::new(), mapping: FxHashMap::default(), interner, }; let value = value .try_fold_with(&mut generalize, DebruijnIndex::INNERMOST) .unwrap(); Binders::new( VariableKinds::from_iter(interner, generalize.binders), value, ) } } impl TypeFolder for Generalize { fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty { let binder_vec = &mut self.binders; let new_index = self.mapping.entry(bound_var).or_insert_with(|| { let i = binder_vec.len(); binder_vec.push(VariableKind::Ty(TyVariableKind::General)); i }); let new_var = BoundVar::new(outer_binder, *new_index); TyKind::BoundVar(new_var).intern(TypeFolder::interner(self)) } fn fold_free_var_const( &mut self, ty: Ty, bound_var: BoundVar, outer_binder: DebruijnIndex, ) -> Const { let binder_vec = &mut self.binders; let new_index = self.mapping.entry(bound_var).or_insert_with(|| { let i = binder_vec.len(); binder_vec.push(VariableKind::Const(ty.clone())); i }); let new_var = BoundVar::new(outer_binder, *new_index); ConstData { ty, value: ConstValue::BoundVar(new_var), } .intern(TypeFolder::interner(self)) } fn fold_free_var_lifetime( &mut self, bound_var: BoundVar, outer_binder: DebruijnIndex, ) -> Lifetime { let binder_vec = &mut self.binders; let new_index = self.mapping.entry(bound_var).or_insert_with(|| { let i = binder_vec.len(); binder_vec.push(VariableKind::Lifetime); i }); let new_var = BoundVar::new(outer_binder, *new_index); LifetimeData::BoundVar(new_var).intern(TypeFolder::interner(self)) } fn interner(&self) -> I { self.interner } }