Skip to content

Commit 6e8eb3d

Browse files
committed
Auto merge of rust-lang#117967 - adetaylor:fix-lifetime-elision-bug, r=<try>
Fix ambiguous cases of multiple & in elided self lifetimes ```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 rust-lang#117715
2 parents 06194ca + a22130e commit 6e8eb3d

19 files changed

+522
-47
lines changed

compiler/rustc_resolve/src/late.rs

+56-22
Original file line numberDiff line numberDiff line change
@@ -2153,13 +2153,17 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21532153
// Handle `self` specially.
21542154
if index == 0 && has_self {
21552155
let self_lifetime = self.find_lifetime_for_self(ty);
2156-
if let Set1::One(lifetime) = self_lifetime {
2156+
elision_lifetime = match self_lifetime {
21572157
// We found `self` elision.
2158-
elision_lifetime = Elision::Self_(lifetime);
2159-
} else {
2158+
Set1::One(lifetime) => Elision::Self_(lifetime),
2159+
// `self` itself had ambiguous lifetimes, e.g.
2160+
// &Box<&Self>. In this case we won't consider
2161+
// taking an alternative parameter lifetime; just avoid elision
2162+
// entirely.
2163+
Set1::Many => Elision::Err,
21602164
// We do not have `self` elision: disregard the `Elision::Param` that we may
21612165
// have found.
2162-
elision_lifetime = Elision::None;
2166+
Set1::Empty => Elision::None,
21632167
}
21642168
}
21652169
debug!("(resolving function / closure) recorded parameter");
@@ -2179,15 +2183,55 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21792183

21802184
/// List all the lifetimes that appear in the provided type.
21812185
fn find_lifetime_for_self(&self, ty: &'ast Ty) -> Set1<LifetimeRes> {
2182-
struct SelfVisitor<'r, 'a, 'tcx> {
2186+
/// Visits a type to find all the &references, and determines the
2187+
/// set of lifetimes for all of those references where the referent
2188+
/// contains Self.
2189+
struct FindReferenceVisitor<'r, 'a, 'tcx> {
21832190
r: &'r Resolver<'a, 'tcx>,
21842191
impl_self: Option<Res>,
21852192
lifetime: Set1<LifetimeRes>,
21862193
}
21872194

2195+
impl<'a> Visitor<'a> for FindReferenceVisitor<'_, '_, '_> {
2196+
fn visit_ty(&mut self, ty: &'a Ty) {
2197+
trace!("FindReferenceVisitor considering ty={:?}", ty);
2198+
if let TyKind::Ref(lt, _) = ty.kind {
2199+
// See if anything inside the &thing contains Self
2200+
let mut visitor =
2201+
SelfVisitor { r: self.r, impl_self: self.impl_self, self_found: false };
2202+
visitor.visit_ty(ty);
2203+
trace!("FindReferenceVisitor: SelfVisitor self_found={:?}", visitor.self_found);
2204+
if visitor.self_found {
2205+
let lt_id = if let Some(lt) = lt {
2206+
lt.id
2207+
} else {
2208+
let res = self.r.lifetimes_res_map[&ty.id];
2209+
let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() };
2210+
start
2211+
};
2212+
let lt_res = self.r.lifetimes_res_map[&lt_id];
2213+
trace!("FindReferenceVisitor inserting res={:?}", lt_res);
2214+
self.lifetime.insert(lt_res);
2215+
}
2216+
}
2217+
visit::walk_ty(self, ty)
2218+
}
2219+
2220+
// A type may have an expression as a const generic argument.
2221+
// We do not want to recurse into those.
2222+
fn visit_expr(&mut self, _: &'a Expr) {}
2223+
}
2224+
2225+
/// Visitor which checks the referent of a &Thing to see if the
2226+
/// Thing contains Self
2227+
struct SelfVisitor<'r, 'a, 'tcx> {
2228+
r: &'r Resolver<'a, 'tcx>,
2229+
impl_self: Option<Res>,
2230+
self_found: bool,
2231+
}
2232+
21882233
impl SelfVisitor<'_, '_, '_> {
2189-
// Look for `self: &'a Self` - also desugared from `&'a self`,
2190-
// and if that matches, use it for elision and return early.
2234+
// Look for `self: &'a Self` - also desugared from `&'a self`
21912235
fn is_self_ty(&self, ty: &Ty) -> bool {
21922236
match ty.kind {
21932237
TyKind::ImplicitSelf => true,
@@ -2206,19 +2250,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
22062250
impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> {
22072251
fn visit_ty(&mut self, ty: &'a Ty) {
22082252
trace!("SelfVisitor considering ty={:?}", ty);
2209-
if let TyKind::Ref(lt, ref mt) = ty.kind
2210-
&& self.is_self_ty(&mt.ty)
2211-
{
2212-
let lt_id = if let Some(lt) = lt {
2213-
lt.id
2214-
} else {
2215-
let res = self.r.lifetimes_res_map[&ty.id];
2216-
let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() };
2217-
start
2218-
};
2219-
let lt_res = self.r.lifetimes_res_map[&lt_id];
2220-
trace!("SelfVisitor inserting res={:?}", lt_res);
2221-
self.lifetime.insert(lt_res);
2253+
if self.is_self_ty(ty) {
2254+
trace!("SelfVisitor found Self");
2255+
self.self_found = true;
22222256
}
22232257
visit::walk_ty(self, ty)
22242258
}
@@ -2249,9 +2283,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
22492283
Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_)
22502284
)
22512285
});
2252-
let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
2286+
let mut visitor = FindReferenceVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
22532287
visitor.visit_ty(ty);
2254-
trace!("SelfVisitor found={:?}", visitor.lifetime);
2288+
trace!("FindReferenceVisitor found={:?}", visitor.lifetime);
22552289
visitor.lifetime
22562290
}
22572291

tests/crashes/122903-1.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//@ known-bug: #122903
22
impl Struct {
3-
async fn box_box_ref_Struct(
4-
self: Box<Box<Self, impl FnMut(&mut Box<Box<Self, impl FnMut(&mut Self)>>)>>,
3+
fn box_box_ref_Struct(
4+
self: impl FnMut(Box<impl FnMut(&mut Self)>),
55
) -> &u32 {
66
f
77
}

tests/crashes/122903-2.rs

-9
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@ check-pass
2+
3+
struct Foo<'a>(&'a str);
4+
5+
impl<'b> Foo<'b> {
6+
fn a<'a>(self: Self, a: &'a str) -> &str {
7+
a
8+
}
9+
fn b<'a>(self: Foo<'b>, a: &'a str) -> &str {
10+
a
11+
}
12+
}
13+
14+
struct Foo2<'a>(&'a u32);
15+
impl<'a> Foo2<'a> {
16+
fn foo(self: &Self) -> &u32 { self.0 } // ok
17+
fn bar(self: &Foo2<'a>) -> &u32 { self.0 } // ok (do not look into `Foo`)
18+
fn baz2(self: Self, arg: &u32) -> &u32 { arg } // use lt from `arg`
19+
fn baz3(self: Foo2<'a>, arg: &u32) -> &u32 { arg } // use lt from `arg`
20+
}
21+
22+
fn main() {}

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

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

43
#![feature(arbitrary_self_types)]
@@ -21,22 +20,27 @@ impl Struct {
2120
// Test using multiple `&Self`:
2221

2322
async fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
23+
//~^ ERROR missing lifetime specifier
2424
f
2525
}
2626

2727
async fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
28+
//~^ ERROR missing lifetime specifier
2829
f
2930
}
3031

3132
async fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
33+
//~^ ERROR missing lifetime specifier
3234
f
3335
}
3436

3537
async fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
38+
//~^ ERROR missing lifetime specifier
3639
f
3740
}
3841

3942
async fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
43+
//~^ ERROR missing lifetime specifier
4044
f
4145
}
4246
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
error[E0106]: missing lifetime specifier
2+
--> $DIR/multiple-ref-self-async.rs:22:74
3+
|
4+
LL | async fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
5+
| ------------------ --- ^ expected named 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 one of `self`'s 2 lifetimes or `f`
8+
help: consider introducing a named lifetime parameter
9+
|
10+
LL | async fn wrap_ref_Self_ref_Self<'a>(self: Wrap<&'a Self, &'a Self>, f: &'a u8) -> &'a u8 {
11+
| ++++ ++ ++ ++ ++
12+
13+
error[E0106]: missing lifetime specifier
14+
--> $DIR/multiple-ref-self-async.rs:27:84
15+
|
16+
LL | async fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
17+
| ----------------------- ---- ^ expected named lifetime parameter
18+
|
19+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
20+
help: consider introducing a named lifetime parameter
21+
|
22+
LL | async fn box_wrap_ref_Self_ref_Self<'a>(self: Box<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 {
23+
| ++++ ++ ++ ++ ++
24+
25+
error[E0106]: missing lifetime specifier
26+
--> $DIR/multiple-ref-self-async.rs:32:84
27+
|
28+
LL | async fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
29+
| ----------------------- ---- ^ expected named lifetime parameter
30+
|
31+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
32+
help: consider introducing a named lifetime parameter
33+
|
34+
LL | async fn pin_wrap_ref_Self_ref_Self<'a>(self: Pin<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 {
35+
| ++++ ++ ++ ++ ++
36+
37+
error[E0106]: missing lifetime specifier
38+
--> $DIR/multiple-ref-self-async.rs:37:93
39+
|
40+
LL | async fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
41+
| ---------------------------- ---- ^ expected named lifetime parameter
42+
|
43+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
44+
help: consider introducing a named lifetime parameter
45+
|
46+
LL | async fn box_box_wrap_ref_Self_ref_Self<'a>(self: Box<Box<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 {
47+
| ++++ ++ ++ ++ ++
48+
49+
error[E0106]: missing lifetime specifier
50+
--> $DIR/multiple-ref-self-async.rs:42:93
51+
|
52+
LL | async fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
53+
| ---------------------------- ---- ^ expected named lifetime parameter
54+
|
55+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
56+
help: consider introducing a named lifetime parameter
57+
|
58+
LL | async fn box_pin_wrap_ref_Self_ref_Self<'a>(self: Box<Pin<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 {
59+
| ++++ ++ ++ ++ ++
60+
61+
error: aborting due to 5 previous errors
62+
63+
For more information about this error, try `rustc --explain E0106`.

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

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

@@ -20,22 +18,27 @@ impl Struct {
2018
// Test using multiple `&Self`:
2119

2220
fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
21+
//~^ ERROR missing lifetime specifier
2322
f
2423
}
2524

2625
fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
26+
//~^ ERROR missing lifetime specifier
2727
f
2828
}
2929

3030
fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
31+
//~^ ERROR missing lifetime specifier
3132
f
3233
}
3334

3435
fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
36+
//~^ ERROR missing lifetime specifier
3537
f
3638
}
3739

3840
fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
41+
//~^ ERROR missing lifetime specifier
3942
f
4043
}
4144
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
error[E0106]: missing lifetime specifier
2+
--> $DIR/multiple-ref-self.rs:20:68
3+
|
4+
LL | fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
5+
| ------------------ --- ^ expected named 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 one of `self`'s 2 lifetimes or `f`
8+
help: consider introducing a named lifetime parameter
9+
|
10+
LL | fn wrap_ref_Self_ref_Self<'a>(self: Wrap<&'a Self, &'a Self>, f: &'a u8) -> &'a u8 {
11+
| ++++ ++ ++ ++ ++
12+
13+
error[E0106]: missing lifetime specifier
14+
--> $DIR/multiple-ref-self.rs:25:78
15+
|
16+
LL | fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
17+
| ----------------------- ---- ^ expected named lifetime parameter
18+
|
19+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
20+
help: consider introducing a named lifetime parameter
21+
|
22+
LL | fn box_wrap_ref_Self_ref_Self<'a>(self: Box<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 {
23+
| ++++ ++ ++ ++ ++
24+
25+
error[E0106]: missing lifetime specifier
26+
--> $DIR/multiple-ref-self.rs:30:78
27+
|
28+
LL | fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
29+
| ----------------------- ---- ^ expected named lifetime parameter
30+
|
31+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
32+
help: consider introducing a named lifetime parameter
33+
|
34+
LL | fn pin_wrap_ref_Self_ref_Self<'a>(self: Pin<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 {
35+
| ++++ ++ ++ ++ ++
36+
37+
error[E0106]: missing lifetime specifier
38+
--> $DIR/multiple-ref-self.rs:35:87
39+
|
40+
LL | fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
41+
| ---------------------------- ---- ^ expected named lifetime parameter
42+
|
43+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
44+
help: consider introducing a named lifetime parameter
45+
|
46+
LL | fn box_box_wrap_ref_Self_ref_Self<'a>(self: Box<Box<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 {
47+
| ++++ ++ ++ ++ ++
48+
49+
error[E0106]: missing lifetime specifier
50+
--> $DIR/multiple-ref-self.rs:40:87
51+
|
52+
LL | fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
53+
| ---------------------------- ---- ^ expected named lifetime parameter
54+
|
55+
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f`
56+
help: consider introducing a named lifetime parameter
57+
|
58+
LL | fn box_pin_wrap_ref_Self_ref_Self<'a>(self: Box<Pin<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 {
59+
| ++++ ++ ++ ++ ++
60+
61+
error: aborting due to 5 previous errors
62+
63+
For more information about this error, try `rustc --explain E0106`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use std::pin::Pin;
2+
trait Trait {
3+
fn method<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 {
4+
f
5+
}
6+
}
7+
8+
impl<P> Trait for Pin<P> {
9+
// This should not hide `&Self`, which would cause this to compile.
10+
fn method(self: Pin<&Self>, f: &u32) -> &u32 {
11+
//~^ ERROR `impl` item signature doesn't match `trait`
12+
f
13+
//~^ ERROR lifetime may not live long enough
14+
}
15+
}
16+
17+
fn main() {}

0 commit comments

Comments
 (0)