Footgun with lifetimes and `Self` shorthand in methods

I've had enough experience with Rust that I rarely get stuck on borrow-checking issues, but there is one mistake I've made a couple of times that has had me confused for a long time before I eventually realized what was going on.

The code below fails to compile:

struct Wrapper<'a, T> {
    inner: &'a mut T,
}

impl<'a, T> Wrapper<'a, T> {
    fn new(inner: &'a mut T) -> Self {
        Self { inner }
    }

    fn reborrow(&mut self) -> Wrapper<'_, T> {
        Self { inner: self.inner }
    }
}

With an error like:

error: lifetime may not live long enough
  --> test.rs:11:23
   |
 5 | impl<'a, T> Wrapper<'a, T> {
   |      -- lifetime `'a` defined here
...
10 |     fn reborrow(&mut self) -> Wrapper<'_, T> {
   |                 - let's call the lifetime of this reference `'1`
11 |         Self { inner: self.inner }
   |                       ^^^^^^^^^^ this usage requires that `'1` must outlive `'a`

The mistake here is that using Self in the reborrow method refers not just to Wrapper but specifically to Wrapper<'a, T>, with a different lifetime than intended.

Changing it to this resolves the problem:

fn reborrow(&mut self) -> Wrapper<'_, T> {
    Wrapper { inner: self.inner }
}

As now the lifetime will be inferred to the intended value.

Any thoughts on how the compiler could catch this kind of mistake or make it more obvious what is happening, without spurious warnings?

15 Likes

Worth a diagnostics issue if there isn’t one already. Definitely an issue that has stumped me a few times.

2 Likes

The PR mentioned at the top didn't land.

9 Likes