This code passes the compiler (for clarification lifetimes are not elided):
struct Foo<'a> {
_field: &'a i32,
}
fn test<'a, 'b, 'c>(_x: &'a mut Foo<'c>, _y: &'b bool) { // case 1
}
fn main() {
let f = &mut Foo { _field: &0 };
{
let p = false;
test(f, &p);
}
}
If I use 'b
instead of 'c
in test
's definition like so:
fn test<'a, 'b>(_x: &'a mut Foo<'b>, _y: &'b bool) { // case 2
}
the code fails to compile ("p does not live long enough")!
What I would expect to happen at the call of test
in case 2 is:
'a
is set to the actual lifetime of f
,'b
is set to the intersection of the Foo
's actual lifetime and &p
's actual lifetime which is &p
's lifetime,and everything should be fine, as in case 1.
Instead, what actually seems to happen in case 2 is that 'b
is forced to become the lifetime of the Foo
which is too big for &p
's lifetime, hence the compiler error 'p does not live long enough'. True?
Even stranger (case 3): this only fails if test
takes a &mut. If I leave the <'b>
in, but remove the mut
like so:
fn test<'a, 'b>(_x: &'a Foo<'b>, _y: &'b bool) { // case 3
}
the code passes again.
Anyone to shed light on this?
Cheers.
Noting the difference with mut
was a key observation. I think that it will make more sense if you change the type of the second argument and give one possible implementation:
fn test<'a, 'b>(_x: &'a mut Foo<'b>, _y: &'b i32) {
_x._field = _y;
}
This function has the ability to mutate _x
. That mutation also includes storing a new reference in _field
. However, if we were able to store a reference that had a shorter lifetime (the intersection you mentioned), as soon as the inner block ended, the reference in the Foo
would become invalid and we would have violated Rust's memory safety guarantees!
When you use an immutable reference, you don't have this danger, so the compiler allows it.
You have discovered an important thing - Rust doesn't always care what you do in the function. When checking if a function call is valid, only the type signature of the function is used.
I'm sure there's a fancy way of saying this using the proper terms like contravariance and covariance, but I don't know those well enough to use them properly! ^_^
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With