Auto merge of #45298 - toidiu:ak-44493-infer-predicate, r=nikomatsakis

Ak 44493 infer predicate

 **WIP**  Implements #44493

Things to do:

- [x] add feature gate and appropriate tests (see [forge](https://forge.rust-lang.org/feature-guide.html) for some details)
- [x] add a unit testing system similar to `#[rustc_variance]`
  - [x] to see how, maybe `rg rustc_variance` and take some notes
- [ ] add more tests:
- [x] we need to decide how to handle `struct Foo<'a, T> { x: &'a T::Item }`
- [x] handle explicit predicates on types
- [ ] handle explicit predicates on `dyn Trait` (this could be put off to a follow-up PR)
- [ ] handle explicit predicates on projections (this could be put off to a follow-up PR)
This commit is contained in:
bors 2018-04-12 23:07:07 +00:00
commit c4a03283cd
44 changed files with 1415 additions and 21 deletions

1
.gitignore vendored
View File

@ -83,6 +83,7 @@ __pycache__/
/src/libstd_unicode/UnicodeData.txt
/stage[0-9]+/
/target
target/
/test/
/tmp/
TAGS

View File

@ -500,6 +500,7 @@ define_dep_nodes!( <'tcx>
[] GenericsOfItem(DefId),
[] PredicatesOfItem(DefId),
[] InferredOutlivesOf(DefId),
[] InferredOutlivesCrate(CrateNum),
[] SuperPredicatesOfItem(DefId),
[] TraitDefOfItem(DefId),
[] AdtDefOfItem(DefId),

View File

@ -1100,6 +1100,20 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::CrateVariancesMap {
}
}
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::CratePredicatesMap<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
let ty::CratePredicatesMap {
ref predicates,
// This is just an irrelevant helper value.
empty_predicate: _,
} = *self;
predicates.hash_stable(hcx, hasher);
}
}
impl_stable_hash_for!(struct ty::AssociatedItem {
def_id,
name,

View File

@ -155,6 +155,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::crate_variances<'tcx> {
}
}
impl<'tcx> QueryDescription<'tcx> for queries::inferred_outlives_crate<'tcx> {
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
format!("computing the inferred outlives predicates for items in this crate")
}
}
impl<'tcx> QueryDescription<'tcx> for queries::mir_shims<'tcx> {
fn describe(tcx: TyCtxt, def: ty::InstanceDef<'tcx>) -> String {
format!("generating MIR shim for `{}`",

View File

@ -102,6 +102,7 @@ define_maps! { <'tcx>
/// associated generics and predicates.
[] fn generics_of: GenericsOfItem(DefId) -> &'tcx ty::Generics,
[] fn predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>,
[] fn explicit_predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>,
/// Maps from the def-id of a trait to the list of
/// super-predicates. This is a subset of the full list of
@ -139,7 +140,11 @@ define_maps! { <'tcx>
[] fn variances_of: ItemVariances(DefId) -> Lrc<Vec<ty::Variance>>,
/// Maps from def-id of a type to its (inferred) outlives.
[] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Vec<ty::Predicate<'tcx>>,
[] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc<Vec<ty::Predicate<'tcx>>>,
/// Maps from def-id of a type to its (inferred) outlives.
[] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum)
-> Lrc<ty::CratePredicatesMap<'tcx>>,
/// Maps from an impl/trait def-id to a list of the def-ids of its items
[] fn associated_item_def_ids: AssociatedItemDefIds(DefId) -> Lrc<Vec<DefId>>,

View File

@ -1007,6 +1007,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::GenericsOfItem => { force!(generics_of, def_id!()); }
DepKind::PredicatesOfItem => { force!(predicates_of, def_id!()); }
DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); }
DepKind::InferredOutlivesCrate => { force!(inferred_outlives_crate, LOCAL_CRATE); }
DepKind::SuperPredicatesOfItem => { force!(super_predicates_of, def_id!()); }
DepKind::TraitDefOfItem => { force!(trait_def, def_id!()); }
DepKind::AdtDefOfItem => { force!(adt_def, def_id!()); }

View File

@ -956,6 +956,22 @@ pub enum Predicate<'tcx> {
ConstEvaluatable(DefId, &'tcx Substs<'tcx>),
}
/// The crate outlives map is computed during typeck and contains the
/// outlives of every item in the local crate. You should not use it
/// directly, because to do so will make your pass dependent on the
/// HIR of every item in the local crate. Instead, use
/// `tcx.inferred_outlives_of()` to get the outlives for a *particular*
/// item.
pub struct CratePredicatesMap<'tcx> {
/// For each struct with outlive bounds, maps to a vector of the
/// predicate of its outlive bounds. If an item has no outlives
/// bounds, it will have no entry.
pub predicates: FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
/// An empty vector, useful for cloning.
pub empty_predicate: Lrc<Vec<ty::Predicate<'tcx>>>,
}
impl<'tcx> AsRef<Predicate<'tcx>> for Predicate<'tcx> {
fn as_ref(&self) -> &Predicate<'tcx> {
self

