@@ -78,6 +78,8 @@ use rustc_middle::mir::{self, dump_mir, MirPass};
7878use  rustc_middle:: ty:: { self ,  InstanceKind ,  Ty ,  TyCtxt ,  TypeVisitableExt } ; 
7979use  rustc_target:: abi:: { FieldIdx ,  VariantIdx } ; 
8080
81+ use  crate :: pass_manager:: validate_body; 
82+ 
8183pub  struct  ByMoveBody ; 
8284
8385impl < ' tcx >  MirPass < ' tcx >  for  ByMoveBody  { 
@@ -131,20 +133,40 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
131133            |( parent_field_idx,  parent_capture) ,  ( child_field_idx,  child_capture) | { 
132134                // Store this set of additional projections (fields and derefs). 
133135                // We need to re-apply them later. 
134-                 let  child_precise_captures =
135-                     & child_capture. place . projections [ parent_capture. place . projections . len ( ) ..] ; 
136+                 let  mut  child_precise_captures = child_capture. place . projections 
137+                     [ parent_capture. place . projections . len ( ) ..] 
138+                     . to_vec ( ) ; 
136139
137-                 // If the parent captures by-move, and the child captures by-ref, then we 
138-                 // need to peel an additional `deref` off of the body of the child. 
139-                 let  needs_deref = child_capture. is_by_ref ( )  && !parent_capture. is_by_ref ( ) ; 
140-                 if  needs_deref { 
141-                     assert_ne ! ( 
142-                         coroutine_kind, 
143-                         ty:: ClosureKind :: FnOnce , 
140+                 // If the parent capture is by-ref, then we need to apply an additional 
141+                 // deref before applying any further projections to this place. 
142+                 if  parent_capture. is_by_ref ( )  { 
143+                     child_precise_captures. insert ( 
144+                         0 , 
145+                         Projection  {  ty :  parent_capture. place . ty ( ) ,  kind :  ProjectionKind :: Deref  } , 
146+                     ) ; 
147+                 } 
148+                 // If the child capture is by-ref, then we need to apply a "ref" 
149+                 // projection (i.e. `&`) at the end. But wait! We don't have that 
150+                 // as a projection kind. So instead, we can apply its dual and 
151+                 // *peel* a deref off of the place when it shows up in the MIR body. 
152+                 // Luckily, by construction this is always possible. 
153+                 let  peel_deref = if  child_capture. is_by_ref ( )  { 
154+                     assert ! ( 
155+                         parent_capture. is_by_ref( )  || coroutine_kind != ty:: ClosureKind :: FnOnce , 
144156                        "`FnOnce` coroutine-closures return coroutines that capture from \  
145157
146158                    ) ; 
147-                 } 
159+                     true 
160+                 }  else  { 
161+                     false 
162+                 } ; 
163+ 
164+                 // Regarding the behavior above, you may think that it's redundant to both 
165+                 // insert a deref and then peel a deref if the parent and child are both 
166+                 // captured by-ref. This would be correct, except for the case where we have 
167+                 // precise capturing projections, since the inserted deref is to the *beginning* 
168+                 // and the peeled deref is at the *end*. I cannot seem to actually find a 
169+                 // case where this happens, though, but let's keep this code flexible. 
148170
149171                // Finally, store the type of the parent's captured place. We need 
150172                // this when building the field projection in the MIR body later on. 
@@ -164,7 +186,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
164186                    ( 
165187                        FieldIdx :: from_usize ( parent_field_idx + num_args) , 
166188                        parent_capture_ty, 
167-                         needs_deref , 
189+                         peel_deref , 
168190                        child_precise_captures, 
169191                    ) , 
170192                ) 
@@ -192,6 +214,10 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
192214        let  mut  by_move_body = body. clone ( ) ; 
193215        MakeByMoveBody  {  tcx,  field_remapping,  by_move_coroutine_ty } . visit_body ( & mut  by_move_body) ; 
194216        dump_mir ( tcx,  false ,  "coroutine_by_move" ,  & 0 ,  & by_move_body,  |_,  _| Ok ( ( ) ) ) ; 
217+ 
218+         // Let's just always validate this body. 
219+         validate_body ( tcx,  & mut  by_move_body,  "Initial coroutine_by_move body" . to_string ( ) ) ; 
220+ 
195221        // FIXME: use query feeding to generate the body right here and then only store the `DefId` of the new body. 
196222        by_move_body. source  = mir:: MirSource :: from_instance ( InstanceKind :: CoroutineKindShim  { 
197223            coroutine_def_id :  coroutine_def_id. to_def_id ( ) , 
@@ -202,7 +228,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
202228
203229struct  MakeByMoveBody < ' tcx >  { 
204230    tcx :  TyCtxt < ' tcx > , 
205-     field_remapping :  UnordMap < FieldIdx ,  ( FieldIdx ,  Ty < ' tcx > ,  bool ,  & ' tcx   [ Projection < ' tcx > ] ) > , 
231+     field_remapping :  UnordMap < FieldIdx ,  ( FieldIdx ,  Ty < ' tcx > ,  bool ,  Vec < Projection < ' tcx > > ) > , 
206232    by_move_coroutine_ty :  Ty < ' tcx > , 
207233} 
208234
@@ -223,14 +249,14 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> {
223249        if  place. local  == ty:: CAPTURE_STRUCT_LOCAL 
224250            && let  Some ( ( & mir:: ProjectionElem :: Field ( idx,  _) ,  projection) )  =
225251                place. projection . split_first ( ) 
226-             && let  Some ( & ( remapped_idx,  remapped_ty,  needs_deref ,  bridging_projections) )  =
252+             && let  Some ( & ( remapped_idx,  remapped_ty,  peel_deref ,   ref  bridging_projections) )  =
227253                self . field_remapping . get ( & idx) 
228254        { 
229255            // As noted before, if the parent closure captures a field by value, and 
230256            // the child captures a field by ref, then for the by-move body we're 
231257            // generating, we also are taking that field by value. Peel off a deref, 
232258            // since a layer of ref'ing has now become redundant. 
233-             let  final_projections = if  needs_deref  { 
259+             let  final_projections = if  peel_deref  { 
234260                let  Some ( ( mir:: ProjectionElem :: Deref ,  projection) )  = projection. split_first ( ) 
235261                else  { 
236262                    bug ! ( 
0 commit comments