@@ -972,26 +972,38 @@ impl Constructor for PyType {
972
972
if let Some ( ref slots) = heaptype_slots {
973
973
let mut offset = base_member_count;
974
974
for member in slots. as_slice ( ) {
975
- let member_def = PyMemberDef {
976
- name : member. to_string ( ) ,
977
- kind : MemberKind :: ObjectEx ,
978
- getter : MemberGetter :: Offset ( offset) ,
979
- setter : MemberSetter :: Offset ( offset) ,
980
- doc : None ,
981
- } ;
982
- let member_descriptor: PyRef < PyMemberDescriptor > =
983
- vm. ctx . new_pyref ( PyMemberDescriptor {
984
- common : PyDescriptorOwned {
985
- typ : typ. clone ( ) ,
986
- name : vm. ctx . intern_str ( member. as_str ( ) ) ,
987
- qualname : PyRwLock :: new ( None ) ,
988
- } ,
989
- member : member_def,
990
- } ) ;
991
-
992
975
let attr_name = vm. ctx . intern_str ( member. to_string ( ) ) ;
993
- if !typ. has_attr ( attr_name) {
994
- typ. set_attr ( attr_name, member_descriptor. into ( ) ) ;
976
+
977
+ // Special handling for __dict__ slot - use getset_descriptor instead of member_descriptor
978
+ if member. as_str ( ) == "__dict__" {
979
+ if !typ. has_attr ( attr_name) {
980
+ let dict_descriptor = unsafe {
981
+ vm. ctx
982
+ . new_getset ( "__dict__" , & typ, subtype_get_dict, subtype_set_dict)
983
+ } ;
984
+ typ. set_attr ( attr_name, dict_descriptor. into ( ) ) ;
985
+ }
986
+ } else {
987
+ let member_def = PyMemberDef {
988
+ name : member. to_string ( ) ,
989
+ kind : MemberKind :: ObjectEx ,
990
+ getter : MemberGetter :: Offset ( offset) ,
991
+ setter : MemberSetter :: Offset ( offset) ,
992
+ doc : None ,
993
+ } ;
994
+ let member_descriptor: PyRef < PyMemberDescriptor > =
995
+ vm. ctx . new_pyref ( PyMemberDescriptor {
996
+ common : PyDescriptorOwned {
997
+ typ : typ. clone ( ) ,
998
+ name : vm. ctx . intern_str ( member. as_str ( ) ) ,
999
+ qualname : PyRwLock :: new ( None ) ,
1000
+ } ,
1001
+ member : member_def,
1002
+ } ) ;
1003
+
1004
+ if !typ. has_attr ( attr_name) {
1005
+ typ. set_attr ( attr_name, member_descriptor. into ( ) ) ;
1006
+ }
995
1007
}
996
1008
997
1009
offset += 1 ;
@@ -1005,13 +1017,34 @@ impl Constructor for PyType {
1005
1017
// (with exceptions, e.g function)
1006
1018
// Also, type subclasses don't need their own __dict__ descriptor
1007
1019
// since they inherit it from type
1008
- if !inherits_from_type {
1020
+ // Additionally, if __slots__ contains __dict__, don't add descriptor
1021
+ // as the slot handles __dict__ directly
1022
+ let has_dict_slot = attributes
1023
+ . get ( identifier ! ( vm, __slots__) )
1024
+ . and_then ( |slots| {
1025
+ if let Ok ( tuple) = slots. clone ( ) . downcast :: < PyTuple > ( ) {
1026
+ Some ( tuple. iter ( ) . any ( |item| {
1027
+ item. downcast_ref :: < PyStr > ( )
1028
+ . map ( |s| s. as_str ( ) == "__dict__" )
1029
+ . unwrap_or ( false )
1030
+ } ) )
1031
+ } else if let Ok ( string) = slots. clone ( ) . downcast :: < PyStr > ( ) {
1032
+ Some ( string. as_str ( ) == "__dict__" )
1033
+ } else {
1034
+ None
1035
+ }
1036
+ } )
1037
+ . unwrap_or ( false ) ;
1038
+
1039
+ if !inherits_from_type && !has_dict_slot {
1009
1040
let __dict__ = identifier ! ( vm, __dict__) ;
1010
- attributes. entry ( __dict__) . or_insert_with ( || unsafe {
1011
- vm. ctx
1012
- . new_getset ( "__dict__" , & typ, subtype_get_dict, subtype_set_dict)
1013
- . into ( )
1014
- } ) ;
1041
+ if !attributes. contains_key ( __dict__) {
1042
+ attributes. insert ( __dict__, unsafe {
1043
+ vm. ctx
1044
+ . new_getset ( "__dict__" , & typ, subtype_get_dict, subtype_set_dict)
1045
+ . into ( )
1046
+ } ) ;
1047
+ }
1015
1048
}
1016
1049
1017
1050
if let Some ( cell) = attributes. get ( identifier ! ( vm, __classcell__) ) {
0 commit comments