Skip to content

Commit b8dfe07

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 a997b26 commit b8dfe07

File tree

1 file changed

+39
-21
lines changed

1 file changed

+39
-21
lines changed

compiler/rustc_mir_transform/src/coroutine/by_move_body.rs

+39-21
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@
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};
@@ -78,6 +77,16 @@ use rustc_middle::hir::place::{Projection, ProjectionKind};
7877
use rustc_middle::mir::visit::MutVisitor;
7978
use rustc_middle::mir::{self, dump_mir};
8079
use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt};
80+
use rustc_type_ir::data_structures::IndexMap;
81+
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+
}
8190

8291
pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
8392
tcx: TyCtxt<'tcx>,
@@ -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,18 +193,18 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
180193

181194
(
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
.collect();
193206

194-
if coroutine_kind == ty::ClosureKind::FnOnce {
207+
if matches!(coroutine_kind, ty::ClosureKind::FnOnce) {
195208
assert_eq!(field_remapping.len(), tcx.closure_captures(parent_def_id).len());
196209
// The by-move body is just the body :)
197210
return coroutine_def_id.to_def_id();
@@ -210,6 +223,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
210223
);
211224

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

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

241255
struct MakeByMoveBody<'tcx> {
242256
tcx: TyCtxt<'tcx>,
243-
field_remapping: UnordMap<FieldIdx, (FieldIdx, Ty<'tcx>, bool, Vec<Projection<'tcx>>)>,
257+
field_remapping: IndexMap<FieldIdx, CaptureInfo<'tcx>>,
244258
by_move_coroutine_ty: Ty<'tcx>,
245259
}
246260

@@ -261,8 +275,12 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> {
261275
if place.local == ty::CAPTURE_STRUCT_LOCAL
262276
&& let Some((&mir::ProjectionElem::Field(idx, _), projection)) =
263277
place.projection.split_first()
264-
&& let Some(&(remapped_idx, remapped_ty, peel_deref, ref bridging_projections)) =
265-
self.field_remapping.get(&idx)
278+
&& let Some(&CaptureInfo {
279+
remapped_idx,
280+
remapped_ty,
281+
peel_deref,
282+
ref bridging_projections,
283+
}) = self.field_remapping.get(&idx)
266284
{
267285
// As noted before, if the parent closure captures a field by value, and
268286
// the child captures a field by ref, then for the by-move body we're

0 commit comments

Comments
 (0)