To my understanding, the code, Rust Playground should not pass compiling, but it compiles, why?
use std::marker::*;
#[derive(Debug)]
struct WhatAboutThis<'a> {
name: i32,
_a: PhantomData<&'a WhatAboutThis<'a>>,
}
impl<'a> WhatAboutThis<'a> {
fn x(self: &'a mut &'a Self) {}
}
fn main() {
// tricky can't outlive 'a
let mut tricky = WhatAboutThis {
name: 32,
_a: PhantomData,
};
// &mut &'1 tricky
let p = &mut &tricky;
// signature of x: fn x(self: &'a mut &'a Self) {}
// 1. &mut T is invariant at T, so '1 == 'a
// 2. T is &'1 tricky, '1 should not outlive strike
// 3. tricky can't outlive 'a, neither, because of _a: PhantomData<&'a WhatAboutThis<'a>>
// so, '1 == 'a == scope_life_of(tricky)
p.x();
// move tricky, should fail to compile because '1 is still alive
let z = tricky;
println!("{:?}", z);
}
WhatAboutThis<'w> is covariant in 'w, so the underlined portion just chooses some 'm to create a &'m WhatAboutThis<'m> that matches the lifetime of the &'m mut (which need only stick around until the call to p.x()).
To avoid the covariance (for fun and profit) during construction of the &mut & _... hmm... I don't know if there is a safe way to do so. This accomplishes it:
fn hmm<'x, 'y>(self: &'x mut &'y mut Self) -> &'x mut &'y Self {
let ptr: *mut &'y mut Self = self;
let ptr = ptr as *mut &'y Self;
unsafe { &mut *ptr }
}
// ...
let p = (&mut tricky).hmm();
But that doesn't really mean much as a &'a mut Self must also be created to call hmm with the necessary lifetimes in the playground, and that alone is enough to create the borrowed-forever scenario.
Generics or TAIT or something might be able to create the &'a mut &'a WhatAboutThis<'a> without borrowing it forever before the creation.
What means create a &'m WhatAboutThis<'m> ? Is the WhatAboutThis<'m> indeed the tricky? If it is tricky, then tricky is a instance of WhatAboutThis<'m>, which holds a reference of &'m WhatAboutThis<'m>.
Seems you are talking about a 'm and 'm < 'a. Then WhatAboutThis<'m> should not be the tricky.
// Call this a WhatAboutThis<'w>
let mut tricky = WhatAboutThis {
name: 32,
_a: PhantomData,
};
// This is a &'m WhatAboutThis<'m> ('w: 'm)
let mut r = &tricky;
// This is a &'m mut &'m WhatAboutThis<'m>
let p = &mut r;
// Due to this call
p.x();
let y = r; // fails (r is borrowed forever -- for `'m`)
// This is fine (tricky is not borrowed forever; `'w` > `'m`)
let z = tricky;
error[E0505]: cannot move out of `tricky` because it is borrowed
--> src/main.rs:38:13
|
16 | let tricky = WhatAboutThis {
| ------ binding `tricky` declared here
...
22 | let p = &mut &tricky;
| ------- borrow of `tricky` occurs here
...
38 | let z = tricky;
| ^^^^^^
| |
| move out of `tricky` occurs here
| borrow later used here
For more information about this error, try `rustc --explain E0505`.
impl<'a> T<'a> {
fn method(this: &mut &'a Self) {}
}
let ref : &'any T<'short> = &'any T<'long>; // as long as T is covariant
ref.method(); // will call T::<'short>::method(&mut &'short Self)
// not T::<'long>::method(&mut &'long Self)