Skip to content

Commit a15cf8d

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 fd0a331 commit a15cf8d

File tree

5 files changed

+76
-9
lines changed

5 files changed

+76
-9
lines changed

compiler/rustc_resolve/src/late.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -2052,13 +2052,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
20522052
// Handle `self` specially.
20532053
if index == 0 && has_self {
20542054
let self_lifetime = self.find_lifetime_for_self(ty);
2055-
if let Set1::One(lifetime) = self_lifetime {
2055+
elision_lifetime = match self_lifetime {
20562056
// We found `self` elision.
2057-
elision_lifetime = Elision::Self_(lifetime);
2058-
} else {
2057+
Set1::One(lifetime) => Elision::Self_(lifetime),
2058+
// `self` itself had ambiguous lifetimes, e.g.
2059+
// &Box<&Self>
2060+
Set1::Many => Elision::Err,
20592061
// We do not have `self` elision: disregard the `Elision::Param` that we may
20602062
// have found.
2061-
elision_lifetime = Elision::None;
2063+
Set1::Empty => Elision::None,
20622064
}
20632065
}
20642066
debug!("(resolving function / closure) recorded parameter");
@@ -2082,6 +2084,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
20822084
r: &'r Resolver<'a, 'tcx>,
20832085
impl_self: Option<Res>,
20842086
lifetime: Set1<LifetimeRes>,
2087+
self_found: bool,
20852088
}
20862089

20872090
impl SelfVisitor<'_, '_, '_> {
@@ -2105,7 +2108,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21052108
impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> {
21062109
fn visit_ty(&mut self, ty: &'a Ty) {
21072110
trace!("SelfVisitor considering ty={:?}", ty);
2108-
if let TyKind::Ref(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) {
2111+
if self.is_self_ty(ty) {
2112+
trace!("SelfVisitor found Self");
2113+
self.self_found = true;
2114+
}
2115+
if let TyKind::Ref(lt, _) = ty.kind {
21092116
let lt_id = if let Some(lt) = lt {
21102117
lt.id
21112118
} else {
@@ -2146,10 +2153,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
21462153
Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_)
21472154
)
21482155
});
2149-
let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
2156+
let mut visitor =
2157+
SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty, self_found: false };
21502158
visitor.visit_ty(ty);
2151-
trace!("SelfVisitor found={:?}", visitor.lifetime);
2152-
visitor.lifetime
2159+
trace!("SelfVisitor found={:?}, self_found={:?}", visitor.lifetime, visitor.self_found);
2160+
if visitor.self_found { visitor.lifetime } else { Set1::Empty }
21532161
}
21542162

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