diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index f783ee017c..679fbf52d4 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -495,9 +495,18 @@ pub fn object_get_dict(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult PyResult<()> { - obj.set_dict(dict) - .map_err(|_| vm.new_attribute_error("This object has no __dict__".to_owned())) + +pub fn object_set_dict(obj: PyObjectRef, dict: PySetterValue, vm: &VirtualMachine) -> PyResult<()> { + match dict { + PySetterValue::Assign(dict) => { + obj.set_dict(dict) + .map_err(|_| vm.new_attribute_error("This object has no __dict__".to_owned())) + } + PySetterValue::Delete => { + obj.delete_dict() + .map_err(|_| vm.new_attribute_error("This object has no deletable __dict__".to_owned())) + } + } } pub fn init(ctx: &Context) { diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index 15df5ff3c5..e1d46bf494 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -1288,7 +1288,7 @@ fn subtype_set_dict(obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) - descr_set(&descr, obj, PySetterValue::Assign(value), vm) } None => { - object::object_set_dict(obj, value.try_into_value(vm)?, vm)?; + object::object_set_dict(obj, PySetterValue::Delete, vm)?; Ok(()) } } diff --git a/vm/src/function/getset.rs b/vm/src/function/getset.rs index 827158e834..4d66b6dd26 100644 --- a/vm/src/function/getset.rs +++ b/vm/src/function/getset.rs @@ -36,8 +36,10 @@ where { #[inline] fn from_setter_value(vm: &VirtualMachine, obj: PySetterValue) -> PyResult { - let obj = obj.ok_or_else(|| vm.new_type_error("can't delete attribute".to_owned()))?; - T::try_from_object(vm, obj) + match obj { + PySetterValue::Assign(obj) => T::try_from_object(vm, obj), + PySetterValue::Delete => T::try_from_object(vm, vm.ctx.none()), + } } } diff --git a/vm/src/object/core.rs b/vm/src/object/core.rs index b326935464..fc0d1e56ff 100644 --- a/vm/src/object/core.rs +++ b/vm/src/object/core.rs @@ -717,6 +717,19 @@ impl PyObject { } } + pub fn delete_dict(&self) -> Result<(), ()> { + match self.instance_dict() { + Some(_) => { + unsafe { + let ptr = self as *const _ as *mut PyObject; + (*ptr).0.dict = None; + } + Ok(()) + } + None => Err(()), + } + } + #[inline(always)] pub fn payload_if_subclass(&self, vm: &VirtualMachine) -> Option<&T> { if self.class().fast_issubclass(T::class(&vm.ctx)) {