Skip to content

Commit

Permalink
Auto merge of #117967 - adetaylor:fix-lifetime-elision-bug, r=<try>
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Dec 11, 2023
2 parents 6f40082 + 15ce755 commit 57fd743
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 14 deletions.
26 changes: 16 additions & 10 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2105,13 +2105,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");
Expand All @@ -2135,6 +2137,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<'_, '_, '_> {
Expand All @@ -2158,9 +2161,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 {
Expand Down Expand Up @@ -2201,10 +2206,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
Expand Down
6 changes: 5 additions & 1 deletion tests/ui/self/elision/ref-assoc-async.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// edition:2018
// check-pass

#![allow(non_snake_case)]

Expand All @@ -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
}
}

Expand Down
77 changes: 77 additions & 0 deletions tests/ui/self/elision/ref-assoc-async.stderr
Original file line number Diff line number Diff line change
@@ -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

7 changes: 5 additions & 2 deletions tests/ui/self/elision/ref-assoc.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// check-pass

#![allow(non_snake_case)]

use std::pin::Pin;
Expand All @@ -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
}
}

Expand Down
77 changes: 77 additions & 0 deletions tests/ui/self/elision/ref-assoc.stderr
Original file line number Diff line number Diff line change
@@ -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: &'a <Struct as Trait>::AssocType, f: &'a u32) -> &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<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &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<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &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<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &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<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &u32 {
| ++++ ++ ++

error: aborting due to 5 previous errors

29 changes: 29 additions & 0 deletions tests/ui/self/elision/ref-self-multi.rs
Original file line number Diff line number Diff line change
@@ -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() { }
5 changes: 5 additions & 0 deletions tests/ui/self/elision/ref-self.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,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() { }
17 changes: 16 additions & 1 deletion tests/ui/self/elision/ref-self.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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<&'a Self, Self>, f: &'a u8) -> &u8 {
| ++++ ++ ++

error: aborting due to 7 previous errors
error: lifetime may not live long enough
--> $DIR/ref-self.rs:58: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: &'a Box<Self>, f: &'a u32) -> &u32 {
| ++++ ++ ++

error: aborting due to 8 previous errors

0 comments on commit 57fd743

Please sign in to comment.