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