@@ -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 } => {
@@ -218,19 +216,45 @@ pub(super) fn layout<
218
216
let variants = 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
+ // NOTE(@dingxiangfei2009): rewrite this when let-chain #53667
224
+ // is stabilized
225
+ if let Some ( inner_local) = relocated_upvars[ local] {
226
+ if let Ineligible ( Some ( promoted_field) ) = assignments[ inner_local] {
227
+ is_ineligible. insert ( field, promoted_field) ;
228
+ continue ;
229
+ }
230
+ }
231
+ }
232
+ match assignments[ local] {
233
+ Assigned ( v) if v == index => { }
234
+ Ineligible ( Some ( promoted_field) ) => {
235
+ is_ineligible. insert ( field, promoted_field) ;
236
+ }
237
+ Ineligible ( None ) => {
238
+ panic ! ( "an ineligible local should have been promoted into the prefix" )
239
+ }
240
+ Assigned ( _) => {
241
+ panic ! ( "an eligible local should have been assigned to exactly one variant" )
242
+ }
243
+ Unassigned => {
244
+ panic ! ( "each saved local should have been inspected at least once" )
245
+ }
246
+ }
247
+ }
221
248
// 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 ,
249
+ let fields: IndexVec < _ , _ > = variant_fields
250
+ . iter_enumerated ( )
251
+ . filter_map ( |( field, & local) | {
252
+ if is_ineligible. contains ( field) { None } else { Some ( local_layouts[ local] ) }
229
253
} )
230
- . map ( |local| local_layouts [ * local ] ) ;
254
+ . collect ( ) ;
231
255
232
256
let mut variant = calc. univariant (
233
- & variant_only_tys . collect :: < IndexVec < _ , _ > > ( ) ,
257
+ & fields ,
234
258
& ReprOptions :: default ( ) ,
235
259
StructKind :: Prefixed ( prefix_size, prefix_align. abi ) ,
236
260
) ?;
@@ -254,19 +278,14 @@ pub(super) fn layout<
254
278
IndexVec :: from_elem_n ( FieldIdx :: new ( invalid_field_idx) , invalid_field_idx) ;
255
279
256
280
let mut offsets_and_memory_index = iter:: zip ( offsets, memory_index) ;
257
- let combined_offsets = variant_fields
281
+ let combined_offsets = is_ineligible
258
282
. 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
- }
283
+ . map ( |( i, & is_ineligible) | {
284
+ let ( offset, memory_index) = if let Some ( field_idx) = is_ineligible {
285
+ ( promoted_offsets[ field_idx] , promoted_memory_index[ field_idx] )
286
+ } else {
287
+ let ( offset, memory_index) = offsets_and_memory_index. next ( ) . unwrap ( ) ;
288
+ ( offset, promoted_memory_index. len ( ) as u32 + memory_index)
270
289
} ;
271
290
combined_inverse_memory_index[ memory_index] = i;
272
291
offset
0 commit comments