Skip to main content

rustc_next_trait_solver/
placeholder.rs

1use core::panic;
2
3use rustc_type_ir::data_structures::IndexMap;
4use rustc_type_ir::inherent::*;
5use rustc_type_ir::{
6    self as ty, InferCtxtLike, Interner, PlaceholderConst, PlaceholderRegion, PlaceholderType,
7    TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
8};
9
10pub struct BoundVarReplacer<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner>
11where
12    Infcx: InferCtxtLike<Interner = I>,
13    I: Interner,
14{
15    infcx: &'a Infcx,
16    // These three maps track the bound variable that were replaced by placeholders. It might be
17    // nice to remove these since we already have the `kind` in the placeholder; we really just need
18    // the `var` (but we *could* bring that into scope if we were to track them as we pass them).
19    mapped_regions: IndexMap<ty::PlaceholderRegion<I>, ty::BoundRegion<I>>,
20    mapped_types: IndexMap<ty::PlaceholderType<I>, ty::BoundTy<I>>,
21    mapped_consts: IndexMap<ty::PlaceholderConst<I>, ty::BoundConst<I>>,
22    // The current depth relative to *this* folding, *not* the entire normalization. In other words,
23    // the depth of binders we've passed here.
24    current_index: ty::DebruijnIndex,
25    // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy:
26    // we don't actually create a universe until we see a bound var we have to replace.
27    universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
28}
29
30impl<'a, Infcx, I> BoundVarReplacer<'a, Infcx, I>
31where
32    Infcx: InferCtxtLike<Interner = I>,
33    I: Interner,
34{
35    /// Returns a type with all bound vars replaced by placeholders,
36    /// together with mappings from the new placeholders back to the original variable.
37    ///
38    /// Panics if there are any bound vars that use a binding level above `universe_indices.len()`.
39    pub fn replace_bound_vars<T: TypeFoldable<I>>(
40        infcx: &'a Infcx,
41        universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
42        value: T,
43    ) -> (
44        T,
45        IndexMap<ty::PlaceholderRegion<I>, ty::BoundRegion<I>>,
46        IndexMap<ty::PlaceholderType<I>, ty::BoundTy<I>>,
47        IndexMap<ty::PlaceholderConst<I>, ty::BoundConst<I>>,
48    ) {
49        let mut replacer = BoundVarReplacer {
50            infcx,
51            mapped_regions: Default::default(),
52            mapped_types: Default::default(),
53            mapped_consts: Default::default(),
54            current_index: ty::INNERMOST,
55            universe_indices,
56        };
57
58        let value = value.fold_with(&mut replacer);
59
60        (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
61    }
62
63    fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex {
64        let infcx = self.infcx;
65        let index =
66            self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1;
67        let universe = self.universe_indices[index].unwrap_or_else(|| {
68            for i in self.universe_indices.iter_mut().take(index + 1) {
69                *i = i.or_else(|| Some(infcx.create_next_universe()))
70            }
71            self.universe_indices[index].unwrap()
72        });
73        universe
74    }
75}
76
77impl<Infcx, I> TypeFolder<I> for BoundVarReplacer<'_, Infcx, I>
78where
79    Infcx: InferCtxtLike<Interner = I>,
80    I: Interner,
81{
82    fn cx(&self) -> I {
83        self.infcx.cx()
84    }
85
86    fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
87        self.current_index.shift_in(1);
88        let t = t.super_fold_with(self);
89        self.current_index.shift_out(1);
90        t
91    }
92
93    fn fold_region(&mut self, r: I::Region) -> I::Region {
94        match r.kind() {
95            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
96                if debruijn.as_usize()
97                    >= self.current_index.as_usize() + self.universe_indices.len() =>
98            {
99                {
    ::core::panicking::panic_fmt(format_args!("Bound vars {1:#?} outside of `self.universe_indices`: {0:#?}",
            self.universe_indices, r));
};panic!(
100                    "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}",
101                    self.universe_indices
102                );
103            }
104            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br)
105                if debruijn >= self.current_index =>
106            {
107                let universe = self.universe_for(debruijn);
108                let p = PlaceholderRegion::new(universe, br);
109                self.mapped_regions.insert(p, br);
110                Region::new_placeholder(self.cx(), p)
111            }
112            _ => r,
113        }
114    }
115
116    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
117        match t.kind() {
118            ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), _)
119                if debruijn.as_usize() + 1
120                    > self.current_index.as_usize() + self.universe_indices.len() =>
121            {
122                {
    ::core::panicking::panic_fmt(format_args!("Bound vars {1:#?} outside of `self.universe_indices`: {0:#?}",
            self.universe_indices, t));
};panic!(
123                    "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}",
124                    self.universe_indices
125                );
126            }
127            ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty)
128                if debruijn >= self.current_index =>
129            {
130                let universe = self.universe_for(debruijn);
131                let p = PlaceholderType::new(universe, bound_ty);
132                self.mapped_types.insert(p, bound_ty);
133                Ty::new_placeholder(self.cx(), p)
134            }
135            _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
136            _ => t,
137        }
138    }
139
140    fn fold_const(&mut self, ct: I::Const) -> I::Const {
141        match ct.kind() {
142            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), _)
143                if debruijn.as_usize() + 1
144                    > self.current_index.as_usize() + self.universe_indices.len() =>
145            {
146                {
    ::core::panicking::panic_fmt(format_args!("Bound vars {1:#?} outside of `self.universe_indices`: {0:#?}",
            self.universe_indices, ct));
};panic!(
147                    "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}",
148                    self.universe_indices
149                );
150            }
151            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const)
152                if debruijn >= self.current_index =>
153            {
154                let universe = self.universe_for(debruijn);
155                let p = PlaceholderConst::new(universe, bound_const);
156                self.mapped_consts.insert(p, bound_const);
157                Const::new_placeholder(self.cx(), p)
158            }
159            _ => ct.super_fold_with(self),
160        }
161    }
162
163    fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
164        if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
165    }
166}