mirror of https://github.com/python/cpython
gh-121404: extract compiler_lookup_arg out of compiler_make_closure (#122181)
This commit is contained in:
parent
794546fd53
commit
9ac606080a
|
@ -1611,29 +1611,30 @@ finally:
|
||||||
static int
|
static int
|
||||||
compiler_get_ref_type(struct compiler *c, PyObject *name)
|
compiler_get_ref_type(struct compiler *c, PyObject *name)
|
||||||
{
|
{
|
||||||
int scope;
|
|
||||||
if (c->u->u_scope_type == COMPILER_SCOPE_CLASS &&
|
if (c->u->u_scope_type == COMPILER_SCOPE_CLASS &&
|
||||||
(_PyUnicode_EqualToASCIIString(name, "__class__") ||
|
(_PyUnicode_EqualToASCIIString(name, "__class__") ||
|
||||||
_PyUnicode_EqualToASCIIString(name, "__classdict__"))) {
|
_PyUnicode_EqualToASCIIString(name, "__classdict__"))) {
|
||||||
return CELL;
|
return CELL;
|
||||||
}
|
}
|
||||||
PySTEntryObject *ste = SYMTABLE_ENTRY(c);
|
PySTEntryObject *ste = SYMTABLE_ENTRY(c);
|
||||||
scope = _PyST_GetScope(ste, name);
|
int scope = _PyST_GetScope(ste, name);
|
||||||
if (scope == 0) {
|
if (scope == 0) {
|
||||||
PyErr_Format(PyExc_SystemError,
|
PyErr_Format(PyExc_SystemError,
|
||||||
"_PyST_GetScope(name=%R) failed: "
|
"_PyST_GetScope(name=%R) failed: "
|
||||||
"unknown scope in unit %S (%R); "
|
"unknown scope in unit %S (%R); "
|
||||||
"symbols: %R; locals: %R; globals: %R",
|
"symbols: %R; locals: %R; "
|
||||||
|
"globals: %R",
|
||||||
name,
|
name,
|
||||||
c->u->u_metadata.u_name, ste->ste_id,
|
c->u->u_metadata.u_name, ste->ste_id,
|
||||||
ste->ste_symbols, c->u->u_metadata.u_varnames, c->u->u_metadata.u_names);
|
ste->ste_symbols, c->u->u_metadata.u_varnames,
|
||||||
|
c->u->u_metadata.u_names);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
compiler_lookup_arg(PyObject *dict, PyObject *name)
|
dict_lookup_arg(PyObject *dict, PyObject *name)
|
||||||
{
|
{
|
||||||
PyObject *v = PyDict_GetItemWithError(dict, name);
|
PyObject *v = PyDict_GetItemWithError(dict, name);
|
||||||
if (v == NULL) {
|
if (v == NULL) {
|
||||||
|
@ -1642,6 +1643,45 @@ compiler_lookup_arg(PyObject *dict, PyObject *name)
|
||||||
return PyLong_AS_LONG(v);
|
return PyLong_AS_LONG(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compiler_lookup_arg(struct compiler *c, PyCodeObject *co, PyObject *name)
|
||||||
|
{
|
||||||
|
/* Special case: If a class contains a method with a
|
||||||
|
* free variable that has the same name as a method,
|
||||||
|
* the name will be considered free *and* local in the
|
||||||
|
* class. It should be handled by the closure, as
|
||||||
|
* well as by the normal name lookup logic.
|
||||||
|
*/
|
||||||
|
int reftype = compiler_get_ref_type(c, name);
|
||||||
|
if (reftype == -1) {
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
int arg;
|
||||||
|
if (reftype == CELL) {
|
||||||
|
arg = dict_lookup_arg(c->u->u_metadata.u_cellvars, name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
arg = dict_lookup_arg(c->u->u_metadata.u_freevars, name);
|
||||||
|
}
|
||||||
|
if (arg == -1) {
|
||||||
|
PyObject *freevars = _PyCode_GetFreevars(co);
|
||||||
|
if (freevars == NULL) {
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
PyErr_Format(PyExc_SystemError,
|
||||||
|
"compiler_lookup_arg(name=%R) with reftype=%d failed in %S; "
|
||||||
|
"freevars of code %S: %R",
|
||||||
|
name,
|
||||||
|
reftype,
|
||||||
|
c->u->u_metadata.u_name,
|
||||||
|
co->co_name,
|
||||||
|
freevars);
|
||||||
|
Py_DECREF(freevars);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
compiler_make_closure(struct compiler *c, location loc,
|
compiler_make_closure(struct compiler *c, location loc,
|
||||||
PyCodeObject *co, Py_ssize_t flags)
|
PyCodeObject *co, Py_ssize_t flags)
|
||||||
|
@ -1653,40 +1693,8 @@ compiler_make_closure(struct compiler *c, location loc,
|
||||||
LOAD_DEREF but LOAD_CLOSURE is needed.
|
LOAD_DEREF but LOAD_CLOSURE is needed.
|
||||||
*/
|
*/
|
||||||
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
|
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
|
||||||
|
int arg = compiler_lookup_arg(c, co, name);
|
||||||
/* Special case: If a class contains a method with a
|
RETURN_IF_ERROR(arg);
|
||||||
free variable that has the same name as a method,
|
|
||||||
the name will be considered free *and* local in the
|
|
||||||
class. It should be handled by the closure, as
|
|
||||||
well as by the normal name lookup logic.
|
|
||||||
*/
|
|
||||||
int reftype = compiler_get_ref_type(c, name);
|
|
||||||
if (reftype == -1) {
|
|
||||||
return ERROR;
|
|
||||||
}
|
|
||||||
int arg;
|
|
||||||
if (reftype == CELL) {
|
|
||||||
arg = compiler_lookup_arg(c->u->u_metadata.u_cellvars, name);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
arg = compiler_lookup_arg(c->u->u_metadata.u_freevars, name);
|
|
||||||
}
|
|
||||||
if (arg == -1) {
|
|
||||||
PyObject *freevars = _PyCode_GetFreevars(co);
|
|
||||||
if (freevars == NULL) {
|
|
||||||
PyErr_Clear();
|
|
||||||
}
|
|
||||||
PyErr_Format(PyExc_SystemError,
|
|
||||||
"compiler_lookup_arg(name=%R) with reftype=%d failed in %S; "
|
|
||||||
"freevars of code %S: %R",
|
|
||||||
name,
|
|
||||||
reftype,
|
|
||||||
c->u->u_metadata.u_name,
|
|
||||||
co->co_name,
|
|
||||||
freevars);
|
|
||||||
Py_DECREF(freevars);
|
|
||||||
return ERROR;
|
|
||||||
}
|
|
||||||
ADDOP_I(c, loc, LOAD_CLOSURE, arg);
|
ADDOP_I(c, loc, LOAD_CLOSURE, arg);
|
||||||
}
|
}
|
||||||
flags |= MAKE_FUNCTION_CLOSURE;
|
flags |= MAKE_FUNCTION_CLOSURE;
|
||||||
|
@ -2460,7 +2468,7 @@ compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno)
|
||||||
/* Set __classdictcell__ if necessary */
|
/* Set __classdictcell__ if necessary */
|
||||||
if (SYMTABLE_ENTRY(c)->ste_needs_classdict) {
|
if (SYMTABLE_ENTRY(c)->ste_needs_classdict) {
|
||||||
/* Store __classdictcell__ into class namespace */
|
/* Store __classdictcell__ into class namespace */
|
||||||
int i = compiler_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__classdict__));
|
int i = dict_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__classdict__));
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
compiler_exit_scope(c);
|
compiler_exit_scope(c);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
|
@ -2474,7 +2482,7 @@ compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno)
|
||||||
/* Return __classcell__ if it is referenced, otherwise return None */
|
/* Return __classcell__ if it is referenced, otherwise return None */
|
||||||
if (SYMTABLE_ENTRY(c)->ste_needs_class_closure) {
|
if (SYMTABLE_ENTRY(c)->ste_needs_class_closure) {
|
||||||
/* Store __classcell__ into class namespace & return it */
|
/* Store __classcell__ into class namespace & return it */
|
||||||
int i = compiler_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__class__));
|
int i = dict_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__class__));
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
compiler_exit_scope(c);
|
compiler_exit_scope(c);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
|
|
Loading…
Reference in New Issue