Skip to content

Commit 6ab363c

Browse files
committed
Iterate over parent captures first, as there is a 1:N mapping of parent captures to child captures
1 parent 47f80b9 commit 6ab363c

File tree

1 file changed

+63
-71
lines changed

1 file changed

+63
-71
lines changed

compiler/rustc_mir_transform/src/coroutine/by_move_body.rs

+63-71
Original file line numberDiff line numberDiff line change
@@ -126,92 +126,84 @@ 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()
136+
.peekable();
137+
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()
146144
{
147-
let (mut parent_field_idx, mut parent_capture);
148-
loop {
149-
(parent_field_idx, parent_capture) =
150-
*parent_captures.peek().expect("we ran out of parent captures!");
151-
// A parent matches a child they share the same prefix of projections.
152-
// The child may have more, if it is capturing sub-fields out of
153-
// something that is captured by-move in the parent closure.
154-
if child_prefix_matches_parent_projections(parent_capture, child_capture) {
155-
break;
156-
}
157-
// Make sure the field was used at least once.
158-
assert!(
159-
field_used_at_least_once,
160-
"we captured {parent_capture:#?} but it was not used in the child coroutine?"
161-
);
162-
field_used_at_least_once = false;
163-
// Skip this field.
164-
let _ = parent_captures.next().unwrap();
165-
}
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;
148+
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();
166156

167-
// Store this set of additional projections (fields and derefs).
168-
// We need to re-apply them later.
169-
let child_precise_captures =
170-
&child_capture.place.projections[parent_capture.place.projections.len()..];
157+
// Store this set of additional projections (fields and derefs).
158+
// We need to re-apply them later.
159+
let child_precise_captures =
160+
&child_capture.place.projections[parent_capture.place.projections.len()..];
171161

172-
// If the parent captures by-move, and the child captures by-ref, then we
173-
// need to peel an additional `deref` off of the body of the child.
174-
let needs_deref = child_capture.is_by_ref() && !parent_capture.is_by_ref();
175-
if needs_deref {
176-
assert_ne!(
177-
coroutine_kind,
178-
ty::ClosureKind::FnOnce,
179-
"`FnOnce` coroutine-closures return coroutines that capture from \
162+
// If the parent captures by-move, and the child captures by-ref, then we
163+
// need to peel an additional `deref` off of the body of the child.
164+
let needs_deref = child_capture.is_by_ref() && !parent_capture.is_by_ref();
165+
if needs_deref {
166+
assert_ne!(
167+
coroutine_kind,
168+
ty::ClosureKind::FnOnce,
169+
"`FnOnce` coroutine-closures return coroutines that capture from \
180170
their body; it will always result in a borrowck error!"
181-
);
182-
}
171+
);
172+
}
183173

184-
// Finally, store the type of the parent's captured place. We need
185-
// this when building the field projection in the MIR body later on.
186-
let mut parent_capture_ty = parent_capture.place.ty();
187-
parent_capture_ty = match parent_capture.info.capture_kind {
188-
ty::UpvarCapture::ByValue => parent_capture_ty,
189-
ty::UpvarCapture::ByRef(kind) => Ty::new_ref(
190-
tcx,
191-
tcx.lifetimes.re_erased,
192-
parent_capture_ty,
193-
kind.to_mutbl_lossy(),
194-
),
195-
};
174+
// Finally, store the type of the parent's captured place. We need
175+
// this when building the field projection in the MIR body later on.
176+
let mut parent_capture_ty = parent_capture.place.ty();
177+
parent_capture_ty = match parent_capture.info.capture_kind {
178+
ty::UpvarCapture::ByValue => parent_capture_ty,
179+
ty::UpvarCapture::ByRef(kind) => Ty::new_ref(
180+
tcx,
181+
tcx.lifetimes.re_erased,
182+
parent_capture_ty,
183+
kind.to_mutbl_lossy(),
184+
),
185+
};
196186

197-
field_remapping.insert(
198-
FieldIdx::from_usize(child_field_idx + num_args),
199-
(
200-
FieldIdx::from_usize(parent_field_idx + num_args),
201-
parent_capture_ty,
202-
needs_deref,
203-
child_precise_captures,
204-
),
205-
);
187+
field_remapping.insert(
188+
FieldIdx::from_usize(child_field_idx + num_args),
189+
(
190+
FieldIdx::from_usize(parent_field_idx + num_args),
191+
parent_capture_ty,
192+
needs_deref,
193+
child_precise_captures,
194+
),
195+
);
206196

207-
field_used_at_least_once = true;
208-
}
197+
field_used_at_least_once = true;
198+
}
209199

210-
// Pop the last parent capture
211-
if field_used_at_least_once {
212-
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+
);
213205
}
214-
assert_eq!(parent_captures.next(), None, "leftover parent captures?");
206+
assert_eq!(child_captures.next(), None, "leftover child captures?");
215207

216208
if coroutine_kind == ty::ClosureKind::FnOnce {
217209
assert_eq!(field_remapping.len(), tcx.closure_captures(parent_def_id).len());

0 commit comments

Comments
 (0)