Skip to content

Commit 8efcf41

Browse files
committed
Allow lifetime elision in arbitrary_self_types
1 parent 548add7 commit 8efcf41

5 files changed

+166
-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 skip = 0;
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+
skip = 1;
21672174
}
21682175
}
21692176
}
2177+
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) if is_self_ty(path.res) => {
2178+
skip = 1;
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(skip)
21822193
.map(|(i, input)| {
21832194
let mut gather = GatherLifetimes {
21842195
map: self.map,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(arbitrary_self_types)]
2+
3+
#[derive(Debug)]
4+
struct Foo;
5+
6+
impl Foo {
7+
fn a(self: &Box<Foo>, f: &Foo) -> &Foo { f } //~ ERROR E0106
8+
9+
fn b(self: &Box<Foo>, f: &Foo) -> &Box<Foo> { self } //~ ERROR E0106
10+
11+
fn c(this: &Box<Foo>, f: &Foo) -> &Foo { f } //~ ERROR E0106
12+
}
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0106]: missing lifetime specifier
2+
--> $DIR/arbitrary_self_types_inexact_lifetime.rs:7: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:9: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:11: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: aborting due to 3 previous errors
26+
27+
For more information about this error, try `rustc --explain E0106`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#![feature(arbitrary_self_types)]
2+
3+
use std::pin::Pin;
4+
5+
#[derive(Debug)]
6+
struct Foo;
7+
#[derive(Debug)]
8+
struct Bar<'a>(&'a Foo);
9+
10+
impl std::ops::Deref for Bar<'_> {
11+
type Target = Foo;
12+
fn deref(&self) -> &Self::Target {
13+
&self.0
14+
}
15+
}
16+
17+
impl Foo {
18+
fn a(&self) -> Bar<'_> {
19+
Bar(self)
20+
}
21+
22+
fn b(c: &Self) -> Bar<'_> {
23+
Bar(c)
24+
}
25+
26+
fn c(self: Bar<'_>) -> Bar<'_> {
27+
self
28+
}
29+
30+
fn d(e: Bar<'_>) -> Bar<'_> {
31+
e
32+
}
33+
34+
fn e(self: &Self) -> Bar<'_> {
35+
Bar(self)
36+
}
37+
38+
fn f(self: Bar<'_>) -> impl std::fmt::Debug {
39+
self
40+
//~^ ERROR cannot infer an appropriate lifetime
41+
}
42+
43+
fn g(self: Bar<'_>) -> impl std::fmt::Debug + '_ {
44+
self
45+
}
46+
}
47+
48+
impl<'a> Bar<'a> {
49+
fn a(self: Bar<'a>, f: &Foo) -> (Bar<'a>, &Foo) { (self, f) }
50+
fn b(self: Self, f: &Foo) -> (Bar<'a>, &Foo) { (self, f) }
51+
fn c(self: Bar<'a>, f: &Foo) -> (Self, &Foo) { (self, f) }
52+
}
53+
54+
impl Bar<'_> {
55+
fn e(self: Self, f: &Foo) -> (Self, &Foo) { (self, f) }
56+
}
57+
58+
struct Baz<T: Unpin> {
59+
field: T,
60+
}
61+
62+
impl<T: Unpin> Baz<T> {
63+
fn field(self: Pin<&mut Self>) -> Pin<&mut T> {
64+
let this = Pin::get_mut(self);
65+
Pin::new(&mut this.field)
66+
}
67+
}
68+
69+
fn main() {
70+
let foo = Foo;
71+
{ foo.a() };
72+
{ Foo::b(&foo) };
73+
{ Bar(&foo).c() };
74+
{ Foo::d(Bar(&foo)) };
75+
{ foo.e() };
76+
{ Bar(&foo).f() };
77+
{ Bar(&foo).g() };
78+
let mut baz = Baz { field: 0u8 };
79+
{ Pin::new(&mut baz).field() };
80+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error: cannot infer an appropriate lifetime
2+
--> $DIR/arbitrary_self_types_lifetime.rs:39: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 38:5
10+
--> $DIR/arbitrary_self_types_lifetime.rs:38: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 38:5
18+
|
19+
LL | fn f(self: Bar<'_>) -> impl std::fmt::Debug + '_ {
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
21+
22+
error: aborting due to previous error
23+

0 commit comments

Comments
 (0)