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    Region, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
8};
9use tracing::debug;
10
11pub struct BoundVarReplacer<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner>
12where
13    Infcx: InferCtxtLike<Interner = I>,
14    I: Interner,
15{
16    infcx: &'a Infcx,
17    // These three maps track the bound variable that were replaced by placeholders. It might be
18    // nice to remove these since we already have the `kind` in the placeholder; we really just need
19    // the `var` (but we *could* bring that into scope if we were to track them as we pass them).
20    mapped_regions: IndexMap<ty::PlaceholderRegion<I>, ty::BoundRegion<I>>,
21    mapped_types: IndexMap<ty::PlaceholderType<I>, ty::BoundTy<I>>,
22    mapped_consts: IndexMap<ty::PlaceholderConst<I>, ty::BoundConst<I>>,
23    // The current depth relative to *this* folding, *not* the entire normalization. In other words,
24    // the depth of binders we've passed here.
25    current_index: ty::DebruijnIndex,
26    // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy:
27    // we don't actually create a universe until we see a bound var we have to replace.
28    universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
29}
30
31impl<'a, Infcx, I> BoundVarReplacer<'a, Infcx, I>
32where
33    Infcx: InferCtxtLike<Interner = I>,
34    I: Interner,
35{
36    /// Returns a type with all bound vars replaced by placeholders,
37    /// together with mappings from the new placeholders back to the original variable.
38    ///
39    /// Panics if there are any bound vars that use a binding level above `universe_indices.len()`.
40    pub fn replace_bound_vars<T: TypeFoldable<I>>(
41        infcx: &'a Infcx,
42        universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
43        value: T,
44    ) -> (
45        T,
46        IndexMap<ty::PlaceholderRegion<I>, ty::BoundRegion<I>>,
47        IndexMap<ty::PlaceholderType<I>, ty::BoundTy<I>>,
48        IndexMap<ty::PlaceholderConst<I>, ty::BoundConst<I>>,
49    ) {
50        let old_universes = universe_indices.clone();
51        let mut replacer = BoundVarReplacer {
52            infcx,
53            mapped_regions: Default::default(),
54            mapped_types: Default::default(),
55            mapped_consts: Default::default(),
56            current_index: ty::INNERMOST,
57            universe_indices,
58        };
59
60        let value = value.fold_with(&mut replacer);
61        let BoundVarReplacer {
62            mapped_regions,
63            mapped_types,
64            mapped_consts,
65            universe_indices,
66            infcx: _,
67            current_index: _,
68        } = replacer;
69
70        if infcx.cx().assumptions_on_binders() {
71            for (old, new) in old_universes.into_iter().zip(universe_indices.iter()) {
72                if let (None, Some(new)) = (old, new) {
73                    // FIXME(-Zassumptions-on-binders): `replace_bound_vars` does not have enough
74                    // context to compute placeholder assumptions for the binders it enters.
75                    infcx.insert_placeholder_assumptions(
76                        *new,
77                        Some(rustc_type_ir::region_constraint::Assumptions::empty()),
78                    );
79                }
80            }
81        }
82
83        (value, mapped_regions, mapped_types, mapped_consts)
84    }
85
86    fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex {
87        let infcx = self.infcx;
88        let index =
89            self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1;
90        let universe = self.universe_indices[index].unwrap_or_else(|| {
91            for i in self.universe_indices.iter_mut().take(index + 1) {
92                *i = i.or_else(|| Some(infcx.create_next_universe()))
93            }
94            self.universe_indices[index].unwrap()
95        });
96        universe
97    }
98}
99
100impl<Infcx, I> TypeFolder<I> for BoundVarReplacer<'_, Infcx, I>
101where
102    Infcx: InferCtxtLike<Interner = I>,
103    I: Interner,
104{
105    fn cx(&self) -> I {
106        self.infcx.cx()
107    }
108
109    fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
110        self.current_index.shift_in(1);
111        let t = t.super_fold_with(self);
112        self.current_index.shift_out(1);
113        t
114    }
115
116    fn fold_region(&mut self, r: Region<I>) -> Region<I> {
117        match r.kind() {
118            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
119                if debruijn.as_usize()
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, r));
};panic!(
123                    "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}",
124                    self.universe_indices
125                );
126            }
127            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br)
128                if debruijn >= self.current_index =>
129            {
130                let universe = self.universe_for(debruijn);
131                let p = PlaceholderRegion::new(universe, br);
132                self.mapped_regions.insert(p, br);
133                Region::new_placeholder(self.cx(), p)
134            }
135            _ => r,
136        }
137    }
138
139    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
140        match t.kind() {
141            ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), _)
142                if debruijn.as_usize() + 1
143                    > self.current_index.as_usize() + self.universe_indices.len() =>
144            {
145                {
    ::core::panicking::panic_fmt(format_args!("Bound vars {1:#?} outside of `self.universe_indices`: {0:#?}",
            self.universe_indices, t));
};panic!(
146                    "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}",
147                    self.universe_indices
148                );
149            }
150            ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty)
151                if debruijn >= self.current_index =>
152            {
153                let universe = self.universe_for(debruijn);
154                let p = PlaceholderType::new(universe, bound_ty);
155                self.mapped_types.insert(p, bound_ty);
156                Ty::new_placeholder(self.cx(), p)
157            }
158            _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
159            _ => t,
160        }
161    }
162
163    fn fold_const(&mut self, ct: I::Const) -> I::Const {
164        match ct.kind() {
165            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), _)
166                if debruijn.as_usize() + 1
167                    > self.current_index.as_usize() + self.universe_indices.len() =>
168            {
169                {
    ::core::panicking::panic_fmt(format_args!("Bound vars {1:#?} outside of `self.universe_indices`: {0:#?}",
            self.universe_indices, ct));
};panic!(
170                    "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}",
171                    self.universe_indices
172                );
173            }
174            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const)
175                if debruijn >= self.current_index =>
176            {
177                let universe = self.universe_for(debruijn);
178                let p = PlaceholderConst::new(universe, bound_const);
179                self.mapped_consts.insert(p, bound_const);
180                Const::new_placeholder(self.cx(), p)
181            }
182            _ => ct.super_fold_with(self),
183        }
184    }
185
186    fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
187        if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
188    }
189}
190
191/// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came.
192pub struct PlaceholderReplacer<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner>
193where
194    Infcx: InferCtxtLike<Interner = I>,
195    I: Interner,
196{
197    infcx: &'a Infcx,
198    mapped_regions: IndexMap<ty::PlaceholderRegion<I>, ty::BoundRegion<I>>,
199    mapped_types: IndexMap<ty::PlaceholderType<I>, ty::BoundTy<I>>,
200    mapped_consts: IndexMap<ty::PlaceholderConst<I>, ty::BoundConst<I>>,
201    universe_indices: &'a [Option<ty::UniverseIndex>],
202    current_index: ty::DebruijnIndex,
203}
204
205impl<'a, Infcx, I> PlaceholderReplacer<'a, Infcx, I>
206where
207    Infcx: InferCtxtLike<Interner = I>,
208    I: Interner,
209{
210    pub fn replace_placeholders<T: TypeFoldable<I>>(
211        infcx: &'a Infcx,
212        mapped_regions: IndexMap<ty::PlaceholderRegion<I>, ty::BoundRegion<I>>,
213        mapped_types: IndexMap<ty::PlaceholderType<I>, ty::BoundTy<I>>,
214        mapped_consts: IndexMap<ty::PlaceholderConst<I>, ty::BoundConst<I>>,
215        universe_indices: &'a [Option<ty::UniverseIndex>],
216        value: T,
217    ) -> T {
218        let mut replacer = PlaceholderReplacer {
219            infcx,
220            mapped_regions,
221            mapped_types,
222            mapped_consts,
223            universe_indices,
224            current_index: ty::INNERMOST,
225        };
226        value.fold_with(&mut replacer)
227    }
228}
229
230impl<'a, Infcx, I> TypeFolder<I> for PlaceholderReplacer<'a, Infcx, I>
231where
232    Infcx: InferCtxtLike<Interner = I>,
233    I: Interner,
234{
235    fn cx(&self) -> I {
236        self.infcx.cx()
237    }
238
239    fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
240        if !t.has_placeholders() && !t.has_infer() {
241            return t;
242        }
243        self.current_index.shift_in(1);
244        let t = t.super_fold_with(self);
245        self.current_index.shift_out(1);
246        t
247    }
248
249    fn fold_region(&mut self, r0: Region<I>) -> Region<I> {
250        let r1 = match r0.kind() {
251            ty::ReVar(vid) => self.infcx.opportunistic_resolve_lt_var(vid),
252            _ => r0,
253        };
254
255        let r2 = match r1.kind() {
256            ty::RePlaceholder(p) => {
257                let replace_var = self.mapped_regions.get(&p);
258                match replace_var {
259                    Some(replace_var) => {
260                        let index = self
261                            .universe_indices
262                            .iter()
263                            .position(|u| #[allow(non_exhaustive_omitted_patterns)] match u {
    Some(pu) if *pu == p.universe => true,
    _ => false,
}matches!(u, Some(pu) if *pu == p.universe))
264                            .unwrap_or_else(|| {
    ::core::panicking::panic_fmt(format_args!("Unexpected placeholder universe."));
}panic!("Unexpected placeholder universe."));
265                        let db = ty::DebruijnIndex::from_usize(
266                            self.universe_indices.len() - index + self.current_index.as_usize() - 1,
267                        );
268                        Region::new_bound(self.cx(), db, *replace_var)
269                    }
270                    None => r1,
271                }
272            }
273            _ => r1,
274        };
275
276        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_next_trait_solver/src/placeholder.rs:276",
                        "rustc_next_trait_solver::placeholder",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_next_trait_solver/src/placeholder.rs"),
                        ::tracing_core::__macro_support::Option::Some(276u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_next_trait_solver::placeholder"),
                        ::tracing_core::field::FieldSet::new(&["message",
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("r0")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("r0");
                                            NAME.as_str()
                                        },
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("r1")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("r1");
                                            NAME.as_str()
                                        },
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("r2")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("r2");
                                            NAME.as_str()
                                        }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("fold_region")
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&r0)
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&r1)
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&r2)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(?r0, ?r1, ?r2, "fold_region");
277
278        r2
279    }
280
281    fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
282        let ty = self.infcx.shallow_resolve(ty);
283        match ty.kind() {
284            ty::Placeholder(p) => {
285                let replace_var = self.mapped_types.get(&p);
286                match replace_var {
287                    Some(replace_var) => {
288                        let index = self
289                            .universe_indices
290                            .iter()
291                            .position(|u| #[allow(non_exhaustive_omitted_patterns)] match u {
    Some(pu) if *pu == p.universe => true,
    _ => false,
}matches!(u, Some(pu) if *pu == p.universe))
292                            .unwrap_or_else(|| {
    ::core::panicking::panic_fmt(format_args!("Unexpected placeholder universe."));
}panic!("Unexpected placeholder universe."));
293                        let db = ty::DebruijnIndex::from_usize(
294                            self.universe_indices.len() - index + self.current_index.as_usize() - 1,
295                        );
296                        Ty::new_bound(self.infcx.cx(), db, *replace_var)
297                    }
298                    None => {
299                        if ty.has_infer() {
300                            ty.super_fold_with(self)
301                        } else {
302                            ty
303                        }
304                    }
305                }
306            }
307
308            _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self),
309            _ => ty,
310        }
311    }
312
313    fn fold_const(&mut self, ct: I::Const) -> I::Const {
314        let ct = self.infcx.shallow_resolve_const(ct);
315        if let ty::ConstKind::Placeholder(p) = ct.kind() {
316            let replace_var = self.mapped_consts.get(&p);
317            match replace_var {
318                Some(replace_var) => {
319                    let index = self
320                        .universe_indices
321                        .iter()
322                        .position(|u| #[allow(non_exhaustive_omitted_patterns)] match u {
    Some(pu) if *pu == p.universe => true,
    _ => false,
}matches!(u, Some(pu) if *pu == p.universe))
323                        .unwrap_or_else(|| {
    ::core::panicking::panic_fmt(format_args!("Unexpected placeholder universe."));
}panic!("Unexpected placeholder universe."));
324                    let db = ty::DebruijnIndex::from_usize(
325                        self.universe_indices.len() - index + self.current_index.as_usize() - 1,
326                    );
327                    Const::new_bound(self.infcx.cx(), db, *replace_var)
328                }
329                None => {
330                    if ct.has_infer() {
331                        ct.super_fold_with(self)
332                    } else {
333                        ct
334                    }
335                }
336            }
337        } else {
338            ct.super_fold_with(self)
339        }
340    }
341}