@@ -319,34 +319,35 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
319319        } 
320320
321321        ty:: Coroutine ( _,  args)  => { 
322-             // rust-lang/rust#49918: types can be constructed, stored 
323-             // in the interior, and sit idle when coroutine yields 
324-             // (and is subsequently dropped). 
322+             // rust-lang/rust#49918: Locals can be stored across await points in the coroutine, 
323+             // called interior/witness types. Since we do not compute these witnesses until after 
324+             // building MIR, we consider all coroutines to unconditionally require a drop during 
325+             // MIR building. However, considering the coroutine to unconditionally be drop-live 
326+             // here may unnecessarily require its upvars' regions to be live when they don't need 
327+             // to be, leading to borrowck errors: <https://github.com/rust-lang/rust/issues/116242>. 
325328            // 
326-             // It would be nice to descend into interior of a 
327-             // coroutine to determine what effects dropping it might 
328-             // have (by looking at any drop effects associated with 
329-             // its interior). 
329+             // Here, we implement a more precise approximation for whether the coroutine is 
330+             // drop-live by considering the drop requirement of the witness and upvar types 
331+             // specifically. Note that this is still an approximation because since the coroutine 
332+             // interior has its regions erased, we must add *all* of the upvars to the set of live 
333+             // types if we find that *any* interior type is live. This is because any of the regions 
334+             // captured in the upvars may be stored in the interior, which then has its regions 
335+             // replaced by a binder (conceptually erasing the regions). 
330336            // 
331-             // However, the interior's representation uses things like 
332-             // CoroutineWitness that explicitly assume they are not 
333-             // traversed in such a manner. So instead, we will 
334-             // simplify things for now by treating all coroutines as 
335-             // if they were like trait objects, where its upvars must 
336-             // all be alive for the coroutine's (potential) 
337-             // destructor. 
338-             // 
339-             // In particular, skipping over `_interior` is safe 
340-             // because any side-effects from dropping `_interior` can 
341-             // only take place through references with lifetimes 
342-             // derived from lifetimes attached to the upvars and resume 
343-             // argument, and we *do* incorporate those here. 
337+             // For example, if we capture two upvar references `&'1 (), &'2 ()` and have some type 
338+             // in the interior, `for<'r> { NeedsDrop<'r> }`, we have no way to tell whether the 
339+             // region `'r` came from the `'1` or `'2` region, so we require both are live. This 
340+             // could even be unnecessary if `'r` was actually a `'static` region or some region 
341+             // local to the coroutine! That's why it's an approximation. 
344342            let  args = args. as_coroutine ( ) ; 
345343
346-             // While we conservatively assume that all coroutines require drop 
347-             // to avoid query cycles during MIR building, we can check the actual 
348-             // witness during borrowck to avoid unnecessary liveness constraints. 
349-             if  args. witness ( ) . needs_drop ( tcx,  tcx. erase_regions ( typing_env) )  { 
344+             // Note that we don't care about the the resume type has any drops since this is 
345+             // redundant. There is no storage for the resume type, so if it is actually stored 
346+             // in the interior, we'll already detect the need for a drop by checking the witness. 
347+             let  typing_env = tcx. erase_regions ( typing_env) ; 
348+             let  needs_drop = args. witness ( ) . needs_drop ( tcx,  typing_env) 
349+                 || args. upvar_tys ( ) . iter ( ) . any ( |ty| ty. needs_drop ( tcx,  typing_env) ) ; 
350+             if  needs_drop { 
350351                constraints. outlives . extend ( args. upvar_tys ( ) . iter ( ) . map ( ty:: GenericArg :: from) ) ; 
351352                constraints. outlives . push ( args. resume_ty ( ) . into ( ) ) ; 
352353            } 
0 commit comments