2015-08-06 14:27:21 -04:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2015-08-11 11:33:55 -04:00
|
|
|
// The outlines relation `T: 'a` or `'a: 'b`. This code frequently
|
|
|
|
// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
|
|
|
|
// RFC for reference.
|
2015-08-06 14:27:21 -04:00
|
|
|
|
2016-03-22 17:30:57 +02:00
|
|
|
use infer::InferCtxt;
|
|
|
|
use ty::{self, Ty, TypeFoldable};
|
2015-08-06 14:27:21 -04:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Component<'tcx> {
|
|
|
|
Region(ty::Region),
|
|
|
|
Param(ty::ParamTy),
|
|
|
|
UnresolvedInferenceVariable(ty::InferTy),
|
|
|
|
|
|
|
|
// Projections like `T::Foo` are tricky because a constraint like
|
|
|
|
// `T::Foo: 'a` can be satisfied in so many ways. There may be a
|
|
|
|
// where-clause that says `T::Foo: 'a`, or the defining trait may
|
|
|
|
// include a bound like `type Foo: 'static`, or -- in the most
|
|
|
|
// conservative way -- we can prove that `T: 'a` (more generally,
|
|
|
|
// that all components in the projection outlive `'a`). This code
|
|
|
|
// is not in a position to judge which is the best technique, so
|
|
|
|
// we just product the projection as a component and leave it to
|
|
|
|
// the consumer to decide (but see `EscapingProjection` below).
|
|
|
|
Projection(ty::ProjectionTy<'tcx>),
|
|
|
|
|
|
|
|
// In the case where a projection has escaping regions -- meaning
|
|
|
|
// regions bound within the type itself -- we always use
|
|
|
|
// the most conservative rule, which requires that all components
|
|
|
|
// outlive the bound. So for example if we had a type like this:
|
|
|
|
//
|
|
|
|
// for<'a> Trait1< <T as Trait2<'a,'b>>::Foo >
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
//
|
|
|
|
// then the inner projection (underlined) has an escaping region
|
|
|
|
// `'a`. We consider that outer trait `'c` to meet a bound if `'b`
|
|
|
|
// outlives `'b: 'c`, and we don't consider whether the trait
|
|
|
|
// declares that `Foo: 'static` etc. Therefore, we just return the
|
|
|
|
// free components of such a projection (in this case, `'b`).
|
|
|
|
//
|
|
|
|
// However, in the future, we may want to get smarter, and
|
|
|
|
// actually return a "higher-ranked projection" here. Therefore,
|
|
|
|
// we mark that these components are part of an escaping
|
|
|
|
// projection, so that implied bounds code can avoid relying on
|
|
|
|
// them. This gives us room to improve the regionck reasoning in
|
|
|
|
// the future without breaking backwards compat.
|
|
|
|
EscapingProjection(Vec<Component<'tcx>>),
|
|
|
|
}
|
|
|
|
|
2016-04-29 06:00:23 +03:00
|
|
|
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
2016-05-11 08:48:12 +03:00
|
|
|
/// Returns all the things that must outlive `'a` for the condition
|
|
|
|
/// `ty0: 'a` to hold.
|
|
|
|
pub fn outlives_components(&self, ty0: Ty<'tcx>)
|
|
|
|
-> Vec<Component<'tcx>> {
|
|
|
|
let mut components = vec![];
|
|
|
|
self.compute_components(ty0, &mut components);
|
|
|
|
debug!("components({:?}) = {:?}", ty0, components);
|
|
|
|
components
|
|
|
|
}
|
2015-08-06 14:27:21 -04:00
|
|
|
|
2016-05-11 08:48:12 +03:00
|
|
|
fn compute_components(&self, ty: Ty<'tcx>, out: &mut Vec<Component<'tcx>>) {
|
|
|
|
// Descend through the types, looking for the various "base"
|
|
|
|
// components and collecting them into `out`. This is not written
|
|
|
|
// with `collect()` because of the need to sometimes skip subtrees
|
|
|
|
// in the `subtys` iterator (e.g., when encountering a
|
|
|
|
// projection).
|
|
|
|
match ty.sty {
|
|
|
|
ty::TyClosure(_, ref substs) => {
|
|
|
|
// FIXME(#27086). We do not accumulate from substs, since they
|
|
|
|
// don't represent reachable data. This means that, in
|
|
|
|
// practice, some of the lifetime parameters might not
|
|
|
|
// be in scope when the body runs, so long as there is
|
|
|
|
// no reachable data with that lifetime. For better or
|
|
|
|
// worse, this is consistent with fn types, however,
|
|
|
|
// which can also encapsulate data in this fashion
|
|
|
|
// (though it's somewhat harder, and typically
|
|
|
|
// requires virtual dispatch).
|
|
|
|
//
|
|
|
|
// Note that changing this (in a naive way, at least)
|
|
|
|
// causes regressions for what appears to be perfectly
|
|
|
|
// reasonable code like this:
|
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// fn foo<'a>(p: &Data<'a>) {
|
|
|
|
// bar(|q: &mut Parser| q.read_addr())
|
|
|
|
// }
|
|
|
|
// fn bar(p: Box<FnMut(&mut Parser)+'static>) {
|
|
|
|
// }
|
|
|
|
// ```
|
|
|
|
//
|
|
|
|
// Note that `p` (and `'a`) are not used in the
|
|
|
|
// closure at all, but to meet the requirement that
|
|
|
|
// the closure type `C: 'static` (so it can be coerced
|
|
|
|
// to the object type), we get the requirement that
|
|
|
|
// `'a: 'static` since `'a` appears in the closure
|
|
|
|
// type `C`.
|
|
|
|
//
|
|
|
|
// A smarter fix might "prune" unused `func_substs` --
|
|
|
|
// this would avoid breaking simple examples like
|
|
|
|
// this, but would still break others (which might
|
|
|
|
// indeed be invalid, depending on your POV). Pruning
|
|
|
|
// would be a subtle process, since we have to see
|
|
|
|
// what func/type parameters are used and unused,
|
|
|
|
// taking into consideration UFCS and so forth.
|
2015-08-11 11:33:55 -04:00
|
|
|
|
2016-05-11 08:48:12 +03:00
|
|
|
for &upvar_ty in substs.upvar_tys {
|
|
|
|
self.compute_components(upvar_ty, out);
|
|
|
|
}
|
2015-08-06 14:27:21 -04:00
|
|
|
}
|
2015-08-11 11:33:55 -04:00
|
|
|
|
2016-05-11 08:48:12 +03:00
|
|
|
// OutlivesTypeParameterEnv -- the actual checking that `X:'a`
|
|
|
|
// is implied by the environment is done in regionck.
|
|
|
|
ty::TyParam(p) => {
|
|
|
|
out.push(Component::Param(p));
|
|
|
|
}
|
2015-08-11 11:33:55 -04:00
|
|
|
|
2016-05-11 08:48:12 +03:00
|
|
|
// For projections, we prefer to generate an obligation like
|
|
|
|
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
|
|
|
|
// regionck more ways to prove that it holds. However,
|
|
|
|
// regionck is not (at least currently) prepared to deal with
|
|
|
|
// higher-ranked regions that may appear in the
|
|
|
|
// trait-ref. Therefore, if we see any higher-ranke regions,
|
|
|
|
// we simply fallback to the most restrictive rule, which
|
|
|
|
// requires that `Pi: 'a` for all `i`.
|
|
|
|
ty::TyProjection(ref data) => {
|
|
|
|
if !data.has_escaping_regions() {
|
|
|
|
// best case: no escaping regions, so push the
|
|
|
|
// projection and skip the subtree (thus generating no
|
|
|
|
// constraints for Pi). This defers the choice between
|
|
|
|
// the rules OutlivesProjectionEnv,
|
|
|
|
// OutlivesProjectionTraitDef, and
|
|
|
|
// OutlivesProjectionComponents to regionck.
|
|
|
|
out.push(Component::Projection(*data));
|
|
|
|
} else {
|
|
|
|
// fallback case: hard code
|
|
|
|
// OutlivesProjectionComponents. Continue walking
|
|
|
|
// through and constrain Pi.
|
|
|
|
let subcomponents = self.capture_components(ty);
|
|
|
|
out.push(Component::EscapingProjection(subcomponents));
|
|
|
|
}
|
2015-08-06 14:27:21 -04:00
|
|
|
}
|
2015-08-11 11:33:55 -04:00
|
|
|
|
2016-05-11 08:48:12 +03:00
|
|
|
// If we encounter an inference variable, try to resolve it
|
|
|
|
// and proceed with resolved version. If we cannot resolve it,
|
|
|
|
// then record the unresolved variable as a component.
|
|
|
|
ty::TyInfer(_) => {
|
|
|
|
let ty = self.resolve_type_vars_if_possible(&ty);
|
|
|
|
if let ty::TyInfer(infer_ty) = ty.sty {
|
|
|
|
out.push(Component::UnresolvedInferenceVariable(infer_ty));
|
|
|
|
} else {
|
|
|
|
self.compute_components(ty, out);
|
|
|
|
}
|
2015-08-06 14:27:21 -04:00
|
|
|
}
|
2015-08-11 11:17:15 -04:00
|
|
|
|
2016-05-11 08:48:12 +03:00
|
|
|
// Most types do not introduce any region binders, nor
|
|
|
|
// involve any other subtle cases, and so the WF relation
|
|
|
|
// simply constraints any regions referenced directly by
|
|
|
|
// the type and then visits the types that are lexically
|
|
|
|
// contained within. (The comments refer to relevant rules
|
|
|
|
// from RFC1214.)
|
|
|
|
ty::TyBool | // OutlivesScalar
|
|
|
|
ty::TyChar | // OutlivesScalar
|
|
|
|
ty::TyInt(..) | // OutlivesScalar
|
|
|
|
ty::TyUint(..) | // OutlivesScalar
|
|
|
|
ty::TyFloat(..) | // OutlivesScalar
|
2016-05-10 00:03:59 +08:00
|
|
|
ty::TyEmpty | // ...
|
2016-05-11 08:48:12 +03:00
|
|
|
ty::TyEnum(..) | // OutlivesNominalType
|
|
|
|
ty::TyStruct(..) | // OutlivesNominalType
|
|
|
|
ty::TyBox(..) | // OutlivesNominalType (ish)
|
2016-07-22 18:56:22 +03:00
|
|
|
ty::TyAnon(..) | // OutlivesNominalType (ish)
|
2016-05-11 08:48:12 +03:00
|
|
|
ty::TyStr | // OutlivesScalar (ish)
|
|
|
|
ty::TyArray(..) | // ...
|
|
|
|
ty::TySlice(..) | // ...
|
|
|
|
ty::TyRawPtr(..) | // ...
|
|
|
|
ty::TyRef(..) | // OutlivesReference
|
|
|
|
ty::TyTuple(..) | // ...
|
|
|
|
ty::TyFnDef(..) | // OutlivesFunction (*)
|
|
|
|
ty::TyFnPtr(_) | // OutlivesFunction (*)
|
|
|
|
ty::TyTrait(..) | // OutlivesObject, OutlivesFragment (*)
|
|
|
|
ty::TyError => {
|
|
|
|
// (*) Bare functions and traits are both binders. In the
|
|
|
|
// RFC, this means we would add the bound regions to the
|
|
|
|
// "bound regions list". In our representation, no such
|
|
|
|
// list is maintained explicitly, because bound regions
|
|
|
|
// themselves can be readily identified.
|
2015-12-15 04:31:58 -05:00
|
|
|
|
2016-05-11 08:48:12 +03:00
|
|
|
push_region_constraints(out, ty.regions());
|
|
|
|
for subty in ty.walk_shallow() {
|
|
|
|
self.compute_components(subty, out);
|
|
|
|
}
|
2015-08-06 14:27:21 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-11 08:48:12 +03:00
|
|
|
fn capture_components(&self, ty: Ty<'tcx>) -> Vec<Component<'tcx>> {
|
|
|
|
let mut temp = vec![];
|
|
|
|
push_region_constraints(&mut temp, ty.regions());
|
|
|
|
for subty in ty.walk_shallow() {
|
|
|
|
self.compute_components(subty, &mut temp);
|
|
|
|
}
|
|
|
|
temp
|
2015-08-06 14:27:21 -04:00
|
|
|
}
|
2016-03-17 00:15:31 +02:00
|
|
|
}
|
2015-08-06 14:27:21 -04:00
|
|
|
|
|
|
|
fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region>) {
|
|
|
|
for r in regions {
|
|
|
|
if !r.is_bound() {
|
|
|
|
out.push(Component::Region(r));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|