| use chalk_ir::fold::*; |
| use chalk_ir::interner::HasInterner; |
| use std::fmt::Debug; |
| use tracing::instrument; |
| |
| use super::*; |
| |
| impl<I: Interner> InferenceTable<I> { |
| /// Given the binders from a canonicalized value C, returns a |
| /// substitution S mapping each free variable in C to a fresh |
| /// inference variable. This substitution can then be applied to |
| /// C, which would be equivalent to |
| /// `self.instantiate_canonical(v)`. |
| pub(super) fn fresh_subst( |
| &mut self, |
| interner: &I, |
| binders: &[CanonicalVarKind<I>], |
| ) -> Substitution<I> { |
| Substitution::from_iter( |
| interner, |
| binders.iter().map(|kind| { |
| let param_infer_var = kind.map_ref(|&ui| self.new_variable(ui)); |
| param_infer_var.to_generic_arg(interner) |
| }), |
| ) |
| } |
| |
| /// Variant on `instantiate` that takes a `Canonical<T>`. |
| pub fn instantiate_canonical<T>(&mut self, interner: &I, bound: Canonical<T>) -> T::Result |
| where |
| T: HasInterner<Interner = I> + Fold<I> + Debug, |
| { |
| let subst = self.fresh_subst(interner, &bound.binders.as_slice(interner)); |
| subst.apply(bound.value, interner) |
| } |
| |
| /// Instantiates `arg` with fresh existential variables in the |
| /// given universe; the kinds of the variables are implied by |
| /// `binders`. This is used to apply a universally quantified |
| /// clause like `forall X, 'Y. P => Q`. Here the `binders` |
| /// argument is referring to `X, 'Y`. |
| fn instantiate_in<T>( |
| &mut self, |
| interner: &I, |
| universe: UniverseIndex, |
| binders: impl Iterator<Item = VariableKind<I>>, |
| arg: T, |
| ) -> T::Result |
| where |
| T: Fold<I>, |
| { |
| let binders: Vec<_> = binders |
| .map(|pk| CanonicalVarKind::new(pk, universe)) |
| .collect(); |
| let subst = self.fresh_subst(interner, &binders); |
| subst.apply(arg, interner) |
| } |
| |
| /// Variant on `instantiate_in` that takes a `Binders<T>`. |
| #[instrument(level = "debug", skip(self, interner))] |
| pub fn instantiate_binders_existentially<'a, T>( |
| &mut self, |
| interner: &'a I, |
| arg: Binders<T>, |
| ) -> T::Result |
| where |
| T: Fold<I> + HasInterner<Interner = I>, |
| { |
| let (value, binders) = arg.into_value_and_skipped_binders(); |
| |
| let max_universe = self.max_universe; |
| self.instantiate_in( |
| interner, |
| max_universe, |
| binders.iter(interner).cloned(), |
| value, |
| ) |
| } |
| |
| #[instrument(level = "debug", skip(self, interner))] |
| pub fn instantiate_binders_universally<'a, T>( |
| &mut self, |
| interner: &'a I, |
| arg: Binders<T>, |
| ) -> T::Result |
| where |
| T: Fold<I> + HasInterner<Interner = I>, |
| { |
| let (value, binders) = arg.into_value_and_skipped_binders(); |
| |
| let mut lazy_ui = None; |
| let mut ui = || { |
| lazy_ui.unwrap_or_else(|| { |
| let ui = self.new_universe(); |
| lazy_ui = Some(ui); |
| ui |
| }) |
| }; |
| let parameters: Vec<_> = binders |
| .iter(interner) |
| .cloned() |
| .enumerate() |
| .map(|(idx, pk)| { |
| let placeholder_idx = PlaceholderIndex { ui: ui(), idx }; |
| match pk { |
| VariableKind::Lifetime => { |
| let lt = placeholder_idx.to_lifetime(interner); |
| lt.cast(interner) |
| } |
| VariableKind::Ty(_) => placeholder_idx.to_ty(interner).cast(interner), |
| VariableKind::Const(ty) => { |
| placeholder_idx.to_const(interner, ty).cast(interner) |
| } |
| } |
| }) |
| .collect(); |
| Subst::apply(interner, ¶meters, value) |
| } |
| } |