From ff35dcd95a972d59fa7fbeb8929fed710df366fc Mon Sep 17 00:00:00 2001 From: Jiseok CHOI Date: Sun, 20 Jul 2025 14:11:36 +0900 Subject: [PATCH] feat(vm/slot): implement `Py_TPFLAGS_MANAGED_DICT` for class objects (#5949) --- Lib/test/test_array.py | 2 -- Lib/test/test_importlib/test_metadata_api.py | 2 -- Lib/test/test_property.py | 2 -- Lib/test/test_weakref.py | 2 -- vm/src/builtins/type.rs | 10 ++++++---- vm/src/types/slot.rs | 1 + 6 files changed, 7 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index be89bec52..0c20e27cf 100644 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -1285,8 +1285,6 @@ class NumberTest(BaseTest): self.assertRaises(OverflowError, array.array, self.typecode, [upper+1]) self.assertRaises(OverflowError, a.__setitem__, 0, upper+1) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_subclassing(self): typecode = self.typecode class ExaggeratingArray(array.array): diff --git a/Lib/test/test_importlib/test_metadata_api.py b/Lib/test/test_importlib/test_metadata_api.py index 55c9f8007..33c6e85ee 100644 --- a/Lib/test/test_importlib/test_metadata_api.py +++ b/Lib/test/test_importlib/test_metadata_api.py @@ -139,8 +139,6 @@ class APITests( def test_entry_points_missing_group(self): assert entry_points(group='missing') == () - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_entry_points_allows_no_attributes(self): ep = entry_points().select(group='entries', name='main') with self.assertRaises(AttributeError): diff --git a/Lib/test/test_property.py b/Lib/test/test_property.py index 8411e903b..340f79b84 100644 --- a/Lib/test/test_property.py +++ b/Lib/test/test_property.py @@ -242,8 +242,6 @@ class PropertySubSlots(property): class PropertySubclassTests(unittest.TestCase): - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_slots_docstring_copy_exception(self): try: class Foo(object): diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index 242c076f9..e7cd5962c 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -1132,8 +1132,6 @@ class SubclassableWeakrefTestCase(TestBase): self.assertIn(r1, refs) self.assertIn(r2, refs) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_subclass_refs_with_slots(self): class MyRef(weakref.ref): __slots__ = "slot1", "slot2" diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 94334d4a8..498330fa9 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -1038,9 +1038,6 @@ impl Constructor for PyType { }); } - // TODO: Flags is currently initialized with HAS_DICT. Should be - // updated when __slots__ are supported (toggling the flag off if - // a class has __slots__ defined). let heaptype_slots: Option>> = if let Some(x) = attributes.get(identifier!(vm, __slots__)) { let slots = if x.class().is(vm.ctx.types.str_type) { @@ -1072,7 +1069,12 @@ impl Constructor for PyType { let heaptype_member_count = heaptype_slots.as_ref().map(|x| x.len()).unwrap_or(0); let member_count: usize = base_member_count + heaptype_member_count; - let flags = PyTypeFlags::heap_type_flags() | PyTypeFlags::HAS_DICT; + let mut flags = PyTypeFlags::heap_type_flags(); + // Only add HAS_DICT and MANAGED_DICT if __slots__ is not defined. + if heaptype_slots.is_none() { + flags |= PyTypeFlags::HAS_DICT | PyTypeFlags::MANAGED_DICT; + } + let (slots, heaptype_ext) = { let slots = PyTypeSlots { flags, diff --git a/vm/src/types/slot.rs b/vm/src/types/slot.rs index 88e0f231c..35a387ed7 100644 --- a/vm/src/types/slot.rs +++ b/vm/src/types/slot.rs @@ -122,6 +122,7 @@ bitflags! { #[derive(Copy, Clone, Debug, PartialEq)] #[non_exhaustive] pub struct PyTypeFlags: u64 { + const MANAGED_DICT = 1 << 4; const IMMUTABLETYPE = 1 << 8; const HEAPTYPE = 1 << 9; const BASETYPE = 1 << 10;