@@ -145,7 +145,7 @@ pub(super) fn layout<
145
145
> (
146
146
calc : & super :: LayoutCalculator < impl HasDataLayout > ,
147
147
local_layouts : & IndexSlice < LocalIdx , F > ,
148
- mut prefix_layouts : IndexVec < FieldIdx , F > ,
148
+ relocated_upvars : & IndexSlice < LocalIdx , Option < LocalIdx > > ,
149
149
variant_fields : & IndexSlice < VariantIdx , IndexVec < FieldIdx , LocalIdx > > ,
150
150
storage_conflicts : & BitMatrix < LocalIdx , LocalIdx > ,
151
151
tag_to_layout : impl Fn ( Scalar ) -> F ,
@@ -155,10 +155,8 @@ pub(super) fn layout<
155
155
let ( ineligible_locals, assignments) =
156
156
coroutine_saved_local_eligibility ( local_layouts. len ( ) , variant_fields, storage_conflicts) ;
157
157
158
- // Build a prefix layout, including "promoting" all ineligible
159
- // locals as part of the prefix. We compute the layout of all of
160
- // these fields at once to get optimal packing.
161
- let tag_index = prefix_layouts. len ( ) ;
158
+ // Build a prefix layout, consisting of only the state tag.
159
+ let tag_index = 0 ;
162
160
163
161
// `variant_fields` already accounts for the reserved variants, so no need to add them.
164
162
let max_discr = ( variant_fields. len ( ) - 1 ) as u128 ;
@@ -169,17 +167,17 @@ pub(super) fn layout<
169
167
} ;
170
168
171
169
let promoted_layouts = ineligible_locals. iter ( ) . map ( |local| local_layouts[ local] ) ;
172
- prefix_layouts. push ( tag_to_layout ( tag ) ) ;
173
- prefix_layouts . extend ( promoted_layouts) ;
170
+ let prefix_layouts: IndexVec < _ , _ > =
171
+ [ tag_to_layout ( tag ) ] . into_iter ( ) . chain ( promoted_layouts) . collect ( ) ;
174
172
let prefix =
175
173
calc. univariant ( & prefix_layouts, & ReprOptions :: default ( ) , StructKind :: AlwaysSized ) ?;
176
174
177
175
let ( prefix_size, prefix_align) = ( prefix. size , prefix. align ) ;
178
176
179
- // Split the prefix layout into the "outer" fields (upvars and
180
- // discriminant) and the "promoted" fields. Promoted fields will
181
- // get included in each variant that requested them in
182
- // CoroutineLayout.
177
+ // Split the prefix layout into the discriminant and
178
+ // the "promoted" fields.
179
+ // Promoted fields will get included in each variant
180
+ // that requested them in CoroutineLayout.
183
181
debug ! ( "prefix = {:#?}" , prefix) ;
184
182
let ( outer_fields, promoted_offsets, promoted_memory_index) = match prefix. fields {
185
183
FieldsShape :: Arbitrary { mut offsets, memory_index } => {
@@ -215,22 +213,45 @@ pub(super) fn layout<
215
213
216
214
let mut size = prefix. size ;
217
215
let mut align = prefix. align ;
218
- let variants = variant_fields
216
+ let variants: IndexVec < VariantIdx , _ > = variant_fields
219
217
. iter_enumerated ( )
220
218
. map ( |( index, variant_fields) | {
219
+ let is_unresumed = index == VariantIdx :: new ( 0 ) ;
220
+ let mut is_ineligible = IndexVec :: from_elem_n ( None , variant_fields. len ( ) ) ;
221
+ for ( field, & local) in variant_fields. iter_enumerated ( ) {
222
+ if is_unresumed
223
+ && let Some ( inner_local) = relocated_upvars[ local]
224
+ && let Ineligible ( Some ( promoted_field) ) = assignments[ inner_local]
225
+ {
226
+ is_ineligible. insert ( field, promoted_field) ;
227
+ continue ;
228
+ }
229
+ match assignments[ local] {
230
+ Assigned ( v) if v == index => { }
231
+ Ineligible ( Some ( promoted_field) ) => {
232
+ is_ineligible. insert ( field, promoted_field) ;
233
+ }
234
+ Ineligible ( None ) => {
235
+ panic ! ( "an ineligible local should have been promoted into the prefix" )
236
+ }
237
+ Assigned ( _) => {
238
+ panic ! ( "an eligible local should have been assigned to exactly one variant" )
239
+ }
240
+ Unassigned => {
241
+ panic ! ( "each saved local should have been inspected at least once" )
242
+ }
243
+ }
244
+ }
221
245
// Only include overlap-eligible fields when we compute our variant layout.
222
- let variant_only_tys = variant_fields
223
- . iter ( )
224
- . filter ( |local| match assignments[ * * local] {
225
- Unassigned => unreachable ! ( ) ,
226
- Assigned ( v) if v == index => true ,
227
- Assigned ( _) => unreachable ! ( "assignment does not match variant" ) ,
228
- Ineligible ( _) => false ,
246
+ let fields: IndexVec < _ , _ > = variant_fields
247
+ . iter_enumerated ( )
248
+ . filter_map ( |( field, & local) | {
249
+ if is_ineligible. contains ( field) { None } else { Some ( local_layouts[ local] ) }
229
250
} )
230
- . map ( |local| local_layouts [ * local ] ) ;
251
+ . collect ( ) ;
231
252
232
253
let mut variant = calc. univariant (
233
- & variant_only_tys . collect :: < IndexVec < _ , _ > > ( ) ,
254
+ & fields ,
234
255
& ReprOptions :: default ( ) ,
235
256
StructKind :: Prefixed ( prefix_size, prefix_align. abi ) ,
236
257
) ?;
@@ -254,19 +275,14 @@ pub(super) fn layout<
254
275
IndexVec :: from_elem_n ( FieldIdx :: new ( invalid_field_idx) , invalid_field_idx) ;
255
276
256
277
let mut offsets_and_memory_index = iter:: zip ( offsets, memory_index) ;
257
- let combined_offsets = variant_fields
278
+ let combined_offsets = is_ineligible
258
279
. iter_enumerated ( )
259
- . map ( |( i, local) | {
260
- let ( offset, memory_index) = match assignments[ * local] {
261
- Unassigned => unreachable ! ( ) ,
262
- Assigned ( _) => {
263
- let ( offset, memory_index) = offsets_and_memory_index. next ( ) . unwrap ( ) ;
264
- ( offset, promoted_memory_index. len ( ) as u32 + memory_index)
265
- }
266
- Ineligible ( field_idx) => {
267
- let field_idx = field_idx. unwrap ( ) ;
268
- ( promoted_offsets[ field_idx] , promoted_memory_index[ field_idx] )
269
- }
280
+ . map ( |( i, & is_ineligible) | {
281
+ let ( offset, memory_index) = if let Some ( field_idx) = is_ineligible {
282
+ ( promoted_offsets[ field_idx] , promoted_memory_index[ field_idx] )
283
+ } else {
284
+ let ( offset, memory_index) = offsets_and_memory_index. next ( ) . unwrap ( ) ;
285
+ ( offset, promoted_memory_index. len ( ) as u32 + memory_index)
270
286
} ;
271
287
combined_inverse_memory_index[ memory_index] = i;
272
288
offset
@@ -287,7 +303,7 @@ pub(super) fn layout<
287
303
align = align. max ( variant. align ) ;
288
304
Ok ( variant)
289
305
} )
290
- . collect :: < Result < IndexVec < VariantIdx , _ > , _ > > ( ) ?;
306
+ . try_collect ( ) ?;
291
307
292
308
size = size. align_to ( align. abi ) ;
293
309
0 commit comments