Skip to main content

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