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 } ;
@@ -78,6 +77,16 @@ use rustc_middle::hir::place::{Projection, ProjectionKind};
78
77
use rustc_middle:: mir:: visit:: MutVisitor ;
79
78
use rustc_middle:: mir:: { self , dump_mir} ;
80
79
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
+ }
81
90
82
91
pub ( crate ) fn coroutine_by_move_body_def_id < ' tcx > (
83
92
tcx : TyCtxt < ' tcx > ,
@@ -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,18 +193,18 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
180
193
181
194
(
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
. collect ( ) ;
193
206
194
- if coroutine_kind == ty:: ClosureKind :: FnOnce {
207
+ if matches ! ( coroutine_kind, ty:: ClosureKind :: FnOnce ) {
195
208
assert_eq ! ( field_remapping. len( ) , tcx. closure_captures( parent_def_id) . len( ) ) ;
196
209
// The by-move body is just the body :)
197
210
return coroutine_def_id. to_def_id ( ) ;
@@ -210,6 +223,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
210
223
) ;
211
224
212
225
let mut by_move_body = body. clone ( ) ;
226
+ dump_mir ( tcx, false , "built" , & "before" , & by_move_body, |_, _| Ok ( ( ) ) ) ;
213
227
MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty } . visit_body ( & mut by_move_body) ;
214
228
215
229
// 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>(
240
254
241
255
struct MakeByMoveBody < ' tcx > {
242
256
tcx : TyCtxt < ' tcx > ,
243
- field_remapping : UnordMap < FieldIdx , ( FieldIdx , Ty < ' tcx > , bool , Vec < Projection < ' tcx > > ) > ,
257
+ field_remapping : IndexMap < FieldIdx , CaptureInfo < ' tcx > > ,
244
258
by_move_coroutine_ty : Ty < ' tcx > ,
245
259
}
246
260
@@ -261,8 +275,12 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> {
261
275
if place. local == ty:: CAPTURE_STRUCT_LOCAL
262
276
&& let Some ( ( & mir:: ProjectionElem :: Field ( idx, _) , projection) ) =
263
277
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)
266
284
{
267
285
// As noted before, if the parent closure captures a field by value, and
268
286
// the child captures a field by ref, then for the by-move body we're
0 commit comments