Implement in-band lifetime bindings

This commit is contained in:
Taylor Cramer 2017-11-16 22:59:45 -08:00 committed by Niko Matsakis
parent 1dc0b573e7
commit 91b7920c09
33 changed files with 1026 additions and 136 deletions

View file

@ -2051,4 +2051,6 @@ register_diagnostics! {
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
E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
}

View file

@ -106,6 +106,26 @@ pub struct LoweringContext<'a> {
is_in_loop_condition: bool,
is_in_trait_impl: bool,
// Used to create lifetime definitions from in-band lifetime usages.
// e.g. `fn foo(x: &'x u8) -> &'x u8` to `fn foo<'x>(x: &'x u8) -> &'x u8`
// When a named lifetime is encountered in a function or impl header and
// has not been defined
// (i.e. it doesn't appear in the in_scope_lifetimes list), it is added
// to this list. The results of this list are then added to the list of
// lifetime definitions in the corresponding impl or function generics.
lifetimes_to_define: Vec<(Span, Name)>,
// Whether or not in-band lifetimes are being collected. This is used to
// indicate whether or not we're in a place where new lifetimes will result
// in in-band lifetime definitions, such a function or an impl header.
// This will always be false unless the `in_band_lifetimes` feature is
// enabled.
is_collecting_in_band_lifetimes: bool,
// Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB.
// When `is_collectin_in_band_lifetimes` is true, each lifetime is checked
// against this list to see if it is already in-scope, or if a definition
// needs to be created for it.
in_scope_lifetimes: Vec<Name>,
type_def_lifetime_params: DefIdMap<usize>,
current_hir_id_owner: Vec<(DefIndex, u32)>,
@ -177,6 +197,9 @@ pub fn lower_crate(sess: &Session,
node_id_to_hir_id: IndexVec::new(),
is_generator: false,
is_in_trait_impl: false,
lifetimes_to_define: Vec::new(),
is_collecting_in_band_lifetimes: false,
in_scope_lifetimes: Vec::new(),
}.lower_crate(krate)
}
@ -271,13 +294,23 @@ impl<'a> LoweringContext<'a> {
});
if item_lowered {
if let ItemKind::Impl(_,_,_,_,ref opt_trait_ref,_,_) = item.node {
self.with_trait_impl_ref(opt_trait_ref, |this| {
visit::walk_item(this, item)
});
} else {
visit::walk_item(self, item);
}
let item_lifetimes = match self.lctx.items.get(&item.id).unwrap().node {
hir::Item_::ItemImpl(_,_,_,ref generics,..) |
hir::Item_::ItemTrait(_,_,ref generics,..) =>
generics.lifetimes.clone(),
_ => Vec::new().into(),
};
self.lctx.with_parent_impl_lifetime_defs(&item_lifetimes, |this| {
let this = &mut ItemLowerer { lctx: this };
if let ItemKind::Impl(_,_,_,_,ref opt_trait_ref,_,_) = item.node {
this.with_trait_impl_ref(opt_trait_ref, |this| {
visit::walk_item(this, item)
});
} else {
visit::walk_item(this, item);
}
});
}
}
@ -490,6 +523,124 @@ impl<'a> LoweringContext<'a> {
span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
}
// Creates a new hir::LifetimeDef for every new lifetime encountered
// while evaluating `f`. Definitions are created with the parent provided.
// If no `parent_id` is provided, no definitions will be returned.
fn collect_in_band_lifetime_defs<T, F>(
&mut self,
parent_id: Option<DefId>,
f: F
) -> (Vec<hir::LifetimeDef>, T) where F: FnOnce(&mut LoweringContext) -> T
{
assert!(!self.is_collecting_in_band_lifetimes);
assert!(self.lifetimes_to_define.is_empty());
self.is_collecting_in_band_lifetimes = self.sess.features.borrow().in_band_lifetimes;
let res = f(self);
self.is_collecting_in_band_lifetimes = false;
let lifetimes_to_define = self.lifetimes_to_define.split_off(0);
let lifetime_defs = match parent_id {
Some(parent_id) => lifetimes_to_define.into_iter().map(|(span, name)| {
let def_node_id = self.next_id().node_id;
// Add a definition for the in-band lifetime def
self.resolver.definitions().create_def_with_parent(
parent_id.index,
def_node_id,
DefPathData::LifetimeDef(name.as_str()),
DefIndexAddressSpace::High,
Mark::root()
);
hir::LifetimeDef {
lifetime: hir::Lifetime {
id: def_node_id,
span,
name: hir::LifetimeName::Name(name),
},
bounds: Vec::new().into(),
pure_wrt_drop: false,
in_band: true,
}
}).collect(),
None => Vec::new(),
};
(lifetime_defs, res)
}
// Evaluates `f` with the lifetimes in `lt_defs` in-scope.
// This is used to track which lifetimes have already been defined, and
// which are new in-band lifetimes that need to have a definition created
// for them.
fn with_in_scope_lifetime_defs<T, F>(
&mut self,
lt_defs: &[LifetimeDef],
f: F
) -> T where F: FnOnce(&mut LoweringContext) -> T
{
let old_len = self.in_scope_lifetimes.len();
let lt_def_names = lt_defs.iter().map(|lt_def| lt_def.lifetime.ident.name);
self.in_scope_lifetimes.extend(lt_def_names);
let res = f(self);
self.in_scope_lifetimes.truncate(old_len);
res
}
// Same as the method above, but accepts `hir::LifetimeDef`s
// instead of `ast::LifetimeDef`s.
// This should only be used with generics that have already had their
// in-band lifetimes added. In practice, this means that this function is
// only used when lowering a child item of a trait or impl.
fn with_parent_impl_lifetime_defs<T, F>(
&mut self,
lt_defs: &[hir::LifetimeDef],
f: F
) -> T where F: FnOnce(&mut LoweringContext) -> T
{
let old_len = self.in_scope_lifetimes.len();
let lt_def_names = lt_defs.iter().map(|lt_def| lt_def.lifetime.name.name());
self.in_scope_lifetimes.extend(lt_def_names);
let res = f(self);
self.in_scope_lifetimes.truncate(old_len);
res
}
// Appends in-band lifetime defs to the existing set of out-of-band lifetime defs.
// Evaluates all within the context of the out-of-band defs.
// If provided, `impl_item_id` is used to find the parent impls of impl items so
// that their generics are not duplicated.
fn add_in_band_lifetime_defs<F, T>(
&mut self,
generics: &Generics,
parent_id: Option<DefId>,
f: F
) -> (hir::Generics, T)
where F: FnOnce(&mut LoweringContext) -> T
{
let (in_band_defs, (mut lowered_generics, res)) =
self.with_in_scope_lifetime_defs(&generics.lifetimes, |this| {
this.collect_in_band_lifetime_defs(parent_id, |this| {
(this.lower_generics(generics), f(this))
})
});
lowered_generics.lifetimes =
lowered_generics.lifetimes
.iter().cloned()
.chain(in_band_defs.into_iter())
.collect();
(lowered_generics, res)
}
fn with_catch_scope<T, F>(&mut self, catch_id: NodeId, f: F) -> T
where F: FnOnce(&mut LoweringContext) -> T
{
@ -710,13 +861,14 @@ impl<'a> LoweringContext<'a> {
hir::TyRptr(lifetime, self.lower_mt(mt, itctx))
}
TyKind::BareFn(ref f) => {
hir::TyBareFn(P(hir::BareFnTy {
lifetimes: self.lower_lifetime_defs(&f.lifetimes),
unsafety: self.lower_unsafety(f.unsafety),
abi: f.abi,
decl: self.lower_fn_decl(&f.decl, None, false),
arg_names: self.lower_fn_args_to_names(&f.decl),
}))
self.with_in_scope_lifetime_defs(&f.lifetimes, |this|
hir::TyBareFn(P(hir::BareFnTy {
lifetimes: this.lower_lifetime_defs(&f.lifetimes),
unsafety: this.lower_unsafety(f.unsafety),
abi: f.abi,
decl: this.lower_fn_decl(&f.decl, None, false),
arg_names: this.lower_fn_args_to_names(&f.decl),
})))
}
TyKind::Never => hir::TyNever,
TyKind::Tup(ref tys) => {
@ -906,6 +1058,7 @@ impl<'a> LoweringContext<'a> {
lifetime: def_lifetime,
bounds: Vec::new().into(),
pure_wrt_drop: false,
in_band: false,
});
}
}
@ -1344,23 +1497,44 @@ impl<'a> LoweringContext<'a> {
}
fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
let name = match self.lower_ident(l.ident) {
x if x == "'_" => hir::LifetimeName::Underscore,
x if x == "'static" => hir::LifetimeName::Static,
name => {
if self.is_collecting_in_band_lifetimes &&
!self.in_scope_lifetimes.contains(&name) &&
self.lifetimes_to_define.iter()
.find(|&&(_, lt_name)| lt_name == name)
.is_none()
{
self.lifetimes_to_define.push((l.span, name));
}
hir::LifetimeName::Name(name)
}
};
hir::Lifetime {
id: self.lower_node_id(l.id).node_id,
name: match self.lower_ident(l.ident) {
x if x == "'_" => hir::LifetimeName::Underscore,
x if x == "'static" => hir::LifetimeName::Static,
name => hir::LifetimeName::Name(name),
},
name,
span: l.span,
}
}
fn lower_lifetime_def(&mut self, l: &LifetimeDef) -> hir::LifetimeDef {
hir::LifetimeDef {
let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
self.is_collecting_in_band_lifetimes = false;
let def = hir::LifetimeDef {
lifetime: self.lower_lifetime(&l.lifetime),
bounds: self.lower_lifetimes(&l.bounds),
pure_wrt_drop: l.attrs.iter().any(|attr| attr.check_name("may_dangle")),
}
in_band: false,
};
self.is_collecting_in_band_lifetimes = was_collecting_in_band;
def
}
fn lower_lifetimes(&mut self, lts: &Vec<Lifetime>) -> hir::HirVec<hir::Lifetime> {
@ -1435,15 +1609,19 @@ impl<'a> LoweringContext<'a> {
ref bounded_ty,
ref bounds,
span}) => {
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
bound_lifetimes: self.lower_lifetime_defs(bound_lifetimes),
bounded_ty: self.lower_ty(bounded_ty, ImplTraitContext::Disallowed),
bounds: bounds.iter().filter_map(|bound| match *bound {
// Ignore `?Trait` bounds, they were copied into type parameters already.
TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
_ => Some(self.lower_ty_param_bound(bound, ImplTraitContext::Disallowed))
}).collect(),
span,
self.with_in_scope_lifetime_defs(bound_lifetimes, |this| {
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
bound_lifetimes: this.lower_lifetime_defs(bound_lifetimes),
bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::Disallowed),
bounds: bounds.iter().filter_map(|bound| match *bound {
// Ignore `?Trait` bounds.
// Tthey were copied into type parameters already.
TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
_ => Some(this.lower_ty_param_bound(
bound, ImplTraitContext::Disallowed))
}).collect(),
span,
})
})
}
WherePredicate::RegionPredicate(WhereRegionPredicate{ ref lifetime,
@ -1504,9 +1682,13 @@ impl<'a> LoweringContext<'a> {
p: &PolyTraitRef,
itctx: ImplTraitContext)
-> hir::PolyTraitRef {
let bound_lifetimes = self.lower_lifetime_defs(&p.bound_lifetimes);
let trait_ref = self.with_parent_impl_lifetime_defs(&bound_lifetimes,
|this| this.lower_trait_ref(&p.trait_ref, itctx));
hir::PolyTraitRef {
bound_lifetimes: self.lower_lifetime_defs(&p.bound_lifetimes),
trait_ref: self.lower_trait_ref(&p.trait_ref, itctx),
bound_lifetimes,
trait_ref,
span: p.span,
}
}
@ -1678,11 +1860,15 @@ impl<'a> LoweringContext<'a> {
let body = this.lower_block(body, false);
this.expr_block(body, ThinVec::new())
});
hir::ItemFn(this.lower_fn_decl(decl, fn_def_id, true),
let (generics, fn_decl) =
this.add_in_band_lifetime_defs(generics, fn_def_id, |this|
this.lower_fn_decl(decl, fn_def_id, true));
hir::ItemFn(fn_decl,
this.lower_unsafety(unsafety),
this.lower_constness(constness),
abi,
this.lower_generics(generics),
generics,
body_id)
})
}
@ -1723,29 +1909,42 @@ impl<'a> LoweringContext<'a> {
ItemKind::Impl(unsafety,
polarity,
defaultness,
ref generics,
ref ast_generics,
ref ifce,
ref ty,
ref impl_items) => {
let new_impl_items = impl_items.iter()
.map(|item| self.lower_impl_item_ref(item))
.collect();
let ifce = ifce.as_ref().map(|trait_ref| {
self.lower_trait_ref(trait_ref, ImplTraitContext::Disallowed)
let def_id = self.resolver.definitions().opt_local_def_id(id);
let (generics, (ifce, lowered_ty)) =
self.add_in_band_lifetime_defs(ast_generics, def_id, |this| {
let ifce = ifce.as_ref().map(|trait_ref| {
this.lower_trait_ref(trait_ref, ImplTraitContext::Disallowed)
});
if let Some(ref trait_ref) = ifce {
if let Def::Trait(def_id) = trait_ref.path.def {
this.trait_impls.entry(def_id).or_insert(vec![]).push(id);
}
}
let lowered_ty = this.lower_ty(ty, ImplTraitContext::Disallowed);
(ifce, lowered_ty)
});
let new_impl_items = self.with_in_scope_lifetime_defs(
&ast_generics.lifetimes, |this| {
impl_items.iter()
.map(|item| this.lower_impl_item_ref(item))
.collect()
});
if let Some(ref trait_ref) = ifce {
if let Def::Trait(def_id) = trait_ref.path.def {
self.trait_impls.entry(def_id).or_insert(vec![]).push(id);
}
}
hir::ItemImpl(self.lower_unsafety(unsafety),
self.lower_impl_polarity(polarity),
self.lower_defaultness(defaultness, true /* [1] */),
self.lower_generics(generics),
generics,
ifce,
self.lower_ty(ty, ImplTraitContext::Disallowed),
lowered_ty,
new_impl_items)
}
ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref items) => {
@ -1769,41 +1968,55 @@ impl<'a> LoweringContext<'a> {
let LoweredNodeId { node_id, hir_id } = this.lower_node_id(i.id);
let fn_def_id = this.resolver.definitions().opt_local_def_id(node_id);
let (generics, node) = match i.node {
TraitItemKind::Const(ref ty, ref default) => {
(
this.lower_generics(&i.generics),
hir::TraitItemKind::Const(
this.lower_ty(ty, ImplTraitContext::Disallowed),
default.as_ref().map(|x| {
this.lower_body(None, |this| this.lower_expr(x))
}))
)
}
TraitItemKind::Method(ref sig, None) => {
let names = this.lower_fn_args_to_names(&sig.decl);
this.add_in_band_lifetime_defs(&i.generics, fn_def_id, |this|
hir::TraitItemKind::Method(
this.lower_method_sig(sig, fn_def_id, false),
hir::TraitMethod::Required(names)))
}
TraitItemKind::Method(ref sig, Some(ref body)) => {
let body_id = this.lower_body(Some(&sig.decl), |this| {
let body = this.lower_block(body, false);
this.expr_block(body, ThinVec::new())
});
this.add_in_band_lifetime_defs(&i.generics, fn_def_id, |this|
hir::TraitItemKind::Method(
this.lower_method_sig(sig, fn_def_id, false),
hir::TraitMethod::Provided(body_id)))
}
TraitItemKind::Type(ref bounds, ref default) => {
(
this.lower_generics(&i.generics),
hir::TraitItemKind::Type(
this.lower_bounds(bounds, ImplTraitContext::Disallowed),
default.as_ref().map(|x| {
this.lower_ty(x, ImplTraitContext::Disallowed)
}))
)
}
TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
};
hir::TraitItem {
id: node_id,
hir_id,
name: this.lower_ident(i.ident),
attrs: this.lower_attrs(&i.attrs),
generics: this.lower_generics(&i.generics),
node: match i.node {
TraitItemKind::Const(ref ty, ref default) => {
hir::TraitItemKind::Const(this.lower_ty(ty, ImplTraitContext::Disallowed),
default.as_ref().map(|x| {
this.lower_body(None, |this| this.lower_expr(x))
}))
}
TraitItemKind::Method(ref sig, None) => {
let names = this.lower_fn_args_to_names(&sig.decl);
hir::TraitItemKind::Method(this.lower_method_sig(sig, fn_def_id, false),
hir::TraitMethod::Required(names))
}
TraitItemKind::Method(ref sig, Some(ref body)) => {
let body_id = this.lower_body(Some(&sig.decl), |this| {
let body = this.lower_block(body, false);
this.expr_block(body, ThinVec::new())
});
hir::TraitItemKind::Method(this.lower_method_sig(sig, fn_def_id, false),
hir::TraitMethod::Provided(body_id))
}
TraitItemKind::Type(ref bounds, ref default) => {
hir::TraitItemKind::Type(this.lower_bounds(bounds,
ImplTraitContext::Disallowed),
default.as_ref().map(|x| {
this.lower_ty(x, ImplTraitContext::Disallowed)
}))
}
TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
},
generics,
node,
span: i.span,
}
})
@ -1838,37 +2051,46 @@ impl<'a> LoweringContext<'a> {
let LoweredNodeId { node_id, hir_id } = this.lower_node_id(i.id);
let fn_def_id = this.resolver.definitions().opt_local_def_id(node_id);
let (generics, node) = match i.node {
ImplItemKind::Const(ref ty, ref expr) => {
let body_id = this.lower_body(None, |this| this.lower_expr(expr));
(
this.lower_generics(&i.generics),
hir::ImplItemKind::Const(
this.lower_ty(ty, ImplTraitContext::Disallowed),
body_id
)
)
}
ImplItemKind::Method(ref sig, ref body) => {
let body_id = this.lower_body(Some(&sig.decl), |this| {
let body = this.lower_block(body, false);
this.expr_block(body, ThinVec::new())
});
let impl_trait_return_allow = !this.is_in_trait_impl;
this.add_in_band_lifetime_defs(&i.generics, fn_def_id, |this|
hir::ImplItemKind::Method(
this.lower_method_sig(sig, fn_def_id, impl_trait_return_allow),
body_id))
}
ImplItemKind::Type(ref ty) => (
this.lower_generics(&i.generics),
hir::ImplItemKind::Type(
this.lower_ty(ty, ImplTraitContext::Disallowed)),
),
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
};
hir::ImplItem {
id: node_id,
hir_id,
name: this.lower_ident(i.ident),
attrs: this.lower_attrs(&i.attrs),
generics: this.lower_generics(&i.generics),
generics,
vis: this.lower_visibility(&i.vis, None),
defaultness: this.lower_defaultness(i.defaultness, true /* [1] */),
node: match i.node {
ImplItemKind::Const(ref ty, ref expr) => {
let body_id = this.lower_body(None, |this| this.lower_expr(expr));
hir::ImplItemKind::Const(
this.lower_ty(ty, ImplTraitContext::Disallowed),
body_id
)
}
ImplItemKind::Method(ref sig, ref body) => {
let body_id = this.lower_body(Some(&sig.decl), |this| {
let body = this.lower_block(body, false);
this.expr_block(body, ThinVec::new())
});
let impl_trait_return_allow = !this.is_in_trait_impl;
hir::ImplItemKind::Method(this.lower_method_sig(sig,
fn_def_id,
impl_trait_return_allow),
body_id)
}
ImplItemKind::Type(ref ty) =>
hir::ImplItemKind::Type(this.lower_ty(ty, ImplTraitContext::Disallowed)),
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
},
node,
span: i.span,
}
})
@ -1958,16 +2180,26 @@ impl<'a> LoweringContext<'a> {
fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem {
self.with_parent_def(i.id, |this| {
let node_id = this.lower_node_id(i.id).node_id;
let def_id = this.resolver.definitions().local_def_id(node_id);
hir::ForeignItem {
id: this.lower_node_id(i.id).node_id,
id: node_id,
name: i.ident.name,
attrs: this.lower_attrs(&i.attrs),
node: match i.node {
ForeignItemKind::Fn(ref fdec, ref generics) => {
// Disallow impl Trait in foreign items
hir::ForeignItemFn(this.lower_fn_decl(fdec, None, false),
this.lower_fn_args_to_names(fdec),
this.lower_generics(generics))
let (generics, (fn_dec, fn_args)) =
this.add_in_band_lifetime_defs(
generics,
Some(def_id),
|this| (
this.lower_fn_decl(fdec, None, false),
this.lower_fn_args_to_names(fdec)
)
);
hir::ForeignItemFn(fn_dec, fn_args, generics)
}
ForeignItemKind::Static(ref t, m) => {
hir::ForeignItemStatic(this.lower_ty(t, ImplTraitContext::Disallowed), m)

View file

@ -222,6 +222,10 @@ pub struct LifetimeDef {
pub lifetime: Lifetime,
pub bounds: HirVec<Lifetime>,
pub pure_wrt_drop: bool,
// Indicates that the lifetime definition was synthetically added
// as a result of an in-band lifetime usage like
// `fn foo(x: &'a u8) -> &'a u8 { x }`
pub in_band: bool,
}
/// A "Path" is essentially Rust's notion of a name; for instance:

View file

@ -157,7 +157,8 @@ impl_stable_hash_for!(struct hir::Lifetime {
impl_stable_hash_for!(struct hir::LifetimeDef {
lifetime,
bounds,
pure_wrt_drop
pure_wrt_drop,
in_band
});
impl_stable_hash_for!(struct hir::Path {

View file

@ -493,10 +493,15 @@ for ::middle::resolve_lifetime::Set1<T>
}
}
impl_stable_hash_for!(enum ::middle::resolve_lifetime::LifetimeDefOrigin {
Explicit,
InBand
});
impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region {
Static,
EarlyBound(index, decl),
LateBound(db_index, decl),
EarlyBound(index, decl, is_in_band),
LateBound(db_index, decl, is_in_band),
LateBoundAnon(db_index, anon_index),
Free(call_site_scope_data, decl)
});

View file

@ -281,7 +281,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
// Find the index of the named region that was part of the
// error. We will then search the function parameters for a bound
// region at the right depth with the same index
(Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
(Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
debug!("EarlyBound self.infcx.tcx.hir.local_def_id(id)={:?} \
def_id={:?}", id, def_id);
if id == def_id {
@ -293,7 +293,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
// Find the index of the named region that was part of the
// error. We will then search the function parameters for a bound
// region at the right depth with the same index
(Some(rl::Region::LateBound(debruijn_index, id)), ty::BrNamed(def_id, _)) => {
(
Some(rl::Region::LateBound(debruijn_index, id, _)),
ty::BrNamed(def_id, _)
) => {
debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
debruijn_index.depth);
debug!("self.infcx.tcx.hir.local_def_id(id)={:?}", id);
@ -306,8 +309,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
(Some(rl::Region::Static), _) |
(Some(rl::Region::Free(_, _)), _) |
(Some(rl::Region::EarlyBound(_, _)), _) |
(Some(rl::Region::LateBound(_, _)), _) |
(Some(rl::Region::EarlyBound(_, _, _)), _) |
(Some(rl::Region::LateBound(_, _, _)), _) |
(Some(rl::Region::LateBoundAnon(_, _)), _) |
(None, _) => {
debug!("no arg found");
@ -368,7 +371,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for TyPathVisitor<'a, 'gcx, 'tcx> {
}
}
(Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
(Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
debug!("EarlyBound self.infcx.tcx.hir.local_def_id(id)={:?} \
def_id={:?}", id, def_id);
if id == def_id {
@ -377,7 +380,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for TyPathVisitor<'a, 'gcx, 'tcx> {
}
}
(Some(rl::Region::LateBound(debruijn_index, id)), ty::BrNamed(def_id, _)) => {
(Some(rl::Region::LateBound(debruijn_index, id, _)), ty::BrNamed(def_id, _)) => {
debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
debruijn_index.depth);
debug!("id={:?}", id);
@ -389,8 +392,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for TyPathVisitor<'a, 'gcx, 'tcx> {
}
(Some(rl::Region::Static), _) |
(Some(rl::Region::EarlyBound(_, _)), _) |
(Some(rl::Region::LateBound(_, _)), _) |
(Some(rl::Region::EarlyBound(_, _, _)), _) |
(Some(rl::Region::LateBound(_, _, _)), _) |
(Some(rl::Region::LateBoundAnon(_, _)), _) |
(Some(rl::Region::Free(_, _)), _) |
(None, _) => {

View file

@ -36,11 +36,32 @@ use rustc_back::slice;
use hir;
use hir::intravisit::{self, Visitor, NestedVisitorMap};
/// The origin of a named lifetime definition.
///
/// This is used to prevent the usage of in-band lifetimes in `Fn`/`fn` syntax.
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
pub enum LifetimeDefOrigin {
// Explicit binders like `fn foo<'a>(x: &'a u8)`
Explicit,
// In-band declarations like `fn foo(x: &'a u8)`
InBand,
}
impl LifetimeDefOrigin {
fn from_is_in_band(is_in_band: bool) -> Self {
if is_in_band {
LifetimeDefOrigin::InBand
} else {
LifetimeDefOrigin::Explicit
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
pub enum Region {
Static,
EarlyBound(/* index */ u32, /* lifetime decl */ DefId),
LateBound(ty::DebruijnIndex, /* lifetime decl */ DefId),
EarlyBound(/* index */ u32, /* lifetime decl */ DefId, LifetimeDefOrigin),
LateBound(ty::DebruijnIndex, /* lifetime decl */ DefId, LifetimeDefOrigin),
LateBoundAnon(ty::DebruijnIndex, /* anon index */ u32),
Free(DefId, /* lifetime decl */ DefId),
}
@ -52,14 +73,16 @@ impl Region {
let i = *index;
*index += 1;
let def_id = hir_map.local_def_id(def.lifetime.id);
let origin = LifetimeDefOrigin::from_is_in_band(def.in_band);
debug!("Region::early: index={} def_id={:?}", i, def_id);
(def.lifetime.name, Region::EarlyBound(i, def_id))
(def.lifetime.name, Region::EarlyBound(i, def_id, origin))
}
fn late(hir_map: &Map, def: &hir::LifetimeDef) -> (hir::LifetimeName, Region) {
let depth = ty::DebruijnIndex::new(1);
let def_id = hir_map.local_def_id(def.lifetime.id);
(def.lifetime.name, Region::LateBound(depth, def_id))
let origin = LifetimeDefOrigin::from_is_in_band(def.in_band);
(def.lifetime.name, Region::LateBound(depth, def_id, origin))
}
fn late_anon(index: &Cell<u32>) -> Region {
@ -74,16 +97,16 @@ impl Region {
Region::Static |
Region::LateBoundAnon(..) => None,
Region::EarlyBound(_, id) |
Region::LateBound(_, id) |
Region::EarlyBound(_, id, _) |
Region::LateBound(_, id, _) |
Region::Free(_, id) => Some(id)
}
}
fn shifted(self, amount: u32) -> Region {
match self {
Region::LateBound(depth, id) => {
Region::LateBound(depth.shifted(amount), id)
Region::LateBound(depth, id, origin) => {
Region::LateBound(depth.shifted(amount), id, origin)
}
Region::LateBoundAnon(depth, index) => {
Region::LateBoundAnon(depth.shifted(amount), index)
@ -94,10 +117,10 @@ impl Region {
fn from_depth(self, depth: u32) -> Region {
match self {
Region::LateBound(debruijn, id) => {
Region::LateBound(debruijn, id, origin) => {
Region::LateBound(ty::DebruijnIndex {
depth: debruijn.depth - (depth - 1)
}, id)
}, id, origin)
}
Region::LateBoundAnon(debruijn, index) => {
Region::LateBoundAnon(ty::DebruijnIndex {
@ -110,7 +133,7 @@ impl Region {
fn subst(self, params: &[hir::Lifetime], map: &NamedRegionMap)
-> Option<Region> {
if let Region::EarlyBound(index, _) = self {
if let Region::EarlyBound(index, _, _) = self {
params.get(index as usize).and_then(|lifetime| {
map.defs.get(&lifetime.id).cloned()
})
@ -187,6 +210,9 @@ struct LifetimeContext<'a, 'tcx: 'a> {
// I'm sorry.
trait_ref_hack: bool,
// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
is_in_fn_syntax: bool,
// List of labels in the function/method currently under analysis.
labels_in_fn: Vec<(ast::Name, Span)>,
@ -280,6 +306,7 @@ pub fn krate(sess: &Session,
map: &mut map,
scope: ROOT_SCOPE,
trait_ref_hack: false,
is_in_fn_syntax: false,
labels_in_fn: vec![],
xcrate_object_lifetime_defaults: DefIdMap(),
};
@ -384,6 +411,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
match ty.node {
hir::TyBareFn(ref c) => {
let next_early_index = self.next_early_index();
let was_in_fn_syntax = self.is_in_fn_syntax;
self.is_in_fn_syntax = true;
let scope = Scope::Binder {
lifetimes: c.lifetimes.iter().map(|def| {
Region::late(self.hir_map, def)
@ -397,6 +426,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
this.check_lifetime_defs(old_scope, &c.lifetimes);
intravisit::walk_ty(this, ty);
});
self.is_in_fn_syntax = was_in_fn_syntax;
}
hir::TyTraitObject(ref bounds, ref lifetime) => {
for bound in bounds {
@ -430,7 +460,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// 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(&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);
@ -528,6 +558,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
check_mixed_explicit_and_in_band_defs(&self.sess, &generics.lifetimes);
for ty_param in generics.ty_params.iter() {
walk_list!(self, visit_ty_param_bound, &ty_param.bounds);
if let Some(ref ty) = ty_param.default {
@ -639,6 +670,22 @@ impl ShadowKind {
}
}
fn check_mixed_explicit_and_in_band_defs(
sess: &Session,
lifetime_defs: &[hir::LifetimeDef],
) {
let oob_def = lifetime_defs.iter().find(|lt| !lt.in_band);
let in_band_def = lifetime_defs.iter().find(|lt| lt.in_band);
if let (Some(oob_def), Some(in_band_def)) = (oob_def, in_band_def) {
struct_span_err!(sess, in_band_def.lifetime.span, E0688,
"cannot mix in-band and explicit lifetime definitions")
.span_label(in_band_def.lifetime.span, "in-band lifetime definition here")
.span_label(oob_def.lifetime.span, "explicit lifetime definition here")
.emit();
}
}
fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, shadower: Shadower) {
let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
// lifetime/lifetime shadowing is an error
@ -767,7 +814,7 @@ fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map)
match *set {
Set1::Empty => "BaseDefault".to_string(),
Set1::One(Region::Static) => "'static".to_string(),
Set1::One(Region::EarlyBound(i, _)) => {
Set1::One(Region::EarlyBound(i, _, _)) => {
generics.lifetimes[i as usize].lifetime.name.name().to_string()
}
Set1::One(_) => bug!(),
@ -837,7 +884,8 @@ fn object_lifetime_defaults_for_item(hir_map: &Map, generics: &hir::Generics)
def.lifetime.name == name
}).map_or(Set1::Many, |(i, def)| {
let def_id = hir_map.local_def_id(def.lifetime.id);
Set1::One(Region::EarlyBound(i as u32, def_id))
let origin = LifetimeDefOrigin::from_is_in_band(def.in_band);
Set1::One(Region::EarlyBound(i as u32, def_id, origin))
})
}
}
@ -868,6 +916,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
map: *map,
scope: &wrap_scope,
trait_ref_hack: self.trait_ref_hack,
is_in_fn_syntax: self.is_in_fn_syntax,
labels_in_fn,
xcrate_object_lifetime_defaults,
};
@ -1020,6 +1069,28 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
_ => {}
}
}
// Check for fn-syntax conflicts with in-band lifetime definitions
if self.is_in_fn_syntax {
match def {
Region::EarlyBound(_, _, LifetimeDefOrigin::InBand) |
Region::LateBound(_, _, LifetimeDefOrigin::InBand) => {
struct_span_err!(self.sess, lifetime_ref.span, E0687,
"lifetimes used in `fn` or `Fn` syntax must be \
explicitly declared using `<...>` binders")
.span_label(lifetime_ref.span,
"in-band lifetime definition")
.emit();
},
Region::Static |
Region::EarlyBound(_, _, LifetimeDefOrigin::Explicit) |
Region::LateBound(_, _, LifetimeDefOrigin::Explicit) |
Region::LateBoundAnon(..) |
Region::Free(..) => {}
}
}
self.insert_lifetime(lifetime_ref, def);
} else {
struct_span_err!(self.sess, lifetime_ref.span, E0261,
@ -1033,8 +1104,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
def: Def,
depth: usize,
params: &'tcx hir::PathParameters) {
if params.parenthesized {
let was_in_fn_syntax = self.is_in_fn_syntax;
self.is_in_fn_syntax = true;
self.visit_fn_like_elision(params.inputs(), Some(&params.bindings[0].ty));
self.is_in_fn_syntax = was_in_fn_syntax;
return;
}
@ -1355,7 +1430,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.id) {
match lifetime {
Region::LateBound(debruijn, _) |
Region::LateBound(debruijn, _, _) |
Region::LateBoundAnon(debruijn, _)
if debruijn.depth < self.binder_depth => {
self.have_bound_regions = true;

View file

@ -110,7 +110,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
tcx.types.re_static
}
Some(rl::Region::LateBound(debruijn, id)) => {
Some(rl::Region::LateBound(debruijn, id, _)) => {
let name = lifetime_name(id);
tcx.mk_region(ty::ReLateBound(debruijn,
ty::BrNamed(id, name)))
@ -120,7 +120,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(index)))
}
Some(rl::Region::EarlyBound(index, id)) => {
Some(rl::Region::EarlyBound(index, id, _)) => {
let name = lifetime_name(id);
tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
def_id: id,

View file

@ -784,7 +784,7 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let hir_id = self.tcx.hir.node_to_hir_id(lt.id);
match self.tcx.named_region(hir_id) {
Some(rl::Region::Static) | Some(rl::Region::EarlyBound(..)) => {}
Some(rl::Region::LateBound(debruijn, _)) |
Some(rl::Region::LateBound(debruijn, _, _)) |
Some(rl::Region::LateBoundAnon(debruijn, _))
if debruijn.depth < self.binder_depth => {}
_ => self.has_late_bound_regions = Some(lt.span),

View file

@ -1008,8 +1008,8 @@ impl Clean<Lifetime> for hir::Lifetime {
let hir_id = cx.tcx.hir.node_to_hir_id(self.id);
let def = cx.tcx.named_region(hir_id);
match def {
Some(rl::Region::EarlyBound(_, node_id)) |
Some(rl::Region::LateBound(_, node_id)) |
Some(rl::Region::EarlyBound(_, node_id, _)) |
Some(rl::Region::LateBound(_, node_id, _)) |
Some(rl::Region::Free(_, node_id)) => {
if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() {
return lt;

View file

@ -425,6 +425,9 @@ declare_features! (
// `crate` in paths
(active, crate_in_paths, "1.23.0", Some(45477)),
// In-band lifetime bindings (e.g. `fn foo(x: &'a u8) -> &'a u8`)
(active, in_band_lifetimes, "1.23.0", Some(44524)),
);
declare_features! (

View file

@ -0,0 +1,72 @@
// 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)]
fn foo(x: &'x u8) -> &'x u8 { x }
//~^ ERROR use of undeclared lifetime name
//~^^ ERROR use of undeclared lifetime name
struct X<'a>(&'a u8);
impl<'a> X<'a> {
fn inner(&self) -> &'a u8 {
self.0
}
}
impl<'a> X<'b> {
//~^ ERROR use of undeclared lifetime name
fn inner_2(&self) -> &'b u8 {
//~^ ERROR use of undeclared lifetime name
self.0
}
}
impl X<'b> {
//~^ ERROR use of undeclared lifetime name
fn inner_3(&self) -> &'b u8 {
//~^ ERROR use of undeclared lifetime name
self.0
}
}
struct Y<T>(T);
impl Y<&'a u8> {
//~^ ERROR use of undeclared lifetime name
fn inner(&self) -> &'a u8 {
//~^ ERROR use of undeclared lifetime name
self.0
}
}
trait MyTrait<'a> {
fn my_lifetime(&self) -> &'a u8;
fn any_lifetime() -> &'b u8;
//~^ ERROR use of undeclared lifetime name
fn borrowed_lifetime(&'b self) -> &'b u8;
//~^ ERROR use of undeclared lifetime name
//~^^ ERROR use of undeclared lifetime name
}
impl MyTrait<'a> for Y<&'a u8> {
//~^ ERROR use of undeclared lifetime name
//~^^ ERROR use of undeclared lifetime name
fn my_lifetime(&self) -> &'a u8 { self.0 }
//~^ ERROR use of undeclared lifetime name
fn any_lifetime() -> &'b u8 { &0 }
//~^ ERROR use of undeclared lifetime name
fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
//~^ ERROR use of undeclared lifetime name
//~^^ ERROR use of undeclared lifetime name
}
fn main() {}

View file

@ -0,0 +1,84 @@
// 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(in_band_lifetimes, universal_impl_trait)]
fn foo(x: &'x u8) -> &'x u8 { x }
fn foo2(x: &'a u8, y: &u8) -> &'a u8 { x }
fn check_in_band_can_be_late_bound() {
let _: for<'x> fn(&'x u8, &u8) -> &'x u8 = foo2;
}
struct ForInherentNoParams;
impl ForInherentNoParams {
fn foo(x: &'a u32, y: &u32) -> &'a u32 { x }
}
struct X<'a>(&'a u8);
impl<'a> X<'a> {
fn inner(&self) -> &'a u8 {
self.0
}
fn same_lifetime_as_parameter(&mut self, x: &'a u8) {
self.0 = x;
}
}
impl X<'b> {
fn inner_2(&self) -> &'b u8 {
self.0
}
fn reference_already_introduced_in_band_from_method_with_explicit_binders<'a>(
&'b self, x: &'a u32
) {}
}
struct Y<T>(T);
impl Y<&'a u8> {
fn inner(&self) -> &'a u8 {
self.0
}
}
trait MyTrait<'a> {
fn my_lifetime(&self) -> &'a u8;
fn any_lifetime() -> &'b u8;
fn borrowed_lifetime(&'b self) -> &'b u8;
fn default_impl(&self, x: &'b u32, y: &u32) -> &'b u32 { x }
fn in_band_def_explicit_impl(&self, x: &'b u8);
}
impl MyTrait<'a> for Y<&'a u8> {
fn my_lifetime(&self) -> &'a u8 { self.0 }
fn any_lifetime() -> &'b u8 { &0 }
fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
fn in_band_def_explicit_impl<'b>(&self, x: &'b u8) {}
}
fn test_hrtb_defined_lifetime_where<F>(_: F) where for<'a> F: Fn(&'a u8) {}
fn test_hrtb_defined_lifetime_polytraitref<F>(_: F) where F: for<'a> Fn(&'a u8) {}
fn reference_in_band_from_locals(x: &'test u32) -> &'test u32 {
let y: &'test u32 = x;
y
}
fn in_generics_in_band<T: MyTrait<'a>>(x: &T) {}
fn where_clause_in_band<T>(x: &T) where T: MyTrait<'a> {}
fn impl_trait_in_band(x: &impl MyTrait<'a>) {}
fn main() {}

View file

@ -0,0 +1,26 @@
// 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(in_band_lifetimes)]
fn foo(x: fn(&'a u32)) {}
fn bar(x: &Fn(&'a u32)) {}
fn baz(x: fn(&'a u32), y: &'a u32) {}
struct Foo<'a> { x: &'a u32 }
impl Foo<'a> {
fn bar(&self, x: fn(&'a u32)) {}
}
fn main() {}

View file

@ -0,0 +1,26 @@
error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders
--> $DIR/E0687.rs:14:15
|
14 | fn foo(x: fn(&'a u32)) {}
| ^^ in-band lifetime definition
error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders
--> $DIR/E0687.rs:16:16
|
16 | fn bar(x: &Fn(&'a u32)) {}
| ^^ in-band lifetime definition
error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders
--> $DIR/E0687.rs:18:15
|
18 | fn baz(x: fn(&'a u32), y: &'a u32) {}
| ^^ in-band lifetime definition
error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders
--> $DIR/E0687.rs:23:26
|
23 | fn bar(&self, x: fn(&'a u32)) {}
| ^^ in-band lifetime definition
error: aborting due to 4 previous errors

View file

@ -0,0 +1,18 @@
// 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(in_band_lifetimes, universal_impl_trait)]
fn bar<F>(x: &F) where F: Fn(&'a u32) {}
fn baz(x: &impl Fn(&'a u32)) {}
fn main() {}

View file

@ -0,0 +1,14 @@
error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders
--> $DIR/E0687_where.rs:14:31
|
14 | fn bar<F>(x: &F) where F: Fn(&'a u32) {}
| ^^ in-band lifetime definition
error[E0687]: lifetimes used in `fn` or `Fn` syntax must be explicitly declared using `<...>` binders
--> $DIR/E0687_where.rs:16:21
|
16 | fn baz(x: &impl Fn(&'a u32)) {}
| ^^ in-band lifetime definition
error: aborting due to 2 previous errors

View file

@ -0,0 +1,26 @@
// 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(in_band_lifetimes)]
fn foo<'a>(x: &'a u32, y: &'b u32) {}
struct Foo<'a> { x: &'a u32 }
impl Foo<'a> {
fn bar<'b>(x: &'a u32, y: &'b u32, z: &'c u32) {}
}
impl<'b> Foo<'a> {
fn baz() {}
}
fn main() {}

View file

@ -0,0 +1,26 @@
error[E0688]: cannot mix in-band and explicit lifetime definitions
--> $DIR/E0688.rs:14:28
|
14 | fn foo<'a>(x: &'a u32, y: &'b u32) {}
| -- ^^ in-band lifetime definition here
| |
| explicit lifetime definition here
error[E0688]: cannot mix in-band and explicit lifetime definitions
--> $DIR/E0688.rs:19:44
|
19 | fn bar<'b>(x: &'a u32, y: &'b u32, z: &'c u32) {}
| -- ^^ in-band lifetime definition here
| |
| explicit lifetime definition here
error[E0688]: cannot mix in-band and explicit lifetime definitions
--> $DIR/E0688.rs:22:14
|
22 | impl<'b> Foo<'a> {
| -- ^^ in-band lifetime definition here
| |
| explicit lifetime definition here
error: aborting due to 3 previous errors

View file

@ -0,0 +1,18 @@
// 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(in_band_lifetimes)]
fn foo(x: &'a u32, y: &u32) -> &'a u32 { y }
fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y }
fn main() {}

View file

@ -0,0 +1,18 @@
error[E0621]: explicit lifetime required in the type of `y`
--> $DIR/mismatched.rs:14:42
|
14 | fn foo(x: &'a u32, y: &u32) -> &'a u32 { y }
| - ^ lifetime `'a` required
| |
| consider changing the type of `y` to `&'a u32`
error[E0623]: lifetime mismatch
--> $DIR/mismatched.rs:16:46
|
16 | fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y }
| ------- ------- ^ ...but data from `y` is returned here
| |
| this parameter and the return type are declared with different lifetimes...
error: aborting due to 2 previous errors

View file

@ -0,0 +1,20 @@
// 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(in_band_lifetimes)]
trait Get {
fn baz(&self, x: &'a u32, y: &u32) -> &'a u32 {
y
}
}
fn main() {}

View file

@ -0,0 +1,10 @@
error[E0621]: explicit lifetime required in the type of `y`
--> $DIR/mismatched_trait.rs:16:9
|
15 | fn baz(&self, x: &'a u32, y: &u32) -> &'a u32 {
| - consider changing the type of `y` to `&'a u32`
16 | y
| ^ lifetime `'a` required
error: aborting due to previous error

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.
#![allow(warnings)]
#![feature(in_band_lifetimes)]
trait Get {
fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
}
impl Get for i32 {
fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
x
}
}
fn main() {}

View file

@ -0,0 +1,39 @@
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements
--> $DIR/mismatched_trait_impl.rs:19:5
|
19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
20 | | x
21 | | }
| |_____^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 19:5...
--> $DIR/mismatched_trait_impl.rs:19:5
|
19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
20 | | x
21 | | }
| |_____^
note: ...so that method type is compatible with trait (expected fn(&i32, &'a u32, &u32) -> &'a u32, found fn(&i32, &u32, &u32) -> &u32)
--> $DIR/mismatched_trait_impl.rs:19:5
|
19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
20 | | x
21 | | }
| |_____^
note: but, the lifetime must be valid for the lifetime 'a as defined on the method body at 19:5...
--> $DIR/mismatched_trait_impl.rs:19:5
|
19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
20 | | x
21 | | }
| |_____^
note: ...so that method type is compatible with trait (expected fn(&i32, &'a u32, &u32) -> &'a u32, found fn(&i32, &u32, &u32) -> &u32)
--> $DIR/mismatched_trait_impl.rs:19:5
|
19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
20 | | x
21 | | }
| |_____^
error: aborting due to previous error

View file

@ -0,0 +1,21 @@
// 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(in_band_lifetimes)]
fn foo(x: &'a u32) -> &'a u32 { x }
fn main() {
let mut p = 3;
let r = foo(&p);
p += 1;
println!("{}", r);
}

View file

@ -0,0 +1,10 @@
error[E0506]: cannot assign to `p` because it is borrowed
--> $DIR/mut_while_borrow.rs:19:5
|
18 | let r = foo(&p);
| - borrow of `p` occurs here
19 | p += 1;
| ^^^^^^ assignment to borrowed `p` occurs here
error: aborting due to previous error

View file

@ -0,0 +1,22 @@
// 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(in_band_lifetimes)]
struct Foo {
x: &'test u32,
}
enum Bar {
Baz(&'test u32),
}
fn main() {}

View file

@ -0,0 +1,14 @@
error[E0261]: use of undeclared lifetime name `'test`
--> $DIR/no_in_band_in_struct.rs:15:9
|
15 | x: &'test u32,
| ^^^^^ undeclared lifetime
error[E0261]: use of undeclared lifetime name `'test`
--> $DIR/no_in_band_in_struct.rs:19:10
|
19 | Baz(&'test u32),
| ^^^^^ undeclared lifetime
error: aborting due to 2 previous errors

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.
#![allow(warnings)]
#![feature(in_band_lifetimes)]
fn foo(x: &u32) {
let y: &'test u32 = x;
}
fn foo2(x: &u32) {}
fn bar() {
let y: fn(&'test u32) = foo2;
}
fn main() {}

View file

@ -0,0 +1,14 @@
error[E0261]: use of undeclared lifetime name `'test`
--> $DIR/no_introducing_in_band_in_locals.rs:15:13
|
15 | let y: &'test u32 = x;
| ^^^^^ undeclared lifetime
error[E0261]: use of undeclared lifetime name `'test`
--> $DIR/no_introducing_in_band_in_locals.rs:20:16
|
20 | let y: fn(&'test u32) = foo2;
| ^^^^^ undeclared lifetime
error: aborting due to 2 previous errors

View file

@ -0,0 +1,21 @@
// 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(in_band_lifetimes)]
struct Foo<T>(T);
impl Foo<&'s u8> {
fn bar<'s>(&self, x: &'s u8) {}
fn baz(x: for<'s> fn(&'s u32)) {}
}
fn main() {}

View file

@ -0,0 +1,19 @@
error[E0496]: lifetime name `'s` shadows a lifetime name that is already in scope
--> $DIR/shadow.rs:17:12
|
16 | impl Foo<&'s u8> {
| -- first declared here
17 | fn bar<'s>(&self, x: &'s u8) {}
| ^^ lifetime 's already in scope
error[E0496]: lifetime name `'s` shadows a lifetime name that is already in scope
--> $DIR/shadow.rs:18:19
|
16 | impl Foo<&'s u8> {
| -- first declared here
17 | fn bar<'s>(&self, x: &'s u8) {}
18 | fn baz(x: for<'s> fn(&'s u32)) {}
| ^^ lifetime 's already in scope
error: aborting due to 2 previous errors