Skip to content

Commit

Permalink
Fix more similar cases
Browse files Browse the repository at this point in the history
  • Loading branch information
JelleZijlstra committed May 14, 2023
1 parent c4d9ec4 commit b93f85e
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 14 deletions.
42 changes: 42 additions & 0 deletions Lib/test/test_type_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,48 @@ class Cls:
cls = ns["outer"]()
self.assertEqual(cls.Alias.__value__, "global")

def test_explicit_global_with_no_static_bound(self):
ns = run_code("""
def outer():
class Cls:
global x
type Alias = x
Cls.x = "class"
return Cls
""")
ns["x"] = "global"
cls = ns["outer"]()
self.assertEqual(cls.Alias.__value__, "global")

def test_explicit_global_with_assignment(self):
ns = run_code("""
x = "global"
def outer():
x = "nonlocal"
class Cls:
global x
type Alias = x
x = "global from class"
Cls.x = "class"
return Cls
""")
cls = ns["outer"]()
self.assertEqual(cls.Alias.__value__, "global from class")

def test_explicit_nonlocal(self):
ns = run_code("""
x = "global"
def outer():
x = "nonlocal"
class Cls:
nonlocal x
type Alias = x
x = "class"
return Cls
""")
cls = ns["outer"]()
self.assertEqual(cls.Alias.__value__, "class")


class TypeParamsManglingTest(unittest.TestCase):
def test_mangling(self):
Expand Down
30 changes: 16 additions & 14 deletions Python/symtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -589,26 +589,28 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
}
return 1;
}
// If we were passed class_symbols (i.e., we're in an ste_can_see_class_scope scope)
// and the bound name is in that set, then the name is potentially bound both by
// the immediately enclosing class namespace, and also by an outer function namespace.
// In that case, we want the runtime name resolution to look at only the class
// namespace and the globals (not the namespace providing the bound).
// Similarly, if the name is explicitly global in the class namespace (through the
// global statement), we want to also treat it as a global in this scope.
long class_flags = flags_in_symbols(class_symbols, name);
if (class_flags & DEF_GLOBAL) {
SET_SCOPE(scopes, name, GLOBAL_EXPLICIT);
return 1;
}
else if (class_flags & DEF_BOUND && !(class_flags & DEF_NONLOCAL)) {
SET_SCOPE(scopes, name, GLOBAL_IMPLICIT);
return 1;
}
/* If an enclosing block has a binding for this name, it
is a free variable rather than a global variable.
Note that having a non-NULL bound implies that the block
is nested.
*/
if (bound && PySet_Contains(bound, name)) {
// If we were passed class_symbols (i.e., we're in an ste_can_see_class_scope scope)
// and the bound name is in that set, then the name is potentially bound both by
// the immediately enclosing class namespace, and also by an outer function namespace.
// In that case, we want the runtime name resolution to look at only the class
// namespace and the globals (not the namespace providing the bound).
long class_flags = flags_in_symbols(class_symbols, name);
if (class_flags & DEF_BOUND) {
SET_SCOPE(scopes, name, GLOBAL_IMPLICIT);
return 1;
}
else if (class_flags & DEF_GLOBAL) {
SET_SCOPE(scopes, name, GLOBAL_EXPLICIT);
return 1;
}
SET_SCOPE(scopes, name, FREE);
ste->ste_free = 1;
return PySet_Add(free, name) >= 0;
Expand Down

0 comments on commit b93f85e

Please sign in to comment.