View File

@ -64,6 +64,7 @@ pub fn provide(providers: &mut Providers) {
type_of,
generics_of,
predicates_of,
explicit_predicates_of,
super_predicates_of,
type_param_predicates,
trait_def,
@ -1296,13 +1297,17 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ty::GenericPredicates<'tcx> {
let explicit = explicit_predicates_of(tcx, def_id);
let predicates = if tcx.sess.features_untracked().infer_outlives_requirements {
[&explicit.predicates[..], &tcx.inferred_outlives_of(def_id)[..]].concat()
} else { explicit.predicates };
ty::GenericPredicates {
parent: explicit.parent,
predicates: [&explicit.predicates[..], &tcx.inferred_outlives_of(def_id)[..]].concat()
predicates: predicates,
}
}
fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ty::GenericPredicates<'tcx> {
use rustc::hir::map::*;

View File

@ -4840,11 +4840,11 @@ register_diagnostics! {
E0588, // packed type cannot transitively contain a `[repr(align)]` type
E0592, // duplicate definitions with name `{}`
// E0613, // Removed (merged with E0609)
E0640, // infer outlives
E0627, // yield statement outside of generator literal
E0632, // cannot provide explicit type parameters when `impl Trait` is used in
// argument position.
E0634, // type has conflicting packed representaton hints
E0640, // infer outlives requirements
E0641, // cannot cast to/from a pointer with an unknown kind
E0645, // trait aliases not finished
E0907, // type inside generator must be known in this context

View File

@ -82,6 +82,7 @@ This API is completely unstable and subject to change.
#![feature(slice_patterns)]
#![feature(slice_sort_by_cached_key)]
#![feature(dyn_trait)]
#![feature(underscore_lifetimes)]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;

View File

@ -0,0 +1,82 @@
// Copyright 2013 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.
use hir::map as hir_map;
use rustc::hir;
use rustc::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ty::maps::Providers;
use rustc::ty::{self, CratePredicatesMap, TyCtxt};
use rustc_data_structures::sync::Lrc;
use util::nodemap::FxHashMap;
pub fn explicit_predicates<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
crate_num: CrateNum,
) -> FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>> {
assert_eq!(crate_num, LOCAL_CRATE);
let mut predicates: FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>> = FxHashMap();
// iterate over the entire crate
tcx.hir.krate().visit_all_item_likes(&mut ExplicitVisitor {
tcx: tcx,
explicit_predicates: &mut predicates,
crate_num: crate_num,
});
predicates
}
pub struct ExplicitVisitor<'cx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
explicit_predicates: &'cx mut FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
crate_num: CrateNum,
}
impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for ExplicitVisitor<'cx, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
let def_id = DefId {
krate: self.crate_num,
index: item.hir_id.owner,
};
let local_explicit_predicate = self.tcx.explicit_predicates_of(def_id);
let filtered_predicates = local_explicit_predicate
.predicates
.into_iter()
.filter(|pred| match pred {
ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => true,
ty::Predicate::Trait(..)
| ty::Predicate::Projection(..)
| ty::Predicate::WellFormed(..)
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::ConstEvaluatable(..) => false,
})
.collect();
match item.node {
hir::ItemStruct(..) | hir::ItemEnum(..) => {
self.tcx.adt_def(def_id);
}
_ => {}
}
self.explicit_predicates
.insert(def_id, Lrc::new(filtered_predicates));
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {}
}

View File

@ -0,0 +1,52 @@
// Copyright 2013 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.
use hir::map as hir_map;
use rustc::hir;
use rustc::hir::def_id::{self, CrateNum, DefId, LOCAL_CRATE};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ty::maps::Providers;
use rustc::ty::{self, CratePredicatesMap, TyCtxt};
use rustc_data_structures::sync::Lrc;
use util::nodemap::FxHashMap;
// Create the sets of inferred predicates for each type. These sets
// are initially empty but will grow during the inference step.
pub fn empty_predicate_map<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
) -> FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>> {
let mut predicates = FxHashMap();
// iterate over the entire crate
tcx.hir
.krate()
.visit_all_item_likes(&mut EmptyImplicitVisitor {
tcx,
predicates: &mut predicates,
});
predicates
}
pub struct EmptyImplicitVisitor<'cx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
predicates: &'cx mut FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
}
impl<'a, 'p, 'v> ItemLikeVisitor<'v> for EmptyImplicitVisitor<'a, 'p> {
fn visit_item(&mut self, item: &hir::Item) {
self.predicates
.insert(self.tcx.hir.local_def_id(item.id), Lrc::new(Vec::new()));
}
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {}
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {}
}

View File

