Skip to content

Commit 8d1958f

Browse files
committed
Ambiguous Self lifetimes: don't elide.
struct Concrete(u32); impl Concrete { fn m(self: &Box<Self>) -> &u32 { &self.0 } } resulted in a confusing error. impl Concrete { fn n(self: &Box<&Self>) -> &u32 { &self.0 } } resulted in no error or warning, despite apparent ambiguity over the elided lifetime. This commit changes two aspects of the behavior. Previously, when examining the self type, we considered lifetimes only if they were immediately adjacent to Self. We now consider lifetimes anywhere in the self type. Secondly, if more than one lifetime is discovered in the self type, we disregard it as a possible lifetime elision candidate. This is a compatibility break, and in fact has required some changes to tests which assumed the earlier behavior. Fixes #117715
1 parent 1d0e4af commit 8d1958f

File tree

9 files changed

+246
-21
lines changed

9 files changed

+246
-21
lines changed

compiler/rustc_resolve/src/late.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -2132,13 +2132,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21322132
// Handle `self` specially.
21332133
if index == 0 && has_self {
21342134
let self_lifetime = self.find_lifetime_for_self(ty);
2135-
if let Set1::One(lifetime) = self_lifetime {
2135+
elision_lifetime = match self_lifetime {
21362136
// We found `self` elision.
2137-
elision_lifetime = Elision::Self_(lifetime);
2138-
} else {
2137+
Set1::One(lifetime) => Elision::Self_(lifetime),
2138+
// `self` itself had ambiguous lifetimes, e.g.
2139+
// &Box<&Self>
2140+
Set1::Many => Elision::None,
21392141
// We do not have `self` elision: disregard the `Elision::Param` that we may
21402142
// have found.
2141-
elision_lifetime = Elision::None;
2143+
Set1::Empty => Elision::None,
21422144
}
21432145
}
21442146
debug!("(resolving function / closure) recorded parameter");
@@ -2162,6 +2164,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21622164
r: &'r Resolver<'a, 'tcx>,
21632165
impl_self: Option<Res>,
21642166
lifetime: Set1<LifetimeRes>,
2167+
self_found: bool,
21652168
}
21662169

21672170
impl SelfVisitor<'_, '_, '_> {
@@ -2185,9 +2188,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21852188
impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> {
21862189
fn visit_ty(&mut self, ty: &'a Ty) {
21872190
trace!("SelfVisitor considering ty={:?}", ty);
2188-
if let TyKind::Ref(lt, ref mt) = ty.kind
2189-
&& self.is_self_ty(&mt.ty)
2190-
{
2191+
if self.is_self_ty(ty) {
2192+
trace!("SelfVisitor found Self");
2193+
self.self_found = true;
2194+
}
2195+
if let TyKind::Ref(lt, _) = ty.kind {
21912196
let lt_id = if let Some(lt) = lt {
21922197
lt.id
21932198
} else {
@@ -2228,10 +2233,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
22282233
Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_)
22292234
)
22302235
});
2231-
let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
2236+
let mut visitor =
2237+
SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty, self_found: false };
22322238
visitor.visit_ty(ty);
2233-
trace!("SelfVisitor found={:?}", visitor.lifetime);
2234-
visitor.lifetime
2239+
trace!("SelfVisitor found={:?}, self_found={:?}", visitor.lifetime, visitor.self_found);
2240+
if visitor.self_found { visitor.lifetime } else { Set1::Empty }
22352241
}
22362242

22372243
/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved

tests/ui/self/elision/ref-assoc-async.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//@ edition:2018
2-
//@ check-pass
32

43
#![allow(non_snake_case)]
54

@@ -18,22 +17,27 @@ impl Trait for Struct {
1817
impl Struct {
1918
async fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
2019
f
20+
//~^ ERROR lifetime may not live long enough
2121
}
2222

2323
async fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
2424
f
25+
//~^ ERROR lifetime may not live long enough
2526
}
2627

2728
async fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
2829
f
30+
//~^ ERROR lifetime may not live long enough
2931
}
3032

3133
async fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
3234
f
35+
//~^ ERROR lifetime may not live long enough
3336
}
3437

