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, which means we’re reborrowing a reference that we captured by move.

#![feature(async_closure)]
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.

#![feature(async_closure)]
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.