Skip to content

Commit 2918e2c

Browse files
committed
handle symbols which do not exist in an inlined comprehension's symtable entry
1 parent 98509f0 commit 2918e2c

4 files changed

Lines changed: 46 additions & 24 deletions

File tree

‎Include/internal/pycore_compile.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ PyObject *_PyCompile_MaybeMangle(struct _PyCompiler *c, PyObject *name);
151151
int _PyCompile_MaybeAddStaticAttributeToClass(struct _PyCompiler *c, expr_ty e);
152152
int _PyCompile_GetRefType(struct _PyCompiler *c, PyObject *name);
153153
int _PyCompile_LookupCellvar(struct _PyCompiler *c, PyObject *name);
154-
int _PyCompile_ResolveNameop(struct _PyCompiler *c, PyObject *mangled, int scope,
154+
int _PyCompile_ResolveNameop(struct _PyCompiler *c, PyObject *mangled,
155155
_PyCompile_optype *optype, Py_ssize_t *arg);
156156

157157
int _PyCompile_IsInteractiveTopLevel(struct _PyCompiler *c);

‎Lib/test/test_listcomps.py‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,30 @@ def test_references_super(self):
165165
"""
166166
self._check_in_scopes(code, outputs={"res": [super]})
167167

168+
def test_zero_arg_super_in_inlined_comprehension(self):
169+
class A:
170+
def f(self):
171+
return 42
172+
173+
class B(A):
174+
def f(self):
175+
return [super().f() for _ in (0,)]
176+
177+
def nested(self):
178+
return [[super().f() for _ in (0,)] for _ in (0,)]
179+
180+
def setcomp(self):
181+
return [{super().f() for _ in (0,)}]
182+
183+
def dictcomp(self):
184+
return {0: {1: super().f() for _ in (0,)} for _ in (0,)}
185+
186+
b = B()
187+
self.assertEqual(b.f(), [42])
188+
self.assertEqual(b.nested(), [[42]])
189+
self.assertEqual(b.setcomp(), [{42}])
190+
self.assertEqual(b.dictcomp(), {0: {1: 42}})
191+
168192
def test_references___class__(self):
169193
code = """
170194
res = [__class__ for x in [1]]

‎Python/codegen.c‎

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3326,21 +3326,14 @@ codegen_nameop(compiler *c, location loc,
33263326
return ERROR;
33273327
}
33283328

3329-
int scope = _PyST_GetScope(SYMTABLE_ENTRY(c), mangled);
3330-
if (scope == -1) {
3331-
goto error;
3332-
}
3333-
33343329
_PyCompile_optype optype;
33353330
Py_ssize_t arg = 0;
3336-
if (_PyCompile_ResolveNameop(c, mangled, scope, &optype, &arg) < 0) {
3331+
int scope = _PyCompile_ResolveNameop(c, mangled, &optype, &arg);
3332+
if (scope < 0) {
33373333
Py_DECREF(mangled);
33383334
return ERROR;
33393335
}
33403336

3341-
/* XXX Leave assert here, but handle __doc__ and the like better */
3342-
assert(scope || PyUnicode_READ_CHAR(name, 0) == '_');
3343-
33443337
int op = 0;
33453338
switch (optype) {
33463339
case COMPILE_OP_DEREF:

‎Python/compile.c‎

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -980,15 +980,21 @@ compiler_mod(compiler *c, mod_ty mod)
980980
}
981981

982982
/* Inlined comprehensions are compiled in the enclosing unit. If a name is
983-
* FREE in the comprehension, resolve it in enclosing tables until it is no
984-
* longer FREE. Stop if the next table is a class: nested scopes (including
985-
* inlined comprehensions) do not see class locals, so the name stays FREE.
986-
* __class__ and friends are not allowed to be free through a class; treat
987-
* those loads as implicit globals. */
983+
* FREE in the comprehension, or is absent from its table (scope 0), resolve
984+
* it in enclosing tables until it is bound. Stop if the next table is a class:
985+
* nested scopes (including inlined comprehensions) do not see class locals, so
986+
* the name stays FREE. __class__ and friends are not allowed to be free
987+
* through a class; treat those loads as implicit globals.
988+
*
989+
* Names with no entry (scope 0) include loads synthesized by codegen, such as
990+
* the implicit receiver for zero-arg super(). */
988991
static int
989-
compiler_resolve_inlined_free(PySTEntryObject **ste, int scope, PyObject *name)
992+
compiler_resolve_inlined_free(PySTEntryObject **ste, PyObject *name)
990993
{
991-
while (scope == FREE && (*ste)->ste_type == InlinedComprehensionBlock) {
994+
int scope = _PyST_GetScope(*ste, name);
995+
RETURN_IF_ERROR(scope);
996+
while ((*ste)->ste_type == InlinedComprehensionBlock &&
997+
(scope == FREE || scope == 0)) {
992998
PySTEntryObject *parent = (*ste)->ste_parent;
993999
assert(parent != NULL);
9941000
if (parent->ste_type == ClassBlock) {
@@ -1011,9 +1017,7 @@ _PyCompile_GetRefType(compiler *c, PyObject *name)
10111017
return CELL;
10121018
}
10131019
PySTEntryObject *ste = c->u->u_ste;
1014-
int scope = _PyST_GetScope(ste, name);
1015-
RETURN_IF_ERROR(scope);
1016-
scope = compiler_resolve_inlined_free(&ste, scope, name);
1020+
int scope = compiler_resolve_inlined_free(&ste, name);
10171021
RETURN_IF_ERROR(scope);
10181022
if (scope == 0) {
10191023
PyErr_Format(PyExc_SystemError,
@@ -1104,7 +1108,7 @@ _PyCompile_StaticAttributesAsTuple(compiler *c)
11041108
}
11051109

11061110
int
1107-
_PyCompile_ResolveNameop(compiler *c, PyObject *mangled, int scope,
1111+
_PyCompile_ResolveNameop(compiler *c, PyObject *mangled,
11081112
_PyCompile_optype *optype, Py_ssize_t *arg)
11091113
{
11101114
PyObject *dict = c->u->u_metadata.u_names;
@@ -1113,8 +1117,7 @@ _PyCompile_ResolveNameop(compiler *c, PyObject *mangled, int scope,
11131117
PySTEntryObject *ste = c->u->u_ste;
11141118
assert(ste != NULL);
11151119

1116-
assert(scope >= 0);
1117-
scope = compiler_resolve_inlined_free(&ste, scope, mangled);
1120+
int scope = compiler_resolve_inlined_free(&ste, mangled);
11181121
RETURN_IF_ERROR(scope);
11191122

11201123
switch (scope) {
@@ -1152,11 +1155,13 @@ _PyCompile_ResolveNameop(compiler *c, PyObject *mangled, int scope,
11521155
/* scope can be 0 */
11531156
break;
11541157
}
1158+
/* XXX Handle __doc__ and the like better */
1159+
assert(scope || PyUnicode_READ_CHAR(mangled, 0) == '_');
11551160
if (*optype != COMPILE_OP_FAST) {
11561161
*arg = _PyCompile_DictAddObj(dict, mangled);
11571162
RETURN_IF_ERROR(*arg);
11581163
}
1159-
return SUCCESS;
1164+
return scope;
11601165
}
11611166

11621167
int

0 commit comments

Comments
 (0)