← [ ABORT TO HUD ]
SEQ. 1
SEQ. 2
Non-Lexical Lifetimes (NLL), Reborrowing & Variance
Lifetime Algebra & Non-Lexical Lifetimes
Lifetimes in Rust are not runtime durations; they are static compile-time regions of code over which a reference is guaranteed valid by the borrow checker. Under the Non-Lexical Lifetimes (NLL) engine (Polonius), lifetimes end at their last actual point of use, rather than surviving to the end of the enclosing syntactic scope block.
Subtyping & Variance
Variance describes how the subtyping relationship between types T and U relates to the subtyping relationship between generic types F<T> and F<U>:
| Type Constructor | Variance over 'a | Variance over T | Intuition |
|---|---|---|---|
&'a T | Covariant | Covariant | Can safely substitute a longer lifetime for a shorter one |
&'a mut T | Covariant | Invariant | Cannot substitute subtypes; would allow storing shorter lifetimes into longer-lived references! |
fn(T) -> U | N/A | Contravariant over T, Covariant over U | Function inputs can accept wider supertypes |
Reborrowing vs Moving
When you pass a mutable reference &mut T into a function or bind it to a new identifier, Rust performs a reborrow rather than a move:
fn append_token(tokens: &mut Vec, token_id: u32) {
tokens.push(token_id);
}
let mut stream = Vec::new();
let ref1 = &mut stream;
// Reborrow: ref1 is temporarily suspended, not consumed!
append_token(ref1, 42);
// ref1 is active and usable again here
ref1.push(99);
⌨ HANDS-ON LABVerify NLL Liveness & Lifetime Variance with rustc
⭐ +150 XPDiagnose borrow checker lifetimes, verify early drops under Non-Lexical Lifetimes (NLL), and test mutable invariant constraints.
1Check borrow checker analysis flags with the Polonius borrow checker.
2Run borrow checker tests verifying mutable invariant lifetimes.
OBJECTIVE 1 / 2 — type "hint" if stuck
SYNAPSE VERIFICATION
QUERY 1 // 1
Why is '&mut T' invariant over T?
Because allowing covariance would enable writing a short-lived reference into a location expecting a long-lived reference, causing a use-after-free
Because mutable pointers are always stored in read-only registers
Because Rust does not support runtime reflection for mutable types
Because LLVM disallows pointer aliasing in function prologues