Lifetime confusions. What is `'a` in this code segment?

I'm learning lifetimes. The following example (made up by me) looks confusing. Can you help on the lifetime annotation here? What does 'a resolve to in the caller side?

// This code compiles, which is confusing to me.

fn f<'a>(r: &'a &'a i32) -> &'a i32 {
    *r
}

fn main() {
    let x: i32 = 5;
    let y = &x;
    let w: &i32; // Assigned in the inner scope.
    {
        // Lifetime 'a starts here?
        let z = &y; // &'a &'a i32?
        w = f(z);
        // Lifetime 'a ends here?
    }

    // Compiles, why?
    // Why w is still valid here? Isn't `'a` gone out of scope?
    // How does the `'a` in `f` resolve?
    println!("{:?}", w);
}
1 Like

I think the more practical interpretation of "the 'a thing" is borrow context/set of loans (instead of "lifetime"). I'll be using '{set of borrows} (invented) syntax as a "resolved" lifetime parameter. So, if I write type &'{x} T that means references of this type borrow variable x immutably.

So on your case

let y = &x;

could be "expanded" to

let y: &'{x} i32 = &x;

Similarly,

let z = &y;

expands to

let z: &'{x, y} &'{x} i32 = &y;
// (note: borrow of `x` propagates, because `y` already borrowed `x`)

So, in the function call f(z), we can see that the lifetime parametersborrow contexts on the references are different, but since the function declares them as the same (&'a&'a i32), the both get converted to the superset – '{x, y}.

We can then desugar:

let w: &'{x, y} &'{x, y} i32;
// ...
    w = f::<'{x, y}>(z);

Since the variable w borrows only from x and y, it's safe to use it after the {} block (you can see, there's not a trace of z in the borrow context) and thus the println compiles. :slight_smile:

(Your example would stop compiling, if you also put y in the {} block, because the f's signature is actually quite restrictive – w actually only points to x, despite its type that says it borrows also y. If you modified the signature to fn<'a>(r: &&'a i32) -> 'a i32), it'd compile again).

5 Likes

Ah I see. Thanks for the quick and clear explanation! Your expansion clear shows that it's about the borrow of x and y, nothing to do with z actually (z's lifetime is irrelevant here). I think that's where I went wrong! Thanks for the clear explanation again!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.