Skip to content

Commit b93f85e

Browse files
committed
Fix more similar cases
1 parent c4d9ec4 commit b93f85e

File tree

2 files changed

+58
-14
lines changed

2 files changed

+58
-14
lines changed

Lib/test/test_type_params.py

+42
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,48 @@ class Cls:
544544
cls = ns["outer"]()
545545
self.assertEqual(cls.Alias.__value__, "global")
546546

547+
def test_explicit_global_with_no_static_bound(self):
548+
ns = run_code("""
549+
def outer():
550+
class Cls:
551+
global x
552+
type Alias = x
553+
Cls.x = "class"
554+
return Cls
555+
""")
556+
ns["x"] = "global"
557+
cls = ns["outer"]()
558+
self.assertEqual(cls.Alias.__value__, "global")
559+
560+
def test_explicit_global_with_assignment(self):
561+
ns = run_code("""
562+
x = "global"
563+
def outer():
564+
x = "nonlocal"
565+
class Cls:
566+
global x
567+
type Alias = x
568+
x = "global from class"
569+
Cls.x = "class"
570+
return Cls
571+
""")
572+
cls = ns["outer"]()
573+
self.assertEqual(cls.Alias.__value__, "global from class")
574+
575+
def test_explicit_nonlocal(self):
576+
ns = run_code("""
577+
x = "global"
578+
def outer():
579+
x = "nonlocal"
580+
class Cls:
581+
nonlocal x
582+
type Alias = x
583+
x = "class"
584+
return Cls
585+
""")
586+
cls = ns["outer"]()
587+
self.assertEqual(cls.Alias.__value__, "class")
588+
547589

548590
class TypeParamsManglingTest(unittest.TestCase):
549591
def test_mangling(self):

Python/symtable.c

+16-14
Original file line numberDiff line numberDiff line change
@@ -589,26 +589,28 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
589589
}
590590
return 1;
591591
}
592+
// If we were passed class_symbols (i.e., we're in an ste_can_see_class_scope scope)
593+
// and the bound name is in that set, then the name is potentially bound both by
594+
// the immediately enclosing class namespace, and also by an outer function namespace.
595+
// In that case, we want the runtime name resolution to look at only the class
596+
// namespace and the globals (not the namespace providing the bound).
597+
// Similarly, if the name is explicitly global in the class namespace (through the
598+
// global statement), we want to also treat it as a global in this scope.
599+
long class_flags = flags_in_symbols(class_symbols, name);
600+
if (class_flags & DEF_GLOBAL) {
601+
SET_SCOPE(scopes, name, GLOBAL_EXPLICIT);
602+
return 1;
603+
}
604+
else if (class_flags & DEF_BOUND && !(class_flags & DEF_NONLOCAL)) {
605+
SET_SCOPE(scopes, name, GLOBAL_IMPLICIT);
606+
return 1;
607+
}
592608
/* If an enclosing block has a binding for this name, it
593609
is a free variable rather than a global variable.
594610
Note that having a non-NULL bound implies that the block
595611
is nested.
596612
*/
597613
if (bound && PySet_Contains(bound, name)) {
598-
// If we were passed class_symbols (i.e., we're in an ste_can_see_class_scope scope)
599-
// and the bound name is in that set, then the name is potentially bound both by
600-
// the immediately enclosing class namespace, and also by an outer function namespace.
601-
// In that case, we want the runtime name resolution to look at only the class
602-
// namespace and the globals (not the namespace providing the bound).
603-
long class_flags = flags_in_symbols(class_symbols, name);
604-
if (class_flags & DEF_BOUND) {
605-
SET_SCOPE(scopes, name, GLOBAL_IMPLICIT);
606-
return 1;
607-
}
608-
else if (class_flags & DEF_GLOBAL) {
609-
SET_SCOPE(scopes, name, GLOBAL_EXPLICIT);
610-
return 1;
611-
}
612614
SET_SCOPE(scopes, name, FREE);
613615
ste->ste_free = 1;
614616
return PySet_Add(free, name) >= 0;

0 commit comments

Comments
 (0)