Skip to content

Commit

Permalink
Auto merge of #60944 - taiki-e:arbitrary_self_types-lifetime-elision,…
Browse files Browse the repository at this point in the history
… r=<try>

Allow lifetime elision in arbitrary_self_types

Currently, `self` except `&Self` and `&mut Self` is skipped. By this, other `self`s with lifetime is also ignored.
This PR changes it to only skip `Self`, `&Self` and `&mut Self`, and to handle other `self`s like normal arguments.

Closes #52675
  • Loading branch information
bors committed May 20, 2019
2 parents 589beb9 + 8efcf41 commit 42445de
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 11 deletions.
33 changes: 22 additions & 11 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2121,6 +2121,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
_ => false,
};

// Only skip `Self`, `&Self` and `&mut Self`,
// and to handle other `self`s like normal arguments.
let mut skip = 0;

// In accordance with the rules for lifetime elision, we can determine
// what region to use for elision in the output type in two ways.
// First (determined here), if `self` is by-reference, then the
Expand Down Expand Up @@ -2154,19 +2158,26 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
false
};

if let hir::TyKind::Rptr(lifetime_ref, ref mt) = inputs[0].node {
if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.node {
if is_self_ty(path.res) {
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
let scope = Scope::Elision {
elide: Elide::Exact(lifetime),
s: self.scope,
};
self.with(scope, |_, this| this.visit_ty(output));
return;
match inputs[0].node {
hir::TyKind::Rptr(lifetime_ref, ref mt) => {
if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.node {
if is_self_ty(path.res) {
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
let scope = Scope::Elision {
elide: Elide::Exact(lifetime),
s: self.scope,
};
self.with(scope, |_, this| this.visit_ty(output));
return;
}
skip = 1;
}
}
}
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) if is_self_ty(path.res) => {
skip = 1;
}
_ => {}
}
}

Expand All @@ -2178,7 +2189,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let arg_lifetimes = inputs
.iter()
.enumerate()
.skip(has_self as usize)
.skip(skip)
.map(|(i, input)| {
let mut gather = GatherLifetimes {
map: self.map,
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/self/arbitrary_self_types_inexact_lifetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#![feature(arbitrary_self_types)]

#[derive(Debug)]
struct Foo;

impl Foo {
fn a(self: &Box<Foo>, f: &Foo) -> &Foo { f } //~ ERROR E0106

fn b(self: &Box<Foo>, f: &Foo) -> &Box<Foo> { self } //~ ERROR E0106

fn c(this: &Box<Foo>, f: &Foo) -> &Foo { f } //~ ERROR E0106
}

fn main() {}
27 changes: 27 additions & 0 deletions src/test/ui/self/arbitrary_self_types_inexact_lifetime.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
error[E0106]: missing lifetime specifier
--> $DIR/arbitrary_self_types_inexact_lifetime.rs:7:39
|
LL | fn a(self: &Box<Foo>, f: &Foo) -> &Foo { f }
| ^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `self` or `f`

error[E0106]: missing lifetime specifier
--> $DIR/arbitrary_self_types_inexact_lifetime.rs:9:39
|
LL | fn b(self: &Box<Foo>, f: &Foo) -> &Box<Foo> { self }
| ^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `self` or `f`

error[E0106]: missing lifetime specifier
--> $DIR/arbitrary_self_types_inexact_lifetime.rs:11:39
|
LL | fn c(this: &Box<Foo>, f: &Foo) -> &Foo { f }
| ^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `this` or `f`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0106`.
80 changes: 80 additions & 0 deletions src/test/ui/self/arbitrary_self_types_lifetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#![feature(arbitrary_self_types)]

use std::pin::Pin;

#[derive(Debug)]
struct Foo;
#[derive(Debug)]
struct Bar<'a>(&'a Foo);

impl std::ops::Deref for Bar<'_> {
type Target = Foo;
fn deref(&self) -> &Self::Target {
&self.0
}
}

impl Foo {
fn a(&self) -> Bar<'_> {
Bar(self)
}

fn b(c: &Self) -> Bar<'_> {
Bar(c)
}

fn c(self: Bar<'_>) -> Bar<'_> {
self
}

fn d(e: Bar<'_>) -> Bar<'_> {
e
}

fn e(self: &Self) -> Bar<'_> {
Bar(self)
}

fn f(self: Bar<'_>) -> impl std::fmt::Debug {
self
//~^ ERROR cannot infer an appropriate lifetime
}

fn g(self: Bar<'_>) -> impl std::fmt::Debug + '_ {
self
}
}

impl<'a> Bar<'a> {
fn a(self: Bar<'a>, f: &Foo) -> (Bar<'a>, &Foo) { (self, f) }
fn b(self: Self, f: &Foo) -> (Bar<'a>, &Foo) { (self, f) }
fn c(self: Bar<'a>, f: &Foo) -> (Self, &Foo) { (self, f) }
}

impl Bar<'_> {
fn e(self: Self, f: &Foo) -> (Self, &Foo) { (self, f) }
}

struct Baz<T: Unpin> {
field: T,
}

impl<T: Unpin> Baz<T> {
fn field(self: Pin<&mut Self>) -> Pin<&mut T> {
let this = Pin::get_mut(self);
Pin::new(&mut this.field)
}
}

fn main() {
let foo = Foo;
{ foo.a() };
{ Foo::b(&foo) };
{ Bar(&foo).c() };
{ Foo::d(Bar(&foo)) };
{ foo.e() };
{ Bar(&foo).f() };
{ Bar(&foo).g() };
let mut baz = Baz { field: 0u8 };
{ Pin::new(&mut baz).field() };
}
23 changes: 23 additions & 0 deletions src/test/ui/self/arbitrary_self_types_lifetime.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error: cannot infer an appropriate lifetime
--> $DIR/arbitrary_self_types_lifetime.rs:39:9
|
LL | fn f(self: Bar<'_>) -> impl std::fmt::Debug {
| -------------------- this return type evaluates to the `'static` lifetime...
LL | self
| ^^^^ ...but this borrow...
|
note: ...can't outlive the anonymous lifetime #1 defined on the method body at 38:5
--> $DIR/arbitrary_self_types_lifetime.rs:38:5
|
LL | / fn f(self: Bar<'_>) -> impl std::fmt::Debug {
LL | | self
LL | |
LL | | }
| |_____^
help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 38:5
|
LL | fn f(self: Bar<'_>) -> impl std::fmt::Debug + '_ {
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

0 comments on commit 42445de

Please sign in to comment.