@@ -630,9 +630,9 @@ struct compiler_unit {
630630 PyObject * u_cellvars ; /* cell variables */
631631 PyObject * u_freevars ; /* free variables */
632632
633- // A set of names that should use fast-locals, even if not in a function */
634- PyObject * u_fastlocals ;
635-
633+ PyObject * u_fasthidden ; /* dict; keys are names that are fast-locals only
634+ temporarily within an inlined comprehension. When
635+ value is True, treat as fast-local. */
636636 PyObject * u_private ; /* for private name mangling */
637637
638638 Py_ssize_t u_argcount ; /* number of arguments for block */
@@ -1000,6 +1000,7 @@ compiler_unit_free(struct compiler_unit *u)
10001000 Py_CLEAR (u -> u_varnames );
10011001 Py_CLEAR (u -> u_freevars );
10021002 Py_CLEAR (u -> u_cellvars );
1003+ Py_CLEAR (u -> u_fasthidden );
10031004 Py_CLEAR (u -> u_private );
10041005 PyObject_Free (u );
10051006}
@@ -1671,6 +1672,12 @@ compiler_enter_scope(struct compiler *c, identifier name,
16711672 return ERROR ;
16721673 }
16731674
1675+ u -> u_fasthidden = PyDict_New ();
1676+ if (!u -> u_fasthidden ) {
1677+ compiler_unit_free (u );
1678+ return ERROR ;
1679+ }
1680+
16741681 u -> u_nfblocks = 0 ;
16751682 u -> u_firstlineno = lineno ;
16761683 u -> u_consts = PyDict_New ();
@@ -4118,8 +4125,7 @@ compiler_nameop(struct compiler *c, location loc,
41184125 break ;
41194126 case LOCAL :
41204127 if (c -> u -> u_ste -> ste_type == FunctionBlock ||
4121- (c -> u -> u_fastlocals &&
4122- PySet_Contains (c -> u -> u_fastlocals , mangled )))
4128+ (PyDict_GetItem (c -> u -> u_fasthidden , mangled ) == Py_True ))
41234129 optype = OP_FAST ;
41244130 break ;
41254131 case GLOBAL_IMPLICIT :
@@ -5298,16 +5304,6 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
52985304 // them from the outer scope as needed
52995305 PyObject * k , * v ;
53005306 Py_ssize_t pos = 0 ;
5301- assert (c -> u -> u_fastlocals == NULL );
5302- if (c -> u -> u_ste -> ste_type != FunctionBlock ) {
5303- // comprehension in non-function scope; for isolation, we'll need to
5304- // temporarily override names bound in the comprehension to use fast
5305- // locals, even though nothing else in this frame will
5306- c -> u -> u_fastlocals = PySet_New (0 );
5307- if (c -> u -> u_fastlocals == NULL ) {
5308- return ERROR ;
5309- }
5310- }
53115307 while (PyDict_Next (entry -> ste_symbols , & pos , & k , & v )) {
53125308 assert (PyLong_Check (v ));
53135309 long symbol = PyLong_AS_LONG (v );
@@ -5316,9 +5312,9 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
53165312 // assignment expression to a nonlocal in the comprehension, these don't
53175313 // need handling here since they shouldn't be isolated
53185314 if (symbol & DEF_LOCAL && ~symbol & DEF_NONLOCAL ) {
5319- if (c -> u -> u_fastlocals ) {
5315+ if (c -> u -> u_ste -> ste_type != FunctionBlock ) {
53205316 // non-function scope: override this name to use fast locals
5321- PySet_Add (c -> u -> u_fastlocals , k );
5317+ PyDict_SetItem (c -> u -> u_fasthidden , k , Py_True );
53225318 }
53235319 long scope = (symbol >> SCOPE_OFFSET ) & SCOPE_MASK ;
53245320 PyObject * outv = PyDict_GetItemWithError (c -> u -> u_ste -> ste_symbols , k );
@@ -5392,7 +5388,6 @@ pop_inlined_comprehension_state(struct compiler *c, location loc,
53925388 PyObject * k , * v ;
53935389 Py_ssize_t pos = 0 ;
53945390 if (state .temp_symbols ) {
5395- // restore scope for globals that we temporarily set as locals
53965391 while (PyDict_Next (state .temp_symbols , & pos , & k , & v )) {
53975392 if (PyDict_SetItem (c -> u -> u_ste -> ste_symbols , k , v )) {
53985393 return ERROR ;
@@ -5415,8 +5410,15 @@ pop_inlined_comprehension_state(struct compiler *c, location loc,
54155410 ADDOP_NAME (c , loc , STORE_FAST_MAYBE_NULL , k , varnames );
54165411 }
54175412 }
5418- if (c -> u -> u_fastlocals ) {
5419- Py_CLEAR (c -> u -> u_fastlocals );
5413+ pos = 0 ;
5414+ while (PyDict_Next (c -> u -> u_fasthidden , & pos , & k , & v )) {
5415+ if (v == Py_True ) {
5416+ // we set to False instead of clearing, so we can track which names
5417+ // were temporarily fast-locals and should use CO_FAST_HIDDEN
5418+ if (PyDict_SetItem (c -> u -> u_fasthidden , k , Py_False )) {
5419+ return ERROR ;
5420+ }
5421+ }
54205422 }
54215423 return SUCCESS ;
54225424}
@@ -8333,6 +8335,9 @@ compute_localsplus_info(struct compiler *c, int nlocalsplus,
83338335 assert (offset < nlocalsplus );
83348336 // For now we do not distinguish arg kinds.
83358337 _PyLocals_Kind kind = CO_FAST_LOCAL ;
8338+ if (PyDict_Contains (c -> u -> u_fasthidden , k )) {
8339+ kind |= CO_FAST_HIDDEN ;
8340+ }
83368341 if (PyDict_GetItem (c -> u -> u_cellvars , k ) != NULL ) {
83378342 kind |= CO_FAST_CELL ;
83388343 }
0 commit comments