Commit 1a316cd0 authored by Benjamin Peterson's avatar Benjamin Peterson

cleanup the construction of __qualname__ (closes #19301 again)

parent e3399a5c
...@@ -370,12 +370,13 @@ def _call_with_frames_removed(f, *args, **kwds): ...@@ -370,12 +370,13 @@ def _call_with_frames_removed(f, *args, **kwds):
# Python 3.4a1 3270 (various tweaks to the __class__ closure) # Python 3.4a1 3270 (various tweaks to the __class__ closure)
# Python 3.4a1 3280 (remove implicit class argument) # Python 3.4a1 3280 (remove implicit class argument)
# Python 3.4a4 3290 (changes to __qualname__ computation) # Python 3.4a4 3290 (changes to __qualname__ computation)
# Python 3.4a4 3300 (more changes to __qualname__ computation)
# #
# MAGIC must change whenever the bytecode emitted by the compiler may no # MAGIC must change whenever the bytecode emitted by the compiler may no
# longer be understood by older implementations of the eval loop (usually # longer be understood by older implementations of the eval loop (usually
# due to the addition of new opcodes). # due to the addition of new opcodes).
MAGIC_NUMBER = (3290).to_bytes(2, 'little') + b'\r\n' MAGIC_NUMBER = (3300).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__' _PYCACHE = '__pycache__'
......
...@@ -4519,8 +4519,10 @@ order (MRO) for bases """ ...@@ -4519,8 +4519,10 @@ order (MRO) for bases """
global Y global Y
class Y: class Y:
pass class Inside:
pass
self.assertEqual(Y.__qualname__, 'Y') self.assertEqual(Y.__qualname__, 'Y')
self.assertEqual(Y.Inside.__qualname__, 'Y.Inside')
def test_qualname_dict(self): def test_qualname_dict(self):
ns = {'__qualname__': 'some.name'} ns = {'__qualname__': 'some.name'}
......
...@@ -9,7 +9,9 @@ def global_function(): ...@@ -9,7 +9,9 @@ def global_function():
pass pass
global inner_global_function global inner_global_function
def inner_global_function(): def inner_global_function():
pass def inner_function2():
pass
return inner_function2
return LocalClass return LocalClass
return lambda: inner_function return lambda: inner_function
...@@ -120,6 +122,7 @@ class FunctionPropertiesTest(FuncAttrsTest): ...@@ -120,6 +122,7 @@ class FunctionPropertiesTest(FuncAttrsTest):
self.assertEqual(global_function()()().__qualname__, self.assertEqual(global_function()()().__qualname__,
'global_function.<locals>.inner_function.<locals>.LocalClass') 'global_function.<locals>.inner_function.<locals>.LocalClass')
self.assertEqual(inner_global_function.__qualname__, 'inner_global_function') self.assertEqual(inner_global_function.__qualname__, 'inner_global_function')
self.assertEqual(inner_global_function().__qualname__, 'inner_global_function.<locals>.inner_function2')
self.b.__qualname__ = 'c' self.b.__qualname__ = 'c'
self.assertEqual(self.b.__qualname__, 'c') self.assertEqual(self.b.__qualname__, 'c')
self.b.__qualname__ = 'd' self.b.__qualname__ = 'd'
......
...@@ -94,6 +94,7 @@ enum { ...@@ -94,6 +94,7 @@ enum {
COMPILER_SCOPE_MODULE, COMPILER_SCOPE_MODULE,
COMPILER_SCOPE_CLASS, COMPILER_SCOPE_CLASS,
COMPILER_SCOPE_FUNCTION, COMPILER_SCOPE_FUNCTION,
COMPILER_SCOPE_LAMBDA,
COMPILER_SCOPE_COMPREHENSION, COMPILER_SCOPE_COMPREHENSION,
}; };
...@@ -104,6 +105,7 @@ struct compiler_unit { ...@@ -104,6 +105,7 @@ struct compiler_unit {
PySTEntryObject *u_ste; PySTEntryObject *u_ste;
PyObject *u_name; PyObject *u_name;
PyObject *u_qualname; /* dot-separated qualified name (lazy) */
int u_scope_type; int u_scope_type;
/* The following fields are dicts that map objects to /* The following fields are dicts that map objects to
...@@ -199,6 +201,7 @@ static int compiler_call_helper(struct compiler *c, int n, ...@@ -199,6 +201,7 @@ static int compiler_call_helper(struct compiler *c, int n,
expr_ty starargs, expr_ty starargs,
expr_ty kwargs); expr_ty kwargs);
static int compiler_try_except(struct compiler *, stmt_ty); static int compiler_try_except(struct compiler *, stmt_ty);
static int compiler_set_qualname(struct compiler *);
static PyCodeObject *assemble(struct compiler *, int addNone); static PyCodeObject *assemble(struct compiler *, int addNone);
static PyObject *__doc__; static PyObject *__doc__;
...@@ -506,6 +509,7 @@ compiler_unit_free(struct compiler_unit *u) ...@@ -506,6 +509,7 @@ compiler_unit_free(struct compiler_unit *u)
} }
Py_CLEAR(u->u_ste); Py_CLEAR(u->u_ste);
Py_CLEAR(u->u_name); Py_CLEAR(u->u_name);
Py_CLEAR(u->u_qualname);
Py_CLEAR(u->u_consts); Py_CLEAR(u->u_consts);
Py_CLEAR(u->u_names); Py_CLEAR(u->u_names);
Py_CLEAR(u->u_varnames); Py_CLEAR(u->u_varnames);
...@@ -620,6 +624,11 @@ compiler_enter_scope(struct compiler *c, identifier name, ...@@ -620,6 +624,11 @@ compiler_enter_scope(struct compiler *c, identifier name,
if (compiler_use_new_block(c) == NULL) if (compiler_use_new_block(c) == NULL)
return 0; return 0;
if (u->u_scope_type != COMPILER_SCOPE_MODULE) {
if (!compiler_set_qualname(c))
return 0;
}
return 1; return 1;
} }
...@@ -647,71 +656,77 @@ compiler_exit_scope(struct compiler *c) ...@@ -647,71 +656,77 @@ compiler_exit_scope(struct compiler *c)
} }
static PyObject * static int
compiler_scope_qualname(struct compiler *c, identifier scope_name) compiler_set_qualname(struct compiler *c)
{ {
Py_ssize_t stack_size;
int global_scope;
_Py_static_string(dot, "."); _Py_static_string(dot, ".");
_Py_static_string(locals, "<locals>"); _Py_static_string(dot_locals, ".<locals>");
struct compiler_unit *u; Py_ssize_t stack_size;
PyObject *capsule, *name, *seq, *dot_str, *locals_str; struct compiler_unit *u = c->u;
PyObject *name, *base, *dot_str, *dot_locals_str;
u = c->u;
seq = PyList_New(0);
if (seq == NULL)
return NULL;
base = NULL;
stack_size = PyList_GET_SIZE(c->c_stack); stack_size = PyList_GET_SIZE(c->c_stack);
assert(stack_size >= 1); assert(stack_size >= 1);
global_scope = stack_size == 1; if (stack_size > 1) {
if (scope_name != NULL && !global_scope) { int scope, force_global = 0;
int scope; struct compiler_unit *parent;
PyObject *mangled; PyObject *mangled, *capsule;
capsule = PyList_GET_ITEM(c->c_stack, stack_size - 1); capsule = PyList_GET_ITEM(c->c_stack, stack_size - 1);
u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT); parent = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
assert(u); assert(parent);
mangled = _Py_Mangle(u->u_private, scope_name);
if (!mangled) if (u->u_scope_type == COMPILER_SCOPE_FUNCTION || u->u_scope_type == COMPILER_SCOPE_CLASS) {
return NULL; assert(u->u_name);
scope = PyST_GetScope(u->u_ste, mangled); mangled = _Py_Mangle(parent->u_private, u->u_name);
Py_DECREF(mangled); if (!mangled)
assert(scope != GLOBAL_IMPLICIT); return 0;
if (scope == GLOBAL_EXPLICIT) scope = PyST_GetScope(parent->u_ste, mangled);
global_scope = 1; Py_DECREF(mangled);
} assert(scope != GLOBAL_IMPLICIT);
if (!global_scope) { if (scope == GLOBAL_EXPLICIT)
Py_ssize_t i; force_global = 1;
for (i = 1; i < stack_size; i++) { }
capsule = PyList_GET_ITEM(c->c_stack, i);
u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT); if (!force_global) {
assert(u); if (parent->u_scope_type == COMPILER_SCOPE_FUNCTION
assert(u->u_scope_type != COMPILER_SCOPE_MODULE); || parent->u_scope_type == COMPILER_SCOPE_LAMBDA) {
if (PyList_Append(seq, u->u_name)) dot_locals_str = _PyUnicode_FromId(&dot_locals);
goto _error; if (dot_locals_str == NULL)
if (u->u_scope_type == COMPILER_SCOPE_FUNCTION) { return 0;
locals_str = _PyUnicode_FromId(&locals); base = PyUnicode_Concat(parent->u_qualname, dot_locals_str);
if (locals_str == NULL) if (base == NULL)
goto _error; return 0;
if (PyList_Append(seq, locals_str)) }
goto _error; else {
Py_INCREF(parent->u_qualname);
base = parent->u_qualname;
} }
} }
} }
u = c->u; if (base != NULL) {
if (PyList_Append(seq, u->u_name)) dot_str = _PyUnicode_FromId(&dot);
goto _error; if (dot_str == NULL) {
dot_str = _PyUnicode_FromId(&dot); Py_DECREF(base);
if (dot_str == NULL) return 0;
goto _error; }
name = PyUnicode_Join(dot_str, seq); name = PyUnicode_Concat(base, dot_str);
Py_DECREF(seq); Py_DECREF(base);
return name; if (name == NULL)
return 0;
_error: PyUnicode_Append(&name, u->u_name);
Py_XDECREF(seq); if (name == NULL)
return NULL; return 0;
}
else {
Py_INCREF(u->u_name);
name = u->u_name;
}
u->u_qualname = name;
return 1;
} }
/* Allocate a new block and return a pointer to it. /* Allocate a new block and return a pointer to it.
...@@ -1661,9 +1676,10 @@ compiler_function(struct compiler *c, stmt_ty s) ...@@ -1661,9 +1676,10 @@ compiler_function(struct compiler *c, stmt_ty s)
VISIT_IN_SCOPE(c, stmt, st); VISIT_IN_SCOPE(c, stmt, st);
} }
co = assemble(c, 1); co = assemble(c, 1);
qualname = compiler_scope_qualname(c, s->v.FunctionDef.name); qualname = c->u->u_qualname;
Py_INCREF(qualname);
compiler_exit_scope(c); compiler_exit_scope(c);
if (qualname == NULL || co == NULL) { if (co == NULL) {
Py_XDECREF(qualname); Py_XDECREF(qualname);
Py_XDECREF(co); Py_XDECREF(co);
return 0; return 0;
...@@ -1733,14 +1749,8 @@ compiler_class(struct compiler *c, stmt_ty s) ...@@ -1733,14 +1749,8 @@ compiler_class(struct compiler *c, stmt_ty s)
return 0; return 0;
} }
Py_DECREF(str); Py_DECREF(str);
/* store the __qualname__ */ assert(c->u->u_qualname);
str = compiler_scope_qualname(c, s->v.ClassDef.name); ADDOP_O(c, LOAD_CONST, c->u->u_qualname, consts);
if (!str) {
compiler_exit_scope(c);
return 0;
}
ADDOP_O(c, LOAD_CONST, str, consts);
Py_DECREF(str);
str = PyUnicode_InternFromString("__qualname__"); str = PyUnicode_InternFromString("__qualname__");
if (!str || !compiler_nameop(c, str, Store)) { if (!str || !compiler_nameop(c, str, Store)) {
Py_XDECREF(str); Py_XDECREF(str);
...@@ -1855,7 +1865,7 @@ compiler_lambda(struct compiler *c, expr_ty e) ...@@ -1855,7 +1865,7 @@ compiler_lambda(struct compiler *c, expr_ty e)
if (res < 0) return 0; if (res < 0) return 0;
kw_default_count = res; kw_default_count = res;
} }
if (!compiler_enter_scope(c, name, COMPILER_SCOPE_FUNCTION, if (!compiler_enter_scope(c, name, COMPILER_SCOPE_LAMBDA,
(void *)e, e->lineno)) (void *)e, e->lineno))
return 0; return 0;
...@@ -1874,9 +1884,10 @@ compiler_lambda(struct compiler *c, expr_ty e) ...@@ -1874,9 +1884,10 @@ compiler_lambda(struct compiler *c, expr_ty e)
ADDOP_IN_SCOPE(c, RETURN_VALUE); ADDOP_IN_SCOPE(c, RETURN_VALUE);
} }
co = assemble(c, 1); co = assemble(c, 1);
qualname = compiler_scope_qualname(c, NULL); qualname = c->u->u_qualname;
Py_INCREF(qualname);
compiler_exit_scope(c); compiler_exit_scope(c);
if (qualname == NULL || co == NULL) if (co == NULL)
return 0; return 0;
arglength = asdl_seq_LEN(args->defaults); arglength = asdl_seq_LEN(args->defaults);
...@@ -3151,9 +3162,10 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name, ...@@ -3151,9 +3162,10 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name,
} }
co = assemble(c, 1); co = assemble(c, 1);
qualname = compiler_scope_qualname(c, NULL); qualname = c->u->u_qualname;
Py_INCREF(qualname);
compiler_exit_scope(c); compiler_exit_scope(c);
if (qualname == NULL || co == NULL) if (co == NULL)
goto error; goto error;
if (!compiler_make_closure(c, co, 0, qualname)) if (!compiler_make_closure(c, co, 0, qualname))
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment