1use super::*;
2use crate::fold::shift::Shift;
3
4#[derive(FallibleTypeFolder)]
6pub struct Subst<'s, I: Interner> {
7 parameters: &'s [GenericArg<I>],
11 interner: I,
12}
13
14impl<I: Interner> Subst<'_, I> {
15 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 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 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 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}