Skip to content

Commit 15ce755

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 525c91d commit 15ce755

File tree

8 files changed

+230
-14
lines changed

8 files changed

+230
-14
lines changed

compiler/rustc_resolve/src/late.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -2090,13 +2090,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
20902090
// Handle `self` specially.
20912091
if index == 0 && has_self {
20922092
let self_lifetime = self.find_lifetime_for_self(ty);
2093-
if let Set1::One(lifetime) = self_lifetime {
2093+
elision_lifetime = match self_lifetime {
20942094
// We found `self` elision.
2095-
elision_lifetime = Elision::Self_(lifetime);
2096-
} else {
2095+
Set1::One(lifetime) => Elision::Self_(lifetime),
2096+
// `self` itself had ambiguous lifetimes, e.g.
2097+
// &Box<&Self>
2098+
Set1::Many => Elision::None,
20972099
// We do not have `self` elision: disregard the `Elision::Param` that we may
20982100
// have found.
2099-
elision_lifetime = Elision::None;
2101+
Set1::Empty => Elision::None,
21002102
}
21012103
}
21022104
debug!("(resolving function / closure) recorded parameter");
@@ -2120,6 +2122,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21202122
r: &'r Resolver<'a, 'tcx>,
21212123
impl_self: Option<Res>,
21222124
lifetime: Set1<LifetimeRes>,
2125+
self_found: bool,
21232126
}
21242127

21252128
impl SelfVisitor<'_, '_, '_> {
@@ -2143,9 +2146,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21432146
impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> {
21442147
fn visit_ty(&mut self, ty: &'a Ty) {
21452148
trace!("SelfVisitor considering ty={:?}", ty);
2146-
if let TyKind::Ref(lt, ref mt) = ty.kind
2147-
&& self.is_self_ty(&mt.ty)
2148-
{
2149+
if self.is_self_ty(ty) {
2150+
trace!("SelfVisitor found Self");
2151+
self.self_found = true;
2152+
}
2153+
if let TyKind::Ref(lt, _) = ty.kind {
21492154
let lt_id = if let Some(lt) = lt {
21502155
lt.id
21512156
} else {
@@ -2186,10 +2191,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21862191
Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_)
21872192
)
21882193
});
2189-
let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
2194+
let mut visitor =
2195+
SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty, self_found: false };
21902196
visitor.visit_ty(ty);
2191-
trace!("SelfVisitor found={:?}", visitor.lifetime);
2192-
visitor.lifetime
2197+
trace!("SelfVisitor found={:?}, self_found={:?}", visitor.lifetime, visitor.self_found);
2198+
if visitor.self_found { visitor.lifetime } else { Set1::Empty }
21932199
}
21942200

21952201
/// 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: &'a <Struct as Trait>::AssocType, f: &'a u32) -> &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<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &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<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &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<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &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<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &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.rs

+5
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ impl Struct {
5353
f
5454
//~^ ERROR lifetime may not live long enough
5555
}
56+
57+
fn ref_box_Self(self: &Box<Self>, f: &u32) -> &u32 {
58+
f
59+
//~^ ERROR lifetime may not live long enough
60+
}
5661
}
5762

5863
fn main() { }

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

+16-1
Original file line numberDiff line numberDiff line change
@@ -103,5 +103,20 @@ help: consider introducing a named lifetime parameter and update trait if needed
103103
LL | fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
104104
| ++++ ++ ++
105105

106-
error: aborting due to 7 previous errors
106+
error: lifetime may not live long enough
107+
--> $DIR/ref-self.rs:58:9
108+
|
109+
LL | fn ref_box_Self(self: &Box<Self>, f: &u32) -> &u32 {
110+
| - - let's call the lifetime of this reference `'1`
111+
| |
112+
| let's call the lifetime of this reference `'2`
113+
LL | f
114+
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
115+
|
116+
help: consider introducing a named lifetime parameter and update trait if needed
117+
|
118+
LL | fn ref_box_Self<'a>(self: &'a Box<Self>, f: &'a u32) -> &u32 {
119+
| ++++ ++ ++
120+
121+
error: aborting due to 8 previous errors
107122

0 commit comments

Comments
 (0)