Skip to content

Commit 57fd743

Browse files
committed
Auto merge of #117967 - adetaylor:fix-lifetime-elision-bug, r=<try>
Fix lifetime elision ```rust struct Concrete(u32); impl Concrete { fn m(self: &Box<Self>) -> &u32 { &self.0 } } ``` resulted in a confusing error. ```rust impl Concrete { fn n(self: &Box<&Self>) -> &u32 { &self.0 } } ``` resulted in no error or warning, despite apparent ambiguity over the elided lifetime. Fixes #117715
2 parents 6f40082 + 15ce755 commit 57fd743

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
@@ -2105,13 +2105,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21052105
// Handle `self` specially.
21062106
if index == 0 && has_self {
21072107
let self_lifetime = self.find_lifetime_for_self(ty);
2108-
if let Set1::One(lifetime) = self_lifetime {
2108+
elision_lifetime = match self_lifetime {
21092109
// We found `self` elision.
2110-
elision_lifetime = Elision::Self_(lifetime);
2111-
} else {
2110+
Set1::One(lifetime) => Elision::Self_(lifetime),
2111+
// `self` itself had ambiguous lifetimes, e.g.
2112+
// &Box<&Self>
2113+
Set1::Many => Elision::None,
21122114
// We do not have `self` elision: disregard the `Elision::Param` that we may
21132115
// have found.
2114-
elision_lifetime = Elision::None;
2116+
Set1::Empty => Elision::None,
21152117
}
21162118
}
21172119
debug!("(resolving function / closure) recorded parameter");
@@ -2135,6 +2137,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21352137
r: &'r Resolver<'a, 'tcx>,
21362138
impl_self: Option<Res>,
21372139
lifetime: Set1<LifetimeRes>,
2140+
self_found: bool,
21382141
}
21392142

21402143
impl SelfVisitor<'_, '_, '_> {
@@ -2158,9 +2161,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21582161
impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> {
21592162
fn visit_ty(&mut self, ty: &'a Ty) {
21602163
trace!("SelfVisitor considering ty={:?}", ty);
2161-
if let TyKind::Ref(lt, ref mt) = ty.kind
2162-
&& self.is_self_ty(&mt.ty)
2163-
{
2164+
if self.is_self_ty(ty) {
2165+
trace!("SelfVisitor found Self");
2166+
self.self_found = true;
2167+
}
2168+
if let TyKind::Ref(lt, _) = ty.kind {
21642169
let lt_id = if let Some(lt) = lt {
21652170
lt.id
21662171
} else {
@@ -2201,10 +2206,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
22012206
Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_)
22022207
)
22032208
});
2204-
let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
2209+
let mut visitor =
2210+
SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty, self_found: false };
22052211
visitor.visit_ty(ty);
2206-
trace!("SelfVisitor found={:?}", visitor.lifetime);
2207-
visitor.lifetime
2212+
trace!("SelfVisitor found={:?}, self_found={:?}", visitor.lifetime, visitor.self_found);
2213+
if visitor.self_found { visitor.lifetime } else { Set1::Empty }
22082214
}
22092215

22102216
/// 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)