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

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