Skip to main content

rustc_type_ir/
outlives.rs

1//! The outlives relation `T: 'a` or `'a: 'b`. This code frequently
2//! refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
3//! RFC for reference.
4
5use derive_where::derive_where;
6use smallvec::{SmallVec, smallvec};
7
8use crate::data_structures::SsoHashSet;
9use crate::inherent::*;
10use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _, TypeVisitor};
11use crate::{self as ty, AliasTy, Interner, OutlivesClause, Region, Unnormalized};
12
13#[automatically_derived]
impl<I: Interner> ::core::fmt::Debug for Component<I> where I: Interner {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            Component::Region(ref __field_0) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f, "Region");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
            Component::Param(ref __field_0) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f, "Param");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
            Component::Placeholder(ref __field_0) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f, "Placeholder");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
            Component::UnresolvedInferenceVariable(ref __field_0) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f,
                        "UnresolvedInferenceVariable");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
            Component::Alias(ref __field_0, ref __field_1) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f, "Alias");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::field(&mut __builder, __field_1);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
            Component::EscapingAlias(ref __field_0) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f, "EscapingAlias");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
        }
    }
}#[derive_where(Debug; I: Interner)]
14pub enum Component<I: Interner> {
15    Region(Region<I>),
16    Param(I::ParamTy),
17    Placeholder(ty::PlaceholderType<I>),
18    UnresolvedInferenceVariable(ty::InferTy),
19
20    // Projections like `T::Foo` are tricky because a constraint like
21    // `T::Foo: 'a` can be satisfied in so many ways. There may be a
22    // where-clause that says `T::Foo: 'a`, or the defining trait may
23    // include a bound like `type Foo: 'static`, or -- in the most
24    // conservative way -- we can prove that `T: 'a` (more generally,
25    // that all components in the projection outlive `'a`). This code
26    // is not in a position to judge which is the best technique, so
27    // we just product the projection as a component and leave it to
28    // the consumer to decide (but see `EscapingProjection` below).
29    //
30    // We have to track rigidness because it's also used in param env
31    // elaboration where things are not normalized yet.
32    Alias(ty::IsRigid, ty::AliasTy<I>),
33
34    // In the case where a projection has escaping regions -- meaning
35    // regions bound within the type itself -- we always use
36    // the most conservative rule, which requires that all components
37    // outlive the bound. So for example if we had a type like this:
38    //
39    //     for<'a> Trait1<  <T as Trait2<'a,'b>>::Foo  >
40    //                      ~~~~~~~~~~~~~~~~~~~~~~~~~
41    //
42    // then the inner projection (underlined) has an escaping region
43    // `'a`. We consider that outer trait `'c` to meet a bound if `'b`
44    // outlives `'b: 'c`, and we don't consider whether the trait
45    // declares that `Foo: 'static` etc. Therefore, we just return the
46    // free components of such a projection (in this case, `'b`).
47    //
48    // However, in the future, we may want to get smarter, and
49    // actually return a "higher-ranked projection" here. Therefore,
50    // we mark that these components are part of an escaping
51    // projection, so that implied bounds code can avoid relying on
52    // them. This gives us room to improve the regionck reasoning in
53    // the future without breaking backwards compat.
54    EscapingAlias(Vec<Component<I>>),
55}
56
57/// Push onto `out` all the things that must outlive `'a` for the condition
58/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
59pub fn push_outlives_components<I: Interner>(
60    cx: I,
61    ty: I::Ty,
62    out: &mut SmallVec<[Component<I>; 4]>,
63) {
64    ty.visit_with(&mut OutlivesCollector { cx, out, visited: Default::default() });
65}
66
67struct OutlivesCollector<'a, I: Interner> {
68    cx: I,
69    out: &'a mut SmallVec<[Component<I>; 4]>,
70    visited: SsoHashSet<I::Ty>,
71}
72
73impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
74    #[cfg(not(feature = "nightly"))]
75    type Result = ();
76
77    fn visit_ty(&mut self, ty: I::Ty) -> Self::Result {
78        if !self.visited.insert(ty) {
79            return;
80        }
81        // Descend through the types, looking for the various "base"
82        // components and collecting them into `out`. This is not written
83        // with `collect()` because of the need to sometimes skip subtrees
84        // in the `subtys` iterator (e.g., when encountering a
85        // projection).
86        match ty.kind() {
87            ty::FnDef(_, args) => {
88                let args = args.no_bound_vars().unwrap();
89                // HACK(eddyb) ignore lifetimes found shallowly in `args`.
90                // This is inconsistent with `ty::Adt` (including all args)
91                // and with `ty::Closure` (ignoring all args other than
92                // upvars, of which a `ty::FnDef` doesn't have any), but
93                // consistent with previous (accidental) behavior.
94                // See https://github.com/rust-lang/rust/issues/70917
95                // for further background and discussion.
96                for child in args.iter() {
97                    match child.kind() {
98                        ty::GenericArgKind::Lifetime(_) => {}
99                        ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_) => {
100                            child.visit_with(self);
101                        }
102                    }
103                }
104            }
105
106            ty::Closure(_, args) => {
107                args.as_closure().tupled_upvars_ty().visit_with(self);
108            }
109
110            ty::CoroutineClosure(_, args) => {
111                args.as_coroutine_closure().tupled_upvars_ty().visit_with(self);
112            }
113
114            ty::Coroutine(_, args) => {
115                args.as_coroutine().tupled_upvars_ty().visit_with(self);
116
117                // Coroutines may not outlive a region unless the resume
118                // ty outlives a region. This is because the resume ty may
119                // store data that lives shorter than this outlives region
120                // across yield points, which may subsequently be accessed
121                // after the coroutine is resumed again.
122                //
123                // Conceptually, you may think of the resume arg as an upvar
124                // of `&mut Option<ResumeArgTy>`, since it is kinda like
125                // storage shared between the callee of the coroutine and the
126                // coroutine body.
127                args.as_coroutine().resume_ty().visit_with(self);
128
129                // We ignore regions in the coroutine interior as we don't
130                // want these to affect region inference
131            }
132
133            // All regions are bound inside a witness, and we don't emit
134            // higher-ranked outlives components currently.
135            ty::CoroutineWitness(..) => {}
136
137            // OutlivesTypeParameterEnv -- the actual checking that `X:'a`
138            // is implied by the environment is done in regionck.
139            ty::Param(p) => {
140                self.out.push(Component::Param(p));
141            }
142
143            ty::Placeholder(p) => {
144                self.out.push(Component::Placeholder(p));
145            }
146
147            // For projections, we prefer to generate an obligation like
148            // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
149            // regionck more ways to prove that it holds. However,
150            // regionck is not (at least currently) prepared to deal with
151            // higher-ranked regions that may appear in the
152            // trait-ref. Therefore, if we see any higher-ranked regions,
153            // we simply fallback to the most restrictive rule, which
154            // requires that `Pi: 'a` for all `i`.
155            ty::Alias(is_rigid, alias_ty) => {
156                if !alias_ty.has_escaping_bound_vars() {
157                    // best case: no escaping regions, so push the
158                    // projection and skip the subtree (thus generating no
159                    // constraints for Pi). This defers the choice between
160                    // the rules OutlivesProjectionEnv,
161                    // OutlivesProjectionTraitDef, and
162                    // OutlivesProjectionComponents to regionck.
163                    self.out.push(Component::Alias(is_rigid, alias_ty));
164                } else {
165                    // fallback case: hard code
166                    // OutlivesProjectionComponents. Continue walking
167                    // through and constrain Pi.
168                    let mut subcomponents = ::smallvec::SmallVec::new()smallvec![];
169                    compute_alias_components_recursive(self.cx, alias_ty, &mut subcomponents);
170                    self.out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
171                }
172            }
173
174            // We assume that inference variables are fully resolved.
175            // So, if we encounter an inference variable, just record
176            // the unresolved variable as a component.
177            ty::Infer(infer_ty) => {
178                self.out.push(Component::UnresolvedInferenceVariable(infer_ty));
179            }
180
181            // Most types do not introduce any region binders, nor
182            // involve any other subtle cases, and so the WF relation
183            // simply constraints any regions referenced directly by
184            // the type and then visits the types that are lexically
185            // contained within.
186            ty::Bool
187            | ty::Char
188            | ty::Int(_)
189            | ty::Uint(_)
190            | ty::Float(_)
191            | ty::Str
192            | ty::Never
193            | ty::Error(_) => {
194                // Trivial
195            }
196
197            ty::Bound(_, _) => {
198                // FIXME: Bound vars matter here!
199            }
200
201            ty::Adt(_, _)
202            | ty::Foreign(_)
203            | ty::Array(_, _)
204            | ty::Pat(_, _)
205            | ty::Slice(_)
206            | ty::RawPtr(_, _)
207            | ty::Ref(_, _, _)
208            | ty::FnPtr(..)
209            | ty::UnsafeBinder(_)
210            | ty::Dynamic(_, _)
211            | ty::Tuple(_) => {
212                ty.super_visit_with(self);
213            }
214        }
215    }
216
217    fn visit_region(&mut self, lt: Region<I>) -> Self::Result {
218        if !lt.is_bound() {
219            self.out.push(Component::Region(lt));
220        }
221    }
222}
223
224/// Collect [Component]s for *all* the args of `alias_ty`.
225///
226/// This should not be used to get the components of `alias_ty` itself.
227/// Use [push_outlives_components] instead.
228pub fn compute_alias_components_recursive<I: Interner>(
229    cx: I,
230    alias_ty: ty::AliasTy<I>,
231    out: &mut SmallVec<[Component<I>; 4]>,
232) {
233    let opt_variances = cx.opt_alias_variances(alias_ty.kind);
234
235    let mut visitor = OutlivesCollector { cx, out, visited: Default::default() };
236
237    for (index, child) in alias_ty.args.iter().enumerate() {
238        if opt_variances.and_then(|variances| variances.get(index)) == Some(ty::Bivariant) {
239            continue;
240        }
241        child.visit_with(&mut visitor);
242    }
243}
244
245/// Given a projection like `<T as Foo<'x>>::Bar`, returns any bounds
246/// declared in the trait definition. For example, if the trait were
247///
248/// ```rust
249/// trait Foo<'a> {
250///     type Bar: 'a;
251/// }
252/// ```
253///
254/// If we were given `<T as Foo<'b>>::Bar`, we would return
255/// `'b`. This doesn't work for higher-ranked bounds such as:
256///
257/// ```ignore (this does compile today, previously was marked as compile_fail,E0311)
258/// trait Foo<'a, 'b>
259/// where for<'x> <Self as Foo<'x, 'b>>::Bar: 'x
260/// {
261///     type Bar;
262/// }
263/// ```
264///
265/// This is for simplicity, and because we are not really smart
266/// enough to cope with such bounds anywhere.
267pub fn declared_bounds_from_definition<I: Interner>(
268    cx: I,
269    alias_ty: AliasTy<I>,
270) -> impl Iterator<Item = Region<I>> {
271    let def_id = match alias_ty.kind {
272        ty::AliasTyKind::Projection { def_id } => def_id.into(),
273        ty::AliasTyKind::Inherent { def_id } => def_id.into(),
274        ty::AliasTyKind::Opaque { def_id } => def_id.into(),
275        ty::AliasTyKind::Free { def_id } => def_id.into(),
276    };
277
278    let bounds = cx.item_self_bounds(def_id);
279    bounds
280        .iter_instantiated(cx, alias_ty.args)
281        .map(Unnormalized::skip_norm_wip)
282        .filter_map(|c| c.as_type_outlives_clause())
283        .filter_map(|c| c.no_bound_vars())
284        .map(|OutlivesClause(_, r)| r)
285}