]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/outlives.rs
renamed query
[rust.git] / src / librustc / ty / outlives.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // The outlines relation `T: 'a` or `'a: 'b`. This code frequently
12 // refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
13 // RFC for reference.
14
15 use ty::{self, Ty, TyCtxt, TypeFoldable};
16
17 #[derive(Debug)]
18 pub enum Component<'tcx> {
19     Region(ty::Region<'tcx>),
20     Param(ty::ParamTy),
21     UnresolvedInferenceVariable(ty::InferTy),
22
23     // Projections like `T::Foo` are tricky because a constraint like
24     // `T::Foo: 'a` can be satisfied in so many ways. There may be a
25     // where-clause that says `T::Foo: 'a`, or the defining trait may
26     // include a bound like `type Foo: 'static`, or -- in the most
27     // conservative way -- we can prove that `T: 'a` (more generally,
28     // that all components in the projection outlive `'a`). This code
29     // is not in a position to judge which is the best technique, so
30     // we just product the projection as a component and leave it to
31     // the consumer to decide (but see `EscapingProjection` below).
32     Projection(ty::ProjectionTy<'tcx>),
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     EscapingProjection(Vec<Component<'tcx>>),
55 }
56
57 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
58     /// Returns all the things that must outlive `'a` for the condition
59     /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**.
60     pub fn outlives_components(&self, ty0: Ty<'tcx>)
61                                -> Vec<Component<'tcx>> {
62         let mut components = vec![];
63         self.compute_components(ty0, &mut components);
64         debug!("components({:?}) = {:?}", ty0, components);
65         components
66     }
67
68     fn compute_components(&self, ty: Ty<'tcx>, out: &mut Vec<Component<'tcx>>) {
69         // Descend through the types, looking for the various "base"
70         // components and collecting them into `out`. This is not written
71         // with `collect()` because of the need to sometimes skip subtrees
72         // in the `subtys` iterator (e.g., when encountering a
73         // projection).
74         match ty.sty {
75             ty::TyClosure(def_id, ref substs) => {
76
77                 for upvar_ty in substs.upvar_tys(def_id, *self) {
78                     self.compute_components(upvar_ty, out);
79                 }
80             }
81
82             ty::TyGenerator(def_id, ref substs, ref interior) => {
83                 // Same as the closure case
84                 for upvar_ty in substs.upvar_tys(def_id, *self) {
85                     self.compute_components(upvar_ty, out);
86                 }
87
88                 // But generators can have additional interior types
89                 self.compute_components(interior.witness, out);
90             }
91
92             // OutlivesTypeParameterEnv -- the actual checking that `X:'a`
93             // is implied by the environment is done in regionck.
94             ty::TyParam(p) => {
95                 out.push(Component::Param(p));
96             }
97
98             // For projections, we prefer to generate an obligation like
99             // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
100             // regionck more ways to prove that it holds. However,
101             // regionck is not (at least currently) prepared to deal with
102             // higher-ranked regions that may appear in the
103             // trait-ref. Therefore, if we see any higher-ranke regions,
104             // we simply fallback to the most restrictive rule, which
105             // requires that `Pi: 'a` for all `i`.
106             ty::TyProjection(ref data) => {
107                 if !data.has_escaping_regions() {
108                     // best case: no escaping regions, so push the
109                     // projection and skip the subtree (thus generating no
110                     // constraints for Pi). This defers the choice between
111                     // the rules OutlivesProjectionEnv,
112                     // OutlivesProjectionTraitDef, and
113                     // OutlivesProjectionComponents to regionck.
114                     out.push(Component::Projection(*data));
115                 } else {
116                     // fallback case: hard code
117                     // OutlivesProjectionComponents.  Continue walking
118                     // through and constrain Pi.
119                     let subcomponents = self.capture_components(ty);
120                     out.push(Component::EscapingProjection(subcomponents));
121                 }
122             }
123
124             // We assume that inference variables are fully resolved.
125             // So, if we encounter an inference variable, just record
126             // the unresolved variable as a component.
127             ty::TyInfer(infer_ty) => {
128                 out.push(Component::UnresolvedInferenceVariable(infer_ty));
129             }
130
131             // Most types do not introduce any region binders, nor
132             // involve any other subtle cases, and so the WF relation
133             // simply constraints any regions referenced directly by
134             // the type and then visits the types that are lexically
135             // contained within. (The comments refer to relevant rules
136             // from RFC1214.)
137             ty::TyBool |            // OutlivesScalar
138             ty::TyChar |            // OutlivesScalar
139             ty::TyInt(..) |         // OutlivesScalar
140             ty::TyUint(..) |        // OutlivesScalar
141             ty::TyFloat(..) |       // OutlivesScalar
142             ty::TyNever |           // ...
143             ty::TyAdt(..) |         // OutlivesNominalType
144             ty::TyAnon(..) |        // OutlivesNominalType (ish)
145             ty::TyStr |             // OutlivesScalar (ish)
146             ty::TyArray(..) |       // ...
147             ty::TySlice(..) |       // ...
148             ty::TyRawPtr(..) |      // ...
149             ty::TyRef(..) |         // OutlivesReference
150             ty::TyTuple(..) |       // ...
151             ty::TyFnDef(..) |       // OutlivesFunction (*)
152             ty::TyFnPtr(_) |        // OutlivesFunction (*)
153             ty::TyDynamic(..) |       // OutlivesObject, OutlivesFragment (*)
154             ty::TyError => {
155                 // (*) Bare functions and traits are both binders. In the
156                 // RFC, this means we would add the bound regions to the
157                 // "bound regions list".  In our representation, no such
158                 // list is maintained explicitly, because bound regions
159                 // themselves can be readily identified.
160
161                 push_region_constraints(out, ty.regions());
162                 for subty in ty.walk_shallow() {
163                     self.compute_components(subty, out);
164                 }
165             }
166         }
167     }
168
169     fn capture_components(&self, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
170         let mut temp = vec![];
171         push_region_constraints(&mut temp, ty.regions());
172         for subty in ty.walk_shallow() {
173             self.compute_components(subty, &mut temp);
174         }
175         temp
176     }
177 }
178
179 fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region<'tcx>>) {
180     for r in regions {
181         if !r.is_late_bound() {
182             out.push(Component::Region(r));
183         }
184     }
185 }