rustc_infer/infer/canonical/
instantiate.rs

1//! This module contains code to instantiate new values into a
2//! `Canonical<'tcx, T>`.
3//!
4//! For an overview of what canonicalization is and how it fits into
5//! rustc, check out the [chapter in the rustc dev guide][c].
6//!
7//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
8
9use rustc_macros::extension;
10use rustc_middle::bug;
11use rustc_middle::ty::fold::{FnMutDelegate, TypeFoldable};
12use rustc_middle::ty::{self, GenericArgKind, TyCtxt};
13
14use crate::infer::canonical::{Canonical, CanonicalVarValues};
15
16/// FIXME(-Znext-solver): This or public because it is shared with the
17/// new trait solver implementation. We should deduplicate canonicalization.
18#[extension(pub trait CanonicalExt<'tcx, V>)]
19impl<'tcx, V> Canonical<'tcx, V> {
20    /// Instantiate the wrapped value, replacing each canonical value
21    /// with the value given in `var_values`.
22    fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
23    where
24        V: TypeFoldable<TyCtxt<'tcx>>,
25    {
26        self.instantiate_projected(tcx, var_values, |value| value.clone())
27    }
28
29    /// Allows one to apply a instantiation to some subset of
30    /// `self.value`. Invoke `projection_fn` with `self.value` to get
31    /// a value V that is expressed in terms of the same canonical
32    /// variables bound in `self` (usually this extracts from subset
33    /// of `self`). Apply the instantiation `var_values` to this value
34    /// V, replacing each of the canonical variables.
35    fn instantiate_projected<T>(
36        &self,
37        tcx: TyCtxt<'tcx>,
38        var_values: &CanonicalVarValues<'tcx>,
39        projection_fn: impl FnOnce(&V) -> T,
40    ) -> T
41    where
42        T: TypeFoldable<TyCtxt<'tcx>>,
43    {
44        assert_eq!(self.variables.len(), var_values.len());
45        let value = projection_fn(&self.value);
46        instantiate_value(tcx, var_values, value)
47    }
48}
49
50/// Instantiate the values from `var_values` into `value`. `var_values`
51/// must be values for the set of canonical variables that appear in
52/// `value`.
53pub(super) fn instantiate_value<'tcx, T>(
54    tcx: TyCtxt<'tcx>,
55    var_values: &CanonicalVarValues<'tcx>,
56    value: T,
57) -> T
58where
59    T: TypeFoldable<TyCtxt<'tcx>>,
60{
61    if var_values.var_values.is_empty() {
62        value
63    } else {
64        let delegate = FnMutDelegate {
65            regions: &mut |br: ty::BoundRegion| match var_values[br.var].unpack() {
66                GenericArgKind::Lifetime(l) => l,
67                r => bug!("{:?} is a region but value is {:?}", br, r),
68            },
69            types: &mut |bound_ty: ty::BoundTy| match var_values[bound_ty.var].unpack() {
70                GenericArgKind::Type(ty) => ty,
71                r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
72            },
73            consts: &mut |bound_ct: ty::BoundVar| match var_values[bound_ct].unpack() {
74                GenericArgKind::Const(ct) => ct,
75                c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
76            },
77        };
78
79        tcx.replace_escaping_bound_vars_uncached(value, delegate)
80    }
81}