Auto merge of #49251 - nikomatsakis:issue-15872-elision-impl-header, r=cramertj
support elision in impl headers You can now do things like: ``` impl MyTrait<'_> for &u32 { ... } ``` Each `'_` or elided lifetime is a fresh parameter. `'_` and elision are still not permitted in associated type values. (Plausibly we could support that if there is a single input lifetime.) The original lifetime elision RFC was a bit unclear on this point: [as documented here, I think this is the correct interpretation, both because it fits existing impls and it's most analogous to the behavior in fns](https://github.com/rust-lang/rust/issues/15872#issuecomment-338700138). We do not support elision with deprecated forms: ``` impl MyTrait for std::cell::Ref<u32> { } // ERROR ``` Builds on the in-band lifetime stuff. r? @cramertj Fixes #15872
This commit is contained in:
commit
b4aa80dd73
20 changed files with 2081 additions and 1107 deletions
|
@ -420,7 +420,10 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
|
||||||
LifetimeName::Name(name) => {
|
LifetimeName::Name(name) => {
|
||||||
visitor.visit_name(lifetime.span, name);
|
visitor.visit_name(lifetime.span, name);
|
||||||
}
|
}
|
||||||
LifetimeName::Static | LifetimeName::Implicit | LifetimeName::Underscore => {}
|
LifetimeName::Fresh(_) |
|
||||||
|
LifetimeName::Static |
|
||||||
|
LifetimeName::Implicit |
|
||||||
|
LifetimeName::Underscore => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -203,9 +203,31 @@ pub struct Lifetime {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
|
#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
|
||||||
pub enum LifetimeName {
|
pub enum LifetimeName {
|
||||||
|
/// User typed nothing. e.g. the lifetime in `&u32`.
|
||||||
Implicit,
|
Implicit,
|
||||||
|
|
||||||
|
/// User typed `'_`.
|
||||||
Underscore,
|
Underscore,
|
||||||
|
|
||||||
|
/// Synthetic name generated when user elided a lifetime in an impl header,
|
||||||
|
/// e.g. the lifetimes in cases like these:
|
||||||
|
///
|
||||||
|
/// impl Foo for &u32
|
||||||
|
/// impl Foo<'_> for u32
|
||||||
|
///
|
||||||
|
/// in that case, we rewrite to
|
||||||
|
///
|
||||||
|
/// impl<'f> Foo for &'f u32
|
||||||
|
/// impl<'f> Foo<'f> for u32
|
||||||
|
///
|
||||||
|
/// where `'f` is something like `Fresh(0)`. The indices are
|
||||||
|
/// unique per impl, but not necessarily continuous.
|
||||||
|
Fresh(usize),
|
||||||
|
|
||||||
|
/// User wrote `'static`
|
||||||
Static,
|
Static,
|
||||||
|
|
||||||
|
/// Some user-given name like `'x`
|
||||||
Name(Name),
|
Name(Name),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,7 +236,7 @@ impl LifetimeName {
|
||||||
use self::LifetimeName::*;
|
use self::LifetimeName::*;
|
||||||
match *self {
|
match *self {
|
||||||
Implicit => keywords::Invalid.name(),
|
Implicit => keywords::Invalid.name(),
|
||||||
Underscore => keywords::UnderscoreLifetime.name(),
|
Fresh(_) | Underscore => keywords::UnderscoreLifetime.name(),
|
||||||
Static => keywords::StaticLifetime.name(),
|
Static => keywords::StaticLifetime.name(),
|
||||||
Name(name) => name,
|
Name(name) => name,
|
||||||
}
|
}
|
||||||
|
@ -235,7 +257,13 @@ impl Lifetime {
|
||||||
use self::LifetimeName::*;
|
use self::LifetimeName::*;
|
||||||
match self.name {
|
match self.name {
|
||||||
Implicit | Underscore => true,
|
Implicit | Underscore => true,
|
||||||
Static | Name(_) => false,
|
|
||||||
|
// It might seem surprising that `Fresh(_)` counts as
|
||||||
|
// *not* elided -- but this is because, as far as the code
|
||||||
|
// in the compiler is concerned -- `Fresh(_)` variants act
|
||||||
|
// equivalently to "some fresh name". They correspond to
|
||||||
|
// early-bound regions on an impl, in other words.
|
||||||
|
Fresh(_) | Static | Name(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::ImplItemId {
|
||||||
impl_stable_hash_for!(enum hir::LifetimeName {
|
impl_stable_hash_for!(enum hir::LifetimeName {
|
||||||
Implicit,
|
Implicit,
|
||||||
Underscore,
|
Underscore,
|
||||||
|
Fresh(index),
|
||||||
Static,
|
Static,
|
||||||
Name(name)
|
Name(name)
|
||||||
});
|
});
|
||||||
|
|
|
@ -31,6 +31,7 @@ use syntax::ptr::P;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
use errors::DiagnosticBuilder;
|
use errors::DiagnosticBuilder;
|
||||||
use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
|
use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
|
||||||
|
use session::Session;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use rustc::lint;
|
use rustc::lint;
|
||||||
|
|
||||||
|
@ -468,11 +469,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
fn visit_item(&mut self, item: &'tcx hir::Item) {
|
fn visit_item(&mut self, item: &'tcx hir::Item) {
|
||||||
match item.node {
|
match item.node {
|
||||||
hir::ItemFn(ref decl, _, _, _, ref generics, _) => {
|
hir::ItemFn(ref decl, _, _, _, ref generics, _) => {
|
||||||
self.visit_early_late(None,
|
self.visit_early_late(None, decl, generics, |this| {
|
||||||
decl,
|
intravisit::walk_item(this, item);
|
||||||
generics,
|
|
||||||
|this| {
|
|
||||||
intravisit::walk_item(this, item);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,7 +503,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
let lifetimes = generics.lifetimes()
|
let lifetimes = generics
|
||||||
|
.lifetimes()
|
||||||
.map(|def| Region::early(&self.tcx.hir, &mut index, def))
|
.map(|def| Region::early(&self.tcx.hir, &mut index, def))
|
||||||
.collect();
|
.collect();
|
||||||
let next_early_index = index + generics.ty_params().count() as u32;
|
let next_early_index = index + generics.ty_params().count() as u32;
|
||||||
|
@ -526,12 +525,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
|
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
|
||||||
match item.node {
|
match item.node {
|
||||||
hir::ForeignItemFn(ref decl, _, ref generics) => {
|
hir::ForeignItemFn(ref decl, _, ref generics) => {
|
||||||
self.visit_early_late(None,
|
self.visit_early_late(None, decl, generics, |this| {
|
||||||
decl,
|
intravisit::walk_foreign_item(this, item);
|
||||||
generics,
|
})
|
||||||
|this| {
|
|
||||||
intravisit::walk_foreign_item(this, item);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
hir::ForeignItemStatic(..) => {
|
hir::ForeignItemStatic(..) => {
|
||||||
intravisit::walk_foreign_item(self, item);
|
intravisit::walk_foreign_item(self, item);
|
||||||
|
@ -586,7 +582,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
// cc #48468
|
// cc #48468
|
||||||
self.resolve_elided_lifetimes(slice::from_ref(lifetime), false)
|
self.resolve_elided_lifetimes(slice::from_ref(lifetime), false)
|
||||||
}
|
}
|
||||||
LifetimeName::Static | LifetimeName::Name(_) => {
|
LifetimeName::Fresh(_) | LifetimeName::Static | LifetimeName::Name(_) => {
|
||||||
// If the user wrote an explicit name, use that.
|
// If the user wrote an explicit name, use that.
|
||||||
self.visit_lifetime(lifetime);
|
self.visit_lifetime(lifetime);
|
||||||
}
|
}
|
||||||
|
@ -670,7 +666,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
if let Some(elision_region) = elision {
|
if let Some(elision_region) = elision {
|
||||||
let scope = Scope::Elision {
|
let scope = Scope::Elision {
|
||||||
elide: Elide::Exact(elision_region),
|
elide: Elide::Exact(elision_region),
|
||||||
s: self.scope
|
s: self.scope,
|
||||||
};
|
};
|
||||||
self.with(scope, |_old_scope, this| {
|
self.with(scope, |_old_scope, this| {
|
||||||
let scope = Scope::Binder {
|
let scope = Scope::Binder {
|
||||||
|
@ -716,12 +712,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
&trait_item.generics,
|
&trait_item.generics,
|
||||||
|this| intravisit::walk_trait_item(this, trait_item),
|
|this| intravisit::walk_trait_item(this, trait_item),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
Type(ref bounds, ref ty) => {
|
Type(ref bounds, ref ty) => {
|
||||||
let generics = &trait_item.generics;
|
let generics = &trait_item.generics;
|
||||||
let mut index = self.next_early_index();
|
let mut index = self.next_early_index();
|
||||||
debug!("visit_ty: index = {}", index);
|
debug!("visit_ty: index = {}", index);
|
||||||
let lifetimes = generics.lifetimes()
|
let lifetimes = generics
|
||||||
|
.lifetimes()
|
||||||
.map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
|
.map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -741,12 +738,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
this.visit_ty(ty);
|
this.visit_ty(ty);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
Const(_, _) => {
|
Const(_, _) => {
|
||||||
// Only methods and types support generics.
|
// Only methods and types support generics.
|
||||||
assert!(trait_item.generics.params.is_empty());
|
assert!(trait_item.generics.params.is_empty());
|
||||||
intravisit::walk_trait_item(self, trait_item);
|
intravisit::walk_trait_item(self, trait_item);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,12 +758,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
&impl_item.generics,
|
&impl_item.generics,
|
||||||
|this| intravisit::walk_impl_item(this, impl_item),
|
|this| intravisit::walk_impl_item(this, impl_item),
|
||||||
)
|
)
|
||||||
},
|
}
|
||||||
Type(ref ty) => {
|
Type(ref ty) => {
|
||||||
let generics = &impl_item.generics;
|
let generics = &impl_item.generics;
|
||||||
let mut index = self.next_early_index();
|
let mut index = self.next_early_index();
|
||||||
debug!("visit_ty: index = {}", index);
|
debug!("visit_ty: index = {}", index);
|
||||||
let lifetimes = generics.lifetimes()
|
let lifetimes = generics
|
||||||
|
.lifetimes()
|
||||||
.map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
|
.map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -781,12 +779,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
this.visit_generics(generics);
|
this.visit_generics(generics);
|
||||||
this.visit_ty(ty);
|
this.visit_ty(ty);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
Const(_, _) => {
|
Const(_, _) => {
|
||||||
// Only methods and types support generics.
|
// Only methods and types support generics.
|
||||||
assert!(impl_item.generics.params.is_empty());
|
assert!(impl_item.generics.params.is_empty());
|
||||||
intravisit::walk_impl_item(self, impl_item);
|
intravisit::walk_impl_item(self, impl_item);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,7 +820,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
|
fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
|
||||||
check_mixed_explicit_and_in_band_defs(
|
check_mixed_explicit_and_in_band_defs(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
&generics.lifetimes().cloned().collect::<Vec<_>>()
|
&generics.lifetimes().cloned().collect::<Vec<_>>(),
|
||||||
);
|
);
|
||||||
for ty_param in generics.ty_params() {
|
for ty_param in generics.ty_params() {
|
||||||
walk_list!(self, visit_ty_param_bound, &ty_param.bounds);
|
walk_list!(self, visit_ty_param_bound, &ty_param.bounds);
|
||||||
|
@ -842,7 +840,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
self.trait_ref_hack = true;
|
self.trait_ref_hack = true;
|
||||||
let next_early_index = self.next_early_index();
|
let next_early_index = self.next_early_index();
|
||||||
let scope = Scope::Binder {
|
let scope = Scope::Binder {
|
||||||
lifetimes: bound_generic_params.lifetimes()
|
lifetimes: bound_generic_params
|
||||||
|
.lifetimes()
|
||||||
.map(|def| Region::late(&self.tcx.hir, def))
|
.map(|def| Region::late(&self.tcx.hir, def))
|
||||||
.collect(),
|
.collect(),
|
||||||
s: self.scope,
|
s: self.scope,
|
||||||
|
@ -890,8 +889,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
) {
|
) {
|
||||||
debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
|
debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
|
||||||
|
|
||||||
if !self.trait_ref_hack ||
|
if !self.trait_ref_hack
|
||||||
trait_ref.bound_generic_params.iter().any(|p| p.is_lifetime_param())
|
|| trait_ref
|
||||||
|
.bound_generic_params
|
||||||
|
.iter()
|
||||||
|
.any(|p| p.is_lifetime_param())
|
||||||
{
|
{
|
||||||
if self.trait_ref_hack {
|
if self.trait_ref_hack {
|
||||||
span_err!(
|
span_err!(
|
||||||
|
@ -903,7 +905,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
let next_early_index = self.next_early_index();
|
let next_early_index = self.next_early_index();
|
||||||
let scope = Scope::Binder {
|
let scope = Scope::Binder {
|
||||||
lifetimes: trait_ref.bound_generic_params
|
lifetimes: trait_ref
|
||||||
|
.bound_generic_params
|
||||||
.lifetimes()
|
.lifetimes()
|
||||||
.map(|def| Region::late(&self.tcx.hir, def))
|
.map(|def| Region::late(&self.tcx.hir, def))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -1144,7 +1147,8 @@ fn compute_object_lifetime_defaults(
|
||||||
.map(|set| match *set {
|
.map(|set| match *set {
|
||||||
Set1::Empty => "BaseDefault".to_string(),
|
Set1::Empty => "BaseDefault".to_string(),
|
||||||
Set1::One(Region::Static) => "'static".to_string(),
|
Set1::One(Region::Static) => "'static".to_string(),
|
||||||
Set1::One(Region::EarlyBound(i, _, _)) => generics.lifetimes()
|
Set1::One(Region::EarlyBound(i, _, _)) => generics
|
||||||
|
.lifetimes()
|
||||||
.nth(i as usize)
|
.nth(i as usize)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.lifetime
|
.lifetime
|
||||||
|
@ -1182,7 +1186,8 @@ fn object_lifetime_defaults_for_item(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
generics.ty_params()
|
generics
|
||||||
|
.ty_params()
|
||||||
.map(|param| {
|
.map(|param| {
|
||||||
let mut set = Set1::Empty;
|
let mut set = Set1::Empty;
|
||||||
|
|
||||||
|
@ -1278,17 +1283,21 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
if let hir::map::NodeLifetime(hir_lifetime) = this.tcx.hir.get(node_id) {
|
if let hir::map::NodeLifetime(hir_lifetime) = this.tcx.hir.get(node_id) {
|
||||||
let span = hir_lifetime.span;
|
let span = hir_lifetime.span;
|
||||||
let id = hir_lifetime.id;
|
let id = hir_lifetime.id;
|
||||||
debug!("id ={:?} span = {:?} hir_lifetime = {:?}",
|
debug!(
|
||||||
node_id,
|
"id ={:?} span = {:?} hir_lifetime = {:?}",
|
||||||
span,
|
node_id, span, hir_lifetime
|
||||||
hir_lifetime);
|
);
|
||||||
|
|
||||||
this.tcx
|
this.tcx
|
||||||
.struct_span_lint_node(lint::builtin::SINGLE_USE_LIFETIME,
|
.struct_span_lint_node(
|
||||||
id,
|
lint::builtin::SINGLE_USE_LIFETIME,
|
||||||
span,
|
id,
|
||||||
&format!("lifetime name `{}` only used once",
|
span,
|
||||||
hir_lifetime.name.name()))
|
&format!(
|
||||||
|
"lifetime name `{}` only used once",
|
||||||
|
hir_lifetime.name.name()
|
||||||
|
),
|
||||||
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1379,8 +1388,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
next_early_index,
|
next_early_index,
|
||||||
abstract_type_parent,
|
abstract_type_parent,
|
||||||
..
|
..
|
||||||
} if (!only_abstract_type_parent || abstract_type_parent)
|
} if (!only_abstract_type_parent || abstract_type_parent) =>
|
||||||
=> return next_early_index,
|
{
|
||||||
|
return next_early_index
|
||||||
|
}
|
||||||
|
|
||||||
Scope::Binder { s, .. }
|
Scope::Binder { s, .. }
|
||||||
| Scope::Body { s, .. }
|
| Scope::Body { s, .. }
|
||||||
|
@ -1698,8 +1709,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
|
// Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
|
||||||
hir::map::NodeForeignItem(_) | hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) =>
|
hir::map::NodeForeignItem(_) | hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) => None,
|
||||||
None,
|
|
||||||
// Everything else (only closures?) doesn't
|
// Everything else (only closures?) doesn't
|
||||||
// actually enjoy elision in return types.
|
// actually enjoy elision in return types.
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -1894,7 +1904,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
lint::builtin::ELIDED_LIFETIME_IN_PATH,
|
lint::builtin::ELIDED_LIFETIME_IN_PATH,
|
||||||
id,
|
id,
|
||||||
span,
|
span,
|
||||||
&format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"))
|
&format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"),
|
||||||
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
let error = loop {
|
let error = loop {
|
||||||
|
@ -1933,25 +1944,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut err = struct_span_err!(
|
let mut err = report_missing_lifetime_specifiers(self.tcx.sess, span, lifetime_refs.len());
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
|
||||||
E0106,
|
|
||||||
"missing lifetime specifier{}",
|
|
||||||
if lifetime_refs.len() > 1 { "s" } else { "" }
|
|
||||||
);
|
|
||||||
let msg = if lifetime_refs.len() > 1 {
|
|
||||||
format!("expected {} lifetime parameters", lifetime_refs.len())
|
|
||||||
} else {
|
|
||||||
format!("expected lifetime parameter")
|
|
||||||
};
|
|
||||||
err.span_label(span, msg);
|
|
||||||
|
|
||||||
if let Some(params) = error {
|
if let Some(params) = error {
|
||||||
if lifetime_refs.len() == 1 {
|
if lifetime_refs.len() == 1 {
|
||||||
self.report_elision_failure(&mut err, params);
|
self.report_elision_failure(&mut err, params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2086,7 +2086,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
hir::LifetimeName::Implicit | hir::LifetimeName::Name(_) => {}
|
hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
|
||||||
|
hir::LifetimeName::Name(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2138,7 +2139,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
))
|
))
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
hir::LifetimeName::Implicit | hir::LifetimeName::Name(_) => {
|
hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
|
||||||
|
hir::LifetimeName::Name(_) => {
|
||||||
self.resolve_lifetime_ref(bound);
|
self.resolve_lifetime_ref(bound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2146,9 +2148,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_lifetime_def_for_shadowing(&self,
|
fn check_lifetime_def_for_shadowing(
|
||||||
mut old_scope: ScopeRef,
|
&self,
|
||||||
lifetime: &'tcx hir::Lifetime) {
|
mut old_scope: ScopeRef,
|
||||||
|
lifetime: &'tcx hir::Lifetime,
|
||||||
|
) {
|
||||||
for &(label, label_span) in &self.labels_in_fn {
|
for &(label, label_span) in &self.labels_in_fn {
|
||||||
// FIXME (#24278): non-hygienic comparison
|
// FIXME (#24278): non-hygienic comparison
|
||||||
if lifetime.name.name() == label {
|
if lifetime.name.name() == label {
|
||||||
|
@ -2216,14 +2220,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
self.map.defs.insert(lifetime_ref.id, def);
|
self.map.defs.insert(lifetime_ref.id, def);
|
||||||
|
|
||||||
match def {
|
match def {
|
||||||
Region::LateBoundAnon(..) |
|
Region::LateBoundAnon(..) | Region::Static => {
|
||||||
Region::Static => {
|
|
||||||
// These are anonymous lifetimes or lifetimes that are not declared.
|
// These are anonymous lifetimes or lifetimes that are not declared.
|
||||||
}
|
}
|
||||||
|
|
||||||
Region::Free(_, def_id) |
|
Region::Free(_, def_id)
|
||||||
Region::LateBound(_, def_id, _) |
|
| Region::LateBound(_, def_id, _)
|
||||||
Region::EarlyBound(_, def_id, _) => {
|
| Region::EarlyBound(_, def_id, _) => {
|
||||||
// A lifetime declared by the user.
|
// A lifetime declared by the user.
|
||||||
if !self.lifetime_uses.contains_key(&def_id) {
|
if !self.lifetime_uses.contains_key(&def_id) {
|
||||||
self.lifetime_uses
|
self.lifetime_uses
|
||||||
|
@ -2255,8 +2258,7 @@ fn insert_late_bound_lifetimes(
|
||||||
) {
|
) {
|
||||||
debug!(
|
debug!(
|
||||||
"insert_late_bound_lifetimes(decl={:?}, generics={:?})",
|
"insert_late_bound_lifetimes(decl={:?}, generics={:?})",
|
||||||
decl,
|
decl, generics
|
||||||
generics
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut constrained_by_input = ConstrainedCollector {
|
let mut constrained_by_input = ConstrainedCollector {
|
||||||
|
@ -2335,8 +2337,7 @@ fn insert_late_bound_lifetimes(
|
||||||
debug!(
|
debug!(
|
||||||
"insert_late_bound_lifetimes: \
|
"insert_late_bound_lifetimes: \
|
||||||
lifetime {:?} with id {:?} is late-bound",
|
lifetime {:?} with id {:?} is late-bound",
|
||||||
lifetime.lifetime.name,
|
lifetime.lifetime.name, lifetime.lifetime.id
|
||||||
lifetime.lifetime.id
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let inserted = map.late_bound.insert(lifetime.lifetime.id);
|
let inserted = map.late_bound.insert(lifetime.lifetime.id);
|
||||||
|
@ -2403,3 +2404,27 @@ fn insert_late_bound_lifetimes(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn report_missing_lifetime_specifiers(
|
||||||
|
sess: &Session,
|
||||||
|
span: Span,
|
||||||
|
count: usize,
|
||||||
|
) -> DiagnosticBuilder<'_> {
|
||||||
|
let mut err = struct_span_err!(
|
||||||
|
sess,
|
||||||
|
span,
|
||||||
|
E0106,
|
||||||
|
"missing lifetime specifier{}",
|
||||||
|
if count > 1 { "s" } else { "" }
|
||||||
|
);
|
||||||
|
|
||||||
|
let msg = if count > 1 {
|
||||||
|
format!("expected {} lifetime parameters", count)
|
||||||
|
} else {
|
||||||
|
format!("expected lifetime parameter")
|
||||||
|
};
|
||||||
|
|
||||||
|
err.span_label(span, msg);
|
||||||
|
|
||||||
|
err
|
||||||
|
}
|
||||||
|
|
22
src/test/ui/feature-gate-in_band_lifetimes-impl.rs
Normal file
22
src/test/ui/feature-gate-in_band_lifetimes-impl.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(underscore_lifetimes)]
|
||||||
|
|
||||||
|
trait MyTrait<'a> { }
|
||||||
|
|
||||||
|
impl<'a> MyTrait<'a> for &u32 { }
|
||||||
|
//~^ ERROR missing lifetime specifier
|
||||||
|
|
||||||
|
impl<'a> MyTrait<'_> for &'a f32 { }
|
||||||
|
//~^ ERROR missing lifetime specifier
|
||||||
|
|
||||||
|
fn main() {}
|
15
src/test/ui/feature-gate-in_band_lifetimes-impl.stderr
Normal file
15
src/test/ui/feature-gate-in_band_lifetimes-impl.stderr
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
error[E0106]: missing lifetime specifier
|
||||||
|
--> $DIR/feature-gate-in_band_lifetimes-impl.rs:16:26
|
||||||
|
|
|
||||||
|
LL | impl<'a> MyTrait<'a> for &u32 { }
|
||||||
|
| ^ expected lifetime parameter
|
||||||
|
|
||||||
|
error[E0106]: missing lifetime specifier
|
||||||
|
--> $DIR/feature-gate-in_band_lifetimes-impl.rs:19:18
|
||||||
|
|
|
||||||
|
LL | impl<'a> MyTrait<'_> for &'a f32 { }
|
||||||
|
| ^^ expected lifetime parameter
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0106`.
|
38
src/test/ui/in-band-lifetimes/impl/assoc-type.rs
Normal file
38
src/test/ui/in-band-lifetimes/impl/assoc-type.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that we do not yet support elision in associated types, even
|
||||||
|
// when there is just one name we could take from the impl header.
|
||||||
|
|
||||||
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
#![feature(in_band_lifetimes)]
|
||||||
|
#![feature(underscore_lifetimes)]
|
||||||
|
|
||||||
|
trait MyTrait {
|
||||||
|
type Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyTrait for &i32 {
|
||||||
|
type Output = &i32;
|
||||||
|
//~^ ERROR missing lifetime specifier
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyTrait for &u32 {
|
||||||
|
type Output = &'_ i32;
|
||||||
|
//~^ ERROR missing lifetime specifier
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is what you have to do:
|
||||||
|
impl MyTrait for &'a f32 {
|
||||||
|
type Output = &'a f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
15
src/test/ui/in-band-lifetimes/impl/assoc-type.stderr
Normal file
15
src/test/ui/in-band-lifetimes/impl/assoc-type.stderr
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
error[E0106]: missing lifetime specifier
|
||||||
|
--> $DIR/assoc-type.rs:24:19
|
||||||
|
|
|
||||||
|
LL | type Output = &i32;
|
||||||
|
| ^ expected lifetime parameter
|
||||||
|
|
||||||
|
error[E0106]: missing lifetime specifier
|
||||||
|
--> $DIR/assoc-type.rs:29:20
|
||||||
|
|
|
||||||
|
LL | type Output = &'_ i32;
|
||||||
|
| ^^ expected lifetime parameter
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0106`.
|
45
src/test/ui/in-band-lifetimes/impl/dyn-trait.rs
Normal file
45
src/test/ui/in-band-lifetimes/impl/dyn-trait.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that `impl MyTrait<'_> for &i32` is equivalent to `impl<'a,
|
||||||
|
// 'b> MyTrait<'a> for &'b i32`.
|
||||||
|
|
||||||
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
#![feature(dyn_trait)]
|
||||||
|
#![feature(in_band_lifetimes)]
|
||||||
|
#![feature(underscore_lifetimes)]
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
// Equivalent to `Box<dyn Debug + 'static>`:
|
||||||
|
trait StaticTrait { }
|
||||||
|
impl StaticTrait for Box<dyn Debug> { }
|
||||||
|
|
||||||
|
// Equivalent to `Box<dyn Debug + 'static>`:
|
||||||
|
trait NotStaticTrait { }
|
||||||
|
impl NotStaticTrait for Box<dyn Debug + '_> { }
|
||||||
|
|
||||||
|
fn static_val<T: StaticTrait>(_: T) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
|
||||||
|
static_val(x); //~ ERROR cannot infer
|
||||||
|
}
|
||||||
|
|
||||||
|
fn not_static_val<T: NotStaticTrait>(_: T) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_dyn_debug_not_static<'a>(x: Box<dyn Debug + 'a>) {
|
||||||
|
not_static_val(x); // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
22
src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr
Normal file
22
src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
|
||||||
|
--> $DIR/dyn-trait.rs:34:16
|
||||||
|
|
|
||||||
|
LL | static_val(x); //~ ERROR cannot infer
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 33:1...
|
||||||
|
--> $DIR/dyn-trait.rs:33:1
|
||||||
|
|
|
||||||
|
LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= note: ...so that the expression is assignable:
|
||||||
|
expected std::boxed::Box<std::fmt::Debug>
|
||||||
|
found std::boxed::Box<std::fmt::Debug + 'a>
|
||||||
|
= note: but, the lifetime must be valid for the static lifetime...
|
||||||
|
= note: ...so that the types are compatible:
|
||||||
|
expected StaticTrait
|
||||||
|
found StaticTrait
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0495`.
|
23
src/test/ui/in-band-lifetimes/impl/path-elided.rs
Normal file
23
src/test/ui/in-band-lifetimes/impl/path-elided.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
#![feature(in_band_lifetimes)]
|
||||||
|
#![feature(underscore_lifetimes)]
|
||||||
|
|
||||||
|
trait MyTrait { }
|
||||||
|
|
||||||
|
struct Foo<'a> { x: &'a u32 }
|
||||||
|
|
||||||
|
impl MyTrait for Foo {
|
||||||
|
//~^ ERROR missing lifetime specifier
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
9
src/test/ui/in-band-lifetimes/impl/path-elided.stderr
Normal file
9
src/test/ui/in-band-lifetimes/impl/path-elided.stderr
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0106]: missing lifetime specifier
|
||||||
|
--> $DIR/path-elided.rs:19:18
|
||||||
|
|
|
||||||
|
LL | impl MyTrait for Foo {
|
||||||
|
| ^^^ expected lifetime parameter
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0106`.
|
47
src/test/ui/in-band-lifetimes/impl/path-underscore.rs
Normal file
47
src/test/ui/in-band-lifetimes/impl/path-underscore.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that `impl MyTrait for Foo<'_>` works.
|
||||||
|
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
#![feature(in_band_lifetimes)]
|
||||||
|
#![feature(underscore_lifetimes)]
|
||||||
|
|
||||||
|
trait MyTrait { }
|
||||||
|
|
||||||
|
struct Foo<'a> { x: &'a u32 }
|
||||||
|
|
||||||
|
impl MyTrait for Foo<'_> {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn impls_my_trait<T: MyTrait>() { }
|
||||||
|
|
||||||
|
fn impls_my_trait_val<T: MyTrait>(_: T) {
|
||||||
|
impls_my_trait::<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_where_clause()
|
||||||
|
where for<'a> Foo<'a>: MyTrait { }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = 22;
|
||||||
|
let f = Foo { x: &x };
|
||||||
|
|
||||||
|
// This type is `Foo<'x>` for a local lifetime `'x`; so the impl
|
||||||
|
// must apply to any lifetime to apply to this.
|
||||||
|
impls_my_trait_val(f);
|
||||||
|
|
||||||
|
impls_my_trait::<Foo<'static>>();
|
||||||
|
|
||||||
|
random_where_clause();
|
||||||
|
}
|
43
src/test/ui/in-band-lifetimes/impl/ref-underscore.rs
Normal file
43
src/test/ui/in-band-lifetimes/impl/ref-underscore.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that `impl MyTrait for &i32` works and is equivalent to any lifetime.
|
||||||
|
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
#![feature(in_band_lifetimes)]
|
||||||
|
#![feature(underscore_lifetimes)]
|
||||||
|
|
||||||
|
trait MyTrait { }
|
||||||
|
|
||||||
|
impl MyTrait for &i32 {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn impls_my_trait<T: MyTrait>() { }
|
||||||
|
|
||||||
|
fn impls_my_trait_val<T: MyTrait>(_: T) {
|
||||||
|
impls_my_trait::<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_where_clause()
|
||||||
|
where for<'a> &'a i32: MyTrait { }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = 22;
|
||||||
|
let f = &x;
|
||||||
|
|
||||||
|
impls_my_trait_val(f);
|
||||||
|
|
||||||
|
impls_my_trait::<&'static i32>();
|
||||||
|
|
||||||
|
random_where_clause();
|
||||||
|
}
|
21
src/test/ui/in-band-lifetimes/impl/trait-elided.rs
Normal file
21
src/test/ui/in-band-lifetimes/impl/trait-elided.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
#![feature(in_band_lifetimes)]
|
||||||
|
#![feature(underscore_lifetimes)]
|
||||||
|
|
||||||
|
trait MyTrait<'a> { }
|
||||||
|
|
||||||
|
impl MyTrait for u32 {
|
||||||
|
//~^ ERROR missing lifetime specifier
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
9
src/test/ui/in-band-lifetimes/impl/trait-elided.stderr
Normal file
9
src/test/ui/in-band-lifetimes/impl/trait-elided.stderr
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0106]: missing lifetime specifier
|
||||||
|
--> $DIR/trait-elided.rs:17:6
|
||||||
|
|
|
||||||
|
LL | impl MyTrait for u32 {
|
||||||
|
| ^^^^^^^ expected lifetime parameter
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0106`.
|
48
src/test/ui/in-band-lifetimes/impl/trait-underscore.rs
Normal file
48
src/test/ui/in-band-lifetimes/impl/trait-underscore.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that `impl MyTrait<'_> for &i32` is equivalent to `impl<'a,
|
||||||
|
// 'b> MyTrait<'a> for &'b i32`.
|
||||||
|
//
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
#![feature(in_band_lifetimes)]
|
||||||
|
#![feature(underscore_lifetimes)]
|
||||||
|
|
||||||
|
trait MyTrait<'a> { }
|
||||||
|
|
||||||
|
// This is equivalent to `MyTrait<'a> for &'b i32`, which is proven by
|
||||||
|
// the code below.
|
||||||
|
impl MyTrait<'_> for &i32 {
|
||||||
|
}
|
||||||
|
|
||||||
|
// When called, T will be `&'x i32` for some `'x`, so since we can
|
||||||
|
// prove that `&'x i32: for<'a> MyTrait<'a>, then we know that the
|
||||||
|
// lifetime parameter above is disconnected.
|
||||||
|
fn impls_my_trait<T: for<'a> MyTrait<'a>>() { }
|
||||||
|
|
||||||
|
fn impls_my_trait_val<T: for<'a> MyTrait<'a>>(_: T) {
|
||||||
|
impls_my_trait::<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_where_clause()
|
||||||
|
where for<'a, 'b> &'a i32: MyTrait<'b> { }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = 22;
|
||||||
|
let f = &x;
|
||||||
|
impls_my_trait_val(f);
|
||||||
|
|
||||||
|
impls_my_trait::<&'static i32>();
|
||||||
|
|
||||||
|
random_where_clause();
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Check that the `'_` in `dyn Trait + '_` acts like ordinary elision,
|
||||||
|
// and not like an object lifetime default.
|
||||||
|
//
|
||||||
|
// cc #48468
|
||||||
|
|
||||||
|
#![feature(dyn_trait)]
|
||||||
|
#![feature(underscore_lifetimes)]
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
x: Box<dyn Debug + '_>, //~ ERROR missing lifetime specifier
|
||||||
|
//~^ ERROR E0228
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -0,0 +1,16 @@
|
||||||
|
error[E0106]: missing lifetime specifier
|
||||||
|
--> $DIR/dyn-trait-underscore-in-struct.rs:22:24
|
||||||
|
|
|
||||||
|
LL | x: Box<dyn Debug + '_>, //~ ERROR missing lifetime specifier
|
||||||
|
| ^^ expected lifetime parameter
|
||||||
|
|
||||||
|
error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
|
||||||
|
--> $DIR/dyn-trait-underscore-in-struct.rs:22:12
|
||||||
|
|
|
||||||
|
LL | x: Box<dyn Debug + '_>, //~ ERROR missing lifetime specifier
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors occurred: E0106, E0228.
|
||||||
|
For more information about an error, try `rustc --explain E0106`.
|
Loading…
Add table
Add a link
Reference in a new issue