Skip to content

Commit

Permalink
Auto merge of rust-lang#117967 - adetaylor:fix-lifetime-elision-bug, …
Browse files Browse the repository at this point in the history
…r=<try>

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 rust-lang#117715
  • Loading branch information
bors committed Jan 9, 2024
2 parents ae9d24d + c46b820 commit e65790b
Show file tree
Hide file tree
Showing 13 changed files with 445 additions and 17 deletions.
28 changes: 18 additions & 10 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2105,13 +2105,17 @@ 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>. In this case we won't consider
// taking an alternative parameter lifetime; just avoid elision
// entirely.
Set1::Many => Elision::Err,
// 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 +2139,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 +2163,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 +2208,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
11 changes: 10 additions & 1 deletion tests/ui/self/elision/multiple-ref-self-async.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// check-pass
// edition:2018

#![feature(arbitrary_self_types)]
Expand All @@ -21,23 +20,33 @@ impl Struct {
// Test using multiple `&Self`:

async fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
//~^ ERROR missing lifetime specifier
f
//~^ ERROR lifetime may not live long enough
}

async fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
//~^ ERROR missing lifetime specifier
f
//~^ ERROR lifetime may not live long enough
}

async fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
//~^ ERROR missing lifetime specifier
f
//~^ ERROR lifetime may not live long enough
}

async fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
//~^ ERROR missing lifetime specifier
f
//~^ ERROR lifetime may not live long enough
}

async fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
//~^ ERROR missing lifetime specifier
f
//~^ ERROR lifetime may not live long enough
}
}

Expand Down
108 changes: 108 additions & 0 deletions tests/ui/self/elision/multiple-ref-self-async.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
error[E0106]: missing lifetime specifier
--> $DIR/multiple-ref-self-async.rs:22:74
|
LL | async fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
| ------------------ --- ^ expected named lifetime parameter
|
= 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`
help: consider introducing a named lifetime parameter
|
LL | async fn wrap_ref_Self_ref_Self<'a>(self: Wrap<&'a Self, &'a Self>, f: &'a u8) -> &'a u8 {
| ++++ ++ ++ ++ ++

error[E0106]: missing lifetime specifier
--> $DIR/multiple-ref-self-async.rs:28:84
|
LL | async fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
| ----------------------- ---- ^ expected named lifetime parameter
|
= 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`
help: consider introducing a named lifetime parameter
|
LL | async fn box_wrap_ref_Self_ref_Self<'a>(self: Box<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 {
| ++++ ++ ++ ++ ++

error[E0106]: missing lifetime specifier
--> $DIR/multiple-ref-self-async.rs:34:84
|
LL | async fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
| ----------------------- ---- ^ expected named lifetime parameter
|
= 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`
help: consider introducing a named lifetime parameter
|
LL | async fn pin_wrap_ref_Self_ref_Self<'a>(self: Pin<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 {
| ++++ ++ ++ ++ ++

error[E0106]: missing lifetime specifier
--> $DIR/multiple-ref-self-async.rs:40:93
|
LL | async fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
| ---------------------------- ---- ^ expected named lifetime parameter
|
= 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`
help: consider introducing a named lifetime parameter
|
LL | async fn box_box_wrap_ref_Self_ref_Self<'a>(self: Box<Box<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 {
| ++++ ++ ++ ++ ++

error[E0106]: missing lifetime specifier
--> $DIR/multiple-ref-self-async.rs:46:93
|
LL | async fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
| ---------------------------- ---- ^ expected named lifetime parameter
|
= 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`
help: consider introducing a named lifetime parameter
|
LL | async fn box_pin_wrap_ref_Self_ref_Self<'a>(self: Box<Pin<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 {
| ++++ ++ ++ ++ ++

error: lifetime may not live long enough
--> $DIR/multiple-ref-self-async.rs:24:9
|
LL | async fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
| - let's call the lifetime of this reference `'1`
LL |
LL | f
| ^ returning this value requires that `'1` must outlive `'static`

error: lifetime may not live long enough
--> $DIR/multiple-ref-self-async.rs:30:9
|
LL | async fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
| - let's call the lifetime of this reference `'1`
LL |
LL | f
| ^ returning this value requires that `'1` must outlive `'static`

error: lifetime may not live long enough
--> $DIR/multiple-ref-self-async.rs:36:9
|
LL | async fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
| - let's call the lifetime of this reference `'1`
LL |
LL | f
| ^ returning this value requires that `'1` must outlive `'static`

error: lifetime may not live long enough
--> $DIR/multiple-ref-self-async.rs:42:9
|
LL | async fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
| - let's call the lifetime of this reference `'1`
LL |
LL | f
| ^ returning this value requires that `'1` must outlive `'static`

error: lifetime may not live long enough
--> $DIR/multiple-ref-self-async.rs:48:9
|
LL | async fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
| - let's call the lifetime of this reference `'1`
LL |
LL | f
| ^ returning this value requires that `'1` must outlive `'static`

error: aborting due to 10 previous errors

For more information about this error, try `rustc --explain E0106`.
7 changes: 5 additions & 2 deletions tests/ui/self/elision/multiple-ref-self.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// check-pass

#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]

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

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

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

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

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

fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
//~^ ERROR missing lifetime specifier
f
}
}
Expand Down
63 changes: 63 additions & 0 deletions tests/ui/self/elision/multiple-ref-self.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
error[E0106]: missing lifetime specifier
--> $DIR/multiple-ref-self.rs:20:68
|
LL | fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
| ------------------ --- ^ expected named lifetime parameter
|
= 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`
help: consider introducing a named lifetime parameter
|
LL | fn wrap_ref_Self_ref_Self<'a>(self: Wrap<&'a Self, &'a Self>, f: &'a u8) -> &'a u8 {
| ++++ ++ ++ ++ ++

error[E0106]: missing lifetime specifier
--> $DIR/multiple-ref-self.rs:25:78
|
LL | fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
| ----------------------- ---- ^ expected named lifetime parameter
|
= 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`
help: consider introducing a named lifetime parameter
|
LL | fn box_wrap_ref_Self_ref_Self<'a>(self: Box<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 {
| ++++ ++ ++ ++ ++

error[E0106]: missing lifetime specifier
--> $DIR/multiple-ref-self.rs:30:78
|
LL | fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
| ----------------------- ---- ^ expected named lifetime parameter
|
= 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`
help: consider introducing a named lifetime parameter
|
LL | fn pin_wrap_ref_Self_ref_Self<'a>(self: Pin<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 {
| ++++ ++ ++ ++ ++

error[E0106]: missing lifetime specifier
--> $DIR/multiple-ref-self.rs:35:87
|
LL | fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
| ---------------------------- ---- ^ expected named lifetime parameter
|
= 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`
help: consider introducing a named lifetime parameter
|
LL | fn box_box_wrap_ref_Self_ref_Self<'a>(self: Box<Box<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 {
| ++++ ++ ++ ++ ++

error[E0106]: missing lifetime specifier
--> $DIR/multiple-ref-self.rs:40:87
|
LL | fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
| ---------------------------- ---- ^ expected named lifetime parameter
|
= 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`
help: consider introducing a named lifetime parameter
|
LL | fn box_pin_wrap_ref_Self_ref_Self<'a>(self: Box<Pin<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 {
| ++++ ++ ++ ++ ++

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0106`.
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
Loading

0 comments on commit e65790b

Please sign in to comment.