]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_infer/src/infer/outlives/components.rs
Rollup merge of #98101 - vladimir-ea:stdlib_watch_os, r=thomcc
[rust.git] / compiler / rustc_infer / src / infer / outlives / components.rs
1 // The outlines 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
5 use rustc_data_structures::sso::SsoHashSet;
6 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
7 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
8 use smallvec::{smallvec, SmallVec};
9
10 #[derive(Debug)]
11 pub enum Component<'tcx> {
12     Region(ty::Region<'tcx>),
13     Param(ty::ParamTy),
14     UnresolvedInferenceVariable(ty::InferTy),
15
16     // Projections like `T::Foo` are tricky because a constraint like
17     // `T::Foo: 'a` can be satisfied in so many ways. There may be a
18     // where-clause that says `T::Foo: 'a`, or the defining trait may
19     // include a bound like `type Foo: 'static`, or -- in the most
20     // conservative way -- we can prove that `T: 'a` (more generally,
21     // that all components in the projection outlive `'a`). This code
22     // is not in a position to judge which is the best technique, so
23     // we just product the projection as a component and leave it to
24     // the consumer to decide (but see `EscapingProjection` below).
25     Projection(ty::ProjectionTy<'tcx>),
26
27     // In the case where a projection has escaping regions -- meaning
28     // regions bound within the type itself -- we always use
29     // the most conservative rule, which requires that all components
30     // outlive the bound. So for example if we had a type like this:
31     //
32     //     for<'a> Trait1<  <T as Trait2<'a,'b>>::Foo  >
33     //                      ~~~~~~~~~~~~~~~~~~~~~~~~~
34     //
35     // then the inner projection (underlined) has an escaping region
36     // `'a`. We consider that outer trait `'c` to meet a bound if `'b`
37     // outlives `'b: 'c`, and we don't consider whether the trait
38     // declares that `Foo: 'static` etc. Therefore, we just return the
39     // free components of such a projection (in this case, `'b`).
40     //
41     // However, in the future, we may want to get smarter, and
42     // actually return a "higher-ranked projection" here. Therefore,
43     // we mark that these components are part of an escaping
44     // projection, so that implied bounds code can avoid relying on
45     // them. This gives us room to improve the regionck reasoning in
46     // the future without breaking backwards compat.
47     EscapingProjection(Vec<Component<'tcx>>),
48 }
49
50 /// Push onto `out` all the things that must outlive `'a` for the condition
51 /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
52 pub fn push_outlives_components<'tcx>(
53     tcx: TyCtxt<'tcx>,
54     ty0: Ty<'tcx>,
55     out: &mut SmallVec<[Component<'tcx>; 4]>,
56 ) {
57     let mut visited = SsoHashSet::new();
58     compute_components(tcx, ty0, out, &mut visited);
59     debug!("components({:?}) = {:?}", ty0, out);
60 }
61
62 fn compute_components<'tcx>(
63     tcx: TyCtxt<'tcx>,
64     ty: Ty<'tcx>,
65     out: &mut SmallVec<[Component<'tcx>; 4]>,
66     visited: &mut SsoHashSet<GenericArg<'tcx>>,
67 ) {
68     // Descend through the types, looking for the various "base"
69     // components and collecting them into `out`. This is not written
70     // with `collect()` because of the need to sometimes skip subtrees
71     // in the `subtys` iterator (e.g., when encountering a
72     // projection).
73     match *ty.kind() {
74             ty::FnDef(_, substs) => {
75                 // HACK(eddyb) ignore lifetimes found shallowly in `substs`.
76                 // This is inconsistent with `ty::Adt` (including all substs)
77                 // and with `ty::Closure` (ignoring all substs other than
78                 // upvars, of which a `ty::FnDef` doesn't have any), but
79                 // consistent with previous (accidental) behavior.
80                 // See https://github.com/rust-lang/rust/issues/70917
81                 // for further background and discussion.
82                 for child in substs {
83                     match child.unpack() {
84                         GenericArgKind::Type(ty) => {
85                             compute_components(tcx, ty, out, visited);
86                         }
87                         GenericArgKind::Lifetime(_) => {}
88                         GenericArgKind::Const(_) => {
89                             compute_components_recursive(tcx, child, out, visited);
90                         }
91                     }
92                 }
93             }
94
95             ty::Array(element, _) => {
96                 // Don't look into the len const as it doesn't affect regions
97                 compute_components(tcx, element, out, visited);
98             }
99
100             ty::Closure(_, ref substs) => {
101                 let tupled_ty = substs.as_closure().tupled_upvars_ty();
102                 compute_components(tcx, tupled_ty, out, visited);
103             }
104
105             ty::Generator(_, ref substs, _) => {
106                 // Same as the closure case
107                 let tupled_ty = substs.as_generator().tupled_upvars_ty();
108                 compute_components(tcx, tupled_ty, out, visited);
109
110                 // We ignore regions in the generator interior as we don't
111                 // want these to affect region inference
112             }
113
114             // All regions are bound inside a witness
115             ty::GeneratorWitness(..) => (),
116
117             // OutlivesTypeParameterEnv -- the actual checking that `X:'a`
118             // is implied by the environment is done in regionck.
119             ty::Param(p) => {
120                 out.push(Component::Param(p));
121             }
122
123             // For projections, we prefer to generate an obligation like
124             // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
125             // regionck more ways to prove that it holds. However,
126             // regionck is not (at least currently) prepared to deal with
127             // higher-ranked regions that may appear in the
128             // trait-ref. Therefore, if we see any higher-ranked regions,
129             // we simply fallback to the most restrictive rule, which
130             // requires that `Pi: 'a` for all `i`.
131             ty::Projection(ref data) => {
132                 if !data.has_escaping_bound_vars() {
133                     // best case: no escaping regions, so push the
134                     // projection and skip the subtree (thus generating no
135                     // constraints for Pi). This defers the choice between
136                     // the rules OutlivesProjectionEnv,
137                     // OutlivesProjectionTraitDef, and
138                     // OutlivesProjectionComponents to regionck.
139                     out.push(Component::Projection(*data));
140                 } else {
141                     // fallback case: hard code
142                     // OutlivesProjectionComponents.  Continue walking
143                     // through and constrain Pi.
144                     let mut subcomponents = smallvec![];
145                     let mut subvisited = SsoHashSet::new();
146                     compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited);
147                     out.push(Component::EscapingProjection(subcomponents.into_iter().collect()));
148                 }
149             }
150
151             // We assume that inference variables are fully resolved.
152             // So, if we encounter an inference variable, just record
153             // the unresolved variable as a component.
154             ty::Infer(infer_ty) => {
155                 out.push(Component::UnresolvedInferenceVariable(infer_ty));
156             }
157
158             // Most types do not introduce any region binders, nor
159             // involve any other subtle cases, and so the WF relation
160             // simply constraints any regions referenced directly by
161             // the type and then visits the types that are lexically
162             // contained within. (The comments refer to relevant rules
163             // from RFC1214.)
164             ty::Bool |            // OutlivesScalar
165             ty::Char |            // OutlivesScalar
166             ty::Int(..) |         // OutlivesScalar
167             ty::Uint(..) |        // OutlivesScalar
168             ty::Float(..) |       // OutlivesScalar
169             ty::Never |           // ...
170             ty::Adt(..) |         // OutlivesNominalType
171             ty::Opaque(..) |      // OutlivesNominalType (ish)
172             ty::Foreign(..) |     // OutlivesNominalType
173             ty::Str |             // OutlivesScalar (ish)
174             ty::Slice(..) |       // ...
175             ty::RawPtr(..) |      // ...
176             ty::Ref(..) |         // OutlivesReference
177             ty::Tuple(..) |       // ...
178             ty::FnPtr(_) |        // OutlivesFunction (*)
179             ty::Dynamic(..) |     // OutlivesObject, OutlivesFragment (*)
180             ty::Placeholder(..) |
181             ty::Bound(..) |
182             ty::Error(_) => {
183                 // (*) Function pointers and trait objects are both binders.
184                 // In the RFC, this means we would add the bound regions to
185                 // the "bound regions list".  In our representation, no such
186                 // list is maintained explicitly, because bound regions
187                 // themselves can be readily identified.
188                 compute_components_recursive(tcx, ty.into(), out, visited);
189             }
190         }
191 }
192
193 /// Collect [Component]s for *all* the substs of `parent`.
194 ///
195 /// This should not be used to get the components of `parent` itself.
196 /// Use [push_outlives_components] instead.
197 pub(super) fn compute_components_recursive<'tcx>(
198     tcx: TyCtxt<'tcx>,
199     parent: GenericArg<'tcx>,
200     out: &mut SmallVec<[Component<'tcx>; 4]>,
201     visited: &mut SsoHashSet<GenericArg<'tcx>>,
202 ) {
203     for child in parent.walk_shallow(visited) {
204         match child.unpack() {
205             GenericArgKind::Type(ty) => {
206                 compute_components(tcx, ty, out, visited);
207             }
208             GenericArgKind::Lifetime(lt) => {
209                 // Ignore late-bound regions.
210                 if !lt.is_late_bound() {
211                     out.push(Component::Region(lt));
212                 }
213             }
214             GenericArgKind::Const(_) => {
215                 compute_components_recursive(tcx, child, out, visited);
216             }
217         }
218     }
219 }