Fix impl Trait Lifetime Handling

After this change, impl Trait existentials are
desugared to a new `abstract type` definition
paired with a set of lifetimes to apply.

In-scope generics are included as parents of the
`abstract type` generics. Parent regions are
replaced with static, and parent regions
referenced in the `impl Trait` type are duplicated
at the end of the `abstract type`'s generics.
This commit is contained in:
Taylor Cramer 2017-10-15 13:43:06 -07:00
parent d0f8e2913a
commit bc4810d907
24 changed files with 884 additions and 133 deletions

View File

@ -2019,4 +2019,5 @@ register_diagnostics! {
E0628, // generators cannot have explicit arguments
E0631, // type mismatch in closure arguments
E0637, // "'_" is not a valid lifetime bound
E0657, // `impl Trait` can only capture lifetimes bound at the fn level
}

View File

@ -591,8 +591,11 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
}
visitor.visit_lifetime(lifetime);
}
TyImplTraitExistential(ref bounds) => {
TyImplTraitExistential(ref existty, ref lifetimes) => {
let ExistTy { ref generics, ref bounds } = *existty;
walk_generics(visitor, generics);
walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_lifetime, lifetimes);
}
TyImplTraitUniversal(_, ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);

View File

@ -42,8 +42,9 @@
use dep_graph::DepGraph;
use hir;
use hir::map::{Definitions, DefKey};
use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX};
use hir::HirVec;
use hir::map::{Definitions, DefKey, DefPathData};
use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX, DefIndexAddressSpace};
use hir::def::{Def, PathResolution};
use lint::builtin::PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES;
use middle::cstore::CrateStore;
@ -52,7 +53,7 @@ use session::Session;
use util::common::FN_OUTPUT_NAME;
use util::nodemap::{DefIdMap, FxHashMap, NodeMap};
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashSet};
use std::fmt::Debug;
use std::iter;
use std::mem;
@ -777,7 +778,24 @@ impl<'a> LoweringContext<'a> {
t.span, GateIssue::Language,
"`impl Trait` in return position is experimental");
}
hir::TyImplTraitExistential(self.lower_bounds(bounds, itctx))
let def_index = self.resolver.definitions().opt_def_index(t.id).unwrap();
let hir_bounds = self.lower_bounds(bounds, itctx);
let (lifetimes, lifetime_defs) =
self.lifetimes_from_impl_trait_bounds(def_index, &hir_bounds);
hir::TyImplTraitExistential(hir::ExistTy {
generics: hir::Generics {
lifetimes: lifetime_defs,
// Type parameters are taken from environment:
ty_params: Vec::new().into(),
where_clause: hir::WhereClause {
id: self.next_id().node_id,
predicates: Vec::new().into(),
},
span: t.span,
},
bounds: hir_bounds,
}, lifetimes)
},
ImplTraitContext::Universal(def_id) => {
let has_feature = self.sess.features.borrow().universal_impl_trait;
@ -808,6 +826,111 @@ impl<'a> LoweringContext<'a> {
})
}
fn lifetimes_from_impl_trait_bounds(
&mut self,
parent_index: DefIndex,
bounds: &hir::TyParamBounds
) -> (HirVec<hir::Lifetime>, HirVec<hir::LifetimeDef>) {
// This visitor walks over impl trait bounds and creates defs for all lifetimes which
// appear in the bounds, excluding lifetimes that are created within the bounds.
// e.g. 'a, 'b, but not 'c in `impl for<'c> SomeTrait<'a, 'b, 'c>`
struct ImplTraitLifetimeCollector<'r, 'a: 'r> {
context: &'r mut LoweringContext<'a>,
parent: DefIndex,
currently_bound_lifetimes: Vec<Name>,
already_defined_lifetimes: HashSet<Name>,
output_lifetimes: Vec<hir::Lifetime>,
output_lifetime_defs: Vec<hir::LifetimeDef>,
}
impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a> {
fn nested_visit_map<'this>(&'this mut self)
-> hir::intravisit::NestedVisitorMap<'this, 'v> {
hir::intravisit::NestedVisitorMap::None
}
fn visit_poly_trait_ref(&mut self,
polytr: &'v hir::PolyTraitRef,
_: hir::TraitBoundModifier) {
let old_len = self.currently_bound_lifetimes.len();
// Record the introduction of 'a in `for<'a> ...`
for lt_def in &polytr.bound_lifetimes {
// Introduce lifetimes one at a time so that we can handle
// cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd> ...`
if let hir::LifetimeName::Name(name) = lt_def.lifetime.name {
self.currently_bound_lifetimes.push(name);
}
// Visit the lifetime bounds
for lt_bound in &lt_def.bounds {
self.visit_lifetime(&lt_bound);
}
}
hir::intravisit::walk_trait_ref(self, &polytr.trait_ref);
self.currently_bound_lifetimes.truncate(old_len);
}
fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
// Exclude '_, 'static, and elided lifetimes (there should be no elided lifetimes)
if let hir::LifetimeName::Name(lifetime_name) = lifetime.name {
if !self.currently_bound_lifetimes.contains(&lifetime_name) &&
!self.already_defined_lifetimes.contains(&lifetime_name)
{
self.already_defined_lifetimes.insert(lifetime_name);
let name = hir::LifetimeName::Name(lifetime_name);
self.output_lifetimes.push(hir::Lifetime {
id: self.context.next_id().node_id,
span: lifetime.span,
name,
});
let def_node_id = self.context.next_id().node_id;
self.context.resolver.definitions().create_def_with_parent(
self.parent,
def_node_id,
DefPathData::LifetimeDef(lifetime_name.as_str()),
DefIndexAddressSpace::High,
Mark::root()
);
let def_lifetime = hir::Lifetime {
id: def_node_id,
span: lifetime.span,
name,
};
self.output_lifetime_defs.push(hir::LifetimeDef {
lifetime: def_lifetime,
bounds: Vec::new().into(),
pure_wrt_drop: false,
});
}
}
}
}
let mut lifetime_collector = ImplTraitLifetimeCollector {
context: self,
parent: parent_index,
currently_bound_lifetimes: Vec::new(),
already_defined_lifetimes: HashSet::new(),
output_lifetimes: Vec::new(),
output_lifetime_defs: Vec::new(),
};
for bound in bounds {
hir::intravisit::walk_ty_param_bound(&mut lifetime_collector, &bound);
}
(
lifetime_collector.output_lifetimes.into(),
lifetime_collector.output_lifetime_defs.into()
)
}
fn lower_foreign_mod(&mut self, fm: &ForeignMod) -> hir::ForeignMod {
hir::ForeignMod {
abi: fm.abi,

View File

@ -1436,6 +1436,12 @@ pub struct BareFnTy {
pub arg_names: HirVec<Spanned<Name>>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct ExistTy {
pub generics: Generics,
pub bounds: TyParamBounds,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
/// The different kinds of types recognized by the compiler
pub enum Ty_ {
@ -1463,7 +1469,16 @@ pub enum Ty_ {
TyTraitObject(HirVec<PolyTraitRef>, Lifetime),
/// An exsitentially quantified (there exists a type satisfying) `impl
/// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime.
TyImplTraitExistential(TyParamBounds),
///
/// The `ExistTy` structure emulates an
/// `abstract type Foo<'a, 'b>: MyTrait<'a, 'b>;`.
///
/// The `HirVec<Lifetime>` is the list of lifetimes applied as parameters
/// to the `abstract type`, e.g. the `'c` and `'d` in `-> Foo<'c, 'd>`.
/// This list is only a list of lifetimes and not type parameters
/// because all in-scope type parameters are captured by `impl Trait`,
/// so they are resolved directly through the parent `Generics`.
TyImplTraitExistential(ExistTy, HirVec<Lifetime>),
/// An universally quantified (for all types satisfying) `impl
/// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime.
TyImplTraitUniversal(DefId, TyParamBounds),

View File

@ -421,8 +421,10 @@ impl<'a> State<'a> {
self.print_lifetime(lifetime)?;
}
}
hir::TyImplTraitExistential(ref bounds) |
hir::TyImplTraitUniversal(_, ref bounds) => {
hir::TyImplTraitExistential(ref existty, ref _lifetimes) => {
self.print_bounds("impl", &existty.bounds[..])?;
}
hir::TyImplTraitUniversal(_, ref bounds) => {
self.print_bounds("impl", &bounds[..])?;
}
hir::TyArray(ref ty, v) => {

View File

@ -277,6 +277,11 @@ impl_stable_hash_for!(struct hir::BareFnTy {
arg_names
});
impl_stable_hash_for!(struct hir::ExistTy {
generics,
bounds
});
impl_stable_hash_for!(enum hir::Ty_ {
TySlice(t),
TyArray(t, body_id),
@ -287,7 +292,7 @@ impl_stable_hash_for!(enum hir::Ty_ {
TyTup(ts),
TyPath(qpath),
TyTraitObject(trait_refs, lifetime),
TyImplTraitExistential(bounds),
TyImplTraitExistential(existty, lifetimes),
TyImplTraitUniversal(def_id, bounds),
TyTypeof(body_id),
TyErr,

View File

@ -84,7 +84,7 @@ impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> {
(&ty::ReFree(_), &ty::ReEarlyBound(_)) |
(&ty::ReEarlyBound(_), &ty::ReFree(_)) |
(&ty::ReFree(_), &ty::ReFree(_)) =>
self.free_regions.relation.contains(&sub_region, &super_region),
self.free_regions.sub_free_regions(&sub_region, &super_region),
_ =>
false,
@ -158,19 +158,39 @@ impl<'tcx> FreeRegionMap<'tcx> {
}
}
// Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
// (with the exception that `'static: 'x` is not notable)
/// Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
/// (with the exception that `'static: 'x` is not notable)
pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
if (is_free(sub) || *sub == ty::ReStatic) && is_free(sup) {
self.relation.add(sub, sup)
}
}
/// True if `r_a <= r_b` is known to hold. Both `r_a` and `r_b`
/// must be free regions from the function header.
pub fn sub_free_regions<'a, 'gcx>(&self,
r_a: Region<'tcx>,
r_b: Region<'tcx>)
-> bool {
debug!("sub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
assert!(is_free(r_a));
assert!(is_free(r_b));
let result = r_a == r_b || self.relation.contains(&r_a, &r_b);
debug!("sub_free_regions: result={}", result);
result
}
/// Compute the least-upper-bound of two free regions. In some
/// cases, this is more conservative than necessary, in order to
/// avoid making arbitrary choices. See
/// `TransitiveRelation::postdom_upper_bound` for more details.
pub fn lub_free_regions<'a, 'gcx>(&self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
r_a: Region<'tcx>,
r_b: Region<'tcx>)
-> Region<'tcx> {
debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
assert!(is_free(r_a));
assert!(is_free(r_b));
let result = if r_a == r_b { r_a } else {

View File

@ -52,6 +52,7 @@ impl Region {
let i = *index;
*index += 1;
let def_id = hir_map.local_def_id(def.lifetime.id);
debug!("Region::early: index={} def_id={:?}", i, def_id);
(def.lifetime.name, Region::EarlyBound(i, def_id))
}
@ -201,6 +202,11 @@ enum Scope<'a> {
/// declaration `Binder` and the location it's referenced from.
Binder {
lifetimes: FxHashMap<hir::LifetimeName, Region>,
/// if we extend this scope with another scope, what is the next index
/// we should use for an early-bound region?
next_early_index: u32,
s: ScopeRef<'a>
},
@ -343,8 +349,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let lifetimes = generics.lifetimes.iter().map(|def| {
Region::early(self.hir_map, &mut index, def)
}).collect();
let next_early_index = index + generics.ty_params.len() as u32;
let scope = Scope::Binder {
lifetimes,
next_early_index,
s: ROOT_SCOPE
};
self.with(scope, |old_scope, this| {
@ -372,12 +380,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
debug!("visit_ty: ty={:?}", ty);
match ty.node {
hir::TyBareFn(ref c) => {
let next_early_index = self.next_early_index();
let scope = Scope::Binder {
lifetimes: c.lifetimes.iter().map(|def| {
Region::late(self.hir_map, def)
}).collect(),
Region::late(self.hir_map, def)
}).collect(),
next_early_index,
s: self.scope
};
self.with(scope, |old_scope, this| {
@ -405,6 +416,60 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
};
self.with(scope, |_, this| this.visit_ty(&mt.ty));
}
hir::TyImplTraitExistential(ref exist_ty, ref lifetimes) => {
// Resolve the lifetimes that are applied to the existential type.
// These are resolved in the current scope.
// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
// `fn foo<'a>() -> MyAnonTy<'a> { ... }`
// ^ ^this gets resolved in the current scope
for lifetime in lifetimes {
self.visit_lifetime(lifetime);
// Check for predicates like `impl for<'a> SomeTrait<impl OtherTrait<'a>>`
// and ban them. Type variables instantiated inside binders aren't
// well-supported at the moment, so this doesn't work.
// In the future, this should be fixed and this error should be removed.
let def = self.map.defs.get(&lifetime.id);
if let Some(&Region::LateBound(_, def_id)) = def {
if let Some(node_id) = self.hir_map.as_local_node_id(def_id) {
// Ensure that the parent of the def is an item, not HRTB
let parent_id = self.hir_map.get_parent_node(node_id);
let parent_impl_id = hir::ImplItemId { node_id: parent_id };
let parent_trait_id = hir::TraitItemId { node_id: parent_id };
let krate = self.hir_map.forest.krate();
if !(krate.items.contains_key(&parent_id) ||
krate.impl_items.contains_key(&parent_impl_id) ||
krate.trait_items.contains_key(&parent_trait_id))
{
span_err!(self.sess, lifetime.span, E0657,
"`impl Trait` can only capture lifetimes \
bound at the fn or impl level");
}
}
}
}
// Resolve the lifetimes in the bounds to the lifetime defs in the generics.
// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
// `abstract type MyAnonTy<'b>: MyTrait<'b>;`
// ^ ^ this gets resolved in the scope of
// the exist_ty generics
let hir::ExistTy { ref generics, ref bounds } = *exist_ty;
let mut index = self.next_early_index();
debug!("visit_ty: index = {}", index);
let lifetimes = generics.lifetimes.iter()
.map(|lt_def| Region::early(self.hir_map, &mut index, lt_def))
.collect();
let next_early_index = index + generics.ty_params.len() as u32;
let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope };
self.with(scope, |_old_scope, this| {
this.visit_generics(generics);
for bound in bounds {
this.visit_ty_param_bound(bound);
}
});
}
_ => {
intravisit::walk_ty(self, ty)
}
@ -477,10 +542,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
.. }) => {
if !bound_lifetimes.is_empty() {
self.trait_ref_hack = true;
let next_early_index = self.next_early_index();
let scope = Scope::Binder {
lifetimes: bound_lifetimes.iter().map(|def| {
Region::late(self.hir_map, def)
}).collect(),
}).collect(),
next_early_index,
s: self.scope
};
let result = self.with(scope, |old_scope, this| {
@ -524,10 +591,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
span_err!(self.sess, trait_ref.span, E0316,
"nested quantification of lifetimes");
}
let next_early_index = self.next_early_index();
let scope = Scope::Binder {
lifetimes: trait_ref.bound_lifetimes.iter().map(|def| {
Region::late(self.hir_map, def)
}).collect(),
}).collect(),
next_early_index,
s: self.scope
};
self.with(scope, |old_scope, this| {
@ -659,7 +728,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) {
Scope::Root => { return; }
Scope::Binder { ref lifetimes, s } => {
Scope::Binder { ref lifetimes, s, next_early_index: _ } => {
// FIXME (#24278): non-hygienic comparison
if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) {
let node_id = hir_map.as_local_node_id(def.id().unwrap())
@ -860,8 +929,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
}).collect();
let next_early_index = index + generics.ty_params.len() as u32;
let scope = Scope::Binder {
lifetimes,
next_early_index,
s: self.scope
};
self.with(scope, move |old_scope, this| {
@ -870,7 +942,29 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
});
}
/// Returns the next index one would use for an early-bound-region
/// if extending the current scope.
fn next_early_index(&self) -> u32 {
let mut scope = self.scope;
loop {
match *scope {
Scope::Root =>
return 0,
Scope::Binder { next_early_index, .. } =>
return next_early_index,
Scope::Body { s, .. } |
Scope::Elision { s, .. } |
Scope::ObjectLifetimeDefault { s, .. } =>
scope = s,
}
}
}
fn resolve_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) {
debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref);
// Walk up the scope chain, tracking the number of fn scopes
// that we pass through, until we find a lifetime with the
// given name or we run out of scopes.
@ -889,7 +983,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
break None;
}
Scope::Binder { ref lifetimes, s } => {
Scope::Binder { ref lifetimes, s, next_early_index: _ } => {
if let Some(&def) = lifetimes.get(&lifetime_ref.name) {
break Some(def.shifted(late_depth));
} else {
@ -1520,7 +1614,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
return;
}
Scope::Binder { ref lifetimes, s } => {
Scope::Binder { ref lifetimes, s, next_early_index: _ } => {
if let Some(&def) = lifetimes.get(&lifetime.name) {
let node_id = self.hir_map
.as_local_node_id(def.id().unwrap())
@ -1549,7 +1643,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
probably a bug in syntax::fold");
}
debug!("{} resolved to {:?} span={:?}",
debug!("insert_lifetime: {} resolved to {:?} span={:?}",
self.hir_map.node_to_string(lifetime_ref.id),
def,
self.sess.codemap().span_to_string(lifetime_ref.span));
@ -1709,7 +1803,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
}
fn visit_ty(&mut self, ty: &hir::Ty) {
if let hir::TyImplTraitExistential(_) = ty.node {
if let hir::TyImplTraitExistential(..) = ty.node {
self.impl_trait = true;
}
intravisit::walk_ty(self, ty);

View File

@ -220,11 +220,11 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
tcx.intern_substs(&result)
}
fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
defs: &ty::Generics,
mk_region: &mut FR,
mk_type: &mut FT)
pub fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
defs: &ty::Generics,
mk_region: &mut FR,
mk_type: &mut FT)
where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {

View File

@ -1015,6 +1015,10 @@ define_print! {
TyForeign(def_id) => parameterized(f, subst::Substs::empty(), def_id, &[]),
TyProjection(ref data) => data.print(f, cx),
TyAnon(def_id, substs) => {
if cx.is_verbose {
return write!(f, "TyAnon({:?}, {:?})", def_id, substs);
}
ty::tls::with(|tcx| {
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
// by looking up the projections associated with the def_id.

View File

@ -1487,7 +1487,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
match ty.node {
hir::TyImplTraitExistential(_) => {
hir::TyImplTraitExistential(..) => {
let def_id = self.tcx.hir.local_def_id(ty.id);
self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id);
}

View File

@ -21,7 +21,7 @@ use middle::resolve_lifetime as rl;
use namespace::Namespace;
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
use rustc::ty::{self, RegionKind, Ty, TyCtxt, ToPredicate, TypeFoldable};
use rustc::ty::wf::object_region_bounds;
use rustc_back::slice;
use require_c_abi_if_variadic;
@ -1034,9 +1034,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
hir::TyTraitObject(ref bounds, ref lifetime) => {
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
}
hir::TyImplTraitExistential(_) => {
hir::TyImplTraitExistential(_, ref lifetimes) => {
let def_id = tcx.hir.local_def_id(ast_ty.id);
tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id))
self.impl_trait_ty_to_ty(def_id, lifetimes)
}
hir::TyImplTraitUniversal(fn_def_id, _) => {
let impl_trait_def_id = tcx.hir.local_def_id(ast_ty.id);
@ -1097,6 +1097,43 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
result_ty
}
pub fn impl_trait_ty_to_ty(&self, def_id: DefId, lifetimes: &[hir::Lifetime]) -> Ty<'tcx> {
debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes);
let tcx = self.tcx();
let generics = tcx.generics_of(def_id);
// Fill in the substs of the parent generics
debug!("impl_trait_ty_to_ty: generics={:?}", generics);
let mut substs = Vec::with_capacity(generics.count());
if let Some(parent_id) = generics.parent {
let parent_generics = tcx.generics_of(parent_id);
Substs::fill_item(
&mut substs, tcx, parent_generics,
&mut |def, _| tcx.mk_region(
ty::ReEarlyBound(def.to_early_bound_region_data())),
&mut |def, _| tcx.mk_param_from_def(def)
);
// Replace all lifetimes with 'static
for subst in &mut substs {
if let Some(_) = subst.as_region() {
*subst = Kind::from(&RegionKind::ReStatic);
}
}
debug!("impl_trait_ty_to_ty: substs from parent = {:?}", substs);
}
assert_eq!(substs.len(), generics.parent_count());
// Fill in our own generics with the resolved lifetimes
assert_eq!(lifetimes.len(), generics.own_count());
substs.extend(lifetimes.iter().map(|lt|
Kind::from(self.ast_region_to_region(lt, None))));
debug!("impl_trait_ty_to_ty: final substs = {:?}", substs);
tcx.mk_anon(def_id, tcx.intern_substs(&substs))
}
pub fn ty_of_arg(&self,
ty: &hir::Ty,
expected_ty: Option<Ty<'tcx>>)

View File

@ -213,7 +213,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// associated fresh inference variable. Writeback resolves these
// variables to get the concrete type, which can be used to
// deanonymize TyAnon, after typeck is done with all functions.
anon_types: RefCell<NodeMap<Ty<'tcx>>>,
anon_types: RefCell<DefIdMap<AnonTypeDecl<'tcx>>>,
/// Each type parameter has an implicit region bound that
/// indicates it must outlive at least the function body (the user
@ -226,6 +226,43 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
body_id: Option<hir::BodyId>,
}
/// Information about the anonymous, abstract types whose values we
/// are inferring in this function (these are the `impl Trait` that
/// appear in the return type).
#[derive(Debug)]
struct AnonTypeDecl<'tcx> {
/// The substitutions that we apply to the abstract that that this
/// `impl Trait` desugars to. e.g., if:
///
/// fn foo<'a, 'b, T>() -> impl Trait<'a>
///
/// winds up desugared to:
///
/// abstract type Foo<'x, T>: Trait<'x>
/// fn foo<'a, 'b, T>() -> Foo<'a, T>
///
/// then `substs` would be `['a, T]`.
substs: &'tcx Substs<'tcx>,
/// The type variable that represents the value of the abstract type
/// that we require. In other words, after we compile this function,
/// we will be created a constraint like:
///
/// Foo<'a, T> = ?C
///
/// where `?C` is the value of this type variable. =) It may
/// naturally refer to the type and lifetime parameters in scope
/// in this function, though ultimately it should only reference
/// those that are arguments to `Foo` in the constraint above. (In
/// other words, `?C` should not include `'b`, even though it's a
/// lifetime parameter on `foo`.)
concrete_ty: Ty<'tcx>,
/// A list of all required region bounds on the impl Trait type,
/// e.g. `'a` and `'b` in `fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b`.
required_region_bounds: Vec<ty::Region<'tcx>>,
}
impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
type Target = InferCtxt<'a, 'gcx, 'tcx>;
fn deref(&self) -> &Self::Target {
@ -622,7 +659,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
deferred_call_resolutions: RefCell::new(DefIdMap()),
deferred_cast_checks: RefCell::new(Vec::new()),
deferred_generator_interiors: RefCell::new(Vec::new()),
anon_types: RefCell::new(NodeMap()),
anon_types: RefCell::new(DefIdMap()),
implicit_region_bound,
body_id,
}
@ -870,7 +907,10 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env,
&fn_sig);
check_fn(&inh, param_env, fn_sig, decl, id, body, false).0
let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, false).0;
// Ensure anon_types have been instantiated prior to entering regionck
fcx.instantiate_anon_types(&fn_sig.output());
fcx
} else {
let fcx = FnCtxt::new(&inh, param_env, body.value.id);
let expected_type = tcx.type_of(def_id);
@ -1909,20 +1949,34 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
/// Replace all anonymized types with fresh inference variables
/// and record them for writeback.
fn instantiate_anon_types<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
debug!("instantiate_anon_types(value={:?})", value);
value.fold_with(&mut BottomUpFolder { tcx: self.tcx, fldop: |ty| {
if let ty::TyAnon(def_id, substs) = ty.sty {
debug!("instantiate_anon_types: TyAnon(def_id={:?}, substs={:?})", def_id, substs);
// Use the same type variable if the exact same TyAnon appears more
// than once in the return type (e.g. if it's passed to a type alias).
let id = self.tcx.hir.as_local_node_id(def_id).unwrap();
if let Some(ty_var) = self.anon_types.borrow().get(&id) {
return ty_var;
if let Some(anon_defn) = self.anon_types.borrow().get(&def_id) {
return anon_defn.concrete_ty;
}
let span = self.tcx.def_span(def_id);
let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span));
self.anon_types.borrow_mut().insert(id, ty_var);
let predicates_of = self.tcx.predicates_of(def_id);
let bounds = predicates_of.instantiate(self.tcx, substs);
debug!("instantiate_anon_types: bounds={:?}", bounds);
let required_region_bounds =
self.tcx.required_region_bounds(ty, bounds.predicates.clone());
debug!("instantiate_anon_types: required_region_bounds={:?}",
required_region_bounds);
self.anon_types.borrow_mut().insert(def_id, AnonTypeDecl {
substs,
concrete_ty: ty_var,
required_region_bounds,
});
debug!("instantiate_anon_types: ty_var={:?}", ty_var);
for predicate in bounds.predicates {
// Change the predicate to refer to the type variable,
@ -1931,8 +1985,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let predicate = self.instantiate_anon_types(&predicate);
// Require that the predicate holds for the concrete type.
let cause = traits::ObligationCause::new(span, self.body_id,
let cause = traits::ObligationCause::new(span,
self.body_id,
traits::SizedReturnType);
debug!("instantiate_anon_types: predicate={:?}", predicate);
self.register_predicate(traits::Obligation::new(cause,
self.param_env,
predicate));

View File

@ -92,6 +92,7 @@ use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty};
use rustc::infer::{self, OutlivesEnvironment};
use rustc::ty::adjustment;
use rustc::ty::outlives::Component;
use std::mem;
use std::ops::Deref;
@ -135,7 +136,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
item_id: ast::NodeId,
span: Span,
wf_tys: &[Ty<'tcx>]) {
debug!("regionck_item(item.id={:?}, wf_tys={:?}", item_id, wf_tys);
debug!("regionck_item(item.id={:?}, wf_tys={:?})", item_id, wf_tys);
let subject = self.tcx.hir.local_def_id(item_id);
let mut rcx = RegionCtxt::new(self,
RepeatingScope(item_id),
@ -336,10 +337,13 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
debug!("visit_fn_body body.id {:?} call_site_scope: {:?}",
body.id(), call_site_scope);
let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope));
let body_hir_id = self.tcx.hir.node_to_hir_id(body_id.node_id);
self.type_of_node_must_outlive(infer::CallReturn(span),
body_hir_id,
call_site_region);
self.constrain_anon_types();
}
fn visit_region_obligations(&mut self, node_id: ast::NodeId)
@ -358,6 +362,194 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
self.body_id);
}
/// Go through each of the existential `impl Trait` types that
/// appear in the function signature. For example, if the current
/// function is as follows:
///
/// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>)
///
/// we would iterate through the `impl Bar<'a>` and the
/// `impl Bar<'b>` here. Remember that each of them has
/// their own "abstract type" definition created for them. As
/// we iterate, we have a `def_id` that corresponds to this
/// definition, and a set of substitutions `substs` that are
/// being supplied to this abstract typed definition in the
/// signature:
///
/// abstract type Foo1<'x>: Bar<'x>;
/// abstract type Foo2<'x>: Bar<'x>;
/// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
/// ^^^^ ^^ substs
/// def_id
///
/// In addition, for each of the types we will have a type
/// variable `concrete_ty` containing the concrete type that
/// this function uses for `Foo1` and `Foo2`. That is,
/// conceptually, there is a constraint like:
///
/// for<'a> (Foo1<'a> = C)
///
/// where `C` is `concrete_ty`. For this equation to be satisfiable,
/// the type `C` can only refer to two regions: `'static` and `'a`.
///
/// The problem is that this type `C` may contain arbitrary
/// region variables. In fact, it is fairly likely that it
/// does! Consider this possible definition of `foo`:
///
/// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) {
/// (&*x, &*y)
/// }
///
/// Here, the values for the concrete types of the two impl
/// traits will include inference variables:
///
/// &'0 i32
/// &'1 i32
///
/// Ordinarily, the subtyping rules would ensure that these are
/// sufficiently large. But since `impl Bar<'a>` isn't a specific
/// type per se, we don't get such constraints by default. This
/// is where this function comes into play. It adds extra
/// constraints to ensure that all the regions which appear in the
/// inferred type are regions that could validly appear.
///
/// This is actually a bit of a tricky constraint in general. We
/// want to say that each variable (e.g., `'0``) can only take on
/// values that were supplied as arguments to the abstract type
/// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in
/// scope. We don't have a constraint quite of this kind in the current
/// region checker.
///
/// What we *do* have is the `<=` relation. So what we do is to
/// find the LUB of all the arguments that appear in the substs:
/// in this case, that would be `LUB('a) = 'a`, and then we apply
/// that as a least bound to the variables (e.g., `'a <= '0`).
///
/// In some cases this is pretty suboptimal. Consider this example:
///
/// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... }
///
/// Here, the regions `'a` and `'b` appear in the substitutions,
/// so we would generate `LUB('a, 'b)` as a kind of "minimal upper
/// bound", but that turns out be `'static` -- which is clearly
/// too strict!
fn constrain_anon_types(&mut self) {
debug!("constrain_anon_types()");
for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() {
let concrete_ty = self.resolve_type(anon_defn.concrete_ty);
debug!("constrain_anon_types: def_id={:?}", def_id);
debug!("constrain_anon_types: anon_defn={:#?}", anon_defn);
debug!("constrain_anon_types: concrete_ty={:?}", concrete_ty);
let abstract_type_generics = self.tcx.generics_of(def_id);
let span = self.tcx.def_span(def_id);
// If there are required region bounds, we can just skip
// ahead. There will already be a registered region
// obligation related `concrete_ty` to those regions.
if anon_defn.required_region_bounds.len() != 0 {
continue;
}
// There were no `required_region_bounds`,
// so we have to search for a `least_region`.
// Go through all the regions used as arguments to the
// abstract type. These are the parameters to the abstract
// type; so in our example above, `substs` would contain
// `['a]` for the first impl trait and `'b` for the
// second.
let mut least_region = None;
for region_def in &abstract_type_generics.regions {
// Find the index of this region in the list of substitutions.
let index = region_def.index as usize;
// Get the value supplied for this region from the substs.
let subst_arg = anon_defn.substs[index].as_region().unwrap();
// Compute the least upper bound of it with the other regions.
debug!("constrain_anon_types: least_region={:?}", least_region);
debug!("constrain_anon_types: subst_arg={:?}", subst_arg);
match least_region {
None => least_region = Some(subst_arg),
Some(lr) => {
if self.outlives_environment
.free_region_map()
.sub_free_regions(lr, subst_arg) {
// keep the current least region
} else if self.outlives_environment
.free_region_map()
.sub_free_regions(subst_arg, lr) {
// switch to `subst_arg`
least_region = Some(subst_arg);
} else {
// There are two regions (`lr` and
// `subst_arg`) which are not relatable. We can't
// find a best choice.
self.tcx
.sess
.struct_span_err(span, "ambiguous lifetime bound in `impl Trait`")
.span_label(span,
format!("neither `{}` nor `{}` outlives the other",
lr, subst_arg))
.emit();
least_region = Some(self.tcx.mk_region(ty::ReEmpty));
break;
}
}
}
}
let least_region = least_region.unwrap_or(self.tcx.types.re_static);
debug!("constrain_anon_types: least_region={:?}", least_region);
// Require that the type `concrete_ty` outlives
// `least_region`, modulo any type parameters that appear
// in the type, which we ignore. This is because impl
// trait values are assumed to capture all the in-scope
// type parameters. This little loop here just invokes
// `outlives` repeatedly, draining all the nested
// obligations that result.
let mut types = vec![concrete_ty];
let bound_region = |r| self.sub_regions(infer::CallReturn(span), least_region, r);
while let Some(ty) = types.pop() {
let mut components = self.tcx.outlives_components(ty);
while let Some(component) = components.pop() {
match component {
Component::Region(r) => {
bound_region(r);
}
Component::Param(_) => {
// ignore type parameters like `T`, they are captured
// implicitly by the `impl Trait`
}
Component::UnresolvedInferenceVariable(_) => {
// we should get an error that more type
// annotations are needed in this case
self.tcx.sess.delay_span_bug(span, "unresolved inf var in anon");
}
Component::Projection(ty::ProjectionTy { substs, item_def_id: _ }) => {
for r in substs.regions() {
bound_region(r);
}
types.extend(substs.types());
}
Component::EscapingProjection(more_components) => {
components.extend(more_components);
}
}
}
}
}
}
fn resolve_regions_and_report_errors(&self) {
self.fcx.resolve_regions_and_report_errors(self.subject_def_id,
&self.region_scope_tree,

View File

@ -18,8 +18,9 @@ use rustc::hir::def_id::{DefId, DefIndex};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::infer::{InferCtxt};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::fold::{TypeFolder,TypeFoldable};
use rustc::util::nodemap::DefIdSet;
use rustc::ty::fold::{TypeFolder, TypeFoldable};
use rustc::ty::subst::{Kind, Substs};
use rustc::util::nodemap::{DefIdSet, FxHashMap};
use syntax::ast;
use syntax_pos::Span;
use std::mem;
@ -285,8 +286,23 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
fn visit_anon_types(&mut self) {
let gcx = self.tcx().global_tcx();
for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
let inside_ty = self.resolve(&concrete_ty, &node_id);
for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() {
let node_id = gcx.hir.as_local_node_id(def_id).unwrap();
let inside_ty = self.resolve(&anon_defn.concrete_ty, &node_id);
// Use substs to build up a reverse map from regions
// to their identity mappings.
// This is necessary because of `impl Trait` lifetimes
// are computed by replacing existing lifetimes with 'static
// and remapping only those used in the `impl Trait` return type,
// resulting in the parameters shifting.
let id_substs = Substs::identity_for_item(gcx, def_id);
let map: FxHashMap<Kind<'tcx>, Kind<'gcx>> =
anon_defn.substs
.iter()
.enumerate()
.map(|(index, subst)| (*subst, id_substs[index]))
.collect();
// Convert the type from the function into a type valid outside
// the function, by replacing invalid regions with 'static,
@ -295,25 +311,39 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
match *r {
// 'static and early-bound regions are valid.
ty::ReStatic |
ty::ReEarlyBound(_) |
ty::ReEmpty => r,
ty::ReFree(_) |
ty::ReLateBound(..) |
ty::ReScope(_) |
ty::ReSkolemized(..) => {
let span = node_id.to_span(&self.fcx.tcx);
span_err!(self.tcx().sess, span, E0564,
"only named lifetimes are allowed in `impl Trait`, \
but `{}` was found in the type `{}`", r, inside_ty);
gcx.types.re_static
}
ty::ReVar(_) |
ty::ReErased => {
let span = node_id.to_span(&self.fcx.tcx);
span_bug!(span, "invalid region in impl Trait: {:?}", r);
}
// All other regions, we map them appropriately to their adjusted
// indices, erroring if we find any lifetimes that were not mapped
// into the new set.
_ => if let Some(r1) =
map.get(&Kind::from(r)).and_then(|k| k.as_region()) { r1 } else
{
// No mapping was found. This means that
// it is either a disallowed lifetime,
// which will be caught by regionck, or it
// is a region in a non-upvar closure
// generic, which is explicitly
// allowed. If that surprises you, read
// on.
//
// The case of closure is a somewhat
// subtle (read: hacky) consideration. The
// problem is that our closure types
// currently include all the lifetime
// parameters declared on the enclosing
// function, even if they are unused by
// the closure itself. We can't readily
// filter them out, so here we replace
// those values with `'empty`. This can't
// really make a difference to the rest of
// the compiler; those regions are ignored
// for the outlives relation, and hence
// don't affect trait selection or auto
// traits, and they are erased during
// trans.
gcx.types.re_empty
},
}
});

View File

@ -935,6 +935,10 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
NodeTy(&hir::Ty { node: hir::TyImplTraitExistential(ref exist_ty, _), .. }) => {
(&exist_ty.generics, None)
}
_ => (&no_generics, None)
};
@ -1358,6 +1362,8 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
use rustc::hir::map::*;
use rustc::hir::*;
debug!("explicit_predicates_of(def_id={:?})", def_id);
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
let node = tcx.hir.get(node_id);
@ -1412,17 +1418,28 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
NodeTy(&Ty { node: TyImplTraitExistential(ref bounds), span, .. }) => {
NodeTy(&Ty { node: TyImplTraitExistential(ref exist_ty, _), span, .. }) => {
let substs = Substs::identity_for_item(tcx, def_id);
let anon_ty = tcx.mk_anon(def_id, substs);
debug!("explicit_predicates_of: anon_ty={:?}", anon_ty);
// Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
let bounds = compute_bounds(&icx, anon_ty, bounds,
let bounds = compute_bounds(&icx,
anon_ty,
&exist_ty.bounds,
SizedByDefault::Yes,
span);
debug!("explicit_predicates_of: bounds={:?}", bounds);
let predicates = bounds.predicates(tcx, anon_ty);
debug!("explicit_predicates_of: predicates={:?}", predicates);
return ty::GenericPredicates {
parent: None,
predicates: bounds.predicates(tcx, anon_ty)
predicates: predicates
};
}

View File

@ -1960,9 +1960,8 @@ impl Clean<Type> for hir::Ty {
}
}
TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
TyImplTraitExistential(ref bounds) |
TyImplTraitUniversal(_, ref bounds) =>
ImplTrait(bounds.clean(cx)),
TyImplTraitExistential(ref exist_ty, ref _lts) => ImplTrait(exist_ty.bounds.clean(cx)),
TyImplTraitUniversal(_, ref bounds) => ImplTrait(bounds.clean(cx)),
TyInfer | TyErr => Infer,
TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
}

View File

@ -0,0 +1,36 @@
// Copyright 2017 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(warnings)]
#![feature(conservative_impl_trait)]
trait Id<T> {}
trait Lt<'a> {}
impl<'a> Lt<'a> for () {}
impl<T> Id<T> for T {}
fn free_fn_capture_hrtb_in_impl_trait()
-> impl for<'a> Id<impl Lt<'a>>
//~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level [E0657]
{
()
}
struct Foo;
impl Foo {
fn impl_fn_capture_hrtb_in_impl_trait()
-> impl for<'a> Id<impl Lt<'a>>
//~^ ERROR `impl Trait` can only capture lifetimes bound at the fn or impl level
{
()
}
}
fn main() {}

View File

@ -1,43 +0,0 @@
// Copyright 2016 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.
#![feature(conservative_impl_trait)]
// Helper creating a fake borrow, captured by the impl Trait.
fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () }
fn stack() -> impl Copy {
//~^ ERROR only named lifetimes are allowed in `impl Trait`
let x = 0;
&x
}
fn late_bound(x: &i32) -> impl Copy {
//~^ ERROR only named lifetimes are allowed in `impl Trait`
x
}
// FIXME(#34511) Should work but doesn't at the moment,
// region-checking needs an overhault to support this.
fn early_bound<'a>(x: &'a i32) -> impl Copy {
//~^ ERROR only named lifetimes are allowed in `impl Trait`
x
}
fn ambiguous<'a, 'b>(x: &'a [u32], y: &'b [u32]) -> impl Iterator<Item=u32> {
//~^ ERROR only named lifetimes are allowed in `impl Trait`
if x.len() < y.len() {
x.iter().cloned()
} else {
y.iter().cloned()
}
}
fn main() {}

View File

@ -0,0 +1,39 @@
// Copyright 2017 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.
#![feature(conservative_impl_trait)]
use std::fmt::Debug;
fn elided(x: &i32) -> impl Copy { x }
//~^ ERROR cannot infer an appropriate lifetime
fn explicit<'a>(x: &'a i32) -> impl Copy { x }
//~^ ERROR cannot infer an appropriate lifetime
trait LifetimeTrait<'a> {}
impl<'a> LifetimeTrait<'a> for &'a i32 {}
fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
//~^ ERROR cannot infer an appropriate lifetime
// Tests that a closure type contianing 'b cannot be returned from a type where
// only 'a was expected.
fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
//~^ ERROR lifetime mismatch
move |_| println!("{}", y)
}
fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
//~^ ERROR the parameter type `T` may not live long enough
x
}
fn main() {}

View File

@ -0,0 +1,23 @@
// Copyright 2017 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.
#![feature(conservative_impl_trait)]
use std::fmt::Debug;
trait MultiRegionTrait<'a, 'b> {}
impl<'a, 'b> MultiRegionTrait<'a, 'b> for (&'a u32, &'b u32) {}
fn no_least_region<'a, 'b>(x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> {
//~^ ERROR ambiguous lifetime bound
(x, y)
}
fn main() {}

View File

@ -0,0 +1,24 @@
// Copyright 2017 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.
#![feature(conservative_impl_trait)]
use std::fmt::Debug;
trait Any {}
impl<T> Any for T {}
// Check that type parameters are captured and not considered 'static
fn foo<T>(x: T) -> impl Any + 'static {
//~^ ERROR the parameter type `T` may not live long enough
x
}
fn main() {}

View File

@ -0,0 +1,97 @@
// Copyright 2017 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.
#![feature(conservative_impl_trait)]
#![allow(warnings)]
use std::fmt::Debug;
fn any_lifetime<'a>() -> &'a u32 { &5 }
fn static_lifetime() -> &'static u32 { &5 }
fn any_lifetime_as_static_impl_trait() -> impl Debug {
any_lifetime()
}
fn lifetimes_as_static_impl_trait() -> impl Debug {
static_lifetime()
}
fn no_params_or_lifetimes_is_static() -> impl Debug + 'static {
lifetimes_as_static_impl_trait()
}
fn static_input_type_is_static<T: Debug + 'static>(x: T) -> impl Debug + 'static { x }
fn type_outlives_reference_lifetime<'a, T: Debug>(x: &'a T) -> impl Debug + 'a { x }
trait SingleRegionTrait<'a> {}
impl<'a> SingleRegionTrait<'a> for u32 {}
fn simple_type_hrtb<'b>() -> impl for<'a> SingleRegionTrait<'a> { 5 }
fn closure_hrtb() -> impl for<'a> Fn(&'a u32) { |_| () }
fn mixed_lifetimes<'a>() -> impl for<'b: 'a> Fn(&'b u32) { |_| () }
fn mixed_as_static() -> impl Fn(&'static u32) { mixed_lifetimes() }
trait MultiRegionTrait<'a, 'b>: Debug {}
#[derive(Debug)]
struct MultiRegionStruct<'a, 'b>(&'a u32, &'b u32);
impl<'a, 'b> MultiRegionTrait<'a, 'b> for MultiRegionStruct<'a, 'b> {}
#[derive(Debug)]
struct NoRegionStruct;
impl<'a, 'b> MultiRegionTrait<'a, 'b> for NoRegionStruct {}
fn finds_least_region<'a: 'b, 'b>(x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> {
MultiRegionStruct(x, y)
}
fn finds_explicit_bound<'a: 'b, 'b>
(x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> + 'b
{
MultiRegionStruct(x, y)
}
fn finds_explicit_bound_even_without_least_region<'a, 'b>
(x: &'a u32, y: &'b u32) -> impl MultiRegionTrait<'a, 'b> + 'b
{
NoRegionStruct
}
/* FIXME: `impl Trait<'a> + 'b` should live as long as 'b, even if 'b outlives 'a
fn outlives_bounds_even_with_contained_regions<'a, 'b>
(x: &'a u32, y: &'b u32) -> impl Debug + 'b
{
finds_explicit_bound_even_without_least_region(x, y)
}
*/
fn unnamed_lifetimes_arent_contained_in_impl_trait_and_will_unify<'a, 'b>
(x: &'a u32, y: &'b u32) -> impl Debug
{
fn deref<'lt>(x: &'lt u32) -> impl Debug { *x }
if true { deref(x) } else { deref(y) }
}
fn can_add_region_bound_to_static_type<'a, 'b>(_: &'a u32) -> impl Debug + 'a { 5 }
struct MyVec(Vec<Vec<u8>>);
impl<'unnecessary_lifetime> MyVec {
fn iter_doesnt_capture_unnecessary_lifetime<'s>(&'s self) -> impl Iterator<Item = &'s u8> {
self.0.iter().flat_map(|inner_vec| inner_vec.iter())
}
}
fn main() {}

View File

@ -1,24 +0,0 @@
// Copyright 2016 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.
#![feature(conservative_impl_trait)]
// Helper creating a fake borrow, captured by the impl Trait.
fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () }
fn main() {
let long;
let mut short = 0;
long = borrow(&mut short);
//~^ NOTE borrow occurs here
}
//~^ ERROR `short` does not live long enough
//~| NOTE `short` dropped here while still borrowed
//~| NOTE values in a scope are dropped in the opposite order they are created