From 5d196a58e974d2306ed9adcb1c883c7f4667c48d Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 28 Jun 2025 03:00:53 +0900 Subject: [PATCH 1/2] type.__dict__ --- vm/src/builtins/type.rs | 46 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index ded0ae4b3a3..010f4d0dae0 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -1018,21 +1018,6 @@ impl Constructor for PyType { attributes.insert(identifier!(vm, __hash__), vm.ctx.none.clone().into()); } - // All *classes* should have a dict. Exceptions are *instances* of - // classes that define __slots__ and instances of built-in classes - // (with exceptions, e.g function) - let __dict__ = identifier!(vm, __dict__); - attributes.entry(__dict__).or_insert_with(|| { - vm.ctx - .new_static_getset( - "__dict__", - vm.ctx.types.type_type, - subtype_get_dict, - subtype_set_dict, - ) - .into() - }); - // 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). @@ -1124,15 +1109,28 @@ impl Constructor for PyType { } } - if let Some(cell) = typ.attributes.write().get(identifier!(vm, __classcell__)) { - let cell = PyCellRef::try_from_object(vm, cell.clone()).map_err(|_| { - vm.new_type_error(format!( - "__classcell__ must be a nonlocal cell, not {}", - cell.class().name() - )) - })?; - cell.set(Some(typ.clone().into())); - }; + { + let mut attributes = typ.attributes.write(); + // All *classes* should have a dict. Exceptions are *instances* of + // classes that define __slots__ and instances of built-in classes + // (with exceptions, e.g function) + let __dict__ = identifier!(vm, __dict__); + attributes.entry(__dict__).or_insert_with(|| unsafe { + vm.ctx + .new_getset("__dict__", &typ, subtype_get_dict, subtype_set_dict) + .into() + }); + + if let Some(cell) = attributes.get(identifier!(vm, __classcell__)) { + let cell = PyCellRef::try_from_object(vm, cell.clone()).map_err(|_| { + vm.new_type_error(format!( + "__classcell__ must be a nonlocal cell, not {}", + cell.class().name() + )) + })?; + cell.set(Some(typ.clone().into())); + }; + } // avoid deadlock let attributes = typ From eeaf78fad9e8c1ee8440e22f10d4eb0241554a10 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 28 Jun 2025 11:39:50 +0900 Subject: [PATCH 2/2] fix --- extra_tests/snippets/builtin_type.py | 12 ++++++ vm/src/builtins/type.rs | 57 ++++++++++++++++------------ 2 files changed, 44 insertions(+), 25 deletions(-) diff --git a/extra_tests/snippets/builtin_type.py b/extra_tests/snippets/builtin_type.py index 923028f2cdc..820ee366155 100644 --- a/extra_tests/snippets/builtin_type.py +++ b/extra_tests/snippets/builtin_type.py @@ -595,3 +595,15 @@ def my_repr_func(): # https://github.com/RustPython/RustPython/issues/3100 assert issubclass(types.BuiltinMethodType, types.BuiltinFunctionType) + +assert type.__dict__["__dict__"].__objclass__ is type +assert ( + type(type(type.__dict__["__dict__"]).__objclass__).__name__ == "member_descriptor" +) + + +class A(type): + pass + + +assert "__dict__" not in A.__dict__ diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 010f4d0dae0..1e18d6fd631 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -936,9 +936,9 @@ impl Constructor for PyType { return Err(vm.new_value_error("type name must not contain null characters")); } - let (metatype, base, bases) = if bases.is_empty() { + let (metatype, base, bases, base_is_type) = if bases.is_empty() { let base = vm.ctx.types.object_type.to_owned(); - (metatype, base.clone(), vec![base]) + (metatype, base.clone(), vec![base], false) } else { let bases = bases .iter() @@ -972,8 +972,9 @@ impl Constructor for PyType { }; let base = best_base(&bases, vm)?; + let base_is_type = base.is(vm.ctx.types.type_type); - (metatype, base.to_owned(), bases) + (metatype, base.to_owned(), bases, base_is_type) }; let qualname = dict @@ -1018,6 +1019,25 @@ impl Constructor for PyType { attributes.insert(identifier!(vm, __hash__), vm.ctx.none.clone().into()); } + // All *classes* should have a dict. Exceptions are *instances* of + // classes that define __slots__ and instances of built-in classes + // (with exceptions, e.g function) + // Also, type subclasses don't need their own __dict__ descriptor + // since they inherit it from type + if !base_is_type { + let __dict__ = identifier!(vm, __dict__); + attributes.entry(__dict__).or_insert_with(|| { + vm.ctx + .new_static_getset( + "__dict__", + vm.ctx.types.type_type, + subtype_get_dict, + subtype_set_dict, + ) + .into() + }); + } + // 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). @@ -1109,28 +1129,15 @@ impl Constructor for PyType { } } - { - let mut attributes = typ.attributes.write(); - // All *classes* should have a dict. Exceptions are *instances* of - // classes that define __slots__ and instances of built-in classes - // (with exceptions, e.g function) - let __dict__ = identifier!(vm, __dict__); - attributes.entry(__dict__).or_insert_with(|| unsafe { - vm.ctx - .new_getset("__dict__", &typ, subtype_get_dict, subtype_set_dict) - .into() - }); - - if let Some(cell) = attributes.get(identifier!(vm, __classcell__)) { - let cell = PyCellRef::try_from_object(vm, cell.clone()).map_err(|_| { - vm.new_type_error(format!( - "__classcell__ must be a nonlocal cell, not {}", - cell.class().name() - )) - })?; - cell.set(Some(typ.clone().into())); - }; - } + if let Some(cell) = typ.attributes.write().get(identifier!(vm, __classcell__)) { + let cell = PyCellRef::try_from_object(vm, cell.clone()).map_err(|_| { + vm.new_type_error(format!( + "__classcell__ must be a nonlocal cell, not {}", + cell.class().name() + )) + })?; + cell.set(Some(typ.clone().into())); + }; // avoid deadlock let attributes = typ