@ -0,0 +1,442 @@
// Copyright 2013 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.
#![allow(unused)]
use rustc::hir;
use rustc::hir::def::{CtorKind, Def};
use rustc::hir::def_id::{self, CrateNum, DefId, LOCAL_CRATE};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::map as hir_map;
use rustc::ty::Slice;
use rustc::ty::maps::Providers;
use rustc::ty::outlives::Component;
use rustc::ty::subst::{Kind, Subst, UnpackedKind};
use rustc::ty::{self, AdtKind, CratePredicatesMap, Region, RegionKind, ReprOptions,
ToPolyTraitRef, ToPredicate, Ty, TyCtxt};
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use syntax::{abi, ast};
use syntax_pos::{Span, DUMMY_SP};
/// Infer predicates for the items in the crate.
///
/// global_inferred_outlives: this is initially the empty map that
/// was generated by walking the items in the crate. This will
/// now be filled with inferred predicates.
pub fn infer_predicates<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
) -> FxHashMap<DefId, RequiredPredicates<'tcx>> {
debug!("infer_predicates");
let mut predicates_added = true;
let mut global_inferred_outlives = FxHashMap::default();
// If new predicates were added then we need to re-calculate
// all crates since there could be new implied predicates.
while predicates_added {
predicates_added = false;
let mut visitor = InferVisitor {
tcx: tcx,
global_inferred_outlives: &mut global_inferred_outlives,
predicates_added: &mut predicates_added,
explicit_map: explicit_map,
};
// Visit all the crates and infer predicates
tcx.hir.krate().visit_all_item_likes(&mut visitor);
}
global_inferred_outlives
}
pub struct InferVisitor<'cx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
global_inferred_outlives: &'cx mut FxHashMap<DefId, RequiredPredicates<'tcx>>,
predicates_added: &'cx mut bool,
explicit_map: &'cx FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
}
/// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
/// must be added to the struct header.
type RequiredPredicates<'tcx> = FxHashSet<ty::OutlivesPredicate<Kind<'tcx>, ty::Region<'tcx>>>;
impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
let item_did = self.tcx.hir.local_def_id(item.id);
debug!("InferVisitor::visit_item(item={:?})", item_did);
let node_id = self.tcx
.hir
.as_local_node_id(item_did)
.expect("expected local def-id");
let item = match self.tcx.hir.get(node_id) {
hir::map::NodeItem(item) => item,
_ => bug!(),
};
let mut item_required_predicates = RequiredPredicates::default();
match item.node {
hir::ItemUnion(..) | hir::ItemEnum(..) | hir::ItemStruct(..) => {
let adt_def = self.tcx.adt_def(item_did);
// Iterate over all fields in item_did
for field_def in adt_def.all_fields() {
// Calculating the predicate requirements necessary
// for item_did.
//
// For field of type &'a T (reference) or TyAdt
// (struct/enum/union) there will be outlive
// requirements for adt_def.
let field_ty = self.tcx.type_of(field_def.did);
insert_required_predicates_to_be_wf(
self.tcx,
field_ty,
self.global_inferred_outlives,
&mut item_required_predicates,
self.explicit_map,
);
}
}
_ => {}
};
// If new predicates were added (`local_predicate_map` has more
// predicates than the `global_inferred_outlives`), the new predicates
// might result in implied predicates for their parent types.
// Therefore mark `predicates_added` as true and which will ensure
// we walk the crates again and re-calculate predicates for all
// items.
let item_predicates_len: usize = self.global_inferred_outlives
.get(&item_did)
.map(|p| p.len())
.unwrap_or(0);
if item_required_predicates.len() > item_predicates_len {
*self.predicates_added = true;
self.global_inferred_outlives
.insert(item_did, item_required_predicates);
}
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {}
}
fn insert_required_predicates_to_be_wf<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
field_ty: Ty<'tcx>,
global_inferred_outlives: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
required_predicates: &mut RequiredPredicates<'tcx>,
explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
) {
for ty in field_ty.walk() {
match ty.sty {
// The field is of type &'a T which means that we will have
// a predicate requirement of T: 'a (T outlives 'a).
//
// We also want to calculate potential predicates for the T
ty::TyRef(region, mt) => {
insert_outlives_predicate(tcx, mt.ty.into(), region, required_predicates);
}
// For each TyAdt (struct/enum/union) type `Foo<'a, T>`, we
// can load the current set of inferred and explicit
// predicates from `global_inferred_outlives` and filter the
// ones that are TypeOutlives.
//
ty::TyAdt(def, substs) => {
// First check the inferred predicates
//
// Example 1:
//
// struct Foo<'a, T> {
// field1: Bar<'a, T>
// }
//
// struct Bar<'b, U> {
// field2: &'b U
// }
//
// Here, when processing the type of `field1`, we would
// request the set of implicit predicates computed for `Bar`
// thus far. This will initially come back empty, but in next
// round we will get `U: 'b`. We then apply the substitution
// `['b => 'a, U => T]` and thus get the requirement that `T:
// 'a` holds for `Foo`.
if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did) {
for unsubstituted_predicate in unsubstituted_predicates {
// `unsubstituted_predicate` is `U: 'b` in the
// example above. So apply the substitution to
// get `T: 'a` (or `predicate`):
let predicate = unsubstituted_predicate.subst(tcx, substs);
insert_outlives_predicate(
tcx,
predicate.0,
predicate.1,
required_predicates,
);
}
}
// Check if the type has any explicit predicates that need
// to be added to `required_predicates`
// let _: () = substs.region_at(0);
check_explicit_predicates(tcx, &def.did, substs, required_predicates, explicit_map);
}
ty::TyDynamic(obj, region) => {
// FIXME This corresponds to `dyn Trait<..>`. In this
// case, we should use the explicit predicates as
// well.
if let Some(p) = obj.principal() {
check_explicit_predicates(
tcx,
&p.skip_binder().def_id,
&[region.into()],
required_predicates,
explicit_map,
);
}
}
ty::TyProjection(obj) => {
// FIXME This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the
// explicit predicates as well.
check_explicit_predicates(
tcx,
&obj.item_def_id,
obj.substs,
required_predicates,
explicit_map,
);
}
_ => {}
}
}
}
/// We also have to check the explicit predicates
/// declared on the type.
///
/// struct Foo<'a, T> {
/// field1: Bar<T>
/// }
///
/// struct Bar<U> where U: 'static, U: Foo {
/// ...
/// }
///
/// Here, we should fetch the explicit predicates, which
/// will give us `U: 'static` and `U: Foo`. The latter we
/// can ignore, but we will want to process `U: 'static`,
/// applying the substitution as above.
fn check_explicit_predicates<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
def_id: &DefId,
substs: &[Kind<'tcx>],
required_predicates: &mut RequiredPredicates<'tcx>,
explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
) {
if let Some(general_predicates) = explicit_map.get(def_id) {
for general_predicate in general_predicates.iter() {
match general_predicate {
// `poly` is `PolyTypeOutlivesPredicate<OutlivesPredicate<Ty>>`
// where OutlivesPredicate<type1, region1> is the predicate
// we want to add.
ty::Predicate::TypeOutlives(poly) => {
let predicate = poly.0.subst(tcx, substs);
insert_outlives_predicate(
tcx,
predicate.0.into(),
predicate.1,
required_predicates,
);
}
// `poly` is `PolyRegionOutlivesPredicate<OutlivesPredicate<Ty>>`
// where OutlivesPredicate<region1, region2> is the predicate
// we want to add.
ty::Predicate::RegionOutlives(poly) => {
let predicate = poly.0.subst(tcx, substs);
insert_outlives_predicate(
tcx,
predicate.0.into(),
predicate.1,
required_predicates,
);
}
ty::Predicate::Trait(..)
| ty::Predicate::Projection(..)
| ty::Predicate::WellFormed(..)
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::ConstEvaluatable(..) => (),
}
}
}
}
/// Given a requirement `T: 'a` or `'b: 'a`, deduce the
/// outlives_component and add it to `required_predicates`
fn insert_outlives_predicate<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
kind: Kind<'tcx>,
outlived_region: Region<'tcx>,
required_predicates: &mut RequiredPredicates<'tcx>,
) {
// If the `'a` region is bound within the field type itself, we
// don't want to propagate this constraint to the header.
if !is_free_region(outlived_region) {
return;
}
match kind.unpack() {
UnpackedKind::Type(ty) => {
// `T: 'outlived_region` for some type `T`
// But T could be a lot of things:
// e.g., if `T = &'b u32`, then `'b: 'outlived_region` is
// what we want to add.
//
// Or if within `struct Foo<U>` you had `T = Vec<U>`, then
// we would want to add `U: 'outlived_region`
for component in tcx.outlives_components(ty) {
match component {
Component::Region(r) => {
// This would arise from something like:
//
// ```
// struct Foo<'a, 'b> {
// x: &'a &'b u32
// }
// ```
//
// Here `outlived_region = 'a` and `kind = &'b
// u32`. Decomposing `&'b u32` into
// components would yield `'b`, and we add the
// where clause that `'b: 'a`.
insert_outlives_predicate(
tcx,
r.into(),
outlived_region,
required_predicates,
);
}
Component::Param(param_ty) => {
// param_ty: ty::ParamTy
// This would arise from something like:
//
// ```
// struct Foo<'a, U> {
// x: &'a Vec<U>
// }
// ```
//
// Here `outlived_region = 'a` and `kind =
// Vec<U>`. Decomposing `Vec<U>` into
// components would yield `U`, and we add the
// where clause that `U: 'a`.
let ty: Ty<'tcx> = tcx.mk_param(param_ty.idx, param_ty.name);
required_predicates
.insert(ty::OutlivesPredicate(ty.into(), outlived_region));
}
Component::Projection(proj_ty) => {
// This would arise from something like:
//
// ```
// struct Foo<'a, T: Iterator> {
// x: &'a <T as Iterator>::Item
// }
// ```
//
// Here we want to add an explicit `where <T as Iterator>::Item: 'a`.
let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs);
required_predicates
.insert(ty::OutlivesPredicate(ty.into(), outlived_region));
}
Component::EscapingProjection(_) => {
// As above, but the projection involves
// late-bound regions. Therefore, the WF
// requirement is not checked in type definition
// but at fn call site, so ignore it.
//
// ```
// struct Foo<'a, T: Iterator> {
// x: for<'b> fn(<&'b T as Iterator>::Item)
// // ^^^^^^^^^^^^^^^^^^^^^^^^^
// }
// ```
//
// Since `'b` is not in scope on `Foo`, can't
// do anything here, ignore it.
}
Component::UnresolvedInferenceVariable(_) => bug!("not using infcx"),
}
}
}
UnpackedKind::Lifetime(r) => {
if !is_free_region(r) {
return;
}
required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region));
}
}
}
fn is_free_region(region: Region<'_>) -> bool {
// First, screen for regions that might appear in a type header.
match region {
// *These* correspond to `T: 'a` relationships where `'a` is
// either declared on the type or `'static`:
//
// struct Foo<'a, T> {
// field: &'a T, // this would generate a ReEarlyBound referencing `'a`
// field2: &'static T, // this would generate a ReStatic
// }
//
// We care about these, so fall through.
RegionKind::ReStatic | RegionKind::ReEarlyBound(_) => true,
// Late-bound regions can appear in `fn` types:
//
// struct Foo<T> {
// field: for<'b> fn(&'b T) // e.g., 'b here
// }
//
// The type above might generate a `T: 'b` bound, but we can
// ignore it. We can't put it on the struct header anyway.
RegionKind::ReLateBound(..) => false,
// These regions don't appear in types from type declarations:
RegionKind::ReEmpty
| RegionKind::ReErased
| RegionKind::ReClosureBound(..)
| RegionKind::ReCanonical(..)
| RegionKind::ReScope(..)
| RegionKind::ReVar(..)
| RegionKind::ReSkolemized(..)
| RegionKind::ReFree(..) => {
bug!("unexpected region in outlives inference: {:?}", region);
}
}
}

