Skip to content

Commit

Permalink
pythongh-96497: Mangle name before symtable lookup in 'symtable_exten…
Browse files Browse the repository at this point in the history
…d_namedexpr_scope' (pythonGH-96561)

(cherry picked from commit 664965a)

Co-authored-by: wookie184 <wookie1840@gmail.com>
  • Loading branch information
wookie184 authored and miss-islington committed Feb 17, 2024
1 parent ebf8eb2 commit f898a33
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 4 deletions.
22 changes: 22 additions & 0 deletions Lib/test/test_named_expressions.py
Expand Up @@ -298,6 +298,16 @@ def test_named_expression_invalid_set_comprehension_iterable_expression(self):
with self.assertRaisesRegex(SyntaxError, msg):
exec(f"lambda: {code}", {}) # Function scope

def test_named_expression_invalid_mangled_class_variables(self):
code = """class Foo:
def bar(self):
[[(__x:=2) for _ in range(2)] for __x in range(2)]
"""

with self.assertRaisesRegex(SyntaxError,
"assignment expression cannot rebind comprehension iteration variable '__x'"):
exec(code, {}, {})


class NamedExpressionAssignmentTest(unittest.TestCase):

Expand Down Expand Up @@ -674,6 +684,18 @@ def test_named_expression_scope_in_genexp(self):
for idx, elem in enumerate(genexp):
self.assertEqual(elem, b[idx] + a)

def test_named_expression_scope_mangled_names(self):
class Foo:
def f(self_):
global __x1
__x1 = 0
[_Foo__x1 := 1 for a in [2]]
self.assertEqual(__x1, 1)
[__x1 := 2 for a in [3]]
self.assertEqual(__x1, 2)

Foo().f()
self.assertEqual(_Foo__x1, 2)

if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,2 @@
Fix incorrect resolution of mangled class variables used in assignment
expressions in comprehensions.
14 changes: 10 additions & 4 deletions Python/symtable.c
Expand Up @@ -1254,16 +1254,22 @@ symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block,
}

static long
symtable_lookup(struct symtable *st, PyObject *name)
symtable_lookup_entry(struct symtable *st, PySTEntryObject *ste, PyObject *name)
{
PyObject *mangled = _Py_Mangle(st->st_private, name);
if (!mangled)
return 0;
long ret = _PyST_GetSymbol(st->st_cur, mangled);
long ret = _PyST_GetSymbol(ste, mangled);
Py_DECREF(mangled);
return ret;
}

static long
symtable_lookup(struct symtable *st, PyObject *name)
{
return symtable_lookup_entry(st, st->st_cur, name);
}

static int
symtable_add_def_helper(struct symtable *st, PyObject *name, int flag, struct _symtable_entry *ste,
int lineno, int col_offset, int end_lineno, int end_col_offset)
Expand Down Expand Up @@ -1904,7 +1910,7 @@ symtable_extend_namedexpr_scope(struct symtable *st, expr_ty e)
* binding conflict with iteration variables, otherwise skip it
*/
if (ste->ste_comprehension) {
long target_in_scope = _PyST_GetSymbol(ste, target_name);
long target_in_scope = symtable_lookup_entry(st, ste, target_name);
if ((target_in_scope & DEF_COMP_ITER) &&
(target_in_scope & DEF_LOCAL)) {
PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_CONFLICT, target_name);
Expand All @@ -1920,7 +1926,7 @@ symtable_extend_namedexpr_scope(struct symtable *st, expr_ty e)

/* If we find a FunctionBlock entry, add as GLOBAL/LOCAL or NONLOCAL/LOCAL */
if (ste->ste_type == FunctionBlock) {
long target_in_scope = _PyST_GetSymbol(ste, target_name);
long target_in_scope = symtable_lookup_entry(st, ste, target_name);
if (target_in_scope & DEF_GLOBAL) {
if (!symtable_add_def(st, target_name, DEF_GLOBAL, LOCATION(e)))
VISIT_QUIT(st, 0);
Expand Down

0 comments on commit f898a33

Please sign in to comment.