chalk_ir/fold/
subst.rs

1use super::*;
2use crate::fold::shift::Shift;
3
4/// Substitution used during folding
5#[derive(FallibleTypeFolder)]
6pub struct Subst<'s, I: Interner> {
7    /// Values to substitute. A reference to a free variable with
8    /// index `i` will be mapped to `parameters[i]` -- if `i >
9    /// parameters.len()`, then we will leave the variable untouched.
10    parameters: &'s [GenericArg<I>],
11    interner: I,
12}
13
14impl<I: Interner> Subst<'_, I> {
15    /// Applies the substitution by folding
16    pub fn apply<T: TypeFoldable<I>>(interner: I, parameters: &[GenericArg<I>], value: T) -> T {
17        value
18            .try_fold_with(
19                &mut Subst {
20                    parameters,
21                    interner,
22                },
23                DebruijnIndex::INNERMOST,
24            )
25            .unwrap()
26    }
27}
28
29impl<I: Interner> TypeFolder<I> for Subst<'_, I> {
30    fn as_dyn(&mut self) -> &mut dyn TypeFolder<I> {
31        self
32    }
33
34    /// We are eliminating one binder, but binders outside of that get preserved.
35    ///
36    /// So e.g. consider this:
37    ///
38    /// ```notrust
39    /// for<A, B> { for<C> { [A, C] } }
40    /// //          ^ the binder we are substituing with `[u32]`
41    /// ```
42    ///
43    /// Here, `A` would be `^1.0` and `C` would be `^0.0`. We will replace `^0.0` with the
44    /// 0th index from the list (`u32`). We will convert `^1.0` (A) to `^0.0` -- i.e., shift
45    /// it **out** of one level of binder (the `for<C>` binder we are eliminating).
46    ///
47    /// This gives us as a result:
48    ///
49    /// ```notrust
50    /// for<A, B> { [A, u32] }
51    ///              ^ represented as `^0.0`
52    /// ```
53    fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty<I> {
54        if let Some(index) = bound_var.index_if_innermost() {
55            match self.parameters[index].data(TypeFolder::interner(self)) {
56                GenericArgData::Ty(t) => t
57                    .clone()
58                    .shifted_in_from(TypeFolder::interner(self), outer_binder),
59                _ => panic!("mismatched kinds in substitution"),
60            }
61        } else {
62            bound_var
63                .shifted_out()
64                .expect("cannot fail because this is not the innermost")
65                .shifted_in_from(outer_binder)
66                .to_ty(TypeFolder::interner(self))
67        }
68    }
69
70    /// see `fold_free_var_ty`
71    fn fold_free_var_lifetime(
72        &mut self,
73        bound_var: BoundVar,
74        outer_binder: DebruijnIndex,
75    ) -> Lifetime<I> {
76        if let Some(index) = bound_var.index_if_innermost() {
77            match self.parameters[index].data(TypeFolder::interner(self)) {
78                GenericArgData::Lifetime(l) => l
79                    .clone()
80                    .shifted_in_from(TypeFolder::interner(self), outer_binder),
81                _ => panic!("mismatched kinds in substitution"),
82            }
83        } else {
84            bound_var
85                .shifted_out()
86                .unwrap()
87                .shifted_in_from(outer_binder)
88                .to_lifetime(TypeFolder::interner(self))
89        }
90    }
91
92    /// see `fold_free_var_ty`
93    fn fold_free_var_const(
94        &mut self,
95        ty: Ty<I>,
96        bound_var: BoundVar,
97        outer_binder: DebruijnIndex,
98    ) -> Const<I> {
99        if let Some(index) = bound_var.index_if_innermost() {
100            match self.parameters[index].data(TypeFolder::interner(self)) {
101                GenericArgData::Const(c) => c
102                    .clone()
103                    .shifted_in_from(TypeFolder::interner(self), outer_binder),
104                _ => panic!("mismatched kinds in substitution"),
105            }
106        } else {
107            bound_var
108                .shifted_out()
109                .unwrap()
110                .shifted_in_from(outer_binder)
111                .to_const(TypeFolder::interner(self), ty)
112        }
113    }
114
115    fn interner(&self) -> I {
116        self.interner
117    }
118}