Borrow checker insists on the lifetime of a dereferenced value

Viewed 79

Here's a minimal example of the issue I'm having:

struct S<'a> {
    value: &'a mut Option<()>,
}

impl<'a> S<'a> {
    fn f<'b>(&'b mut self) {
        *self.value = Some(());
        let value: &'a () = self.value.as_ref().unwrap();
    }
}

Playground

Error:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
 --> src/lib.rs:8:34
  |
8 |         let value: &'a () = self.value.as_ref().unwrap();
  |                                        ^^^^^^
  |
note: first, the lifetime cannot outlive the lifetime `'b` as defined on the method body at 6:7...
 --> src/lib.rs:6:7
  |
6 |     fn f<'b>(&'b mut self) {
  |          ^^
note: ...so that reference does not outlive borrowed content
 --> src/lib.rs:8:23
  |
8 |         let value: &'a () = self.value.as_ref().unwrap();
  |                             ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 5:6...
 --> src/lib.rs:5:6
  |
5 | impl<'a> S<'a> {
  |      ^^
note: ...so that reference does not outlive borrowed content
 --> src/lib.rs:8:23
  |
8 |         let value: &'a () = self.value.as_ref().unwrap();
  |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The issue is that I'm expecting f's value variable to have the lifetime 'a as I've annotated, but the borrow checker is only content if it's 'b. I need it to be 'a because in my real code I derive a value from it that expects the 'a lifetime. And it also makes sense to me that it should be 'a because (and this is the crux of my confusion:) in self.value I've dereferenced 'b away and should be left with &'a mut Option<()>, i.e. a value with (just) the lifetime 'a.

I can solve it by specifying 'b: 'a but it's actually the opposite (if anything I need 'a: 'b); and also if 'b: 'a then this function mutably borrows indefinitely and I can't touch the S after calling f which is a problem Playground.

I'm not sure if it's overconservative or if I'm actually trying to do something unsound. Looking at the lifetimes at the call-site it makes perfect sense though.


Some information about my real use case: what I have is a buffer of type B, and from that buffer I can derive a value of type T. T isn't just derived from B, it also has a reference to it (imagine fn derive<'a>(self: &'a B) -> T<'a>). T values expire and require management, so I made a manager struct M, and this is where the trouble is: M contains a mutable reference to a B and a cached T. Therefore inside M, the B reference has some lifetime, and T has it too since T refers to B. It's something like this:

struct B { ... }
struct T<'a> { ... }
struct M<'a> {
  b: &mut 'a Option<B>,
  t: T<'a>,
}

So as in my minimal example, I try to obtain the reference of the B (which I expected to have the lifetime of the buffer but it has the lifetime of M) so I could derive from it and then assign the result to the cached T, but I don't have the right lifetime.

0 Answers
Related