@@ -782,8 +782,8 @@ impl PyType {
782782 }
783783
784784 #[ pygetset]
785- const fn __basicsize__ ( & self ) -> usize {
786- self . slots . basicsize
785+ fn __basicsize__ ( & self ) -> usize {
786+ crate :: object :: SIZEOF_PYOBJECT_HEAD + self . slots . basicsize
787787 }
788788
789789 #[ pygetset]
@@ -1338,17 +1338,24 @@ impl Constructor for PyType {
13381338 let member_count: usize = base_member_count + heaptype_member_count;
13391339
13401340 let mut flags = PyTypeFlags :: heap_type_flags ( ) ;
1341+
1342+ // Check if we may add dict
1343+ // We can only add a dict if the primary base class doesn't already have one
1344+ // In CPython, this checks tp_dictoffset == 0
1345+ let may_add_dict = !base. slots . flags . has_feature ( PyTypeFlags :: HAS_DICT ) ;
1346+
13411347 // Add HAS_DICT and MANAGED_DICT if:
1342- // 1. __slots__ is not defined, OR
1348+ // 1. __slots__ is not defined AND base doesn't have dict , OR
13431349 // 2. __dict__ is in __slots__
1344- if heaptype_slots. is_none ( ) || add_dict {
1350+ if ( heaptype_slots. is_none ( ) && may_add_dict ) || add_dict {
13451351 flags |= PyTypeFlags :: HAS_DICT | PyTypeFlags :: MANAGED_DICT ;
13461352 }
13471353
13481354 let ( slots, heaptype_ext) = {
13491355 let slots = PyTypeSlots {
13501356 flags,
13511357 member_count,
1358+ itemsize : base. slots . itemsize ,
13521359 ..PyTypeSlots :: heap_default ( )
13531360 } ;
13541361 let heaptype_ext = HeapTypeExt {
@@ -2009,23 +2016,19 @@ fn calculate_meta_class(
20092016 Ok ( winner)
20102017}
20112018
2019+ /// Returns true if the two types have different instance layouts.
2020+ fn shape_differs ( t1 : & Py < PyType > , t2 : & Py < PyType > ) -> bool {
2021+ t1. __basicsize__ ( ) != t2. __basicsize__ ( ) || t1. slots . itemsize != t2. slots . itemsize
2022+ }
2023+
20122024fn solid_base < ' a > ( typ : & ' a Py < PyType > , vm : & VirtualMachine ) -> & ' a Py < PyType > {
20132025 let base = if let Some ( base) = & typ. base {
20142026 solid_base ( base, vm)
20152027 } else {
20162028 vm. ctx . types . object_type
20172029 } ;
20182030
2019- // Check for extra instance variables (CPython's extra_ivars)
2020- let t_size = typ. __basicsize__ ( ) ;
2021- let b_size = base. __basicsize__ ( ) ;
2022- let t_itemsize = typ. slots . itemsize ;
2023- let b_itemsize = base. slots . itemsize ;
2024-
2025- // Has extra ivars if: sizes differ AND (has items OR t_size > b_size)
2026- let has_extra_ivars = t_size != b_size && ( t_itemsize > 0 || b_itemsize > 0 || t_size > b_size) ;
2027-
2028- if has_extra_ivars { typ } else { base }
2031+ if shape_differs ( typ, base) { typ } else { base }
20292032}
20302033
20312034fn best_base < ' a > ( bases : & ' a [ PyTypeRef ] , vm : & VirtualMachine ) -> PyResult < & ' a Py < PyType > > {
0 commit comments