69
69
70
70
use rustc_abi:: { FieldIdx , VariantIdx } ;
71
71
use rustc_data_structures:: steal:: Steal ;
72
- use rustc_data_structures:: unord:: UnordMap ;
73
72
use rustc_hir as hir;
74
73
use rustc_hir:: def:: DefKind ;
75
74
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
76
75
use rustc_middle:: bug;
77
76
use rustc_middle:: hir:: place:: { Projection , ProjectionKind } ;
78
77
use rustc_middle:: mir:: visit:: MutVisitor ;
79
78
use rustc_middle:: mir:: { self , dump_mir} ;
79
+ use rustc_middle:: ty:: data_structures:: IndexMap ;
80
80
use rustc_middle:: ty:: { self , InstanceKind , Ty , TyCtxt , TypeVisitableExt } ;
81
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
+ }
90
+
82
91
pub ( crate ) fn coroutine_by_move_body_def_id < ' tcx > (
83
92
tcx : TyCtxt < ' tcx > ,
84
93
coroutine_def_id : LocalDefId ,
@@ -125,23 +134,27 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
125
134
. tuple_fields ( )
126
135
. len ( ) ;
127
136
128
- let field_remapping: UnordMap < _ , _ > = ty:: analyze_coroutine_closure_captures (
137
+ let field_remapping: IndexMap < _ , _ > = ty:: analyze_coroutine_closure_captures (
129
138
tcx. closure_captures ( parent_def_id) . iter ( ) . copied ( ) ,
130
139
tcx. closure_captures ( coroutine_def_id) . iter ( ) . skip ( num_args) . copied ( ) ,
131
140
|( parent_field_idx, parent_capture) , ( child_field_idx, child_capture) | {
132
141
// Store this set of additional projections (fields and derefs).
133
142
// 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 ( ) ;
136
147
137
148
// If the parent capture is by-ref, then we need to apply an additional
138
149
// 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
+ } ;
145
158
// If the child capture is by-ref, then we need to apply a "ref"
146
159
// projection (i.e. `&`) at the end. But wait! We don't have that
147
160
// 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>(
167
180
168
181
// Finally, store the type of the parent's captured place. We need
169
182
// 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 {
172
185
ty:: UpvarCapture :: ByValue | ty:: UpvarCapture :: ByUse => parent_capture_ty,
173
186
ty:: UpvarCapture :: ByRef ( kind) => Ty :: new_ref (
174
187
tcx,
@@ -180,19 +193,19 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
180
193
181
194
Some ( (
182
195
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 ,
186
199
peel_deref,
187
- child_precise_captures ,
188
- ) ,
200
+ bridging_projections ,
201
+ } ,
189
202
) )
190
203
} ,
191
204
)
192
205
. flatten ( )
193
206
. collect ( ) ;
194
207
195
- if coroutine_kind == ty:: ClosureKind :: FnOnce {
208
+ if matches ! ( coroutine_kind, ty:: ClosureKind :: FnOnce ) {
196
209
assert_eq ! ( field_remapping. len( ) , tcx. closure_captures( parent_def_id) . len( ) ) ;
197
210
// The by-move body is just the body :)
198
211
return coroutine_def_id. to_def_id ( ) ;
@@ -211,6 +224,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
211
224
) ;
212
225
213
226
let mut by_move_body = body. clone ( ) ;
227
+ dump_mir ( tcx, false , "built" , & "before" , & by_move_body, |_, _| Ok ( ( ) ) ) ;
214
228
MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty } . visit_body ( & mut by_move_body) ;
215
229
216
230
// 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>(
241
255
242
256
struct MakeByMoveBody < ' tcx > {
243
257
tcx : TyCtxt < ' tcx > ,
244
- field_remapping : UnordMap < FieldIdx , ( FieldIdx , Ty < ' tcx > , bool , Vec < Projection < ' tcx > > ) > ,
258
+ field_remapping : IndexMap < FieldIdx , CaptureInfo < ' tcx > > ,
245
259
by_move_coroutine_ty : Ty < ' tcx > ,
246
260
}
247
261
@@ -262,8 +276,12 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> {
262
276
if place. local == ty:: CAPTURE_STRUCT_LOCAL
263
277
&& let Some ( ( & mir:: ProjectionElem :: Field ( idx, _) , projection) ) =
264
278
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)
267
285
{
268
286
// As noted before, if the parent closure captures a field by value, and
269
287
// 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> {
340
358
local : ty:: CAPTURE_STRUCT_LOCAL ,
341
359
projection : [ mir:: ProjectionElem :: Field ( idx, _) ] ,
342
360
} = place. as_ref ( )
343
- && let Some ( & ( _ , _ , true , _ ) ) = self . field_remapping . get ( & idx)
361
+ && let Some ( CaptureInfo { peel_deref : true , .. } ) = self . field_remapping . get ( idx)
344
362
{
345
363
statement. kind = mir:: StatementKind :: Nop ;
346
364
}
0 commit comments