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};
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 mut replacer = BoundVarReplacer {
51            infcx,
52            mapped_regions: Default::default(),
53            mapped_types: Default::default(),
54            mapped_consts: Default::default(),
55            current_index: ty::INNERMOST,
56            universe_indices,
57        };
58
59        let value = value.fold_with(&mut replacer);
60
61        (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
62    }
63
64    fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex {
65        let infcx = self.infcx;
66        let index =
67            self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1;
68        let universe = self.universe_indices[index].unwrap_or_else(|| {
69            for i in self.universe_indices.iter_mut().take(index + 1) {
70                *i = i.or_else(|| Some(infcx.create_next_universe()))
71            }
72            self.universe_indices[index].unwrap()
73        });
74        universe
75    }
76}
77
78impl<Infcx, I> TypeFolder<I> for BoundVarReplacer<'_, Infcx, I>
79where
80    Infcx: InferCtxtLike<Interner = I>,
81    I: Interner,
82{
83    fn cx(&self) -> I {
84        self.infcx.cx()
85    }
86
87    fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
88        self.current_index.shift_in(1);
89        let t = t.super_fold_with(self);
90        self.current_index.shift_out(1);
91        t
92    }
93
94    fn fold_region(&mut self, r: I::Region) -> I::Region {
95        match r.kind() {
96            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
97                if debruijn.as_usize()
98                    >= self.current_index.as_usize() + self.universe_indices.len() =>
99            {
100                {
    ::core::panicking::panic_fmt(format_args!("Bound vars {1:#?} outside of `self.universe_indices`: {0:#?}",
            self.universe_indices, r));
};panic!(
101                    "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}",
102                    self.universe_indices
103                );
104            }
105            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br)
106                if debruijn >= self.current_index =>
107            {
108                let universe = self.universe_for(debruijn);
109                let p = PlaceholderRegion::new(universe, br);
110                self.mapped_regions.insert(p, br);
111                Region::new_placeholder(self.cx(), p)
112            }
113            _ => r,
114        }
115    }
116
117    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
118        match t.kind() {
119            ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), _)
120                if debruijn.as_usize() + 1
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, t));
};panic!(
124                    "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}",
125                    self.universe_indices
126                );
127            }
128            ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty)
129                if debruijn >= self.current_index =>
130            {
131                let universe = self.universe_for(debruijn);
132                let p = PlaceholderType::new(universe, bound_ty);
133                self.mapped_types.insert(p, bound_ty);
134                Ty::new_placeholder(self.cx(), p)
135            }
136            _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
137            _ => t,
138        }
139    }
140
141    fn fold_const(&mut self, ct: I::Const) -> I::Const {
142        match ct.kind() {
143            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), _)
144                if debruijn.as_usize() + 1
145                    > self.current_index.as_usize() + self.universe_indices.len() =>
146            {
147                {
    ::core::panicking::panic_fmt(format_args!("Bound vars {1:#?} outside of `self.universe_indices`: {0:#?}",
            self.universe_indices, ct));
};panic!(
148                    "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}",
149                    self.universe_indices
150                );
151            }
152            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const)
153                if debruijn >= self.current_index =>
154            {
155                let universe = self.universe_for(debruijn);
156                let p = PlaceholderConst::new(universe, bound_const);
157                self.mapped_consts.insert(p, bound_const);
158                Const::new_placeholder(self.cx(), p)
159            }
160            _ => ct.super_fold_with(self),
161        }
162    }
163
164    fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
165        if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
166    }
167}
168
169/// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came.
170pub struct PlaceholderReplacer<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner>
171where
172    Infcx: InferCtxtLike<Interner = I>,
173    I: Interner,
174{
175    infcx: &'a Infcx,
176    mapped_regions: IndexMap<ty::PlaceholderRegion<I>, ty::BoundRegion<I>>,
177    mapped_types: IndexMap<ty::PlaceholderType<I>, ty::BoundTy<I>>,
178    mapped_consts: IndexMap<ty::PlaceholderConst<I>, ty::BoundConst<I>>,
179    universe_indices: &'a [Option<ty::UniverseIndex>],
180    current_index: ty::DebruijnIndex,
181}
182
183impl<'a, Infcx, I> PlaceholderReplacer<'a, Infcx, I>
184where
185    Infcx: InferCtxtLike<Interner = I>,
186    I: Interner,
187{
188    pub fn replace_placeholders<T: TypeFoldable<I>>(
189        infcx: &'a Infcx,
190        mapped_regions: IndexMap<ty::PlaceholderRegion<I>, ty::BoundRegion<I>>,
191        mapped_types: IndexMap<ty::PlaceholderType<I>, ty::BoundTy<I>>,
192        mapped_consts: IndexMap<ty::PlaceholderConst<I>, ty::BoundConst<I>>,
193        universe_indices: &'a [Option<ty::UniverseIndex>],
194        value: T,
195    ) -> T {
196        let mut replacer = PlaceholderReplacer {
197            infcx,
198            mapped_regions,
199            mapped_types,
200            mapped_consts,
201            universe_indices,
202            current_index: ty::INNERMOST,
203        };
204        value.fold_with(&mut replacer)
205    }
206}
207
208impl<'a, Infcx, I> TypeFolder<I> for PlaceholderReplacer<'a, Infcx, I>
209where
210    Infcx: InferCtxtLike<Interner = I>,
211    I: Interner,
212{
213    fn cx(&self) -> I {
214        self.infcx.cx()
215    }
216
217    fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> {
218        if !t.has_placeholders() && !t.has_infer() {
219            return t;
220        }
221        self.current_index.shift_in(1);
222        let t = t.super_fold_with(self);
223        self.current_index.shift_out(1);
224        t
225    }
226
227    fn fold_region(&mut self, r0: I::Region) -> I::Region {
228        let r1 = match r0.kind() {
229            ty::ReVar(vid) => self.infcx.opportunistic_resolve_lt_var(vid),
230            _ => r0,
231        };
232
233        let r2 = match r1.kind() {
234            ty::RePlaceholder(p) => {
235                let replace_var = self.mapped_regions.get(&p);
236                match replace_var {
237                    Some(replace_var) => {
238                        let index = self
239                            .universe_indices
240                            .iter()
241                            .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))
242                            .unwrap_or_else(|| {
    ::core::panicking::panic_fmt(format_args!("Unexpected placeholder universe."));
}panic!("Unexpected placeholder universe."));
243                        let db = ty::DebruijnIndex::from_usize(
244                            self.universe_indices.len() - index + self.current_index.as_usize() - 1,
245                        );
246                        Region::new_bound(self.cx(), db, *replace_var)
247                    }
248                    None => r1,
249                }
250            }
251            _ => r1,
252        };
253
254        {
    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:254",
                        "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(254u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_next_trait_solver::placeholder"),
                        ::tracing_core::field::FieldSet::new(&["message", "r0",
                                        "r1", "r2"],
                            ::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};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("fold_region")
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&r0) as
                                            &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&r1) as
                                            &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&r2) as
                                            &dyn Value))])
            });
    } else { ; }
};debug!(?r0, ?r1, ?r2, "fold_region");
255
256        r2
257    }
258
259    fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
260        let ty = self.infcx.shallow_resolve(ty);
261        match ty.kind() {
262            ty::Placeholder(p) => {
263                let replace_var = self.mapped_types.get(&p);
264                match replace_var {
265                    Some(replace_var) => {
266                        let index = self
267                            .universe_indices
268                            .iter()
269                            .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))
270                            .unwrap_or_else(|| {
    ::core::panicking::panic_fmt(format_args!("Unexpected placeholder universe."));
}panic!("Unexpected placeholder universe."));
271                        let db = ty::DebruijnIndex::from_usize(
272                            self.universe_indices.len() - index + self.current_index.as_usize() - 1,
273                        );
274                        Ty::new_bound(self.infcx.cx(), db, *replace_var)
275                    }
276                    None => {
277                        if ty.has_infer() {
278                            ty.super_fold_with(self)
279                        } else {
280                            ty
281                        }
282                    }
283                }
284            }
285
286            _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self),
287            _ => ty,
288        }
289    }
290
291    fn fold_const(&mut self, ct: I::Const) -> I::Const {
292        let ct = self.infcx.shallow_resolve_const(ct);
293        if let ty::ConstKind::Placeholder(p) = ct.kind() {
294            let replace_var = self.mapped_consts.get(&p);
295            match replace_var {
296                Some(replace_var) => {
297                    let index = self
298                        .universe_indices
299                        .iter()
300                        .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))
301                        .unwrap_or_else(|| {
    ::core::panicking::panic_fmt(format_args!("Unexpected placeholder universe."));
}panic!("Unexpected placeholder universe."));
302                    let db = ty::DebruijnIndex::from_usize(
303                        self.universe_indices.len() - index + self.current_index.as_usize() - 1,
304                    );
305                    Const::new_bound(self.infcx.cx(), db, *replace_var)
306                }
307                None => {
308                    if ct.has_infer() {
309                        ct.super_fold_with(self)
310                    } else {
311                        ct
312                    }
313                }
314            }
315        } else {
316            ct.super_fold_with(self)
317        }
318    }
319}