Skip to content

Commit 8f2f4fc

Browse files
adetaylorx420
authored andcommitted
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 cd567f2 commit 8f2f4fc

File tree

9 files changed

+246
-21
lines changed

9 files changed

+246
-21
lines changed

compiler/rustc_resolve/src/late.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,13 +2175,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21752175
// Handle `self` specially.
21762176
if index == 0 && has_self {
21772177
let self_lifetime = self.find_lifetime_for_self(ty);
2178-
if let Set1::One(lifetime) = self_lifetime {
2178+
elision_lifetime = match self_lifetime {
21792179
// We found `self` elision.
2180-
elision_lifetime = Elision::Self_(lifetime);
2181-
} else {
2180+
Set1::One(lifetime) => Elision::Self_(lifetime),
2181+
// `self` itself had ambiguous lifetimes, e.g.
2182+
// &Box<&Self>
2183+
Set1::Many => Elision::None,
21822184
// We do not have `self` elision: disregard the `Elision::Param` that we may
21832185
// have found.
2184-
elision_lifetime = Elision::None;
2186+
Set1::Empty => Elision::None,
21852187
}
21862188
}
21872189
debug!("(resolving function / closure) recorded parameter");
@@ -2205,6 +2207,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
22052207
r: &'r Resolver<'a, 'tcx>,
22062208
impl_self: Option<Res>,
22072209
lifetime: Set1<LifetimeRes>,
2210+
self_found: bool,
22082211
}
22092212

22102213
impl SelfVisitor<'_, '_, '_> {
@@ -2228,9 +2231,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
22282231
impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> {
22292232
fn visit_ty(&mut self, ty: &'a Ty) {
22302233
trace!("SelfVisitor considering ty={:?}", ty);
2231-
if let TyKind::Ref(lt, ref mt) = ty.kind
2232-
&& self.is_self_ty(&mt.ty)
2233-
{
2234+
if self.is_self_ty(ty) {
2235+
trace!("SelfVisitor found Self");
2236+
self.self_found = true;
2237+
}
2238+
if let TyKind::Ref(lt, _) = ty.kind {
22342239
let lt_id = if let Some(lt) = lt {
22352240
lt.id
22362241
} else {
@@ -2271,10 +2276,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
22712276
Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_)
22722277
)
22732278
});
2274-
let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
2279+
let mut visitor =
2280+
SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty, self_found: false };
22752281
visitor.visit_ty(ty);
2276-
trace!("SelfVisitor found={:?}", visitor.lifetime);
2277-
visitor.lifetime
2282+
trace!("SelfVisitor found={:?}, self_found={:?}", visitor.lifetime, visitor.self_found);
2283+
if visitor.self_found { visitor.lifetime } else { Set1::Empty }
22782284
}
22792285

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

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

Lines changed: 5 additions & 1 deletion
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

Lines changed: 77 additions & 0 deletions
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

Lines changed: 5 additions & 2 deletions
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

Lines changed: 77 additions & 0 deletions
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+
Lines changed: 29 additions & 0 deletions
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

Lines changed: 7 additions & 0 deletions
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

Lines changed: 7 additions & 0 deletions
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)