← [ ABORT TO HUD ]
SEQ. 1
SEQ. 2

Non-Lexical Lifetimes (NLL), Reborrowing & Variance

🔐 Ownership, Borrowing & Advanced Lifetime Algebra16 min120 BASE XP⌨ HANDS-ON LAB

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 ConstructorVariance over 'aVariance over TIntuition
&'a TCovariantCovariantCan safely substitute a longer lifetime for a shorter one
&'a mut TCovariantInvariantCannot substitute subtypes; would allow storing shorter lifetimes into longer-lived references!
fn(T) -> UN/AContravariant over T, Covariant over UFunction 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 XP

Diagnose 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.
lab-sandbox — simulated environment
INFINITY LAB SANDBOX v2.6 — simulated shell
Type the command for the current objective. Helpers: "hint", "solution", "clear".
$
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