View File

@ -7,23 +7,105 @@
// <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.
use rustc::hir::def_id::DefId;
use rustc::ty::{self, TyCtxt};
#![allow(unused)]
#[allow(dead_code)]
use hir::map as hir_map;
use rustc::dep_graph::DepKind;
use rustc::hir;
use rustc::hir::Ty_::*;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::ty::maps::Providers;
use rustc::ty::subst::UnpackedKind;
use rustc::ty::{self, CratePredicatesMap, TyCtxt};
use rustc_data_structures::sync::Lrc;
use util::nodemap::FxHashMap;
mod explicit;
mod implicit_empty;
mod implicit_infer;
/// Code to write unit test for outlives.
pub mod test;
pub fn provide(providers: &mut Providers) {
*providers = Providers {
inferred_outlives_of,
inferred_outlives_crate,
..*providers
};
}
//todo
fn inferred_outlives_of<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, _def_id: DefId)
-> Vec<ty::Predicate<'tcx>> {
Vec::new()
fn inferred_outlives_of<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
item_def_id: DefId,
) -> Lrc<Vec<ty::Predicate<'tcx>>> {
let id = tcx.hir
.as_local_node_id(item_def_id)
.expect("expected local def-id");
match tcx.hir.get(id) {
hir_map::NodeItem(item) => match item.node {
hir::ItemStruct(..) | hir::ItemEnum(..) | hir::ItemUnion(..) => {
let crate_map = tcx.inferred_outlives_crate(LOCAL_CRATE);
let dep_node = item_def_id.to_dep_node(tcx, DepKind::InferredOutlivesOf);
tcx.dep_graph.read(dep_node);
crate_map
.predicates
.get(&item_def_id)
.unwrap_or(&crate_map.empty_predicate)
.clone()
}
_ => Lrc::new(Vec::new()),
},
_ => Lrc::new(Vec::new()),
}
}
fn inferred_outlives_crate<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
crate_num: CrateNum,
) -> Lrc<CratePredicatesMap<'tcx>> {
// Compute a map from each struct/enum/union S to the **explicit**
// outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
// Typically there won't be many of these, except in older code where
// they were mandatory. Nonetheless, we have to ensure that every such
// predicate is satisfied, so they form a kind of base set of requirements
// for the type.
// Compute the inferred predicates
let exp = explicit::explicit_predicates(tcx, crate_num);
let mut global_inferred_outlives = implicit_infer::infer_predicates(tcx, &exp);
// Convert the inferred predicates into the "collected" form the
// global data structure expects.
//
// FIXME -- consider correcting impedance mismatch in some way,
// probably by updating the global data structure.
let mut predicates = global_inferred_outlives
.iter()
.map(|(&def_id, set)| {
let vec: Vec<ty::Predicate<'tcx>> = set.iter()
.map(
|ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() {
UnpackedKind::Type(ty1) => ty::Predicate::TypeOutlives(ty::Binder(
ty::OutlivesPredicate(ty1, region2),
)),
UnpackedKind::Lifetime(region1) => ty::Predicate::RegionOutlives(
ty::Binder(ty::OutlivesPredicate(region1, region2)),
),
},
)
.collect();
(def_id, Lrc::new(vec))
})
.collect();
let empty_predicate = Lrc::new(Vec::new());
Lrc::new(ty::CratePredicatesMap {
predicates,
empty_predicate,
})
}

