提交 ebda7662 编写于 作者: B bors

Auto merge of #45701 - cramertj:impl-trait-this-time, r=eddyb

impl Trait Lifetime Handling

This PR implements the updated strategy for handling `impl Trait` lifetimes, as described in [RFC 1951](https://github.com/rust-lang/rfcs/blob/master/text/1951-expand-impl-trait.md) (cc #42183).

With this PR, the `impl Trait` desugaring works as follows:
```rust
fn foo<T, 'a, 'b, 'c>(...) -> impl Foo<'a, 'b> { ... }
// desugars to
exists type MyFoo<ParentT, 'parent_a, 'parent_b, 'parent_c, 'a, 'b>: Foo<'a, 'b>;
fn foo<T, 'a, 'b, 'c>(...) -> MyFoo<T, 'static, 'static, 'static, 'a, 'b> { ... }
```
All of the in-scope (parent) generics are listed as parent generics of the anonymous type, with parent regions being replaced by `'static`. Parent regions referenced in the `impl Trait` return type are duplicated into the anonymous type's generics and mapped appropriately.

One case came up that wasn't specified in the RFC: it's possible to write a return type that contains multiple regions, neither of which outlives the other. In that case, it's not clear what the required lifetime of the output type should be, so we generate an error.

There's one remaining FIXME in one of the tests: `-> impl Foo<'a, 'b> + 'c` should be able to outlive both `'a` and `'b`, but not `'c`. Currently, it can't outlive any of them. @nikomatsakis and I have discussed this, and there are some complex interactions here if we ever allow `impl<'a, 'b> SomeTrait for AnonType<'a, 'b> { ... }`, so the plan is to hold off on this until we've got a better idea of what the interactions are here.

cc #34511.
Fixes #44727.
......@@ -2019,4 +2019,5 @@ fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
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
}
......@@ -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);
......
......@@ -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 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 @@ fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> P<hir::Ty> {
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 @@ fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> P<hir::Ty> {
})
}
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,
......
......@@ -1461,6 +1461,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_ {
......@@ -1488,7 +1494,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),
......
......@@ -421,8 +421,10 @@ pub fn print_type(&mut self, ty: &hir::Ty) -> io::Result<()> {
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) => {
......
......@@ -295,6 +295,11 @@ fn hash_stable<W: StableHasherResult>(&self,
arg_names
});
impl_stable_hash_for!(struct hir::ExistTy {
generics,
bounds
});
impl_stable_hash_for!(enum hir::Ty_ {
TySlice(t),
TyArray(t, body_id),
......@@ -305,7 +310,7 @@ fn hash_stable<W: StableHasherResult>(&self,
TyTup(ts),
TyPath(qpath),
TyTraitObject(trait_refs, lifetime),
TyImplTraitExistential(bounds),
TyImplTraitExistential(existty, lifetimes),
TyImplTraitUniversal(def_id, bounds),
TyTypeof(body_id),
TyErr,
......
......@@ -84,7 +84,7 @@ pub fn is_subregion_of(&self,
(&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 @@ pub fn relate_free_regions_from_predicates(&mut self,
}
}
// 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 {
......
......@@ -52,6 +52,7 @@ fn early(hir_map: &Map, index: &mut u32, def: &hir::LifetimeDef)
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 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
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 @@ fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
}
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 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
};
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 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
.. }) => {
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 @@ fn visit_poly_trait_ref(&mut self,
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 check_if_label_shadows_lifetime<'a>(sess: &'a Session,
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 @@ fn visit_early_late<F>(&mut self,
}
}).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 @@ fn visit_early_late<F>(&mut self,
});
}
/// 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 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) {
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 @@ fn check_lifetime_def_for_shadowing(&self,
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 @@ fn insert_lifetime(&mut self,
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 visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
}
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);
......
......@@ -220,11 +220,11 @@ pub fn extend_to<FR, FT>(&self,
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> {
......
......@@ -1015,6 +1015,10 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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.
......
......@@ -1514,7 +1514,7 @@ fn encode_info_for_generics(&mut self, generics: &hir::Generics) {
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);
}
......
......@@ -21,7 +21,7 @@
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 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
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 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
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>>)
......
......@@ -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 @@ fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>, def_id: DefId) -> Self {
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 @@ fn instantiate_bounds(&self, span: Span, def_id: DefId, substs: &Substs<'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 @@ fn instantiate_anon_types<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
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));
......
......@@ -92,6 +92,7 @@
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 @@ pub fn regionck_item(&self,
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 @@ fn visit_fn_body(&mut self,
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 @@ fn visit_region_obligations(&mut self, node_id: ast::NodeId)
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,
......
......@@ -18,8 +18,9 @@
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 @@ fn visit_free_region_map(&mut self) {
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 @@ fn visit_anon_types(&mut self) {
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
},
}
});
......
......@@ -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
};
}
......
......@@ -1973,9 +1973,8 @@ fn clean(&self, cx: &DocContext) -> Type {
}
}
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),
}
......
// 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() {}
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// 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.
//
......@@ -10,34 +10,30 @@
#![feature(conservative_impl_trait)]
// Helper creating a fake borrow, captured by the impl Trait.
fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () }
use std::fmt::Debug;
fn stack() -> impl Copy {
//~^ ERROR only named lifetimes are allowed in `impl Trait`
let x = 0;
&x
}
fn elided(x: &i32) -> impl Copy { x }
//~^ ERROR cannot infer an appropriate lifetime
fn late_bound(x: &i32) -> impl Copy {
//~^ ERROR only named lifetimes are allowed in `impl Trait`
x
}
fn explicit<'a>(x: &'a i32) -> impl Copy { x }
//~^ ERROR cannot infer an appropriate lifetime
// 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
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 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 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() {}
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// 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.
//
......@@ -10,15 +10,14 @@
#![feature(conservative_impl_trait)]
// Helper creating a fake borrow, captured by the impl Trait.
fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () }
use std::fmt::Debug;
fn main() {
let long;
let mut short = 0;
long = borrow(&mut short);
//~^ NOTE borrow occurs here
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)
}
//~^ 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
fn main() {}
// 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() {}
// 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() {}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册