Skip to content

Commit 76ab65a

Browse files
committed
Allow lifetime elision in arbitrary_self_types
1 parent 548add7 commit 76ab65a

6 files changed

+211
-11
lines changed

src/librustc/middle/resolve_lifetime.rs

+22-11
Original file line numberDiff line numberDiff line change
@@ -2121,6 +2121,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
21212121
_ => false,
21222122
};
21232123

2124+
// Only skip `Self`, `&Self` and `&mut Self`,
2125+
// and to handle other `self`s like normal arguments.
2126+
let mut should_skip = false;
2127+
21242128
// In accordance with the rules for lifetime elision, we can determine
21252129
// what region to use for elision in the output type in two ways.
21262130
// First (determined here), if `self` is by-reference, then the
@@ -2154,19 +2158,26 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
21542158
false
21552159
};
21562160

2157-
if let hir::TyKind::Rptr(lifetime_ref, ref mt) = inputs[0].node {
2158-
if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.node {
2159-
if is_self_ty(path.res) {
2160-
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
2161-
let scope = Scope::Elision {
2162-
elide: Elide::Exact(lifetime),
2163-
s: self.scope,
2164-
};
2165-
self.with(scope, |_, this| this.visit_ty(output));
2166-
return;
2161+
match inputs[0].node {
2162+
hir::TyKind::Rptr(lifetime_ref, ref mt) => {
2163+
if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.node {
2164+
if is_self_ty(path.res) {
2165+
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
2166+
let scope = Scope::Elision {
2167+
elide: Elide::Exact(lifetime),
2168+
s: self.scope,
2169+
};
2170+
self.with(scope, |_, this| this.visit_ty(output));
2171+
return;
2172+
}
2173+
should_skip = true;
21672174
}
21682175
}
21692176
}
2177+
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) if is_self_ty(path.res) => {
2178+
should_skip = true;
2179+
}
2180+
_ => {}
21702181
}
21712182
}
21722183