View File

@ -13,11 +13,13 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::ty::TyCtxt;
pub fn test_inferred_outlives<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
tcx.hir.krate().visit_all_item_likes(&mut OutlivesTest { tcx });
tcx.hir
.krate()
.visit_all_item_likes(&mut OutlivesTest { tcx });
}
struct OutlivesTest<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>
tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for OutlivesTest<'a, 'tcx> {
@ -28,11 +30,13 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for OutlivesTest<'a, 'tcx> {
// attribute and report an error with various results if found.
if self.tcx.has_attr(item_def_id, "rustc_outlives") {
let inferred_outlives_of = self.tcx.inferred_outlives_of(item_def_id);
span_err!(self.tcx.sess,
span_err!(
self.tcx.sess,
item.span,
E0640,
"{:?}",
inferred_outlives_of);
inferred_outlives_of
);
}
}

View File

@ -426,6 +426,9 @@ declare_features! (
// Use `?` as the Kleene "at most one" operator
(active, macro_at_most_once_rep, "1.25.0", Some(48075), None),
// Infer outlives requirements; RFC 2093
(active, infer_outlives_requirements, "1.26.0", Some(44493), None),
// Multiple patterns with `|` in `if let` and `while let`
(active, if_while_or_patterns, "1.26.0", Some(48215), None),
@ -1023,6 +1026,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
"never will be stable",
cfg_fn!(rustc_attrs))),
// RFC #2093
("infer_outlives_requirements", Normal, Gated(Stability::Unstable,
"infer_outlives_requirements",
"infer outlives requirements is an experimental feature",
cfg_fn!(infer_outlives_requirements))),
("wasm_custom_section", Whitelisted, Gated(Stability::Unstable,
"wasm_custom_section",
"attribute is currently unstable",

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-tidy-linelength
// Test that the outlives computation runs for now...
#![feature(rustc_attrs)]
@ -16,7 +18,7 @@
// https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md#example-1-a-reference
#[rustc_outlives]
struct Direct<'a, T> { //~ ERROR 19:1: 21:2: [] [E0640]
struct Direct<'a, T> { //~ ERROR 21:1: 23:2: [Binder(OutlivesPredicate(T, ReEarlyBound(0, 'a)))] [E0640]
field: &'a T
}

