Skip to content

Commit 9ac6060

Browse files
authored
gh-121404: extract compiler_lookup_arg out of compiler_make_closure (#122181)
1 parent 794546f commit 9ac6060

File tree

1 file changed

+49
-41
lines changed

1 file changed

+49
-41
lines changed

Python/compile.c

+49-41
Original file line numberDiff line numberDiff line change
@@ -1611,29 +1611,30 @@ compiler_mod(struct compiler *c, mod_ty mod)
16111611
static int
16121612
compiler_get_ref_type(struct compiler *c, PyObject *name)
16131613
{
1614-
int scope;
16151614
if (c->u->u_scope_type == COMPILER_SCOPE_CLASS &&
16161615
(_PyUnicode_EqualToASCIIString(name, "__class__") ||
16171616
_PyUnicode_EqualToASCIIString(name, "__classdict__"))) {
16181617
return CELL;
16191618
}
16201619
PySTEntryObject *ste = SYMTABLE_ENTRY(c);
1621-
scope = _PyST_GetScope(ste, name);
1620+
int scope = _PyST_GetScope(ste, name);
16221621
if (scope == 0) {
16231622
PyErr_Format(PyExc_SystemError,
16241623
"_PyST_GetScope(name=%R) failed: "
16251624
"unknown scope in unit %S (%R); "
1626-
"symbols: %R; locals: %R; globals: %R",
1625+
"symbols: %R; locals: %R; "
1626+
"globals: %R",
16271627
name,
16281628
c->u->u_metadata.u_name, ste->ste_id,
1629-
ste->ste_symbols, c->u->u_metadata.u_varnames, c->u->u_metadata.u_names);
1629+
ste->ste_symbols, c->u->u_metadata.u_varnames,
1630+
c->u->u_metadata.u_names);
16301631
return ERROR;
16311632
}
16321633
return scope;
16331634
}
16341635

16351636
static int
1636-
compiler_lookup_arg(PyObject *dict, PyObject *name)
1637+
dict_lookup_arg(PyObject *dict, PyObject *name)
16371638
{
16381639
PyObject *v = PyDict_GetItemWithError(dict, name);
16391640
if (v == NULL) {
@@ -1642,6 +1643,45 @@ compiler_lookup_arg(PyObject *dict, PyObject *name)
16421643
return PyLong_AS_LONG(v);
16431644
}
16441645

1646+
static int
1647+
compiler_lookup_arg(struct compiler *c, PyCodeObject *co, PyObject *name)
1648+
{
1649+
/* Special case: If a class contains a method with a
1650+
* free variable that has the same name as a method,
1651+
* the name will be considered free *and* local in the
1652+
* class. It should be handled by the closure, as
1653+
* well as by the normal name lookup logic.
1654+
*/
1655+
int reftype = compiler_get_ref_type(c, name);
1656+
if (reftype == -1) {
1657+
return ERROR;
1658+
}
1659+
int arg;
1660+
if (reftype == CELL) {
1661+
arg = dict_lookup_arg(c->u->u_metadata.u_cellvars, name);
1662+
}
1663+
else {
1664+
arg = dict_lookup_arg(c->u->u_metadata.u_freevars, name);
1665+
}
1666+
if (arg == -1) {
1667+
PyObject *freevars = _PyCode_GetFreevars(co);
1668+
if (freevars == NULL) {
1669+
PyErr_Clear();
1670+
}
1671+
PyErr_Format(PyExc_SystemError,
1672+
"compiler_lookup_arg(name=%R) with reftype=%d failed in %S; "
1673+
"freevars of code %S: %R",
1674+
name,
1675+
reftype,
1676+
c->u->u_metadata.u_name,
1677+
co->co_name,
1678+
freevars);
1679+
Py_DECREF(freevars);
1680+
return ERROR;
1681+
}
1682+
return arg;
1683+
}
1684+
16451685
static int
16461686
compiler_make_closure(struct compiler *c, location loc,
16471687
PyCodeObject *co, Py_ssize_t flags)
@@ -1653,40 +1693,8 @@ compiler_make_closure(struct compiler *c, location loc,
16531693
LOAD_DEREF but LOAD_CLOSURE is needed.
16541694
*/
16551695
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
1656-
1657-
/* Special case: If a class contains a method with a
1658-
free variable that has the same name as a method,
1659-
the name will be considered free *and* local in the
1660-
class. It should be handled by the closure, as
1661-
well as by the normal name lookup logic.
1662-
*/
1663-
int reftype = compiler_get_ref_type(c, name);
1664-
if (reftype == -1) {
1665-
return ERROR;
1666-
}
1667-
int arg;
1668-
if (reftype == CELL) {
1669-
arg = compiler_lookup_arg(c->u->u_metadata.u_cellvars, name);
1670-
}
1671-
else {
1672-
arg = compiler_lookup_arg(c->u->u_metadata.u_freevars, name);
1673-
}
1674-
if (arg == -1) {
1675-
PyObject *freevars = _PyCode_GetFreevars(co);
1676-
if (freevars == NULL) {
1677-
PyErr_Clear();
1678-
}
1679-
PyErr_Format(PyExc_SystemError,
1680-
"compiler_lookup_arg(name=%R) with reftype=%d failed in %S; "
1681-
"freevars of code %S: %R",
1682-
name,
1683-
reftype,
1684-
c->u->u_metadata.u_name,
1685-
co->co_name,
1686-
freevars);
1687-
Py_DECREF(freevars);
1688-
return ERROR;
1689-
}
1696+
int arg = compiler_lookup_arg(c, co, name);
1697+
RETURN_IF_ERROR(arg);
16901698
ADDOP_I(c, loc, LOAD_CLOSURE, arg);
16911699
}
16921700
flags |= MAKE_FUNCTION_CLOSURE;
@@ -2460,7 +2468,7 @@ compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno)
24602468
/* Set __classdictcell__ if necessary */
24612469
if (SYMTABLE_ENTRY(c)->ste_needs_classdict) {
24622470
/* Store __classdictcell__ into class namespace */
2463-
int i = compiler_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__classdict__));
2471+
int i = dict_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__classdict__));
24642472
if (i < 0) {
24652473
compiler_exit_scope(c);
24662474
return ERROR;
@@ -2474,7 +2482,7 @@ compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno)
24742482
/* Return __classcell__ if it is referenced, otherwise return None */
24752483
if (SYMTABLE_ENTRY(c)->ste_needs_class_closure) {
24762484
/* Store __classcell__ into class namespace & return it */
2477-
int i = compiler_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__class__));
2485+
int i = dict_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__class__));
24782486
if (i < 0) {
24792487
compiler_exit_scope(c);
24802488
return ERROR;

0 commit comments

Comments
 (0)