@@ -2178,7 +2189,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
21782189
let arg_lifetimes = inputs
21792190
.iter()
21802191
.enumerate()
2181-
.skip(has_self as usize)
2192+
.skip(should_skip as usize)
21822193
.map(|(i, input)| {
21832194
let mut gather = GatherLifetimes {
21842195
map: self.map,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// compile-fail
2+
3+
#![feature(arbitrary_self_types)]
4+
5+
use std::pin::Pin;
6+
7+
#[derive(Debug)]
8+
struct Foo;
9+
#[derive(Debug)]
10+
struct Bar<'a>(&'a Foo);
11+
12+
impl std::ops::Deref for Bar<'_> {
13+
type Target = Foo;
14+
fn deref(&self) -> &Self::Target {
15+
&self.0
16+
}
17+
}
18+
19+
impl Foo {
20+
fn f(self: Bar<'_>) -> impl std::fmt::Debug {
21+
self
22+
//~^ ERROR cannot infer an appropriate lifetime
23+
}
24+
}
25+
26+
fn main() {
27+
{ Bar(&Foo).f() };
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error: cannot infer an appropriate lifetime
2+
--> $DIR/arbitrary_self_types_impl_trait_lifetime.rs:21:9
3+
|
4+
LL | fn f(self: Bar<'_>) -> impl std::fmt::Debug {
5+
| -------------------- this return type evaluates to the `'static` lifetime...
6+
LL | self
7+
| ^^^^ ...but this borrow...
8+
|
9+
note: ...can't outlive the anonymous lifetime #1 defined on the method body at 20:5
10+
--> $DIR/arbitrary_self_types_impl_trait_lifetime.rs:20:5
11+
|
12+
LL | / fn f(self: Bar<'_>) -> impl std::fmt::Debug {
13+
LL | | self
14+
LL | |
15+
LL | | }
16+
| |_____^
17+
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 20:5
18+
|
19+
LL | fn f(self: Bar<'_>) -> impl std::fmt::Debug + '_ {
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
21+
22+
error: aborting due to previous error
23+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#![feature(arbitrary_self_types)]
2+
3+
#[derive(Debug)]
4+
struct Foo;
5+
#[derive(Debug)]
6+
struct Bar<'a>(&'a Foo);
7+
8+
impl std::ops::Deref for Bar<'_> {
9+
type Target = Foo;
10+
fn deref(&self) -> &Self::Target {
11+
&self.0
12+
}
13+
}
14+
15+
impl Foo {
16+
fn a(self: &Box<Foo>, f: &Foo) -> &Foo { f } //~ ERROR E0106
17+
18+
fn b(self: &Box<Foo>, f: &Foo) -> &Box<Foo> { self } //~ ERROR E0106
19+
20+
fn c(this: &Box<Foo>, f: &Foo) -> &Foo { f } //~ ERROR E0106
21+
}
22+
23+
impl<'a> Bar<'a> {
24+
fn d(self: Self, f: &Foo, g: &Foo) -> (Bar<'a>, &Foo) { (self, f) } //~ ERROR E0106
25+
}
26+
27+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error[E0106]: missing lifetime specifier
2+
--> $DIR/arbitrary_self_types_inexact_lifetime.rs:16:39
3+
|
4+
LL | fn a(self: &Box<Foo>, f: &Foo) -> &Foo { f }
5+
| ^ expected lifetime parameter
6+
|
7+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `self` or `f`
8+
9+
error[E0106]: missing lifetime specifier
10+
--> $DIR/arbitrary_self_types_inexact_lifetime.rs:18:39
11+
|
12+
LL | fn b(self: &Box<Foo>, f: &Foo) -> &Box<Foo> { self }
13+
| ^ expected lifetime parameter
14+
|
15+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `self` or `f`
16+
17+
error[E0106]: missing lifetime specifier
18+
--> $DIR/arbitrary_self_types_inexact_lifetime.rs:20:39
19+
|
20+
LL | fn c(this: &Box<Foo>, f: &Foo) -> &Foo { f }
21+
| ^ expected lifetime parameter
22+
|
23+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `this` or `f`
24+
25+
error[E0106]: missing lifetime specifier
26+
--> $DIR/arbitrary_self_types_inexact_lifetime.rs:24:53
27+
|
28+
LL | fn d(self: Self, f: &Foo, g: &Foo) -> (Bar<'a>, &Foo) { (self, f) }
29+
| ^ expected lifetime parameter
30+
|
31+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `f` or `g`
32+
33+
error: aborting due to 4 previous errors
34+
35+
For more information about this error, try `rustc --explain E0106`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// compile-pass
2+
3+
#![feature(arbitrary_self_types)]
4+
5+
use std::pin::Pin;
6+
7+
#[derive(Debug)]
8+
struct Foo;
9+
#[derive(Debug)]
10+
struct Bar<'a>(&'a Foo);
11+
12+
impl std::ops::Deref for Bar<'_> {
13+
type Target = Foo;
14+
fn deref(&self) -> &Self::Target {
15+
&self.0
16+
}
17+
}
18+
19+
impl Foo {
20+
fn a(&self) -> Bar<'_> {
21+
Bar(self)
22+
}
23+
24+
fn b(c: &Self) -> Bar<'_> {
25+
Bar(c)
26+
}
27+
28+
fn c(self: Bar<'_>) -> Bar<'_> {
29+
self
30+
}
31+
32+
fn d(e: Bar<'_>) -> Bar<'_> {
33+
e
34+
}
35+
36+
fn e(self: &Self) -> Bar<'_> {
37+
Bar(self)
38+
}
39+
40+
fn f(self: Bar<'_>) -> impl std::fmt::Debug + '_ {
41+
self
42+
}
43+
}
44+
45+
impl<'a> Bar<'a> {
46+
fn a(self: Bar<'a>, f: &Foo) -> (Bar<'a>, &Foo) { (self, f) }
47+
fn b(self: Self, f: &Foo) -> (Bar<'a>, &Foo) { (self, f) }
48+
fn d(self: Bar<'a>, f: &Foo) -> (Self, &Foo) { (self, f) }
49+
}
50+
51+
impl Bar<'_> {
52+
fn e(self: Self, f: &Foo) -> (Self, &Foo) { (self, f) }
53+
}
54+
55+
struct Baz<T: Unpin> {
56+
field: T,
57+
}
58+
59+
impl<T: Unpin> Baz<T> {
60+
fn field(self: Pin<&mut Self>) -> Pin<&mut T> {
61+
let this = Pin::get_mut(self);
62+
Pin::new(&mut this.field)
63+
}
64+
}
65+
66+
fn main() {
67+
let foo = Foo;
68+
{ foo.a() };
69+
{ Foo::b(&foo) };
70+
{ Bar(&foo).c() };
71+
{ Foo::d(Bar(&foo)) };
72+
{ foo.e() };
73+
{ Bar(&foo).f() };
74+
let mut baz = Baz { field: 0u8 };
75+
{ Pin::new(&mut baz).field() };
76+
}

0 commit comments

Comments
 (0)