View File

@ -0,0 +1,18 @@
// Copyright 2015 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.
// Needs an explicit where clause stating outlives condition. (RFC 2093)
// Type T needs to outlive lifetime 'a.
struct Foo<'a, T> {
bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
}
fn main() { }

View File

@ -0,0 +1,17 @@
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/feature-gate-infer_outlives_requirements.rs:15:5
|
LL | struct Foo<'a, T> {
| - help: consider adding an explicit lifetime bound `T: 'a`...
LL | bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
| ^^^^^^^^^^^^
|
note: ...so that the reference type `&'a [T]` does not outlive the data it points at
--> $DIR/feature-gate-infer_outlives_requirements.rs:15:5
|
LL | bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
| ^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.

View File

@ -0,0 +1,38 @@
// Copyright 2018 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.
// must-compile-successfully
#![feature(infer_outlives_requirements)]
// Type T needs to outlive lifetime 'a.
enum Foo<'a, T> {
One(Bar<'a, T>)
}
// Type U needs to outlive lifetime 'b
struct Bar<'b, U> {
field2: &'b U
}
// Type K needs to outlive lifetime 'c.
enum Ying<'c, K> {
One(&'c Yang<K>)
}
struct Yang<V> {
field2: V
}
fn main() {}

View File

@ -0,0 +1,37 @@
// Copyright 2018 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.
// ignore-tidy-linelength
// Needs an explicit where clause stating outlives condition. (RFC 2093)
// Type T needs to outlive lifetime 'a.
enum Foo<'a, T> {
One(Bar<'a, T>)
}
// Type U needs to outlive lifetime 'b
struct Bar<'b, U> {
field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
}
// Type K needs to outlive lifetime 'c.
enum Ying<'c, K> {
One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
}
struct Yang<V> {
field2: V
}
fn main() {}

View File

