@@ -5371,38 +5371,28 @@ typedef struct {
53715371 PyObject * temp_symbols ;
53725372 PyObject * fast_hidden ;
53735373 jump_target_label cleanup ;
5374- jump_target_label end ;
53755374} inlined_comprehension_state ;
53765375
53775376static 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 )
53815380{
53825381 int in_class_block = (SYMTABLE_ENTRY (c )-> ste_type == ClassBlock ) && !c -> u -> u_in_inlined_comp ;
53835382 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+
53865384 PyObject * k , * v ;
53875385 Py_ssize_t pos = 0 ;
53885386 while (PyDict_Next (entry -> ste_symbols , & pos , & k , & v )) {
53895387 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 );
53935390 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 );
54055394 long outsc = SYMBOL_TO_SCOPE (outsymbol );
5395+
54065396 // If a name has different scope inside than outside the comprehension,
54075397 // we need to temporarily handle it with the right scope while
54085398 // compiling the comprehension. If it's free in the comprehension
@@ -5422,16 +5412,16 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
54225412 // update the symbol to the in-comprehension version and save
54235413 // the outer version; we'll restore it after running the
54245414 // comprehension
5425- Py_INCREF (outv );
54265415 if (PyDict_SetItem (SYMTABLE_ENTRY (c )-> ste_symbols , k , v ) < 0 ) {
5427- Py_DECREF (outv );
54285416 return ERROR ;
54295417 }
5430- if ( PyDict_SetItem ( state -> temp_symbols , k , outv ) < 0 ) {
5431- Py_DECREF (outv );
5418+ PyObject * outv = PyLong_FromLong ( outsymbol );
5419+ if (outv == NULL ) {
54325420 return ERROR ;
54335421 }
5422+ int res = PyDict_SetItem (state -> temp_symbols , k , outv );
54345423 Py_DECREF (outv );
5424+ RETURN_IF_ERROR (res );
54355425 }
54365426 // locals handling for names bound in comprehension (DEF_LOCAL |
54375427 // DEF_NONLOCAL occurs in assignment expression to nonlocal)
@@ -5442,9 +5432,8 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
54425432 if (PyDict_GetItemRef (c -> u -> u_metadata .u_fasthidden , k , & orig ) < 0 ) {
54435433 return ERROR ;
54445434 }
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 ) {
54485437 if (PyDict_SetItem (c -> u -> u_metadata .u_fasthidden , k , Py_True ) < 0 ) {
54495438 return ERROR ;
54505439 }
@@ -5459,6 +5448,33 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
54595448 }
54605449 }
54615450 }
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 ) {
54625478 // local names bound in comprehension must be isolated from
54635479 // outer scope; push existing value (which may be NULL if
54645480 // not defined) on stack
@@ -5496,31 +5512,40 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
54965512 // handler or finally block.
54975513 NEW_JUMP_TARGET_LABEL (c , cleanup );
54985514 state -> cleanup = cleanup ;
5499- NEW_JUMP_TARGET_LABEL (c , end );
5500- state -> end = end ;
55015515
55025516 // no need to push an fblock for this "virtual" try/finally; there can't
55035517 // be return/continue/break inside a comprehension
55045518 ADDOP_JUMP (c , loc , SETUP_FINALLY , cleanup );
55055519 }
5520+ return SUCCESS ;
5521+ }
55065522
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 ));
55075532 return SUCCESS ;
55085533}
55095534
55105535static int
55115536restore_inlined_comprehension_locals (struct compiler * c , location loc ,
5512- inlined_comprehension_state state )
5537+ inlined_comprehension_state * state )
55135538{
55145539 PyObject * k ;
55155540 // 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 );
55175542 // 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
55205545 // pushed_locals in simple reverse order
55215546 ADDOP_I (c , loc , SWAP , npops + 1 );
55225547 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 );
55245549 if (k == NULL ) {
55255550 return ERROR ;
55265551 }
@@ -5530,43 +5555,47 @@ restore_inlined_comprehension_locals(struct compiler *c, location loc,
55305555}
55315556
55325557static 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 )
55355560{
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 ) {
55485562 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 );
55505566
55515567 // cleanup from an exception inside the comprehension
5552- USE_LABEL (c , state . cleanup );
5568+ USE_LABEL (c , state -> cleanup );
55535569 // discard incomplete comprehension result (beneath exc on stack)
55545570 ADDOP_I (c , NO_LOCATION , SWAP , 2 );
55555571 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 ));
55595573 ADDOP_I (c , NO_LOCATION , RERAISE , 0 );
55605574
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+ }
55645593 }
5565- Py_CLEAR (state . pushed_locals );
5594+ Py_CLEAR (state -> temp_symbols );
55665595 }
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 );
55705599 if (k == NULL ) {
55715600 return ERROR ;
55725601 }
@@ -5578,11 +5607,21 @@ pop_inlined_comprehension_state(struct compiler *c, location loc,
55785607 }
55795608 Py_DECREF (k );
55805609 }
5581- Py_CLEAR (state . fast_hidden );
5610+ Py_CLEAR (state -> fast_hidden );
55825611 }
55835612 return SUCCESS ;
55845613}
55855614
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+
55865625static inline int
55875626compiler_comprehension_iter (struct compiler * c , location loc ,
55885627 comprehension_ty comp )
@@ -5603,7 +5642,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
56035642 expr_ty val )
56045643{
56055644 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 };
56075646 comprehension_ty outermost ;
56085647#ifndef NDEBUG
56095648 int scope_type = c -> u -> u_scope_type ;
@@ -5671,7 +5710,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
56715710 }
56725711
56735712 if (is_inlined ) {
5674- if (pop_inlined_comprehension_state (c , loc , inline_state )) {
5713+ if (pop_inlined_comprehension_state (c , loc , & inline_state )) {
56755714 goto error ;
56765715 }
56775716 return SUCCESS ;
0 commit comments