Why does mutability affect lifetime check?

In the following code:

struct Bar<'a> {
    baz: &'a usize,
}

struct Foo<'a> {
    bar: Bar<'a>,
}

impl<'a> Foo<'a> {
    fn foo<'b>(&'b mut self) -> &Bar<'b> {
        &self.bar
    }
    
    fn foo_mut<'b>(&'b mut self) -> &mut Bar<'b> {
        &mut self.bar
    }
}

The compiler will turn out error in foo_mut but not in foo:

error[E0308]: mismatched types
  --> src/lib.rs:15:9
   |
15 |         &mut self.bar
   |         ^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected mutable reference `&'b mut Bar<'b>`
              found mutable reference `&'b mut Bar<'a>`
note: the lifetime `'b` as defined here...
  --> src/lib.rs:14:16
   |
14 |     fn foo_mut<'b>(&'b mut self) -> &mut Bar<'b> {
   |                ^^
note: ...does not necessarily outlive the lifetime `'a` as defined here
  --> src/lib.rs:9:6
   |
9  | impl<'a> Foo<'a> {
   |      ^^

Why does foo pass the compilation but foo_mut not?

Due to lifetime inference rules, unspecified return lifetimes get the same annotation as self if self is a reference. So the fully desugared return types are &'b Bar<'b> and &'b mut Bar<'b>. However, the following can't work:

impl<'a> Foo<'a> {
    fn foo_mut<'b>(&'b mut self) -> &'b mut Bar<'b> {
        &mut self.bar
    }
}

because – as the compiler very clearly points it out – &mut self.bar is a &'b mut Bar<'a>, and not a &'b mut Bar<'b>. This would be fine if the reference were immutable, since immutable references only allow reading, so if 'b outlives 'a, then everything is fine.

But mutable references also allow writing through themselves, so the dataflow must be considered bidirectional. This manifests in mutable references being invariant: it is not soundly possible to convert a &'_ mut T<'long> to a &'_ mut T<'short>, because the latter would allow the other side to write a T<'short> into the place pointed by &'_ mut T<'long>, which could potentially result in a use-after-free.

4 Likes

See also

'a T
&'a T covariant covariant
&'a mut T covariant invariant
4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.