Skip to content

Commit 27ca6bb

Browse files
a general improvement in organisation of coroutine capture information
Additional MIR dumps are inserted so that it is easier to inspect the bodies of async closures, including those that captures the state by-value.
1 parent e87d42c commit 27ca6bb

File tree

1 file changed

+40
-22
lines changed

1 file changed

+40
-22
lines changed

compiler/rustc_mir_transform/src/coroutine/by_move_body.rs

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,25 @@
6969
7070
use rustc_abi::{FieldIdx, VariantIdx};
7171
use rustc_data_structures::steal::Steal;
72-
use rustc_data_structures::unord::UnordMap;
7372
use rustc_hir as hir;
7473
use rustc_hir::def::DefKind;
7574
use rustc_hir::def_id::{DefId, LocalDefId};
7675
use rustc_middle::bug;
7776
use rustc_middle::hir::place::{Projection, ProjectionKind};
7877
use rustc_middle::mir::visit::MutVisitor;
7978
use rustc_middle::mir::{self, dump_mir};
79+
use rustc_middle::ty::data_structures::IndexMap;
8080
use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt};
8181

82+
struct CaptureInfo<'tcx> {
83+
/// Field index of the capture in the parent coroutine structure
84+
remapped_idx: FieldIdx,
85+
/// Type of the capture in the parent coroutine structure
86+
remapped_ty: Ty<'tcx>,
87+
peel_deref: bool,
88+
bridging_projections: Vec<Projection<'tcx>>,
89+
}
90+
8291
pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
8392
tcx: TyCtxt<'tcx>,
8493
coroutine_def_id: LocalDefId,
@@ -125,23 +134,27 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
125134
.tuple_fields()
126135
.len();
127136

128-
let field_remapping: UnordMap<_, _> = ty::analyze_coroutine_closure_captures(
137+
let field_remapping: IndexMap<_, _> = ty::analyze_coroutine_closure_captures(
129138
tcx.closure_captures(parent_def_id).iter().copied(),
130139
tcx.closure_captures(coroutine_def_id).iter().skip(num_args).copied(),
131140
|(parent_field_idx, parent_capture), (child_field_idx, child_capture)| {
132141
// Store this set of additional projections (fields and derefs).
133142
// We need to re-apply them later.
134-
let mut child_precise_captures =
135-
child_capture.place.projections[parent_capture.place.projections.len()..].to_vec();
143+
let child_precise_captures = child_capture.place.projections
144+
[parent_capture.place.projections.len()..]
145+
.iter()
146+
.copied();
136147

137148
// If the parent capture is by-ref, then we need to apply an additional
138149
// deref before applying any further projections to this place.
139-
if parent_capture.is_by_ref() {
140-
child_precise_captures.insert(
141-
0,
142-
Projection { ty: parent_capture.place.ty(), kind: ProjectionKind::Deref },
143-
);
144-
}
150+
let bridging_projections = if parent_capture.is_by_ref() {
151+
[Projection { ty: parent_capture.place.ty(), kind: ProjectionKind::Deref }]
152+
.into_iter()
153+
.chain(child_precise_captures)
154+
.collect()
155+
} else {
156+
child_precise_captures.collect()
157+
};
145158
// If the child capture is by-ref, then we need to apply a "ref"
146159
// projection (i.e. `&`) at the end. But wait! We don't have that
147160
// as a projection kind. So instead, we can apply its dual and
@@ -167,8 +180,8 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
167180

168181
// Finally, store the type of the parent's captured place. We need
169182
// this when building the field projection in the MIR body later on.
170-
let mut parent_capture_ty = parent_capture.place.ty();
171-
parent_capture_ty = match parent_capture.info.capture_kind {
183+
let parent_capture_ty = parent_capture.place.ty();
184+
let remapped_ty = match parent_capture.info.capture_kind {
172185
ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => parent_capture_ty,
173186
ty::UpvarCapture::ByRef(kind) => Ty::new_ref(
174187
tcx,
@@ -180,19 +193,19 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
180193

181194
Some((
182195
FieldIdx::from_usize(child_field_idx + num_args),
183-
(
184-
FieldIdx::from_usize(parent_field_idx + num_args),
185-
parent_capture_ty,
196+
CaptureInfo {
197+
remapped_idx: FieldIdx::from_usize(parent_field_idx + num_args),
198+
remapped_ty,
186199
peel_deref,
187-
child_precise_captures,
188-
),
200+
bridging_projections,
201+
},
189202
))
190203
},
191204
)
192205
.flatten()
193206
.collect();
194207

195-
if coroutine_kind == ty::ClosureKind::FnOnce {
208+
if matches!(coroutine_kind, ty::ClosureKind::FnOnce) {
196209
assert_eq!(field_remapping.len(), tcx.closure_captures(parent_def_id).len());
197210
// The by-move body is just the body :)
198211
return coroutine_def_id.to_def_id();
@@ -211,6 +224,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
211224
);
212225

213226
let mut by_move_body = body.clone();
227+
dump_mir(tcx, false, "built", &"before", &by_move_body, |_, _| Ok(()));
214228
MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body);
215229

216230
// This will always be `{closure#1}`, since the original coroutine is `{closure#0}`.
@@ -241,7 +255,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
241255

242256
struct MakeByMoveBody<'tcx> {
243257
tcx: TyCtxt<'tcx>,
244-
field_remapping: UnordMap<FieldIdx, (FieldIdx, Ty<'tcx>, bool, Vec<Projection<'tcx>>)>,
258+
field_remapping: IndexMap<FieldIdx, CaptureInfo<'tcx>>,
245259
by_move_coroutine_ty: Ty<'tcx>,
246260
}
247261

@@ -262,8 +276,12 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> {
262276
if place.local == ty::CAPTURE_STRUCT_LOCAL
263277
&& let Some((&mir::ProjectionElem::Field(idx, _), projection)) =
264278
place.projection.split_first()
265-
&& let Some(&(remapped_idx, remapped_ty, peel_deref, ref bridging_projections)) =
266-
self.field_remapping.get(&idx)
279+
&& let Some(&CaptureInfo {
280+
remapped_idx,
281+
remapped_ty,
282+
peel_deref,
283+
ref bridging_projections,
284+
}) = self.field_remapping.get(&idx)
267285
{
268286
// As noted before, if the parent closure captures a field by value, and
269287
// the child captures a field by ref, then for the by-move body we're
@@ -340,7 +358,7 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> {
340358
local: ty::CAPTURE_STRUCT_LOCAL,
341359
projection: [mir::ProjectionElem::Field(idx, _)],
342360
} = place.as_ref()
343-
&& let Some(&(_, _, true, _)) = self.field_remapping.get(&idx)
361+
&& let Some(CaptureInfo { peel_deref: true, .. }) = self.field_remapping.get(idx)
344362
{
345363
statement.kind = mir::StatementKind::Nop;
346364
}

0 commit comments

Comments
 (0)