Return mutable reference to a field from `&mut self`

Today is one of those extremely rare days when I get blocked by borrow checker and I'm not sure if it is me who is wrong or borrow checker is not smart enough:

struct Container<'a>(&'a mut ());

impl Drop for Container<'_> {
    fn drop(&mut self) {
        todo!()
    }
}

impl<'a> Container<'a> {
    fn new_nested<'b>(&'b mut self) -> Container<'b>
    where
        'a: 'b,
    {
        Self(self.0)
    }
}

fn foo() {
    let mut v = ();
    let mut c = Container(&mut v);
    c.new_nested();
}

My reasoning here is that 'a is a larger lifetime than 'b, so 'b will never outlive 'a. But compiler disagrees:

error: lifetime may not live long enough
  --> src/lib.rs:12:14
   |
9  | impl<'a> Container<'a> {
   |      -- lifetime `'a` defined here
10 |     fn new_nested<'b>(&'b mut self) -> Container<'b>
   |                   -- lifetime `'b` defined here
11 |     where 'a: 'b {
12 |         Self(self.0)
   |              ^^^^^^ this usage requires that `'b` must outlive `'a`
   |
   = help: consider adding the following bound: `'b: 'a`

Adding 'b: 'a is pointless though because it makes the whole thing unusable downstream:

error[E0597]: `c` does not live long enough
  --> src/lib.rs:19:5
   |
18 |     let mut c = Container(&mut v);
   |         ----- binding `c` declared here
19 |     c.new_nested();
   |     ^ borrowed value does not live long enough
20 | }
   | -
   | |
   | `c` dropped here while still borrowed
   | borrow might be used here, when `c` is dropped and runs the `Drop` code for type `Container`

I checked a bunch of similar-looking issues and even tried current version of Polonius on Nightly, can't figure it out :confused_face:

1 Like

When using Self, you are forcing the compiler to use the exact same type (i.e., subtyping does not apply). Change Self(self.0) to Container(self.0), and your code compiles.

Also, you can make this example more idiomatic by relying on lifetime elision:

impl Container<'_> {
    fn new_nested(&mut self) -> Container<'_>
    {
        Container(self.0)
    }
}
fn foo() {
    let mut v = ();
    let mut c = Container(&mut v);
    c.new_nested();
}
6 Likes

Very surprising, but makes a lot of sense in retrospect, thank you!

1 Like