From dda6f86ba30023abaa7b3a84b46cd02e33ed9c4b Mon Sep 17 00:00:00 2001 From: Kuan-Chun Wang Date: Fri, 21 Oct 2022 12:06:50 +0800 Subject: [PATCH] Fix `global` behavior on class (#4234) --- Lib/test/test_dataclasses.py | 2 -- Lib/test/test_pickle.py | 10 ---------- Lib/test/test_pickletools.py | 5 ----- Lib/test/test_typing.py | 6 ------ compiler/codegen/src/compile.rs | 14 ++++++++++++-- 5 files changed, 12 insertions(+), 25 deletions(-) diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 9f74d9d1e..74e47c811 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -1925,8 +1925,6 @@ class TestCase(unittest.TestCase): # Check MRO resolution. self.assertEqual(Child.__mro__, (Child, Parent, Generic, object)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_dataclasses_pickleable(self): global P, Q, R @dataclass diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py index 225f7cc70..3312eb6e0 100644 --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -110,11 +110,6 @@ class PyPicklerTests(AbstractPickleTests, unittest.TestCase): def test_in_band_buffers(self): # TODO: RUSTPYTHON, remove when this passes super().test_in_band_buffers() # TODO: RUSTPYTHON, remove when this passes - # TODO: RUSTPYTHON, pickle.PicklingError - @unittest.expectedFailure - def test_nested_names(self): # TODO: RUSTPYTHON, remove when this passes - super().test_nested_names() # TODO: RUSTPYTHON, remove when this passes - # TODO: RUSTPYTHON, AttributeError: module 'pickle' has no attribute 'PickleBuffer' @unittest.expectedFailure def test_oob_buffers(self): # TODO: RUSTPYTHON, remove when this passes @@ -201,11 +196,6 @@ class InMemoryPickleTests(AbstractPickleTests, AbstractUnpickleTests, def test_load_python2_str_as_bytes(self): # TODO: RUSTPYTHON, remove when this passes super().test_load_python2_str_as_bytes() # TODO: RUSTPYTHON, remove when this passes - # TODO: RUSTPYTHON, pickle.PicklingError - @unittest.expectedFailure - def test_nested_names(self): # TODO: RUSTPYTHON, remove when this passes - super().test_nested_names() # TODO: RUSTPYTHON, remove when this passes - # TODO: RUSTPYTHON, AttributeError: module 'pickle' has no attribute 'PickleBuffer' @unittest.expectedFailure def test_oob_buffers(self): # TODO: RUSTPYTHON, remove when this passes diff --git a/Lib/test/test_pickletools.py b/Lib/test/test_pickletools.py index a77d211fd..1d7afb6e8 100644 --- a/Lib/test/test_pickletools.py +++ b/Lib/test/test_pickletools.py @@ -35,11 +35,6 @@ class OptimizedPickleTests(AbstractPickleTests, unittest.TestCase): def test_in_band_buffers(self): # TODO: RUSTPYTHON, remove when this passes super().test_in_band_buffers() - # TODO: RUSTPYTHON, pickle.PicklingError - @unittest.expectedFailure - def test_nested_names(self): # TODO: RUSTPYTHON, remove when this passes - super().test_nested_names() - def test_notimplemented(self): # TODO: RUSTPYTHON, remove when this passes super().test_notimplemented() diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 052598741..75b5dce82 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1581,8 +1581,6 @@ class ProtocolTests(BaseTestCase): Alias2 = typing.Union[P, typing.Iterable] self.assertEqual(Alias, Alias2) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_protocols_pickleable(self): global P, CP # pickle wants to reference the class by name T = TypeVar('T') @@ -2186,8 +2184,6 @@ class GenericTests(BaseTestCase): self.assertNotEqual(repr(base), '') self.assertEqual(base, base) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_pickle(self): global C # pickle wants to reference the class by name T = TypeVar('T') @@ -4802,8 +4798,6 @@ class AnnotatedTests(BaseTestCase): with self.assertRaisesRegex(TypeError, 'at least two arguments'): Annotated[int] - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_pickle(self): samples = [typing.Any, typing.Union[int, str], typing.Optional[str], Tuple[int, ...], diff --git a/compiler/codegen/src/compile.rs b/compiler/codegen/src/compile.rs index 9475b8c7c..6666d2314 100644 --- a/compiler/codegen/src/compile.rs +++ b/compiler/codegen/src/compile.rs @@ -1275,6 +1275,15 @@ impl Compiler { let prev_class_name = std::mem::replace(&mut self.class_name, Some(name.to_owned())); + // Check if the class is declared global + let symbol_table = self.symbol_table_stack.last().unwrap(); + let symbol = symbol_table.lookup(name.as_ref()).expect( + "The symbol must be present in the symbol table, even when it is undefined in python.", + ); + let mut global_path_prefix = Vec::new(); + if symbol.scope == SymbolScope::GlobalExplicit { + global_path_prefix.append(&mut self.qualified_path); + } self.push_qualified_path(name); let qualified_name = self.qualified_path.join("."); @@ -1287,7 +1296,7 @@ impl Compiler { let dunder_module = self.name("__module__"); self.emit(Instruction::StoreLocal(dunder_module)); self.emit_constant(ConstantData::Str { - value: qualified_name.clone(), + value: qualified_name, }); let qualname = self.name("__qualname__"); self.emit(Instruction::StoreLocal(qualname)); @@ -1323,6 +1332,7 @@ impl Compiler { self.class_name = prev_class_name; self.qualified_path.pop(); + self.qualified_path.append(global_path_prefix.as_mut()); self.ctx = prev_ctx; let mut funcflags = bytecode::MakeFunctionFlags::empty(); @@ -1342,7 +1352,7 @@ impl Compiler { self.emit(Instruction::MakeFunction(funcflags)); self.emit_constant(ConstantData::Str { - value: qualified_name, + value: name.to_owned(), }); let call = self.compile_call_inner(2, bases, keywords)?;