From 550fb3026783fa9927badc1902dad8d0821236dc Mon Sep 17 00:00:00 2001 From: Jiseok CHOI Date: Sat, 12 Jul 2025 00:36:13 +0900 Subject: [PATCH 1/2] feat(vm/slot): implement `Py_TPFLAGS_MANAGED_DICT` for class objects --- Lib/test/test_array.py | 2 -- Lib/test/test_class.py | 17 ++++++++++++++--- 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 + 7 files changed, 21 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index be89bec522f..0c20e27cfda 100644 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -1285,8 +1285,6 @@ def check_overflow(self, lower, upper): 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_class.py b/Lib/test/test_class.py index 29215f06002..0b5cdd186f2 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -851,7 +851,11 @@ def __init__(self, obj): except ImportError: has_inline_values = None -Py_TPFLAGS_MANAGED_DICT = (1 << 2) + +Py_TPFLAGS_MANAGED_DICT = (1 << 4) + +class NoManagedDict: + __slots__ = ('a',) class Plain: pass @@ -865,11 +869,18 @@ def __init__(self): self.c = 3 self.d = 4 - -class TestInlineValues(unittest.TestCase): +class TestNoManagedValues(unittest.TestCase): + def test_flags(self): + self.assertEqual(NoManagedDict.__flags__ & Py_TPFLAGS_MANAGED_DICT, 0) # TODO: RUSTPYTHON @unittest.expectedFailure + def test_no_inline_values_for_slots_class(self): + c = NoManagedDict() + self.assertFalse(has_inline_values(c)) + +class TestInlineValues(unittest.TestCase): + def test_flags(self): self.assertEqual(Plain.__flags__ & Py_TPFLAGS_MANAGED_DICT, Py_TPFLAGS_MANAGED_DICT) self.assertEqual(WithAttrs.__flags__ & Py_TPFLAGS_MANAGED_DICT, Py_TPFLAGS_MANAGED_DICT) diff --git a/Lib/test/test_importlib/test_metadata_api.py b/Lib/test/test_importlib/test_metadata_api.py index 55c9f8007e5..33c6e85ee94 100644 --- a/Lib/test/test_importlib/test_metadata_api.py +++ b/Lib/test/test_importlib/test_metadata_api.py @@ -139,8 +139,6 @@ def test_entry_points_missing_name(self): 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 8411e903b16..340f79b843c 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 242c076f9b3..e7cd5962cf9 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -1132,8 +1132,6 @@ class MyRef(weakref.ref): 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 94334d4a88b..498330fa970 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 88e0f231cbf..35a387ed78f 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; From 32b24c1fd3544eccc5ed6271e28586a1aeb65f65 Mon Sep 17 00:00:00 2001 From: Jiseok CHOI Date: Sun, 20 Jul 2025 13:16:42 +0900 Subject: [PATCH 2/2] rollback test_class --- Lib/test/test_class.py | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index 0b5cdd186f2..29215f06002 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -851,11 +851,7 @@ def __init__(self, obj): except ImportError: has_inline_values = None - -Py_TPFLAGS_MANAGED_DICT = (1 << 4) - -class NoManagedDict: - __slots__ = ('a',) +Py_TPFLAGS_MANAGED_DICT = (1 << 2) class Plain: pass @@ -869,18 +865,11 @@ def __init__(self): self.c = 3 self.d = 4 -class TestNoManagedValues(unittest.TestCase): - def test_flags(self): - self.assertEqual(NoManagedDict.__flags__ & Py_TPFLAGS_MANAGED_DICT, 0) - - # TODO: RUSTPYTHON - @unittest.expectedFailure - def test_no_inline_values_for_slots_class(self): - c = NoManagedDict() - self.assertFalse(has_inline_values(c)) class TestInlineValues(unittest.TestCase): + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_flags(self): self.assertEqual(Plain.__flags__ & Py_TPFLAGS_MANAGED_DICT, Py_TPFLAGS_MANAGED_DICT) self.assertEqual(WithAttrs.__flags__ & Py_TPFLAGS_MANAGED_DICT, Py_TPFLAGS_MANAGED_DICT)