1
Fork 0

Iterate over parent captures first, as there is a 1:N mapping of parent captures to child captures

This commit is contained in:
Oli Scherer 2024-04-09 09:11:41 +00:00
parent bf497b8347
commit e14e7954ae

View file

@ -126,43 +126,33 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
let mut field_remapping = UnordMap::default(); let mut field_remapping = UnordMap::default();
// One parent capture may correspond to several child captures if we end up let mut child_captures = tcx
// refining the set of captures via edition-2021 precise captures. We want to
// match up any number of child captures with one parent capture, so we keep
// peeking off this `Peekable` until the child doesn't match anymore.
let mut parent_captures =
tcx.closure_captures(parent_def_id).iter().copied().enumerate().peekable();
// Make sure we use every field at least once, b/c why are we capturing something
// if it's not used in the inner coroutine.
let mut field_used_at_least_once = false;
for (child_field_idx, child_capture) in tcx
.closure_captures(coroutine_def_id) .closure_captures(coroutine_def_id)
.iter() .iter()
.copied() .copied()
// By construction we capture all the args first. // By construction we capture all the args first.
.skip(num_args) .skip(num_args)
.enumerate() .enumerate()
.peekable();
// One parent capture may correspond to several child captures if we end up
// refining the set of captures via edition-2021 precise captures. We want to
// match up any number of child captures with one parent capture, so we keep
// peeking off this `Peekable` until the child doesn't match anymore.
for (parent_field_idx, parent_capture) in
tcx.closure_captures(parent_def_id).iter().copied().enumerate()
{ {
let (mut parent_field_idx, mut parent_capture); // Make sure we use every field at least once, b/c why are we capturing something
loop { // if it's not used in the inner coroutine.
(parent_field_idx, parent_capture) = let mut field_used_at_least_once = false;
*parent_captures.peek().expect("we ran out of parent captures!");
// A parent matches a child they share the same prefix of projections. // A parent matches a child if they share the same prefix of projections.
// The child may have more, if it is capturing sub-fields out of // The child may have more, if it is capturing sub-fields out of
// something that is captured by-move in the parent closure. // something that is captured by-move in the parent closure.
if child_prefix_matches_parent_projections(parent_capture, child_capture) { while child_captures.peek().map_or(false, |(_, child_capture)| {
break; child_prefix_matches_parent_projections(parent_capture, child_capture)
} }) {
// Make sure the field was used at least once. let (child_field_idx, child_capture) = child_captures.next().unwrap();
assert!(
field_used_at_least_once,
"we captured {parent_capture:#?} but it was not used in the child coroutine?"
);
field_used_at_least_once = false;
// Skip this field.
let _ = parent_captures.next().unwrap();
}
// Store this set of additional projections (fields and derefs). // Store this set of additional projections (fields and derefs).
// We need to re-apply them later. // We need to re-apply them later.
@ -207,11 +197,13 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
field_used_at_least_once = true; field_used_at_least_once = true;
} }
// Pop the last parent capture // Make sure the field was used at least once.
if field_used_at_least_once { assert!(
let _ = parent_captures.next().unwrap(); field_used_at_least_once,
"we captured {parent_capture:#?} but it was not used in the child coroutine?"
);
} }
assert_eq!(parent_captures.next(), None, "leftover parent captures?"); assert_eq!(child_captures.next(), None, "leftover child captures?");
if coroutine_kind == ty::ClosureKind::FnOnce { if coroutine_kind == ty::ClosureKind::FnOnce {
assert_eq!(field_remapping.len(), tcx.closure_captures(parent_def_id).len()); assert_eq!(field_remapping.len(), tcx.closure_captures(parent_def_id).len());