rustc_type_ir/
elaborate.rs

1use std::marker::PhantomData;
2
3use smallvec::smallvec;
4
5use crate::data_structures::HashSet;
6use crate::inherent::*;
7use crate::outlives::{Component, push_outlives_components};
8use crate::{self as ty, Interner, Upcast as _};
9
10/// "Elaboration" is the process of identifying all the predicates that
11/// are implied by a source predicate. Currently, this basically means
12/// walking the "supertraits" and other similar assumptions. For example,
13/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
14/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
15/// `T: Foo`, then we know that `T: 'static`.
16pub struct Elaborator<I: Interner, O> {
17    cx: I,
18    stack: Vec<O>,
19    visited: HashSet<ty::Binder<I, ty::PredicateKind<I>>>,
20    mode: Filter,
21}
22
23enum Filter {
24    All,
25    OnlySelf,
26}
27
28/// Describes how to elaborate an obligation into a sub-obligation.
29pub trait Elaboratable<I: Interner> {
30    fn predicate(&self) -> I::Predicate;
31
32    // Makes a new `Self` but with a different clause that comes from elaboration.
33    fn child(&self, clause: I::Clause) -> Self;
34
35    // Makes a new `Self` but with a different clause and a different cause
36    // code (if `Self` has one, such as [`PredicateObligation`]).
37    fn child_with_derived_cause(
38        &self,
39        clause: I::Clause,
40        span: I::Span,
41        parent_trait_pred: ty::Binder<I, ty::TraitPredicate<I>>,
42        index: usize,
43    ) -> Self;
44}
45
46pub struct ClauseWithSupertraitSpan<I: Interner> {
47    pub pred: I::Predicate,
48    // Span of the supertrait predicatae that lead to this clause.
49    pub supertrait_span: I::Span,
50}
51impl<I: Interner> ClauseWithSupertraitSpan<I> {
52    pub fn new(pred: I::Predicate, span: I::Span) -> Self {
53        ClauseWithSupertraitSpan { pred, supertrait_span: span }
54    }
55}
56impl<I: Interner> Elaboratable<I> for ClauseWithSupertraitSpan<I> {
57    fn predicate(&self) -> <I as Interner>::Predicate {
58        self.pred
59    }
60
61    fn child(&self, clause: <I as Interner>::Clause) -> Self {
62        ClauseWithSupertraitSpan {
63            pred: clause.as_predicate(),
64            supertrait_span: self.supertrait_span,
65        }
66    }
67
68    fn child_with_derived_cause(
69        &self,
70        clause: <I as Interner>::Clause,
71        supertrait_span: <I as Interner>::Span,
72        _parent_trait_pred: crate::Binder<I, crate::TraitPredicate<I>>,
73        _index: usize,
74    ) -> Self {
75        ClauseWithSupertraitSpan { pred: clause.as_predicate(), supertrait_span }
76    }
77}
78
79pub fn elaborate<I: Interner, O: Elaboratable<I>>(
80    cx: I,
81    obligations: impl IntoIterator<Item = O>,
82) -> Elaborator<I, O> {
83    let mut elaborator =
84        Elaborator { cx, stack: Vec::new(), visited: HashSet::default(), mode: Filter::All };
85    elaborator.extend_deduped(obligations);
86    elaborator
87}
88
89impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
90    fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = O>) {
91        // Only keep those bounds that we haven't already seen.
92        // This is necessary to prevent infinite recursion in some
93        // cases. One common case is when people define
94        // `trait Sized: Sized { }` rather than `trait Sized { }`.
95        self.stack.extend(
96            obligations.into_iter().filter(|o| {
97                self.visited.insert(self.cx.anonymize_bound_vars(o.predicate().kind()))
98            }),
99        );
100    }
101
102    /// Filter to only the supertraits of trait predicates, i.e. only the predicates
103    /// that have `Self` as their self type, instead of all implied predicates.
104    pub fn filter_only_self(mut self) -> Self {
105        self.mode = Filter::OnlySelf;
106        self
107    }
108
109    fn elaborate(&mut self, elaboratable: &O) {
110        let cx = self.cx;
111
112        // We only elaborate clauses.
113        let Some(clause) = elaboratable.predicate().as_clause() else {
114            return;
115        };
116
117        let bound_clause = clause.kind();
118        match bound_clause.skip_binder() {
119            ty::ClauseKind::Trait(data) => {
120                // Negative trait bounds do not imply any supertrait bounds
121                if data.polarity != ty::PredicatePolarity::Positive {
122                    return;
123                }
124
125                let map_to_child_clause =
126                    |(index, (clause, span)): (usize, (I::Clause, I::Span))| {
127                        elaboratable.child_with_derived_cause(
128                            clause.instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)),
129                            span,
130                            bound_clause.rebind(data),
131                            index,
132                        )
133                    };
134
135                // Get predicates implied by the trait, or only super predicates if we only care about self predicates.
136                match self.mode {
137                    Filter::All => self.extend_deduped(
138                        cx.explicit_implied_predicates_of(data.def_id())
139                            .iter_identity()
140                            .enumerate()
141                            .map(map_to_child_clause),
142                    ),
143                    Filter::OnlySelf => self.extend_deduped(
144                        cx.explicit_super_predicates_of(data.def_id())
145                            .iter_identity()
146                            .enumerate()
147                            .map(map_to_child_clause),
148                    ),
149                };
150            }
151            // `T: ~const Trait` implies `T: ~const Supertrait`.
152            ty::ClauseKind::HostEffect(data) => self.extend_deduped(
153                cx.explicit_implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| {
154                    elaboratable.child(
155                        trait_ref
156                            .to_host_effect_clause(cx, data.constness)
157                            .instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)),
158                    )
159                }),
160            ),
161            ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
162                // We know that `T: 'a` for some type `T`. We can
163                // often elaborate this. For example, if we know that
164                // `[U]: 'a`, that implies that `U: 'a`. Similarly, if
165                // we know `&'a U: 'b`, then we know that `'a: 'b` and
166                // `U: 'b`.
167                //
168                // We can basically ignore bound regions here. So for
169                // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to
170                // `'a: 'b`.
171
172                // Ignore `for<'a> T: 'a` -- we might in the future
173                // consider this as evidence that `T: 'static`, but
174                // I'm a bit wary of such constructions and so for now
175                // I want to be conservative. --nmatsakis
176                if r_min.is_bound() {
177                    return;
178                }
179
180                let mut components = smallvec![];
181                push_outlives_components(cx, ty_max, &mut components);
182                self.extend_deduped(
183                    components
184                        .into_iter()
185                        .filter_map(|component| elaborate_component_to_clause(cx, component, r_min))
186                        .map(|clause| elaboratable.child(bound_clause.rebind(clause).upcast(cx))),
187                );
188            }
189            ty::ClauseKind::RegionOutlives(..) => {
190                // Nothing to elaborate from `'a: 'b`.
191            }
192            ty::ClauseKind::WellFormed(..) => {
193                // Currently, we do not elaborate WF predicates,
194                // although we easily could.
195            }
196            ty::ClauseKind::Projection(..) => {
197                // Nothing to elaborate in a projection predicate.
198            }
199            ty::ClauseKind::ConstEvaluatable(..) => {
200                // Currently, we do not elaborate const-evaluatable
201                // predicates.
202            }
203            ty::ClauseKind::ConstArgHasType(..) => {
204                // Nothing to elaborate
205            }
206        }
207    }
208}
209
210fn elaborate_component_to_clause<I: Interner>(
211    cx: I,
212    component: Component<I>,
213    outlives_region: I::Region,
214) -> Option<ty::ClauseKind<I>> {
215    match component {
216        Component::Region(r) => {
217            if r.is_bound() {
218                None
219            } else {
220                Some(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r, outlives_region)))
221            }
222        }
223
224        Component::Param(p) => {
225            let ty = Ty::new_param(cx, p);
226            Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, outlives_region)))
227        }
228
229        Component::Placeholder(p) => {
230            let ty = Ty::new_placeholder(cx, p);
231            Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, outlives_region)))
232        }
233
234        Component::UnresolvedInferenceVariable(_) => None,
235
236        Component::Alias(alias_ty) => {
237            // We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
238            // With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
239            Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
240                alias_ty.to_ty(cx),
241                outlives_region,
242            )))
243        }
244
245        Component::EscapingAlias(_) => {
246            // We might be able to do more here, but we don't
247            // want to deal with escaping vars right now.
248            None
249        }
250    }
251}
252
253impl<I: Interner, O: Elaboratable<I>> Iterator for Elaborator<I, O> {
254    type Item = O;
255
256    fn size_hint(&self) -> (usize, Option<usize>) {
257        (self.stack.len(), None)
258    }
259
260    fn next(&mut self) -> Option<Self::Item> {
261        // Extract next item from top-most stack frame, if any.
262        if let Some(obligation) = self.stack.pop() {
263            self.elaborate(&obligation);
264            Some(obligation)
265        } else {
266            None
267        }
268    }
269}
270
271///////////////////////////////////////////////////////////////////////////
272// Supertrait iterator
273///////////////////////////////////////////////////////////////////////////
274
275/// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally)
276/// does not compute the full elaborated super-predicates but just the set of def-ids. It is used
277/// to identify which traits may define a given associated type to help avoid cycle errors,
278/// and to make size estimates for vtable layout computation.
279pub fn supertrait_def_ids<I: Interner>(
280    cx: I,
281    trait_def_id: I::DefId,
282) -> impl Iterator<Item = I::DefId> {
283    let mut set = HashSet::default();
284    let mut stack = vec![trait_def_id];
285
286    set.insert(trait_def_id);
287
288    std::iter::from_fn(move || {
289        let trait_def_id = stack.pop()?;
290
291        for (predicate, _) in cx.explicit_super_predicates_of(trait_def_id).iter_identity() {
292            if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() {
293                if set.insert(data.def_id()) {
294                    stack.push(data.def_id());
295                }
296            }
297        }
298
299        Some(trait_def_id)
300    })
301}
302
303pub fn supertraits<I: Interner>(
304    cx: I,
305    trait_ref: ty::Binder<I, ty::TraitRef<I>>,
306) -> FilterToTraits<I, Elaborator<I, I::Clause>> {
307    elaborate(cx, [trait_ref.upcast(cx)]).filter_only_self().filter_to_traits()
308}
309
310impl<I: Interner> Elaborator<I, I::Clause> {
311    fn filter_to_traits(self) -> FilterToTraits<I, Self> {
312        FilterToTraits { _cx: PhantomData, base_iterator: self }
313    }
314}
315
316/// A filter around an iterator of predicates that makes it yield up
317/// just trait references.
318pub struct FilterToTraits<I: Interner, It: Iterator<Item = I::Clause>> {
319    _cx: PhantomData<I>,
320    base_iterator: It,
321}
322
323impl<I: Interner, It: Iterator<Item = I::Clause>> Iterator for FilterToTraits<I, It> {
324    type Item = ty::Binder<I, ty::TraitRef<I>>;
325
326    fn next(&mut self) -> Option<ty::Binder<I, ty::TraitRef<I>>> {
327        while let Some(pred) = self.base_iterator.next() {
328            if let Some(data) = pred.as_trait_clause() {
329                return Some(data.map_bound(|t| t.trait_ref));
330            }
331        }
332        None
333    }
334
335    fn size_hint(&self) -> (usize, Option<usize>) {
336        let (_, upper) = self.base_iterator.size_hint();
337        (0, upper)
338    }
339}