3538
async fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
3639
f
40+
//~^ ERROR lifetime may not live long enough
3741
}
3842
}
3943

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/ref-assoc-async.rs:19:9
3+
|
4+
LL | async fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
5+
| - - let's call the lifetime of this reference `'1`
6+
| |
7+
| let's call the lifetime of this reference `'2`
8+
LL | f
9+
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
10+
|
11+
help: consider introducing a named lifetime parameter and update trait if needed
12+
|
13+
LL | async fn ref_AssocType<'a>(self: &'a <Struct as Trait>::AssocType, f: &'a u32) -> &u32 {
14+
| ++++ ++ ++
15+
16+
error: lifetime may not live long enough
17+
--> $DIR/ref-assoc-async.rs:24:9
18+
|
19+
LL | async fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
20+
| - - let's call the lifetime of this reference `'1`
21+
| |
22+
| let's call the lifetime of this reference `'2`
23+
LL | f
24+
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
25+
|
26+
help: consider introducing a named lifetime parameter and update trait if needed
27+
|
28+
LL | async fn box_ref_AssocType<'a>(self: Box<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &u32 {
29+
| ++++ ++ ++
30+
31+
error: lifetime may not live long enough
32+
--> $DIR/ref-assoc-async.rs:29:9
33+
|
34+
LL | async fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
35+
| - - let's call the lifetime of this reference `'1`
36+
| |
37+
| let's call the lifetime of this reference `'2`
38+
LL | f
39+
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
40+
|
41+
help: consider introducing a named lifetime parameter and update trait if needed
42+
|
43+
LL | async fn pin_ref_AssocType<'a>(self: Pin<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &u32 {
44+
| ++++ ++ ++
45+
46+
error: lifetime may not live long enough
47+
--> $DIR/ref-assoc-async.rs:34:9
48+
|
49+
LL | async fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
50+
| - - let's call the lifetime of this reference `'1`
51+
| |
52+
| let's call the lifetime of this reference `'2`
53+
LL | f
54+
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
55+
|
56+
help: consider introducing a named lifetime parameter and update trait if needed
57+
|
58+
LL | async fn box_box_ref_AssocType<'a>(self: Box<Box<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &u32 {
59+
| ++++ ++ ++
60+
61+
error: lifetime may not live long enough
62+
--> $DIR/ref-assoc-async.rs:39:9
63+
|
64+
LL | async fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
65+
| - - let's call the lifetime of this reference `'1`
66+
| |
67+
| let's call the lifetime of this reference `'2`
68+
LL | f
69+
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
70+
|
71+
help: consider introducing a named lifetime parameter and update trait if needed
72+
|
73+
LL | async fn box_pin_ref_AssocType<'a>(self: Box<Pin<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &u32 {
74+
| ++++ ++ ++
75+
76+
error: aborting due to 5 previous errors
77+

tests/ui/self/elision/ref-assoc.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
//@ check-pass
2-
31
#![allow(non_snake_case)]
42

53
use std::pin::Pin;
@@ -17,22 +15,27 @@ impl Trait for Struct {
1715
impl Struct {
1816
fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
1917
f
18+
//~^ ERROR lifetime may not live long enough
2019
}
2120

2221
fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
2322
f
23+
//~^ ERROR lifetime may not live long enough
2424
}
2525

2626
fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
2727
f
28+
//~^ ERROR lifetime may not live long enough
2829
}
2930

3031
fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
3132
f
33+
//~^ ERROR lifetime may not live long enough
3234
}
3335

