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 https://github.com/rust-lang/rust/issues/117715
This commit is contained in:
parent
1d0e4afd4c
commit
8d1958f0d2
9 changed files with 246 additions and 21 deletions
|
@ -2132,13 +2132,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
// Handle `self` specially.
|
||||
if index == 0 && has_self {
|
||||
let self_lifetime = self.find_lifetime_for_self(ty);
|
||||
if let Set1::One(lifetime) = self_lifetime {
|
||||
elision_lifetime = match self_lifetime {
|
||||
// We found `self` elision.
|
||||
elision_lifetime = Elision::Self_(lifetime);
|
||||
} else {
|
||||
Set1::One(lifetime) => Elision::Self_(lifetime),
|
||||
// `self` itself had ambiguous lifetimes, e.g.
|
||||
// &Box<&Self>
|
||||
Set1::Many => Elision::None,
|
||||
// We do not have `self` elision: disregard the `Elision::Param` that we may
|
||||
// have found.
|
||||
elision_lifetime = Elision::None;
|
||||
Set1::Empty => Elision::None,
|
||||
}
|
||||
}
|
||||
debug!("(resolving function / closure) recorded parameter");
|
||||
|
@ -2162,6 +2164,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
r: &'r Resolver<'a, 'tcx>,
|
||||
impl_self: Option<Res>,
|
||||
lifetime: Set1<LifetimeRes>,
|
||||
self_found: bool,
|
||||
}
|
||||
|
||||
impl SelfVisitor<'_, '_, '_> {
|
||||
|
@ -2185,9 +2188,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> {
|
||||
fn visit_ty(&mut self, ty: &'a Ty) {
|
||||
trace!("SelfVisitor considering ty={:?}", ty);
|
||||
if let TyKind::Ref(lt, ref mt) = ty.kind
|
||||
&& self.is_self_ty(&mt.ty)
|
||||
{
|
||||
if self.is_self_ty(ty) {
|
||||
trace!("SelfVisitor found Self");
|
||||
self.self_found = true;
|
||||
}
|
||||
if let TyKind::Ref(lt, _) = ty.kind {
|
||||
let lt_id = if let Some(lt) = lt {
|
||||
lt.id
|
||||
} else {
|
||||
|
@ -2228,10 +2233,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_)
|
||||
)
|
||||
});
|
||||
let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
|
||||
let mut visitor =
|
||||
SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty, self_found: false };
|
||||
visitor.visit_ty(ty);
|
||||
trace!("SelfVisitor found={:?}", visitor.lifetime);
|
||||
visitor.lifetime
|
||||
trace!("SelfVisitor found={:?}, self_found={:?}", visitor.lifetime, visitor.self_found);
|
||||
if visitor.self_found { visitor.lifetime } else { Set1::Empty }
|
||||
}
|
||||
|
||||
/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
//@ edition:2018
|
||||
//@ check-pass
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
|
@ -18,22 +17,27 @@ impl Trait for Struct {
|
|||
impl Struct {
|
||||
async fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
|
||||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
async fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
|
||||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
async fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
|
||||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
async fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
|
||||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
async fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
|
||||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
}
|
||||
|
||||
|
|
77
tests/ui/self/elision/ref-assoc-async.stderr
Normal file
77
tests/ui/self/elision/ref-assoc-async.stderr
Normal file
|
@ -0,0 +1,77 @@
|
|||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-assoc-async.rs:19:9
|
||||
|
|
||||
LL | async fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
| |
|
||||
| let's call the lifetime of this reference `'2`
|
||||
LL | f
|
||||
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
||||
|
|
||||
help: consider introducing a named lifetime parameter and update trait if needed
|
||||
|
|
||||
LL | async fn ref_AssocType<'a>(self: &'a <Struct as Trait>::AssocType, f: &'a u32) -> &u32 {
|
||||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-assoc-async.rs:24:9
|
||||
|
|
||||
LL | async fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
| |
|
||||
| let's call the lifetime of this reference `'2`
|
||||
LL | f
|
||||
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
||||
|
|
||||
help: consider introducing a named lifetime parameter and update trait if needed
|
||||
|
|
||||
LL | async fn box_ref_AssocType<'a>(self: Box<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &u32 {
|
||||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-assoc-async.rs:29:9
|
||||
|
|
||||
LL | async fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
| |
|
||||
| let's call the lifetime of this reference `'2`
|
||||
LL | f
|
||||
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
||||
|
|
||||
help: consider introducing a named lifetime parameter and update trait if needed
|
||||
|
|
||||
LL | async fn pin_ref_AssocType<'a>(self: Pin<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &u32 {
|
||||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-assoc-async.rs:34:9
|
||||
|
|
||||
LL | async fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
| |
|
||||
| let's call the lifetime of this reference `'2`
|
||||
LL | f
|
||||
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
||||
|
|
||||
help: consider introducing a named lifetime parameter and update trait if needed
|
||||
|
|
||||
LL | async fn box_box_ref_AssocType<'a>(self: Box<Box<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &u32 {
|
||||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-assoc-async.rs:39:9
|
||||
|
|
||||
LL | async fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
| |
|
||||
| let's call the lifetime of this reference `'2`
|
||||
LL | f
|
||||
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
||||
|
|
||||
help: consider introducing a named lifetime parameter and update trait if needed
|
||||
|
|
||||
LL | async fn box_pin_ref_AssocType<'a>(self: Box<Pin<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &u32 {
|
||||
| ++++ ++ ++
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
//@ check-pass
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use std::pin::Pin;
|
||||
|
@ -17,22 +15,27 @@ impl Trait for Struct {
|
|||
impl Struct {
|
||||
fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
|
||||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
|
||||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
|
||||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
|
||||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
|
||||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
}
|
||||
|
||||
|
|
77
tests/ui/self/elision/ref-assoc.stderr
Normal file
77
tests/ui/self/elision/ref-assoc.stderr
Normal file
|
@ -0,0 +1,77 @@
|
|||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-assoc.rs:17:9
|
||||
|
|
||||
LL | fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
| |
|
||||
| let's call the lifetime of this reference `'2`
|
||||
LL | f
|
||||
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
||||
|
|
||||
help: consider introducing a named lifetime parameter and update trait if needed
|
||||
|
|
||||
LL | fn ref_AssocType<'a>(self: &<Struct as Trait>::AssocType, f: &'a u32) -> &'a u32 {
|
||||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-assoc.rs:22:9
|
||||
|
|
||||
LL | fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
| |
|
||||
| let's call the lifetime of this reference `'2`
|
||||
LL | f
|
||||
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
||||
|
|
||||
help: consider introducing a named lifetime parameter and update trait if needed
|
||||
|
|
||||
LL | fn box_ref_AssocType<'a>(self: Box<&<Struct as Trait>::AssocType>, f: &'a u32) -> &'a u32 {
|
||||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-assoc.rs:27:9
|
||||
|
|
||||
LL | fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
| |
|
||||
| let's call the lifetime of this reference `'2`
|
||||
LL | f
|
||||
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
||||
|
|
||||
help: consider introducing a named lifetime parameter and update trait if needed
|
||||
|
|
||||
LL | fn pin_ref_AssocType<'a>(self: Pin<&<Struct as Trait>::AssocType>, f: &'a u32) -> &'a u32 {
|
||||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-assoc.rs:32:9
|
||||
|
|
||||
LL | fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
| |
|
||||
| let's call the lifetime of this reference `'2`
|
||||
LL | f
|
||||
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
||||
|
|
||||
help: consider introducing a named lifetime parameter and update trait if needed
|
||||
|
|
||||
LL | fn box_box_ref_AssocType<'a>(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &'a u32) -> &'a u32 {
|
||||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-assoc.rs:37:9
|
||||
|
|
||||
LL | fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
| |
|
||||
| let's call the lifetime of this reference `'2`
|
||||
LL | f
|
||||
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
||||
|
|
||||
help: consider introducing a named lifetime parameter and update trait if needed
|
||||
|
|
||||
LL | fn box_pin_ref_AssocType<'a>(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &'a u32) -> &'a u32 {
|
||||
| ++++ ++ ++
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
29
tests/ui/self/elision/ref-self-multi.rs
Normal file
29
tests/ui/self/elision/ref-self-multi.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
//@ run-pass
|
||||
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(unused)]
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
|
||||
struct Struct { }
|
||||
|
||||
struct Wrap<T, P>(T, PhantomData<P>);
|
||||
|
||||
impl<T, P> Deref for Wrap<T, P> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T { &self.0 }
|
||||
}
|
||||
|
||||
impl Struct {
|
||||
fn ref_box_ref_Self(self: &Box<&Self>, f: &u32) -> &u32 {
|
||||
f
|
||||
}
|
||||
|
||||
fn ref_wrap_ref_Self(self: &Wrap<&Self, u32>, f: &u32) -> &u32 {
|
||||
f
|
||||
}
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -1,4 +1,6 @@
|
|||
//@ run-rustfix
|
||||
//@ edition:2018
|
||||
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![allow(non_snake_case, dead_code)]
|
||||
|
||||
|
@ -56,6 +58,11 @@ impl Struct {
|
|||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn ref_box_Self<'a>(self: &Box<Self>, f: &'a u32) -> &'a u32 {
|
||||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
//@ run-rustfix
|
||||
//@ edition:2018
|
||||
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![allow(non_snake_case, dead_code)]
|
||||
|
||||
|
@ -56,6 +58,11 @@ impl Struct {
|
|||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn ref_box_Self(self: &Box<Self>, f: &u32) -> &u32 {
|
||||
f
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-self.rs:24:9
|
||||
--> $DIR/ref-self.rs:26:9
|
||||
|
|
||||
LL | fn ref_self(&self, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
|
@ -14,7 +14,7 @@ LL | fn ref_self<'a>(&self, f: &'a u32) -> &'a u32 {
|
|||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-self.rs:31:9
|
||||
--> $DIR/ref-self.rs:33:9
|
||||
|
|
||||
LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
|
@ -29,7 +29,7 @@ LL | fn ref_Self<'a>(self: &Self, f: &'a u32) -> &'a u32 {
|
|||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-self.rs:36:9
|
||||
--> $DIR/ref-self.rs:38:9
|
||||
|
|
||||
LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
|
@ -44,7 +44,7 @@ LL | fn box_ref_Self<'a>(self: Box<&Self>, f: &'a u32) -> &'a u32 {
|
|||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-self.rs:41:9
|
||||
--> $DIR/ref-self.rs:43:9
|
||||
|
|
||||
LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
|
@ -59,7 +59,7 @@ LL | fn pin_ref_Self<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 {
|
|||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-self.rs:46:9
|
||||
--> $DIR/ref-self.rs:48:9
|
||||
|
|
||||
LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
|
@ -74,7 +74,7 @@ LL | fn box_box_ref_Self<'a>(self: Box<Box<&Self>>, f: &'a u32) -> &'a u32 {
|
|||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-self.rs:51:9
|
||||
--> $DIR/ref-self.rs:53:9
|
||||
|
|
||||
LL | fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
|
@ -89,7 +89,7 @@ LL | fn box_pin_ref_Self<'a>(self: Box<Pin<&Self>>, f: &'a u32) -> &'a u32 {
|
|||
| ++++ ++ ++
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-self.rs:56:9
|
||||
--> $DIR/ref-self.rs:58:9
|
||||
|
|
||||
LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
|
@ -103,5 +103,20 @@ help: consider introducing a named lifetime parameter and update trait if needed
|
|||
LL | fn wrap_ref_Self_Self<'a>(self: Wrap<&Self, Self>, f: &'a u8) -> &'a u8 {
|
||||
| ++++ ++ ++
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/ref-self.rs:63:9
|
||||
|
|
||||
LL | fn ref_box_Self(self: &Box<Self>, f: &u32) -> &u32 {
|
||||
| - - let's call the lifetime of this reference `'1`
|
||||
| |
|
||||
| let's call the lifetime of this reference `'2`
|
||||
LL | f
|
||||
| ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
|
||||
|
|
||||
help: consider introducing a named lifetime parameter and update trait if needed
|
||||
|
|
||||
LL | fn ref_box_Self<'a>(self: &Box<Self>, f: &'a u32) -> &'a u32 {
|
||||
| ++++ ++ ++
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue