@@ -5371,38 +5371,28 @@ typedef struct {
5371
5371
PyObject * temp_symbols ;
5372
5372
PyObject * fast_hidden ;
5373
5373
jump_target_label cleanup ;
5374
- jump_target_label end ;
5375
5374
} inlined_comprehension_state ;
5376
5375
5377
5376
static int
5378
- push_inlined_comprehension_state (struct compiler * c , location loc ,
5379
- PySTEntryObject * entry ,
5380
- inlined_comprehension_state * state )
5377
+ compiler_tweak_inlined_comprehension_scopes (struct compiler * c , location loc ,
5378
+ PySTEntryObject * entry ,
5379
+ inlined_comprehension_state * state )
5381
5380
{
5382
5381
int in_class_block = (SYMTABLE_ENTRY (c )-> ste_type == ClassBlock ) && !c -> u -> u_in_inlined_comp ;
5383
5382
c -> u -> u_in_inlined_comp ++ ;
5384
- // iterate over names bound in the comprehension and ensure we isolate
5385
- // them from the outer scope as needed
5383
+
5386
5384
PyObject * k , * v ;
5387
5385
Py_ssize_t pos = 0 ;
5388
5386
while (PyDict_Next (entry -> ste_symbols , & pos , & k , & v )) {
5389
5387
long symbol = PyLong_AsLong (v );
5390
- if (symbol == -1 && PyErr_Occurred ()) {
5391
- return ERROR ;
5392
- }
5388
+ assert (symbol >= 0 || PyErr_Occurred ());
5389
+ RETURN_IF_ERROR (symbol );
5393
5390
long scope = SYMBOL_TO_SCOPE (symbol );
5394
- PyObject * outv = PyDict_GetItemWithError (SYMTABLE_ENTRY (c )-> ste_symbols , k );
5395
- if (outv == NULL ) {
5396
- if (PyErr_Occurred ()) {
5397
- return ERROR ;
5398
- }
5399
- outv = _PyLong_GetZero ();
5400
- }
5401
- long outsymbol = PyLong_AsLong (outv );
5402
- if (outsymbol == -1 && PyErr_Occurred ()) {
5403
- return ERROR ;
5404
- }
5391
+
5392
+ long outsymbol = _PyST_GetSymbol (SYMTABLE_ENTRY (c ), k );
5393
+ RETURN_IF_ERROR (outsymbol );
5405
5394
long outsc = SYMBOL_TO_SCOPE (outsymbol );
5395
+
5406
5396
// If a name has different scope inside than outside the comprehension,
5407
5397
// we need to temporarily handle it with the right scope while
5408
5398
// compiling the comprehension. If it's free in the comprehension
@@ -5422,16 +5412,16 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
5422
5412
// update the symbol to the in-comprehension version and save
5423
5413
// the outer version; we'll restore it after running the
5424
5414
// comprehension
5425
- Py_INCREF (outv );
5426
5415
if (PyDict_SetItem (SYMTABLE_ENTRY (c )-> ste_symbols , k , v ) < 0 ) {
5427
- Py_DECREF (outv );
5428
5416
return ERROR ;
5429
5417
}
5430
- if ( PyDict_SetItem ( state -> temp_symbols , k , outv ) < 0 ) {
5431
- Py_DECREF (outv );
5418
+ PyObject * outv = PyLong_FromLong ( outsymbol );
5419
+ if (outv == NULL ) {
5432
5420
return ERROR ;
5433
5421
}
5422
+ int res = PyDict_SetItem (state -> temp_symbols , k , outv );
5434
5423
Py_DECREF (outv );
5424
+ RETURN_IF_ERROR (res );
5435
5425
}
5436
5426
// locals handling for names bound in comprehension (DEF_LOCAL |
5437
5427
// DEF_NONLOCAL occurs in assignment expression to nonlocal)
@@ -5442,9 +5432,8 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
5442
5432
if (PyDict_GetItemRef (c -> u -> u_metadata .u_fasthidden , k , & orig ) < 0 ) {
5443
5433
return ERROR ;
5444
5434
}
5445
- int orig_is_true = (orig == Py_True );
5446
- Py_XDECREF (orig );
5447
- if (!orig_is_true ) {
5435
+ assert (orig == NULL || orig == Py_True || orig == Py_False );
5436
+ if (orig != Py_True ) {
5448
5437
if (PyDict_SetItem (c -> u -> u_metadata .u_fasthidden , k , Py_True ) < 0 ) {
5449
5438
return ERROR ;
5450
5439
}
@@ -5459,6 +5448,33 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
5459
5448
}
5460
5449
}
5461
5450
}
5451
+ }
5452
+ }
5453
+ return SUCCESS ;
5454
+ }
5455
+
5456
+ static int
5457
+ codegen_push_inlined_comprehension_locals (struct compiler * c , location loc ,
5458
+ PySTEntryObject * comp ,
5459
+ inlined_comprehension_state * state )
5460
+ {
5461
+ int in_class_block = (SYMTABLE_ENTRY (c )-> ste_type == ClassBlock ) && !c -> u -> u_in_inlined_comp ;
5462
+ PySTEntryObject * outer = SYMTABLE_ENTRY (c );
5463
+ // iterate over names bound in the comprehension and ensure we isolate
5464
+ // them from the outer scope as needed
5465
+ PyObject * k , * v ;
5466
+ Py_ssize_t pos = 0 ;
5467
+ while (PyDict_Next (comp -> ste_symbols , & pos , & k , & v )) {
5468
+ long symbol = PyLong_AsLong (v );
5469
+ assert (symbol >= 0 || PyErr_Occurred ());
5470
+ RETURN_IF_ERROR (symbol );
5471
+ long scope = SYMBOL_TO_SCOPE (symbol );
5472
+
5473
+ long outsymbol = _PyST_GetSymbol (outer , k );
5474
+ RETURN_IF_ERROR (outsymbol );
5475
+ long outsc = SYMBOL_TO_SCOPE (outsymbol );
5476
+
5477
+ if ((symbol & DEF_LOCAL && !(symbol & DEF_NONLOCAL )) || in_class_block ) {
5462
5478
// local names bound in comprehension must be isolated from
5463
5479
// outer scope; push existing value (which may be NULL if
5464
5480
// not defined) on stack
@@ -5496,31 +5512,40 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
5496
5512
// handler or finally block.
5497
5513
NEW_JUMP_TARGET_LABEL (c , cleanup );
5498
5514
state -> cleanup = cleanup ;
5499
- NEW_JUMP_TARGET_LABEL (c , end );
5500
- state -> end = end ;
5501
5515
5502
5516
// no need to push an fblock for this "virtual" try/finally; there can't
5503
5517
// be return/continue/break inside a comprehension
5504
5518
ADDOP_JUMP (c , loc , SETUP_FINALLY , cleanup );
5505
5519
}
5520
+ return SUCCESS ;
5521
+ }
5506
5522
5523
+ static int
5524
+ push_inlined_comprehension_state (struct compiler * c , location loc ,
5525
+ PySTEntryObject * comp ,
5526
+ inlined_comprehension_state * state )
5527
+ {
5528
+ RETURN_IF_ERROR (
5529
+ compiler_tweak_inlined_comprehension_scopes (c , loc , comp , state ));
5530
+ RETURN_IF_ERROR (
5531
+ codegen_push_inlined_comprehension_locals (c , loc , comp , state ));
5507
5532
return SUCCESS ;
5508
5533
}
5509
5534
5510
5535
static int
5511
5536
restore_inlined_comprehension_locals (struct compiler * c , location loc ,
5512
- inlined_comprehension_state state )
5537
+ inlined_comprehension_state * state )
5513
5538
{
5514
5539
PyObject * k ;
5515
5540
// pop names we pushed to stack earlier
5516
- Py_ssize_t npops = PyList_GET_SIZE (state . pushed_locals );
5541
+ Py_ssize_t npops = PyList_GET_SIZE (state -> pushed_locals );
5517
5542
// Preserve the comprehension result (or exception) as TOS. This
5518
- // reverses the SWAP we did in push_inlined_comprehension_state to get
5519
- // the outermost iterable to TOS, so we can still just iterate
5543
+ // reverses the SWAP we did in push_inlined_comprehension_state
5544
+ // to get the outermost iterable to TOS, so we can still just iterate
5520
5545
// pushed_locals in simple reverse order
5521
5546
ADDOP_I (c , loc , SWAP , npops + 1 );
5522
5547
for (Py_ssize_t i = npops - 1 ; i >= 0 ; -- i ) {
5523
- k = PyList_GetItem (state . pushed_locals , i );
5548
+ k = PyList_GetItem (state -> pushed_locals , i );
5524
5549
if (k == NULL ) {
5525
5550
return ERROR ;
5526
5551
}
@@ -5530,43 +5555,47 @@ restore_inlined_comprehension_locals(struct compiler *c, location loc,
5530
5555
}
5531
5556
5532
5557
static int
5533
- pop_inlined_comprehension_state (struct compiler * c , location loc ,
5534
- inlined_comprehension_state state )
5558
+ codegen_pop_inlined_comprehension_locals (struct compiler * c , location loc ,
5559
+ inlined_comprehension_state * state )
5535
5560
{
5536
- c -> u -> u_in_inlined_comp -- ;
5537
- PyObject * k , * v ;
5538
- Py_ssize_t pos = 0 ;
5539
- if (state .temp_symbols ) {
5540
- while (PyDict_Next (state .temp_symbols , & pos , & k , & v )) {
5541
- if (PyDict_SetItem (SYMTABLE_ENTRY (c )-> ste_symbols , k , v )) {
5542
- return ERROR ;
5543
- }
5544
- }
5545
- Py_CLEAR (state .temp_symbols );
5546
- }
5547
- if (state .pushed_locals ) {
5561
+ if (state -> pushed_locals ) {
5548
5562
ADDOP (c , NO_LOCATION , POP_BLOCK );
5549
- ADDOP_JUMP (c , NO_LOCATION , JUMP_NO_INTERRUPT , state .end );
5563
+
5564
+ NEW_JUMP_TARGET_LABEL (c , end );
5565
+ ADDOP_JUMP (c , NO_LOCATION , JUMP_NO_INTERRUPT , end );
5550
5566
5551
5567
// cleanup from an exception inside the comprehension
5552
- USE_LABEL (c , state . cleanup );
5568
+ USE_LABEL (c , state -> cleanup );
5553
5569
// discard incomplete comprehension result (beneath exc on stack)
5554
5570
ADDOP_I (c , NO_LOCATION , SWAP , 2 );
5555
5571
ADDOP (c , NO_LOCATION , POP_TOP );
5556
- if (restore_inlined_comprehension_locals (c , loc , state ) < 0 ) {
5557
- return ERROR ;
5558
- }
5572
+ RETURN_IF_ERROR (restore_inlined_comprehension_locals (c , loc , state ));
5559
5573
ADDOP_I (c , NO_LOCATION , RERAISE , 0 );
5560
5574
5561
- USE_LABEL (c , state .end );
5562
- if (restore_inlined_comprehension_locals (c , loc , state ) < 0 ) {
5563
- return ERROR ;
5575
+ USE_LABEL (c , end );
5576
+ RETURN_IF_ERROR (restore_inlined_comprehension_locals (c , loc , state ));
5577
+ Py_CLEAR (state -> pushed_locals );
5578
+ }
5579
+ return SUCCESS ;
5580
+ }
5581
+
5582
+ static int
5583
+ compiler_revert_inlined_comprehension_scopes (struct compiler * c , location loc ,
5584
+ inlined_comprehension_state * state )
5585
+ {
5586
+ if (state -> temp_symbols ) {
5587
+ PyObject * k , * v ;
5588
+ Py_ssize_t pos = 0 ;
5589
+ while (PyDict_Next (state -> temp_symbols , & pos , & k , & v )) {
5590
+ if (PyDict_SetItem (SYMTABLE_ENTRY (c )-> ste_symbols , k , v )) {
5591
+ return ERROR ;
5592
+ }
5564
5593
}
5565
- Py_CLEAR (state . pushed_locals );
5594
+ Py_CLEAR (state -> temp_symbols );
5566
5595
}
5567
- if (state . fast_hidden ) {
5568
- while (PySet_Size (state . fast_hidden ) > 0 ) {
5569
- PyObject * k = PySet_Pop (state . fast_hidden );
5596
+ if (state -> fast_hidden ) {
5597
+ while (PySet_Size (state -> fast_hidden ) > 0 ) {
5598
+ PyObject * k = PySet_Pop (state -> fast_hidden );
5570
5599
if (k == NULL ) {
5571
5600
return ERROR ;
5572
5601
}
@@ -5578,11 +5607,21 @@ pop_inlined_comprehension_state(struct compiler *c, location loc,
5578
5607
}
5579
5608
Py_DECREF (k );
5580
5609
}
5581
- Py_CLEAR (state . fast_hidden );
5610
+ Py_CLEAR (state -> fast_hidden );
5582
5611
}
5583
5612
return SUCCESS ;
5584
5613
}
5585
5614
5615
+ static int
5616
+ pop_inlined_comprehension_state (struct compiler * c , location loc ,
5617
+ inlined_comprehension_state * state )
5618
+ {
5619
+ c -> u -> u_in_inlined_comp -- ;
5620
+ RETURN_IF_ERROR (codegen_pop_inlined_comprehension_locals (c , loc , state ));
5621
+ RETURN_IF_ERROR (compiler_revert_inlined_comprehension_scopes (c , loc , state ));
5622
+ return SUCCESS ;
5623
+ }
5624
+
5586
5625
static inline int
5587
5626
compiler_comprehension_iter (struct compiler * c , location loc ,
5588
5627
comprehension_ty comp )
@@ -5603,7 +5642,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
5603
5642
expr_ty val )
5604
5643
{
5605
5644
PyCodeObject * co = NULL ;
5606
- inlined_comprehension_state inline_state = {NULL , NULL , NULL , NO_LABEL , NO_LABEL };
5645
+ inlined_comprehension_state inline_state = {NULL , NULL , NULL , NO_LABEL };
5607
5646
comprehension_ty outermost ;
5608
5647
#ifndef NDEBUG
5609
5648
int scope_type = c -> u -> u_scope_type ;
@@ -5671,7 +5710,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
5671
5710
}
5672
5711
5673
5712
if (is_inlined ) {
5674
- if (pop_inlined_comprehension_state (c , loc , inline_state )) {
5713
+ if (pop_inlined_comprehension_state (c , loc , & inline_state )) {
5675
5714
goto error ;
5676
5715
}
5677
5716
return SUCCESS ;
0 commit comments