rustc_type_ir/
elaborate.rs

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