should_reborrow_from_env_of_parent_coroutine_closure in rustc_hir_typeck::upvar - Rust
Description: Determines whether a child capture that is derived from a parent capture should be borrowed with the lifetime of the parent coroutine-closure’s env.

Skip to main content

## should_reborrow_from_env_of_parent_coroutine_closure

# Function should_reborrow_from_env_of_parent_coroutine_closure

Source

    fn should_reborrow_from_env_of_parent_coroutine_closure<'tcx>(
        parent_capture: &CapturedPlace<'tcx>,
        child_capture: &CapturedPlace<'tcx>,
    ) -> bool

Expand description

Determines whether a child capture that is derived from a parent capture should be borrowed with the lifetime of the parent coroutine-closure’s env.

There are two cases when this needs to happen:

(1.) Are we borrowing data owned by the parent closure? We can determine if that is the case by checking if the parent capture is by move, EXCEPT if we apply a deref projection of an immutable reference, reborrows of immutable references which aren’t restricted to the LUB of the lifetimes of the deref chain. This is why `&'short mut &'long T` can be reborrowed as `&'long T`.

    let x = &1i32; // Let's call this lifetime `'1`.
    let c = async move || {
        println!("{:?}", *x);
        // Even though the inner coroutine borrows by ref, we're only capturing `*x`,
        // not `x`, so the inner closure is allowed to reborrow the data for `'1`.
    };

(2.) If a coroutine is mutably borrowing from a parent capture, then that mutable borrow cannot live for longer than either the parent or the borrow that we have on the original upvar. Therefore we always need to borrow the child capture with the lifetime of the parent coroutine-closure’s env.

    let mut x = 1i32;
    let c = async || {
        x = 1;
        // The parent borrows `x` for some `&'1 mut i32`.
        // However, when we call `c()`, we implicitly autoref for the signature of
        // `AsyncFnMut::async_call_mut`. Let's call that lifetime `'call`. Since
        // the maximum that `&'call mut &'1 mut i32` can be reborrowed is `&'call mut i32`,
        // the inner coroutine should capture w/ the lifetime of the coroutine-closure.
    };

If either of these cases apply, then we should capture the borrow with the lifetime of the parent coroutine-closure’s env. Luckily, if this function is not correct, then the program is not unsound, since we still borrowck and validate the choices made from this function – the only side-effect is that the user may receive unnecessary borrowck errors.