1
Fork 0

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:
bors 2018-03-24 13:23:17 +00:00
commit b4aa80dd73
20 changed files with 2081 additions and 1107 deletions

View file

@ -420,7 +420,10 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
LifetimeName::Name(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

View file

@ -203,9 +203,31 @@ pub struct Lifetime {
#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
pub enum LifetimeName {
/// User typed nothing. e.g. the lifetime in `&u32`.
Implicit,
/// User typed `'_`.
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,
/// Some user-given name like `'x`
Name(Name),
}
@ -214,7 +236,7 @@ impl LifetimeName {
use self::LifetimeName::*;
match *self {
Implicit => keywords::Invalid.name(),
Underscore => keywords::UnderscoreLifetime.name(),
Fresh(_) | Underscore => keywords::UnderscoreLifetime.name(),
Static => keywords::StaticLifetime.name(),
Name(name) => name,
}
@ -235,7 +257,13 @@ impl Lifetime {
use self::LifetimeName::*;
match self.name {
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,
}
}

View file

@ -145,6 +145,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::ImplItemId {
impl_stable_hash_for!(enum hir::LifetimeName {
Implicit,
Underscore,
Fresh(index),
Static,
Name(name)
});

View file

@ -31,6 +31,7 @@ use syntax::ptr::P;
use syntax_pos::Span;
use errors::DiagnosticBuilder;
use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
use session::Session;
use std::slice;
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) {
match item.node {
hir::ItemFn(ref decl, _, _, _, ref generics, _) => {
self.visit_early_late(None,
decl,
generics,
|this| {
intravisit::walk_item(this, item);
self.visit_early_late(None, decl, generics, |this| {
intravisit::walk_item(this, item);
});
}
@ -505,7 +503,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
} else {
0
};
let lifetimes = generics.lifetimes()
let lifetimes = generics
.lifetimes()
.map(|def| Region::early(&self.tcx.hir, &mut index, def))
.collect();
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) {
match item.node {
hir::ForeignItemFn(ref decl, _, ref generics) => {
self.visit_early_late(None,
decl,
generics,
|this| {
intravisit::walk_foreign_item(this, item);
})
self.visit_early_late(None, decl, generics, |this| {
intravisit::walk_foreign_item(this, item);
})
}
hir::ForeignItemStatic(..) => {
intravisit::walk_foreign_item(self, item);
@ -586,7 +582,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// cc #48468
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.
self.visit_lifetime(lifetime);
}
@ -670,7 +666,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
if let Some(elision_region) = elision {
let scope = Scope::Elision {
elide: Elide::Exact(elision_region),
s: self.scope
s: self.scope,
};
self.with(scope, |_old_scope, this| {
let scope = Scope::Binder {
@ -716,12 +712,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
&trait_item.generics,
|this| intravisit::walk_trait_item(this, trait_item),
);
},
}
Type(ref bounds, ref ty) => {
let generics = &trait_item.generics;
let mut index = self.next_early_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))
.collect();
@ -741,12 +738,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
this.visit_ty(ty);
}
});
},
}
Const(_, _) => {
// Only methods and types support generics.
assert!(trait_item.generics.params.is_empty());
intravisit::walk_trait_item(self, trait_item);
},
}
}
}
@ -761,12 +758,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
&impl_item.generics,
|this| intravisit::walk_impl_item(this, impl_item),
)
},
}
Type(ref ty) => {
let generics = &impl_item.generics;
let mut index = self.next_early_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))
.collect();
@ -781,12 +779,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
this.visit_generics(generics);
this.visit_ty(ty);
});
},
}
Const(_, _) => {
// Only methods and types support generics.
assert!(impl_item.generics.params.is_empty());
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) {
check_mixed_explicit_and_in_band_defs(
self.tcx,
&generics.lifetimes().cloned().collect::<Vec<_>>()
&generics.lifetimes().cloned().collect::<Vec<_>>(),
);
for ty_param in generics.ty_params() {
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;
let next_early_index = self.next_early_index();
let scope = Scope::Binder {
lifetimes: bound_generic_params.lifetimes()
lifetimes: bound_generic_params
.lifetimes()
.map(|def| Region::late(&self.tcx.hir, def))
.collect(),
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);
if !self.trait_ref_hack ||
trait_ref.bound_generic_params.iter().any(|p| p.is_lifetime_param())
if !self.trait_ref_hack
|| trait_ref
.bound_generic_params
.iter()
.any(|p| p.is_lifetime_param())
{
if self.trait_ref_hack {
span_err!(
@ -903,7 +905,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
}
let next_early_index = self.next_early_index();
let scope = Scope::Binder {
lifetimes: trait_ref.bound_generic_params
lifetimes: trait_ref
.bound_generic_params
.lifetimes()
.map(|def| Region::late(&self.tcx.hir, def))
.collect(),
@ -1144,7 +1147,8 @@ fn compute_object_lifetime_defaults(
.map(|set| match *set {
Set1::Empty => "BaseDefault".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)
.unwrap()
.lifetime
@ -1182,7 +1186,8 @@ fn object_lifetime_defaults_for_item(
}
}
generics.ty_params()
generics
.ty_params()
.map(|param| {
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) {
let span = hir_lifetime.span;
let id = hir_lifetime.id;
debug!("id ={:?} span = {:?} hir_lifetime = {:?}",
node_id,
span,
hir_lifetime);
debug!(
"id ={:?} span = {:?} hir_lifetime = {:?}",
node_id, span, hir_lifetime
);
this.tcx
.struct_span_lint_node(lint::builtin::SINGLE_USE_LIFETIME,
id,
span,
&format!("lifetime name `{}` only used once",
hir_lifetime.name.name()))
.struct_span_lint_node(
lint::builtin::SINGLE_USE_LIFETIME,
id,
span,
&format!(
"lifetime name `{}` only used once",
hir_lifetime.name.name()
),
)
.emit();
}
}
@ -1379,8 +1388,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
next_early_index,
abstract_type_parent,
..
} if (!only_abstract_type_parent || abstract_type_parent)
=> return next_early_index,
} if (!only_abstract_type_parent || abstract_type_parent) =>
{
return next_early_index
}
Scope::Binder { 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).
hir::map::NodeForeignItem(_) | hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) =>
None,
hir::map::NodeForeignItem(_) | hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) => None,
// Everything else (only closures?) doesn't
// actually enjoy elision in return types.
_ => {
@ -1894,7 +1904,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
lint::builtin::ELIDED_LIFETIME_IN_PATH,
id,
span,
&format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"))
&format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"),
)
.emit();
}
let error = loop {
@ -1933,25 +1944,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
};
let mut err = struct_span_err!(
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);
let mut err = report_missing_lifetime_specifiers(self.tcx.sess, span, lifetime_refs.len());
if let Some(params) = error {
if lifetime_refs.len() == 1 {
self.report_elision_failure(&mut err, params);
}
}
err.emit();
}
@ -2086,7 +2086,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
);
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();
}
hir::LifetimeName::Implicit | hir::LifetimeName::Name(_) => {
hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
hir::LifetimeName::Name(_) => {
self.resolve_lifetime_ref(bound);
}
}
@ -2146,9 +2148,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
}
fn check_lifetime_def_for_shadowing(&self,
mut old_scope: ScopeRef,
lifetime: &'tcx hir::Lifetime) {
fn check_lifetime_def_for_shadowing(
&self,
mut old_scope: ScopeRef,
lifetime: &'tcx hir::Lifetime,
) {
for &(label, label_span) in &self.labels_in_fn {
// FIXME (#24278): non-hygienic comparison
if lifetime.name.name() == label {
@ -2216,14 +2220,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
self.map.defs.insert(lifetime_ref.id, def);
match def {
Region::LateBoundAnon(..) |
Region::Static => {
Region::LateBoundAnon(..) | Region::Static => {
// These are anonymous lifetimes or lifetimes that are not declared.
}
Region::Free(_, def_id) |
Region::LateBound(_, def_id, _) |
Region::EarlyBound(_, def_id, _) => {
Region::Free(_, def_id)
| Region::LateBound(_, def_id, _)
| Region::EarlyBound(_, def_id, _) => {
// A lifetime declared by the user.
if !self.lifetime_uses.contains_key(&def_id) {
self.lifetime_uses
@ -2255,8 +2258,7 @@ fn insert_late_bound_lifetimes(
) {
debug!(
"insert_late_bound_lifetimes(decl={:?}, generics={:?})",
decl,
generics
decl, generics
);
let mut constrained_by_input = ConstrainedCollector {
@ -2335,8 +2337,7 @@ fn insert_late_bound_lifetimes(
debug!(
"insert_late_bound_lifetimes: \
lifetime {:?} with id {:?} is late-bound",
lifetime.lifetime.name,
lifetime.lifetime.id
lifetime.lifetime.name, 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
}

View file

@ -0,0 +1,22 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(warnings)]
#![feature(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() {}

View 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`.

View 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() { }

View 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`.

View 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() {
}

View 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`.

View 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() {}

View 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`.

View 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();
}

View 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();
}

View 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() {}

View 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`.

View 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();
}

View file

@ -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() { }

View file

@ -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`.