3436
fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
3537
f
38+
//~^ ERROR lifetime may not live long enough
3639
}
3740
}
3841

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/ref-assoc.rs:17:9
3+
|
4+
LL | fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
5+
| - - let's call the lifetime of this reference `'1`
6+
| |
7+
| let's call the lifetime of this reference `'2`
8+
LL | f
9+
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
10+
|
11+
help: consider introducing a named lifetime parameter and update trait if needed
12+
|
13+
LL | fn ref_AssocType<'a>(self: &<Struct as Trait>::AssocType, f: &'a u32) -> &'a u32 {
14+
| ++++ ++ ++
15+
16+
error: lifetime may not live long enough
17+
--> $DIR/ref-assoc.rs:22:9
18+
|
19+
LL | fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
20+
| - - let's call the lifetime of this reference `'1`
21+
| |
22+
| let's call the lifetime of this reference `'2`
23+
LL | f
24+
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
25+
|
26+
help: consider introducing a named lifetime parameter and update trait if needed
27+
|
28+
LL | fn box_ref_AssocType<'a>(self: Box<&<Struct as Trait>::AssocType>, f: &'a u32) -> &'a u32 {
29+
| ++++ ++ ++
30+
31+
error: lifetime may not live long enough
32+
--> $DIR/ref-assoc.rs:27:9
33+
|
34+
LL | fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
35+
| - - let's call the lifetime of this reference `'1`
36+
| |
37+
| let's call the lifetime of this reference `'2`
38+
LL | f
39+
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
40+
|
41+
help: consider introducing a named lifetime parameter and update trait if needed
42+
|
43+
LL | fn pin_ref_AssocType<'a>(self: Pin<&<Struct as Trait>::AssocType>, f: &'a u32) -> &'a u32 {
44+
| ++++ ++ ++
45+
46+
error: lifetime may not live long enough
47+
--> $DIR/ref-assoc.rs:32:9
48+
|
49+
LL | fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
50+
| - - let's call the lifetime of this reference `'1`
51+
| |
52+
| let's call the lifetime of this reference `'2`
53+
LL | f
54+
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
55+
|
56+
help: consider introducing a named lifetime parameter and update trait if needed
57+
|
58+
LL | fn box_box_ref_AssocType<'a>(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &'a u32) -> &'a u32 {
59+
| ++++ ++ ++
60+
61+
error: lifetime may not live long enough
62+
--> $DIR/ref-assoc.rs:37:9
63+
|
64+
LL | fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
65+
| - - let's call the lifetime of this reference `'1`
66+
| |
67+
| let's call the lifetime of this reference `'2`
68+
LL | f
69+
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
70+
|
71+
help: consider introducing a named lifetime parameter and update trait if needed
72+
|
73+
LL | fn box_pin_ref_AssocType<'a>(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &'a u32) -> &'a u32 {
74+
| ++++ ++ ++
75+
76+
error: aborting due to 5 previous errors
77+
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ run-pass
2+
3+
#![feature(arbitrary_self_types)]
4+
#![allow(non_snake_case)]
5+
#![allow(unused)]
6+
7+
use std::marker::PhantomData;
8+
use std::ops::Deref;
9+
10+
struct Struct { }
11+
12+
struct Wrap<T, P>(T, PhantomData<P>);
13+
14+
impl<T, P> Deref for Wrap<T, P> {
15+
type Target = T;
16+
fn deref(&self) -> &T { &self.0 }
17+
}
18+
19+
impl Struct {
20+
fn ref_box_ref_Self(self: &Box<&Self>, f: &u32) -> &u32 {
21+
f
22+
}
23+
24+
fn ref_wrap_ref_Self(self: &Wrap<&Self, u32>, f: &u32) -> &u32 {
25+
f
26+
}
27+
}
28+
29+
fn main() { }

tests/ui/self/elision/ref-self.fixed

+7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
//@ run-rustfix
2+
//@ edition:2018
3+
24
#![feature(arbitrary_self_types)]
35
#![allow(non_snake_case, dead_code)]
46

@@ -56,6 +58,11 @@ impl Struct {
5658
f
5759
//~^ ERROR lifetime may not live long enough
5860
}
61+
62+
fn ref_box_Self<'a>(self: &Box<Self>, f: &'a u32) -> &'a u32 {
63+
f
64+
//~^ ERROR lifetime may not live long enough
65+
}
5966
}
6067

6168
fn main() {}

tests/ui/self/elision/ref-self.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
//@ run-rustfix
2+
//@ edition:2018
3+
24
#![feature(arbitrary_self_types)]
35
#![allow(non_snake_case, dead_code)]
46

@@ -56,6 +58,11 @@ impl Struct {
5658
f
5759
//~^ ERROR lifetime may not live long enough
5860
}
61+
62+
fn ref_box_Self(self: &Box<Self>, f: &u32) -> &u32 {
63+
f
64+
//~^ ERROR lifetime may not live long enough
65+
}
5966
}
6067

6168
fn main() {}

0 commit comments

Comments
 (0)