@ -0,0 +1,31 @@
error[E0309]: the parameter type `U` may not live long enough
--> $DIR/enum.rs:23:5
|
LL | struct Bar<'b, U> {
| - help: consider adding an explicit lifetime bound `U: 'b`...
LL | field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
|
note: ...so that the reference type `&'b U` does not outlive the data it points at
--> $DIR/enum.rs:23:5
|
LL | field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
error[E0309]: the parameter type `K` may not live long enough
--> $DIR/enum.rs:30:9
|
LL | enum Ying<'c, K> {
| - help: consider adding an explicit lifetime bound `K: 'c`...
LL | One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
| ^^^^^^^^^^^^
|
note: ...so that the reference type `&'c Yang<K>` does not outlive the data it points at
--> $DIR/enum.rs:30:9
|
LL | One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
| ^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0309`.

View File

@ -0,0 +1,30 @@
// Copyright 2015 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.
// ignore-test
// must-compile-successfully
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
trait MakeRef<'a>: 'a {
type Type;
}
impl<'a, T> MakeRef<'a> for Vec<T>
where T: 'a,
{
type Type = &'a T;
}
// explicit-impl: T: 'a
struct Foo<'a, T> {
foo: <Vec<T> as MakeRef<'a>>::Type,
}
fn main() {}

View File

@ -0,0 +1,30 @@
// Copyright 2015 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.
// ignore-test
// must-compile-successfully
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
trait MakeRef<'a> {
type Type;
}
impl<'a, T> MakeRef<'a> for Vec<T>
where T: 'a,
{
type Type = &'a T;
}
// explicit-impl: T: 'a
struct Foo<'a, T> {
foo: <Vec<T> as MakeRef<'a>>::Type,
}
fn main() {}

View File

@ -0,0 +1,30 @@
// Copyright 2015 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.
// ignore-tidy-linelength
// Needs an explicit where clause stating outlives condition. (RFC 2093)
trait MakeRef<'a> {
type Type;
}
impl<'a, T> MakeRef<'a> for Vec<T>
where T: 'a
{
type Type = &'a T;
}
// Type T needs to outlive lifetime 'a, as stated in impl.
struct Foo<'a, T> {
foo: <Vec<T> as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309]
}
fn main() { }

View File

@ -0,0 +1,17 @@
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/explicit-impl.rs:27:5
|
LL | struct Foo<'a, T> {
| - help: consider adding an explicit lifetime bound `T: 'a`...
LL | foo: <Vec<T> as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: ...so that the type `T` will meet its required lifetime bounds
--> $DIR/explicit-impl.rs:27:5
|
LL | foo: <Vec<T> as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.

View File

@ -0,0 +1,27 @@
// Copyright 2015 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.
// must-compile-successfully
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
// explicit-where: infer U: 'b
struct ExFoo<'b, U> {
bar: ExBar<'b, U>
}
struct ExBar<'a, T> where T: 'a {
x: &'a (),
y: T,
}
fn main() {}

View File

@ -0,0 +1,23 @@
// Copyright 2015 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.
// Needs an explicit where clause stating outlives condition. (RFC 2093)
// Type U needs to outlive lifetime 'b.
struct Foo<'b, U> {
bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309]
}
struct Bar<'a, T> where T: 'a {
x: &'a (),
y: T,
}
fn main() { }

View File

@ -0,0 +1,17 @@
error[E0309]: the parameter type `U` may not live long enough
--> $DIR/explicit-where.rs:15:5
|
LL | struct Foo<'b, U> {
| - help: consider adding an explicit lifetime bound `U: 'b`...
LL | bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^
|
note: ...so that the type `U` will meet its required lifetime bounds
--> $DIR/explicit-where.rs:15:5
|
LL | bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.

View File

@ -0,0 +1,22 @@
// Copyright 2015 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.
// must-compile-successfully
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
// multiple-regions: infer 'b: 'a
struct MultiFoo<'a, 'b, T> {
x: &'a &'b T
}
fn main() {}

View File

@ -0,0 +1,19 @@
// Copyright 2018 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.
// Needs an explicit where clause stating outlives condition. (RFC 2093)
// Lifetime 'b needs to outlive lifetime 'a
struct Foo<'a,'b,T> {
x: &'a &'b T //~ ERROR reference has a longer lifetime than the data it references [E0491]
}
fn main() {}

View File

