Commit fd5c4148 authored by Pablo Galindo's avatar Pablo Galindo Committed by GitHub

bpo-38469: Handle named expression scope with global/nonlocal keywords (GH-16755)

The symbol table handing of PEP572's assignment expressions is not resolving correctly the scope of some variables in presence of global/nonlocal keywords in conjunction with comprehensions.
parent 8a6cbf8a
import os import os
import unittest import unittest
GLOBAL_VAR = None
class NamedExpressionInvalidTest(unittest.TestCase): class NamedExpressionInvalidTest(unittest.TestCase):
...@@ -470,5 +471,49 @@ spam()""" ...@@ -470,5 +471,49 @@ spam()"""
self.assertEqual(ns["x"], 2) self.assertEqual(ns["x"], 2)
self.assertEqual(ns["result"], [0, 1, 2]) self.assertEqual(ns["result"], [0, 1, 2])
def test_named_expression_global_scope(self):
sentinel = object()
global GLOBAL_VAR
def f():
global GLOBAL_VAR
[GLOBAL_VAR := sentinel for _ in range(1)]
self.assertEqual(GLOBAL_VAR, sentinel)
try:
f()
self.assertEqual(GLOBAL_VAR, sentinel)
finally:
GLOBAL_VAR = None
def test_named_expression_global_scope_no_global_keyword(self):
sentinel = object()
def f():
GLOBAL_VAR = None
[GLOBAL_VAR := sentinel for _ in range(1)]
self.assertEqual(GLOBAL_VAR, sentinel)
f()
self.assertEqual(GLOBAL_VAR, None)
def test_named_expression_nonlocal_scope(self):
sentinel = object()
def f():
nonlocal_var = None
def g():
nonlocal nonlocal_var
[nonlocal_var := sentinel for _ in range(1)]
g()
self.assertEqual(nonlocal_var, sentinel)
f()
def test_named_expression_nonlocal_scope_no_nonlocal_keyword(self):
sentinel = object()
def f():
nonlocal_var = None
def g():
[nonlocal_var := sentinel for _ in range(1)]
g()
self.assertEqual(nonlocal_var, None)
f()
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()
Fixed a bug where the scope of named expressions was not being resolved
correctly in the presence of the *global* keyword. Patch by Pablo Galindo.
...@@ -1467,10 +1467,16 @@ symtable_extend_namedexpr_scope(struct symtable *st, expr_ty e) ...@@ -1467,10 +1467,16 @@ symtable_extend_namedexpr_scope(struct symtable *st, expr_ty e)
continue; continue;
} }
/* If we find a FunctionBlock entry, add as NONLOCAL/LOCAL */ /* If we find a FunctionBlock entry, add as GLOBAL/LOCAL or NONLOCAL/LOCAL */
if (ste->ste_type == FunctionBlock) { if (ste->ste_type == FunctionBlock) {
if (!symtable_add_def(st, target_name, DEF_NONLOCAL)) long target_in_scope = _PyST_GetSymbol(ste, target_name);
VISIT_QUIT(st, 0); if (target_in_scope & DEF_GLOBAL) {
if (!symtable_add_def(st, target_name, DEF_GLOBAL))
VISIT_QUIT(st, 0);
} else {
if (!symtable_add_def(st, target_name, DEF_NONLOCAL))
VISIT_QUIT(st, 0);
}
if (!symtable_record_directive(st, target_name, e->lineno, e->col_offset)) if (!symtable_record_directive(st, target_name, e->lineno, e->col_offset))
VISIT_QUIT(st, 0); VISIT_QUIT(st, 0);
......
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