Implement in-band lifetime bindings
This commit is contained in:
parent
1dc0b573e7
commit
91b7920c09
33 changed files with 1026 additions and 136 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
});
|
||||
|
|
|
@ -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, _) => {
|
||||
|
|
|
@ -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(¶ms.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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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! (
|
||||
|
|
72
src/test/compile-fail/feature-gate-in_band_lifetimes.rs
Normal file
72
src/test/compile-fail/feature-gate-in_band_lifetimes.rs
Normal 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() {}
|
84
src/test/run-pass/in-band-lifetimes.rs
Normal file
84
src/test/run-pass/in-band-lifetimes.rs
Normal 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() {}
|
26
src/test/ui/in-band-lifetimes/E0687.rs
Normal file
26
src/test/ui/in-band-lifetimes/E0687.rs
Normal 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() {}
|
26
src/test/ui/in-band-lifetimes/E0687.stderr
Normal file
26
src/test/ui/in-band-lifetimes/E0687.stderr
Normal 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
|
||||
|
18
src/test/ui/in-band-lifetimes/E0687_where.rs
Normal file
18
src/test/ui/in-band-lifetimes/E0687_where.rs
Normal 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() {}
|
14
src/test/ui/in-band-lifetimes/E0687_where.stderr
Normal file
14
src/test/ui/in-band-lifetimes/E0687_where.stderr
Normal 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
|
||||
|
26
src/test/ui/in-band-lifetimes/E0688.rs
Normal file
26
src/test/ui/in-band-lifetimes/E0688.rs
Normal 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() {}
|
26
src/test/ui/in-band-lifetimes/E0688.stderr
Normal file
26
src/test/ui/in-band-lifetimes/E0688.stderr
Normal 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
|
||||
|
18
src/test/ui/in-band-lifetimes/mismatched.rs
Normal file
18
src/test/ui/in-band-lifetimes/mismatched.rs
Normal 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() {}
|
18
src/test/ui/in-band-lifetimes/mismatched.stderr
Normal file
18
src/test/ui/in-band-lifetimes/mismatched.stderr
Normal 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
|
||||
|
20
src/test/ui/in-band-lifetimes/mismatched_trait.rs
Normal file
20
src/test/ui/in-band-lifetimes/mismatched_trait.rs
Normal 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() {}
|
10
src/test/ui/in-band-lifetimes/mismatched_trait.stderr
Normal file
10
src/test/ui/in-band-lifetimes/mismatched_trait.stderr
Normal 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
|
||||
|
24
src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs
Normal file
24
src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs
Normal 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() {}
|
39
src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
Normal file
39
src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
Normal 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
|
||||
|
21
src/test/ui/in-band-lifetimes/mut_while_borrow.rs
Normal file
21
src/test/ui/in-band-lifetimes/mut_while_borrow.rs
Normal 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);
|
||||
}
|
10
src/test/ui/in-band-lifetimes/mut_while_borrow.stderr
Normal file
10
src/test/ui/in-band-lifetimes/mut_while_borrow.stderr
Normal 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
|
||||
|
22
src/test/ui/in-band-lifetimes/no_in_band_in_struct.rs
Normal file
22
src/test/ui/in-band-lifetimes/no_in_band_in_struct.rs
Normal 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() {}
|
14
src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr
Normal file
14
src/test/ui/in-band-lifetimes/no_in_band_in_struct.stderr
Normal 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
|
||||
|
|
@ -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() {}
|
|
@ -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
|
||||
|
21
src/test/ui/in-band-lifetimes/shadow.rs
Normal file
21
src/test/ui/in-band-lifetimes/shadow.rs
Normal 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() {}
|
19
src/test/ui/in-band-lifetimes/shadow.stderr
Normal file
19
src/test/ui/in-band-lifetimes/shadow.stderr
Normal 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
|
||||
|
Loading…
Reference in a new issue