hide the __class__ closure from the class body (#12370)

This commit is contained in:
Benjamin Peterson 2013-05-15 15:26:42 -05:00
parent fe361dfab5
commit 312595ce3a
7 changed files with 221 additions and 152 deletions

View file

@ -535,6 +535,37 @@ compiler_enter_scope(struct compiler *c, identifier name,
compiler_unit_free(u);
return 0;
}
if (u->u_ste->ste_needs_class_closure) {
/* Cook up a implicit __class__ cell. */
_Py_IDENTIFIER(__class__);
PyObject *tuple, *name, *zero;
int res;
assert(u->u_scope_type == COMPILER_SCOPE_CLASS);
assert(PyDict_Size(u->u_cellvars) == 0);
name = _PyUnicode_FromId(&PyId___class__);
if (!name) {
compiler_unit_free(u);
return 0;
}
tuple = PyTuple_Pack(2, name, Py_TYPE(name));
if (!tuple) {
compiler_unit_free(u);
return 0;
}
zero = PyLong_FromLong(0);
if (!zero) {
Py_DECREF(tuple);
compiler_unit_free(u);
return 0;
}
res = PyDict_SetItem(u->u_cellvars, tuple, zero);
Py_DECREF(tuple);
Py_DECREF(zero);
if (res < 0) {
compiler_unit_free(u);
return 0;
}
}
u->u_freevars = dictbytype(u->u_ste->ste_symbols, FREE, DEF_FREE_CLASS,
PyDict_Size(u->u_cellvars));
@ -1331,6 +1362,9 @@ compiler_mod(struct compiler *c, mod_ty mod)
static int
get_ref_type(struct compiler *c, PyObject *name)
{
if (c->u->u_scope_type == COMPILER_SCOPE_CLASS &&
!PyUnicode_CompareWithASCIIString(name, "__class__"))
return CELL;
int scope = PyST_GetScope(c->u->u_ste, name);
if (scope == 0) {
char buf[350];
@ -1704,24 +1738,24 @@ compiler_class(struct compiler *c, stmt_ty s)
compiler_exit_scope(c);
return 0;
}
/* return the (empty) __class__ cell */
str = PyUnicode_InternFromString("__class__");
if (str == NULL) {
compiler_exit_scope(c);
return 0;
}
i = compiler_lookup_arg(c->u->u_cellvars, str);
Py_DECREF(str);
if (i == -1) {
/* This happens when nobody references the cell */
PyErr_Clear();
/* Return None */
ADDOP_O(c, LOAD_CONST, Py_None, consts);
}
else {
if (c->u->u_ste->ste_needs_class_closure) {
/* return the (empty) __class__ cell */
str = PyUnicode_InternFromString("__class__");
if (str == NULL) {
compiler_exit_scope(c);
return 0;
}
i = compiler_lookup_arg(c->u->u_cellvars, str);
Py_DECREF(str);
assert(i == 0);
/* Return the cell where to store __class__ */
ADDOP_I(c, LOAD_CLOSURE, i);
}
else {
assert(PyDict_Size(c->u->u_cellvars) == 0);
/* This happens when nobody references the cell. Return None. */
ADDOP_O(c, LOAD_CONST, Py_None, consts);
}
ADDOP_IN_SCOPE(c, RETURN_VALUE);
/* create the code object */
co = assemble(c, 1);