@@ -126,59 +126,33 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
126126
127127 let mut field_remapping = UnordMap :: default ( ) ;
128128
129- // One parent capture may correspond to several child captures if we end up
130- // refining the set of captures via edition-2021 precise captures. We want to
131- // match up any number of child captures with one parent capture, so we keep
132- // peeking off this `Peekable` until the child doesn't match anymore.
133- let mut parent_captures =
134- tcx. closure_captures ( parent_def_id) . iter ( ) . copied ( ) . enumerate ( ) . peekable ( ) ;
135- // Make sure we use every field at least once, b/c why are we capturing something
136- // if it's not used in the inner coroutine.
137- let mut field_used_at_least_once = false ;
138-
139- for ( child_field_idx, child_capture) in tcx
129+ let mut child_captures = tcx
140130 . closure_captures ( coroutine_def_id)
141131 . iter ( )
142132 . copied ( )
143133 // By construction we capture all the args first.
144134 . skip ( num_args)
145135 . enumerate ( )
146- {
147- loop {
148- let Some ( & ( parent_field_idx, parent_capture) ) = parent_captures. peek ( ) else {
149- bug ! ( "we ran out of parent captures!" )
150- } ;
136+ . peekable ( ) ;
151137
152- let PlaceBase :: Upvar ( parent_base) = parent_capture. place . base else {
153- bug ! ( "expected capture to be an upvar" ) ;
154- } ;
155- let PlaceBase :: Upvar ( child_base) = child_capture. place . base else {
156- bug ! ( "expected capture to be an upvar" ) ;
157- } ;
138+ // One parent capture may correspond to several child captures if we end up
139+ // refining the set of captures via edition-2021 precise captures. We want to
140+ // match up any number of child captures with one parent capture, so we keep
141+ // peeking off this `Peekable` until the child doesn't match anymore.
142+ for ( parent_field_idx, parent_capture) in
143+ tcx. closure_captures ( parent_def_id) . iter ( ) . copied ( ) . enumerate ( )
144+ {
145+ // Make sure we use every field at least once, b/c why are we capturing something
146+ // if it's not used in the inner coroutine.
147+ let mut field_used_at_least_once = false ;
158148
159- assert ! (
160- child_capture. place. projections. len( ) >= parent_capture. place. projections. len( )
161- ) ;
162- // A parent matches a child they share the same prefix of projections.
163- // The child may have more, if it is capturing sub-fields out of
164- // something that is captured by-move in the parent closure.
165- if parent_base. var_path . hir_id != child_base. var_path . hir_id
166- || !std:: iter:: zip (
167- & child_capture. place . projections ,
168- & parent_capture. place . projections ,
169- )
170- . all ( |( child, parent) | child. kind == parent. kind )
171- {
172- // Make sure the field was used at least once.
173- assert ! (
174- field_used_at_least_once,
175- "we captured {parent_capture:#?} but it was not used in the child coroutine?"
176- ) ;
177- field_used_at_least_once = false ;
178- // Skip this field.
179- let _ = parent_captures. next ( ) . unwrap ( ) ;
180- continue ;
181- }
149+ // A parent matches a child if they share the same prefix of projections.
150+ // The child may have more, if it is capturing sub-fields out of
151+ // something that is captured by-move in the parent closure.
152+ while child_captures. peek ( ) . map_or ( false , |( _, child_capture) | {
153+ child_prefix_matches_parent_projections ( parent_capture, child_capture)
154+ } ) {
155+ let ( child_field_idx, child_capture) = child_captures. next ( ) . unwrap ( ) ;
182156
183157 // Store this set of additional projections (fields and derefs).
184158 // We need to re-apply them later.
@@ -221,15 +195,15 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
221195 ) ;
222196
223197 field_used_at_least_once = true ;
224- break ;
225198 }
226- }
227199
228- // Pop the last parent capture
229- if field_used_at_least_once {
230- let _ = parent_captures. next ( ) . unwrap ( ) ;
200+ // Make sure the field was used at least once.
201+ assert ! (
202+ field_used_at_least_once,
203+ "we captured {parent_capture:#?} but it was not used in the child coroutine?"
204+ ) ;
231205 }
232- assert_eq ! ( parent_captures . next( ) , None , "leftover parent captures?" ) ;
206+ assert_eq ! ( child_captures . next( ) , None , "leftover child captures?" ) ;
233207
234208 if coroutine_kind == ty:: ClosureKind :: FnOnce {
235209 assert_eq ! ( field_remapping. len( ) , tcx. closure_captures( parent_def_id) . len( ) ) ;
@@ -251,13 +225,31 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
251225 let mut by_move_body = body. clone ( ) ;
252226 MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty } . visit_body ( & mut by_move_body) ;
253227 dump_mir ( tcx, false , "coroutine_by_move" , & 0 , & by_move_body, |_, _| Ok ( ( ) ) ) ;
228+ // FIXME: use query feeding to generate the body right here and then only store the `DefId` of the new body.
254229 by_move_body. source = mir:: MirSource :: from_instance ( InstanceDef :: CoroutineKindShim {
255230 coroutine_def_id : coroutine_def_id. to_def_id ( ) ,
256231 } ) ;
257232 body. coroutine . as_mut ( ) . unwrap ( ) . by_move_body = Some ( by_move_body) ;
258233 }
259234}
260235
236+ fn child_prefix_matches_parent_projections (
237+ parent_capture : & ty:: CapturedPlace < ' _ > ,
238+ child_capture : & ty:: CapturedPlace < ' _ > ,
239+ ) -> bool {
240+ let PlaceBase :: Upvar ( parent_base) = parent_capture. place . base else {
241+ bug ! ( "expected capture to be an upvar" ) ;
242+ } ;
243+ let PlaceBase :: Upvar ( child_base) = child_capture. place . base else {
244+ bug ! ( "expected capture to be an upvar" ) ;
245+ } ;
246+
247+ assert ! ( child_capture. place. projections. len( ) >= parent_capture. place. projections. len( ) ) ;
248+ parent_base. var_path . hir_id == child_base. var_path . hir_id
249+ && std:: iter:: zip ( & child_capture. place . projections , & parent_capture. place . projections )
250+ . all ( |( child, parent) | child. kind == parent. kind )
251+ }
252+
261253struct MakeByMoveBody < ' tcx > {
262254 tcx : TyCtxt < ' tcx > ,
263255 field_remapping : UnordMap < FieldIdx , ( FieldIdx , Ty < ' tcx > , bool , & ' tcx [ Projection < ' tcx > ] ) > ,
0 commit comments