error[E0623]: lifetime mismatch
--> src/lib.rs:9:5
|
8 | fn bar_ref<'a, 'b>(bar: &'b Bar<'a>) -> &'a i32 {
| ----------- -------
| |
| this parameter and the return type are declared with different lifetimes...
9 | bar.0
| ^^^^^ ...but data from `bar` is returned here
Can anyone explain why foo_ref compiles and bar_ref does not? It can't have anything to do with variance, nor can I see how &T being Copy makes a difference.
#[derive(Clone, Copy)]
struct CopyMe; // this represents &'a T
struct MoveMe; // this represents &'a mut T
// this represents the coercion &'a mut T -> &'a T
impl From<MoveMe> for CopyMe {
fn from(m: MoveMe) -> CopyMe {
CopyMe
}
}
struct Foo(CopyMe);
struct Bar(MoveMe);
fn foo_ref(foo: &Foo) -> CopyMe {
foo.0
}
fn bar_ref<'a, 'b>(bar: &Bar) -> CopyMe {
bar.0.into() // Note: trying to move out of something behind a shared reference
}
Now it is obvious how Copy comes into play. Note that &'a mut T coerces to &'a T, but it also consumes &'a mut T. This means that because it isn't Copy it must be moved out of Bar<'a>, but Bar<'a> is behind a shared reference, you can't move out of it. But because &'a T is Copy you can move out of Foo<'a> behind a shared reference.
Normally consuming &'a mut T doesn't matter because of reborrowing, but that doesn't work here, because reborrowing makes the lifetime 'a shorter. And this is where the problem shows up, Rust tries to reborrow, and fails giving a lifetime error.
Note that by making bar_ref take a Bar<'a> directly works: Rust Playground
then for the case where 'b is strictly smaller than 'a, reborrowing (technically unsized corecion?) cannot happen for longer lifetime, otherwise would be dangerous.