Skip to content

Commit

Permalink
permit '_ and &T in impl headers
Browse files Browse the repository at this point in the history
Deprecated forms of elision are not supported.
  • Loading branch information
nikomatsakis committed Mar 22, 2018
1 parent df70060 commit 94468da
Show file tree
Hide file tree
Showing 18 changed files with 617 additions and 51 deletions.
5 changes: 4 additions & 1 deletion src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {}
}
}

Expand Down
272 changes: 227 additions & 45 deletions src/librustc/hir/lowering.rs

Large diffs are not rendered by default.

25 changes: 23 additions & 2 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,21 @@ pub enum LifetimeName {
/// 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,

Expand All @@ -221,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,
}
Expand All @@ -242,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,
}
}

Expand Down
1 change: 1 addition & 0 deletions src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
});
Expand Down
8 changes: 5 additions & 3 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,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);
}
Expand Down Expand Up @@ -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(_) => {}
}
}

Expand Down Expand Up @@ -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);
}
}
Expand Down
22 changes: 22 additions & 0 deletions src/test/ui/feature-gate-in_band_lifetimes-impl.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions src/test/ui/feature-gate-in_band_lifetimes-impl.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 38 additions & 0 deletions src/test/ui/in-band-lifetimes/impl/assoc-type.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions src/test/ui/in-band-lifetimes/impl/assoc-type.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 45 additions & 0 deletions src/test/ui/in-band-lifetimes/impl/dyn-trait.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 22 additions & 0 deletions src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 23 additions & 0 deletions src/test/ui/in-band-lifetimes/impl/path-elided.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 9 additions & 0 deletions src/test/ui/in-band-lifetimes/impl/path-elided.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 47 additions & 0 deletions src/test/ui/in-band-lifetimes/impl/path-underscore.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 43 additions & 0 deletions src/test/ui/in-band-lifetimes/impl/ref-underscore.rs
Original file line number Diff line number Diff line change
@@ -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();
}
Loading

0 comments on commit 94468da

Please sign in to comment.