@@ -550,14 +550,14 @@ static int compiler_sync_comprehension_generator(
550
550
asdl_comprehension_seq * generators , int gen_index ,
551
551
int depth ,
552
552
expr_ty elt , expr_ty val , int type ,
553
- int outermost_iter_is_param );
553
+ int iter_on_stack );
554
554
555
555
static int compiler_async_comprehension_generator (
556
556
struct compiler * c , location loc ,
557
557
asdl_comprehension_seq * generators , int gen_index ,
558
558
int depth ,
559
559
expr_ty elt , expr_ty val , int type ,
560
- int outermost_iter_is_param );
560
+ int iter_on_stack );
561
561
562
562
static int compiler_pattern (struct compiler * , pattern_ty , pattern_context * );
563
563
static int compiler_match (struct compiler * , stmt_ty );
@@ -1229,7 +1229,7 @@ stack_effect(int opcode, int oparg, int jump)
1229
1229
1230
1230
case LOAD_FAST :
1231
1231
case LOAD_FAST_CHECK :
1232
- case LOAD_FAST_OR_NULL :
1232
+ case LOAD_FAST_AND_CLEAR :
1233
1233
return 1 ;
1234
1234
case STORE_FAST :
1235
1235
case STORE_FAST_MAYBE_NULL :
@@ -5150,18 +5150,18 @@ compiler_comprehension_generator(struct compiler *c, location loc,
5150
5150
asdl_comprehension_seq * generators , int gen_index ,
5151
5151
int depth ,
5152
5152
expr_ty elt , expr_ty val , int type ,
5153
- int outermost_iter_is_param )
5153
+ int iter_on_stack )
5154
5154
{
5155
5155
comprehension_ty gen ;
5156
5156
gen = (comprehension_ty )asdl_seq_GET (generators , gen_index );
5157
5157
if (gen -> is_async ) {
5158
5158
return compiler_async_comprehension_generator (
5159
5159
c , loc , generators , gen_index , depth , elt , val , type ,
5160
- outermost_iter_is_param );
5160
+ iter_on_stack );
5161
5161
} else {
5162
5162
return compiler_sync_comprehension_generator (
5163
5163
c , loc , generators , gen_index , depth , elt , val , type ,
5164
- outermost_iter_is_param );
5164
+ iter_on_stack );
5165
5165
}
5166
5166
}
5167
5167
@@ -5170,7 +5170,7 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc,
5170
5170
asdl_comprehension_seq * generators ,
5171
5171
int gen_index , int depth ,
5172
5172
expr_ty elt , expr_ty val , int type ,
5173
- int outermost_iter_is_param )
5173
+ int iter_on_stack )
5174
5174
{
5175
5175
/* generate code for the iterator, then each of the ifs,
5176
5176
and then write to the element */
@@ -5182,37 +5182,39 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc,
5182
5182
comprehension_ty gen = (comprehension_ty )asdl_seq_GET (generators ,
5183
5183
gen_index );
5184
5184
5185
- if (gen_index == 0 && outermost_iter_is_param ) {
5186
- /* Receive outermost iter as an implicit argument */
5187
- c -> u -> u_argcount = 1 ;
5188
- ADDOP_I (c , loc , LOAD_FAST , 0 );
5189
- }
5190
- else {
5191
- /* Sub-iter - calculate on the fly */
5192
- /* Fast path for the temporary variable assignment idiom:
5193
- for y in [f(x)]
5194
- */
5195
- asdl_expr_seq * elts ;
5196
- switch (gen -> iter -> kind ) {
5197
- case List_kind :
5198
- elts = gen -> iter -> v .List .elts ;
5199
- break ;
5200
- case Tuple_kind :
5201
- elts = gen -> iter -> v .Tuple .elts ;
5202
- break ;
5203
- default :
5204
- elts = NULL ;
5185
+ if (!iter_on_stack ) {
5186
+ if (gen_index == 0 ) {
5187
+ /* Receive outermost iter as an implicit argument */
5188
+ c -> u -> u_argcount = 1 ;
5189
+ ADDOP_I (c , loc , LOAD_FAST , 0 );
5205
5190
}
5206
- if (asdl_seq_LEN (elts ) == 1 ) {
5207
- expr_ty elt = asdl_seq_GET (elts , 0 );
5208
- if (elt -> kind != Starred_kind ) {
5209
- VISIT (c , expr , elt );
5210
- start = NO_LABEL ;
5191
+ else {
5192
+ /* Sub-iter - calculate on the fly */
5193
+ /* Fast path for the temporary variable assignment idiom:
5194
+ for y in [f(x)]
5195
+ */
5196
+ asdl_expr_seq * elts ;
5197
+ switch (gen -> iter -> kind ) {
5198
+ case List_kind :
5199
+ elts = gen -> iter -> v .List .elts ;
5200
+ break ;
5201
+ case Tuple_kind :
5202
+ elts = gen -> iter -> v .Tuple .elts ;
5203
+ break ;
5204
+ default :
5205
+ elts = NULL ;
5206
+ }
5207
+ if (asdl_seq_LEN (elts ) == 1 ) {
5208
+ expr_ty elt = asdl_seq_GET (elts , 0 );
5209
+ if (elt -> kind != Starred_kind ) {
5210
+ VISIT (c , expr , elt );
5211
+ start = NO_LABEL ;
5212
+ }
5213
+ }
5214
+ if (IS_LABEL (start )) {
5215
+ VISIT (c , expr , gen -> iter );
5216
+ ADDOP (c , loc , GET_ITER );
5211
5217
}
5212
- }
5213
- if (IS_LABEL (start )) {
5214
- VISIT (c , expr , gen -> iter );
5215
- ADDOP (c , loc , GET_ITER );
5216
5218
}
5217
5219
}
5218
5220
if (IS_LABEL (start )) {
@@ -5287,7 +5289,7 @@ compiler_async_comprehension_generator(struct compiler *c, location loc,
5287
5289
asdl_comprehension_seq * generators ,
5288
5290
int gen_index , int depth ,
5289
5291
expr_ty elt , expr_ty val , int type ,
5290
- int outermost_iter_is_param )
5292
+ int iter_on_stack )
5291
5293
{
5292
5294
NEW_JUMP_TARGET_LABEL (c , start );
5293
5295
NEW_JUMP_TARGET_LABEL (c , except );
@@ -5296,15 +5298,17 @@ compiler_async_comprehension_generator(struct compiler *c, location loc,
5296
5298
comprehension_ty gen = (comprehension_ty )asdl_seq_GET (generators ,
5297
5299
gen_index );
5298
5300
5299
- if (gen_index == 0 && outermost_iter_is_param ) {
5300
- /* Receive outermost iter as an implicit argument */
5301
- c -> u -> u_argcount = 1 ;
5302
- ADDOP_I (c , loc , LOAD_FAST , 0 );
5303
- }
5304
- else {
5305
- /* Sub-iter - calculate on the fly */
5306
- VISIT (c , expr , gen -> iter );
5307
- ADDOP (c , loc , GET_AITER );
5301
+ if (!iter_on_stack ) {
5302
+ if (gen_index == 0 ) {
5303
+ /* Receive outermost iter as an implicit argument */
5304
+ c -> u -> u_argcount = 1 ;
5305
+ ADDOP_I (c , loc , LOAD_FAST , 0 );
5306
+ }
5307
+ else {
5308
+ /* Sub-iter - calculate on the fly */
5309
+ VISIT (c , expr , gen -> iter );
5310
+ ADDOP (c , loc , GET_AITER );
5311
+ }
5308
5312
}
5309
5313
5310
5314
USE_LABEL (c , start );
@@ -5449,7 +5453,7 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
5449
5453
// in the case of a cell, this will actually push the cell
5450
5454
// itself to the stack, then we'll create a new one for the
5451
5455
// comprehension and restore the original one after
5452
- ADDOP_NAME (c , loc , LOAD_FAST_OR_NULL , k , varnames );
5456
+ ADDOP_NAME (c , loc , LOAD_FAST_AND_CLEAR , k , varnames );
5453
5457
if (scope == CELL ) {
5454
5458
ADDOP_NAME (c , loc , MAKE_CELL , k , cellvars );
5455
5459
}
@@ -5459,6 +5463,14 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
5459
5463
}
5460
5464
}
5461
5465
}
5466
+ if (state -> pushed_locals ) {
5467
+ // Outermost iterable expression was already evaluated and is on the
5468
+ // stack, we need to swap it back to TOS. This also rotates the order of
5469
+ // `pushed_locals` on the stack, but this will be reversed when we swap
5470
+ // out the comprehension result in pop_inlined_comprehension_state
5471
+ ADDOP_I (c , loc , SWAP , PyList_GET_SIZE (state -> pushed_locals ) + 1 );
5472
+ }
5473
+
5462
5474
return SUCCESS ;
5463
5475
}
5464
5476
@@ -5479,11 +5491,13 @@ pop_inlined_comprehension_state(struct compiler *c, location loc,
5479
5491
if (state .pushed_locals ) {
5480
5492
// pop names we pushed to stack earlier
5481
5493
Py_ssize_t npops = PyList_GET_SIZE (state .pushed_locals );
5482
- // preserve the list/dict/set result of the comprehension as TOS
5494
+ // Preserve the list/dict/set result of the comprehension as TOS. This
5495
+ // reverses the SWAP we did in push_inlined_comprehension_state to get
5496
+ // the outermost iterable to TOS, so we can still just iterate
5497
+ // pushed_locals in simple reverse order
5483
5498
ADDOP_I (c , loc , SWAP , npops + 1 );
5484
- for (Py_ssize_t i = npops ; i > 0 ; -- i ) {
5485
- // i % npops: pop in order e.g. 0, 3, 2, 1: accounts for the swap
5486
- k = PyList_GetItem (state .pushed_locals , i % npops );
5499
+ for (Py_ssize_t i = npops - 1 ; i >= 0 ; -- i ) {
5500
+ k = PyList_GetItem (state .pushed_locals , i );
5487
5501
if (k == NULL ) {
5488
5502
return ERROR ;
5489
5503
}
@@ -5493,6 +5507,19 @@ pop_inlined_comprehension_state(struct compiler *c, location loc,
5493
5507
return SUCCESS ;
5494
5508
}
5495
5509
5510
+ static inline int
5511
+ compiler_comprehension_iter (struct compiler * c , location loc ,
5512
+ comprehension_ty comp )
5513
+ {
5514
+ VISIT (c , expr , comp -> iter );
5515
+ if (comp -> is_async ) {
5516
+ ADDOP (c , loc , GET_AITER );
5517
+ } else {
5518
+ ADDOP (c , loc , GET_ITER );
5519
+ }
5520
+ return SUCCESS ;
5521
+ }
5522
+
5496
5523
static int
5497
5524
compiler_comprehension (struct compiler * c , expr_ty e , int type ,
5498
5525
identifier name , asdl_comprehension_seq * generators , expr_ty elt ,
@@ -5516,6 +5543,9 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
5516
5543
5517
5544
outermost = (comprehension_ty ) asdl_seq_GET (generators , 0 );
5518
5545
if (is_inlined ) {
5546
+ if (compiler_comprehension_iter (c , loc , outermost )) {
5547
+ goto error ;
5548
+ }
5519
5549
if (push_inlined_comprehension_state (c , loc , entry , & inline_state )) {
5520
5550
goto error ;
5521
5551
}
@@ -5557,10 +5587,13 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
5557
5587
}
5558
5588
5559
5589
ADDOP_I (c , loc , op , 0 );
5590
+ if (is_inlined ) {
5591
+ ADDOP_I (c , loc , SWAP , 2 );
5592
+ }
5560
5593
}
5561
5594
5562
5595
if (compiler_comprehension_generator (c , loc , generators , 0 , 0 ,
5563
- elt , val , type , ! is_inlined ) < 0 ) {
5596
+ elt , val , type , is_inlined ) < 0 ) {
5564
5597
goto error_in_scope ;
5565
5598
}
5566
5599
@@ -5595,13 +5628,8 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
5595
5628
}
5596
5629
Py_DECREF (co );
5597
5630
5598
- VISIT (c , expr , outermost -> iter );
5599
-
5600
- loc = LOC (e );
5601
- if (outermost -> is_async ) {
5602
- ADDOP (c , loc , GET_AITER );
5603
- } else {
5604
- ADDOP (c , loc , GET_ITER );
5631
+ if (compiler_comprehension_iter (c , loc , outermost )) {
5632
+ goto error ;
5605
5633
}
5606
5634
5607
5635
ADDOP_I (c , loc , CALL , 0 );
@@ -8141,6 +8169,7 @@ scan_block_for_locals(basicblock *b, basicblock ***sp)
8141
8169
uint64_t bit = (uint64_t )1 << instr -> i_oparg ;
8142
8170
switch (instr -> i_opcode ) {
8143
8171
case DELETE_FAST :
8172
+ case LOAD_FAST_AND_CLEAR :
8144
8173
unsafe_mask |= bit ;
8145
8174
break ;
8146
8175
case STORE_FAST :
@@ -8194,6 +8223,7 @@ fast_scan_many_locals(basicblock *entryblock, int nlocals)
8194
8223
assert (arg >= 0 );
8195
8224
switch (instr -> i_opcode ) {
8196
8225
case DELETE_FAST :
8226
+ case LOAD_FAST_AND_CLEAR :
8197
8227
states [arg - 64 ] = blocknum - 1 ;
8198
8228
break ;
8199
8229
case STORE_FAST :
0 commit comments