#![allow(unused)]
use std::marker::PhantomData;
struct S<'a> {
_d: PhantomData<&'a i32>
}
fn func<'a>(s: &mut S<'a>, val: &'a i32) {
}
fn main() {
let mut s = S { _d: PhantomData };
let val = 3;
func(&mut s, &val);
}
It fails to compile with this error:
error[E0597]: `val` does not live long enough
--> src/main.rs:14:19
|
14 | func(&mut s, &val);
| ^^^ borrowed value does not live long enough
15 | }
| - `val` dropped here while still borrowed
However if I change the first argument of func from &mut s to &s the problem goes away. What is the explanation for this? Is it that when I use &s lifetime 'a is is taken to be the smallest possible that'll do the job whereas when I use &mut s it is expanded such that it starts from the first let binding in main?
The explanation has to do with variance/subtyping. The gist is that a &mut T makes T invariant. Variance in Rust is purely in terms of lifetimes (e.g. is S<'a> is a subtype of S<'b> if 'a:'b). When something is variant, you can substitute a longer lifetime for a shorter one (also sometimes referred to as "shrinking" the lifetime).
In this case, you cannot shrink down the lifetime because S<'a> becomes invariant as it's behind a mutable reference. That means its lifetime cannot be shrunk to "intersect" with the lifetime of val. If this were allowed, then you could store val into s and leave s pointing at dangling memory.