]>
git.proxmox.com Git - rustc.git/blob - 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.
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.
11 // The outlines relation `T: 'a` or `'a: 'b`. This code frequently
12 // refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
16 use ty
::{self, Ty, TypeFoldable}
;
19 pub enum Component
<'tcx
> {
22 UnresolvedInferenceVariable(ty
::InferTy
),
24 // Projections like `T::Foo` are tricky because a constraint like
25 // `T::Foo: 'a` can be satisfied in so many ways. There may be a
26 // where-clause that says `T::Foo: 'a`, or the defining trait may
27 // include a bound like `type Foo: 'static`, or -- in the most
28 // conservative way -- we can prove that `T: 'a` (more generally,
29 // that all components in the projection outlive `'a`). This code
30 // is not in a position to judge which is the best technique, so
31 // we just product the projection as a component and leave it to
32 // the consumer to decide (but see `EscapingProjection` below).
33 Projection(ty
::ProjectionTy
<'tcx
>),
35 // In the case where a projection has escaping regions -- meaning
36 // regions bound within the type itself -- we always use
37 // the most conservative rule, which requires that all components
38 // outlive the bound. So for example if we had a type like this:
40 // for<'a> Trait1< <T as Trait2<'a,'b>>::Foo >
41 // ~~~~~~~~~~~~~~~~~~~~~~~~~
43 // then the inner projection (underlined) has an escaping region
44 // `'a`. We consider that outer trait `'c` to meet a bound if `'b`
45 // outlives `'b: 'c`, and we don't consider whether the trait
46 // declares that `Foo: 'static` etc. Therefore, we just return the
47 // free components of such a projection (in this case, `'b`).
49 // However, in the future, we may want to get smarter, and
50 // actually return a "higher-ranked projection" here. Therefore,
51 // we mark that these components are part of an escaping
52 // projection, so that implied bounds code can avoid relying on
53 // them. This gives us room to improve the regionck reasoning in
54 // the future without breaking backwards compat.
55 EscapingProjection(Vec
<Component
<'tcx
>>),
58 impl<'a
, 'gcx
, 'tcx
> InferCtxt
<'a
, 'gcx
, 'tcx
> {
59 /// Returns all the things that must outlive `'a` for the condition
60 /// `ty0: 'a` to hold.
61 pub fn outlives_components(&self, ty0
: Ty
<'tcx
>)
62 -> Vec
<Component
<'tcx
>> {
63 let mut components
= vec
![];
64 self.compute_components(ty0
, &mut components
);
65 debug
!("components({:?}) = {:?}", ty0
, components
);
69 fn compute_components(&self, ty
: Ty
<'tcx
>, out
: &mut Vec
<Component
<'tcx
>>) {
70 // Descend through the types, looking for the various "base"
71 // components and collecting them into `out`. This is not written
72 // with `collect()` because of the need to sometimes skip subtrees
73 // in the `subtys` iterator (e.g., when encountering a
76 ty
::TyClosure(_
, ref substs
) => {
77 // FIXME(#27086). We do not accumulate from substs, since they
78 // don't represent reachable data. This means that, in
79 // practice, some of the lifetime parameters might not
80 // be in scope when the body runs, so long as there is
81 // no reachable data with that lifetime. For better or
82 // worse, this is consistent with fn types, however,
83 // which can also encapsulate data in this fashion
84 // (though it's somewhat harder, and typically
85 // requires virtual dispatch).
87 // Note that changing this (in a naive way, at least)
88 // causes regressions for what appears to be perfectly
89 // reasonable code like this:
92 // fn foo<'a>(p: &Data<'a>) {
93 // bar(|q: &mut Parser| q.read_addr())
95 // fn bar(p: Box<FnMut(&mut Parser)+'static>) {
99 // Note that `p` (and `'a`) are not used in the
100 // closure at all, but to meet the requirement that
101 // the closure type `C: 'static` (so it can be coerced
102 // to the object type), we get the requirement that
103 // `'a: 'static` since `'a` appears in the closure
106 // A smarter fix might "prune" unused `func_substs` --
107 // this would avoid breaking simple examples like
108 // this, but would still break others (which might
109 // indeed be invalid, depending on your POV). Pruning
110 // would be a subtle process, since we have to see
111 // what func/type parameters are used and unused,
112 // taking into consideration UFCS and so forth.
114 for &upvar_ty
in substs
.upvar_tys
{
115 self.compute_components(upvar_ty
, out
);
119 // OutlivesTypeParameterEnv -- the actual checking that `X:'a`
120 // is implied by the environment is done in regionck.
122 out
.push(Component
::Param(p
));
125 // For projections, we prefer to generate an obligation like
126 // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
127 // regionck more ways to prove that it holds. However,
128 // regionck is not (at least currently) prepared to deal with
129 // higher-ranked regions that may appear in the
130 // trait-ref. Therefore, if we see any higher-ranke regions,
131 // we simply fallback to the most restrictive rule, which
132 // requires that `Pi: 'a` for all `i`.
133 ty
::TyProjection(ref data
) => {
134 if !data
.has_escaping_regions() {
135 // best case: no escaping regions, so push the
136 // projection and skip the subtree (thus generating no
137 // constraints for Pi). This defers the choice between
138 // the rules OutlivesProjectionEnv,
139 // OutlivesProjectionTraitDef, and
140 // OutlivesProjectionComponents to regionck.
141 out
.push(Component
::Projection(*data
));
143 // fallback case: hard code
144 // OutlivesProjectionComponents. Continue walking
145 // through and constrain Pi.
146 let subcomponents
= self.capture_components(ty
);
147 out
.push(Component
::EscapingProjection(subcomponents
));
151 // If we encounter an inference variable, try to resolve it
152 // and proceed with resolved version. If we cannot resolve it,
153 // then record the unresolved variable as a component.
155 let ty
= self.resolve_type_vars_if_possible(&ty
);
156 if let ty
::TyInfer(infer_ty
) = ty
.sty
{
157 out
.push(Component
::UnresolvedInferenceVariable(infer_ty
));
159 self.compute_components(ty
, out
);
163 // Most types do not introduce any region binders, nor
164 // involve any other subtle cases, and so the WF relation
165 // simply constraints any regions referenced directly by
166 // the type and then visits the types that are lexically
167 // contained within. (The comments refer to relevant rules
169 ty
::TyBool
| // OutlivesScalar
170 ty
::TyChar
| // OutlivesScalar
171 ty
::TyInt(..) | // OutlivesScalar
172 ty
::TyUint(..) | // OutlivesScalar
173 ty
::TyFloat(..) | // OutlivesScalar
175 ty
::TyEnum(..) | // OutlivesNominalType
176 ty
::TyStruct(..) | // OutlivesNominalType
177 ty
::TyBox(..) | // OutlivesNominalType (ish)
178 ty
::TyAnon(..) | // OutlivesNominalType (ish)
179 ty
::TyStr
| // OutlivesScalar (ish)
180 ty
::TyArray(..) | // ...
181 ty
::TySlice(..) | // ...
182 ty
::TyRawPtr(..) | // ...
183 ty
::TyRef(..) | // OutlivesReference
184 ty
::TyTuple(..) | // ...
185 ty
::TyFnDef(..) | // OutlivesFunction (*)
186 ty
::TyFnPtr(_
) | // OutlivesFunction (*)
187 ty
::TyTrait(..) | // OutlivesObject, OutlivesFragment (*)
189 // (*) Bare functions and traits are both binders. In the
190 // RFC, this means we would add the bound regions to the
191 // "bound regions list". In our representation, no such
192 // list is maintained explicitly, because bound regions
193 // themselves can be readily identified.
195 push_region_constraints(out
, ty
.regions());
196 for subty
in ty
.walk_shallow() {
197 self.compute_components(subty
, out
);
203 fn capture_components(&self, ty
: Ty
<'tcx
>) -> Vec
<Component
<'tcx
>> {
204 let mut temp
= vec
![];
205 push_region_constraints(&mut temp
, ty
.regions());
206 for subty
in ty
.walk_shallow() {
207 self.compute_components(subty
, &mut temp
);
213 fn push_region_constraints
<'tcx
>(out
: &mut Vec
<Component
<'tcx
>>, regions
: Vec
<ty
::Region
>) {
216 out
.push(Component
::Region(r
));