@ -0,0 +1,20 @@
error[E0491]: in type `&'a &'b T`, reference has a longer lifetime than the data it references
--> $DIR/multiple-regions.rs:15:5
|
LL | x: &'a &'b T //~ ERROR reference has a longer lifetime than the data it references [E0491]
| ^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime 'a as defined on the struct at 14:1
--> $DIR/multiple-regions.rs:14:1
|
LL | struct Foo<'a,'b,T> {
| ^^^^^^^^^^^^^^^^^^^
note: but the referenced data is only valid for the lifetime 'b as defined on the struct at 14:1
--> $DIR/multiple-regions.rs:14:1
|
LL | struct Foo<'a,'b,T> {
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0491`.

View File

@ -0,0 +1,25 @@
// Copyright 2015 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.
// must-compile-successfully
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
// nested-structs: infer U: 'b and therefore T: 'a
struct NestFoo<'a, T> {
field1: NestBar<'a, T>
}
struct NestBar<'b, U> {
field2: &'b U
}
fn main() {}

View File

@ -0,0 +1,26 @@
// Copyright 2018 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.
// Needs an explicit where clause stating outlives condition. (RFC 2093)
// Type T needs to outlive lifetime 'a. This is not reported due to
// a compilation error in Bar.
struct Foo<'a, T> {
field1: Bar<'a, T>
}
// Type U needs to outlive lifetime 'b
struct Bar<'b, U> {
field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
}
fn main() {}

View File

@ -0,0 +1,17 @@
error[E0309]: the parameter type `U` may not live long enough
--> $DIR/nested-structs.rs:22:5
|
LL | struct Bar<'b, U> {
| - help: consider adding an explicit lifetime bound `U: 'b`...
LL | field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
|
note: ...so that the reference type `&'b U` does not outlive the data it points at
--> $DIR/nested-structs.rs:22:5
|
LL | field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.

View File

@ -0,0 +1,23 @@
// Copyright 2015 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.
// must-compile-successfully
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
// projections: infer <Iterator>::Item: 'a
struct ProjFoo<'a, T: Iterator> {
bar: &'a T::Item
}
fn main() {}

View File

@ -0,0 +1,20 @@
// Copyright 2015 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.
// ignore-tidy-linelength
// Needs an explicit where clause stating outlives condition. RFC 2093
// Associated type <Iterator>::Item needs to outlives lifetime 'a.
struct Foo<'a, T: Iterator> {
bar: &'a T::Item //~ Error the associated type `<T as std::iter::Iterator>::Item` may not live long enough [E0309]
}
fn main() { }

View File

@ -0,0 +1,16 @@
error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
--> $DIR/projections.rs:17:5
|
LL | bar: &'a T::Item //~ Error the associated type `<T as std::iter::Iterator>::Item` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: 'a`...
note: ...so that the reference type `&'a <T as std::iter::Iterator>::Item` does not outlive the data it points at
--> $DIR/projections.rs:17:5
|
LL | bar: &'a T::Item //~ Error the associated type `<T as std::iter::Iterator>::Item` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.

View File

@ -0,0 +1,23 @@
// Copyright 2015 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.
// must-compile-successfully
#![feature(infer_outlives_requirements)]
// Outlives requirementes are inferred (RFC 2093)
// reference: infer T: 'a
struct RefFoo<'a, T> {
bar: &'a [T]
}
fn main() {}

View File

@ -0,0 +1,18 @@
// Copyright 2015 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.
// Needs an explicit where clause stating outlives condition. (RFC 2093)
// Type T needs to outlive lifetime 'a.
struct Foo<'a, T> {
bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
}
fn main() { }

View File

@ -0,0 +1,17 @@
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/reference.rs:15:5
|
LL | struct Foo<'a, T> {
| - help: consider adding an explicit lifetime bound `T: 'a`...
LL | bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
| ^^^^^^^^^^^^
|
note: ...so that the reference type `&'a [T]` does not outlive the data it points at
--> $DIR/reference.rs:15:5
|
LL | bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
| ^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.

View File

@ -0,0 +1,39 @@
// Copyright 2018 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.
// must-compile-successfully
#![feature(infer_outlives_requirements)]
#![feature(untagged_unions)]
#![allow(unions_with_drop_fields)]
// Type T needs to outlive lifetime 'a. This is not reported due to
// a compilation error in Bar.
union Foo<'a, T> {
field1: Bar<'a, T>
}
// Type U needs to outlive lifetime 'b
union Bar<'b, U> {
field2: &'b U
}
// Type K needs to outlive lifetime 'c.
union Ying<'c, K> {
field1: &'c Yang<K>
}
union Yang<V> {
field2: V
}
fn main() {}

View File

@ -0,0 +1,40 @@
// Copyright 2018 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.
// ignore-tidy-linelength
// Needs an explicit where clause stating outlives condition. (RFC 2093)
#![feature(untagged_unions)]
// Type T needs to outlive lifetime 'a. This is not reported due to
// a compilation error in Bar.
union Foo<'a, T> {
field1: Bar<'a, T>
}
// Type U needs to outlive lifetime 'b
union Bar<'b, U> {
field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309]
}
// Type K needs to outlive lifetime 'c.
union Ying<'c, K> {
field1: &'c Yang<K> //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309]
}
union Yang<V> {
field2: V
}
fn main() {}

View File

@ -0,0 +1,31 @@
error[E0309]: the parameter type `U` may not live long enough
--> $DIR/union.rs:25:5
|
LL | union Bar<'b, U> {
| - help: consider adding an explicit lifetime bound `U: 'b`...
LL | field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
|
note: ...so that the reference type `&'b U` does not outlive the data it points at
--> $DIR/union.rs:25:5
|
LL | field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
error[E0309]: the parameter type `K` may not live long enough
--> $DIR/union.rs:31:5
|
LL | union Ying<'c, K> {
| - help: consider adding an explicit lifetime bound `K: 'c`...
LL | field1: &'c Yang<K> //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^^^^
|
note: ...so that the reference type `&'c Yang<K>` does not outlive the data it points at
--> $DIR/union.rs:31:5
|
LL | field1: &'c Yang<K> //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309]
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0309`.