Skip to content

Commit bf676f4

Browse files
committed
Fix lifetime elision
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. Fixes #117715
1 parent 525c91d commit bf676f4

File tree

5 files changed

+76
-11
lines changed

5 files changed

+76
-11
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::Err,
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
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(arbitrary_self_types)]
2+
#![allow(non_snake_case)]
3+
4+
use std::marker::PhantomData;
5+
use std::ops::Deref;
6+
use std::pin::Pin;
7+
8+
struct Struct { }
9+
10+
struct Wrap<T, P>(T, PhantomData<P>);
11+
12+
impl<T, P> Deref for Wrap<T, P> {
13+
type Target = T;
14+
fn deref(&self) -> &T { &self.0 }
15+
}
16+
17+
impl Struct {
18+
fn ref_box_ref_Self(self: &Box<&Self>, f: &u32) -> &u32 {
19+
f
20+
//~^ ERROR missing lifetime specifier
21+
}
22+
}
23+
24+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0106]: missing lifetime specifier
2+
--> $DIR/ref-self-multi.rs:18:56
3+
|
4+
LL | fn ref_box_ref_Self(self: &Box<&Self>, f: &u32) -> &u32 {
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 ref_box_ref_Self<'a>(self: &'a Box<&'a Self>, f: &'a u32) -> &'a u32 {
11+
| ++++ ++ ++ ++ ++
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0106`.

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)