From c40d24ed68eb97b9024f891336a29c4f867ee92d Mon Sep 17 00:00:00 2001 From: Myeongseon Choi Date: Mon, 10 Feb 2025 10:30:17 +0900 Subject: [PATCH 1/3] Implement delete object dictionary - Add support for deleting object dictionaries - Modify object_set_dict to handle dictionary deletion - Update setter value handling to support delete operations --- vm/src/builtins/object.rs | 15 ++++++++++++--- vm/src/builtins/type.rs | 2 +- vm/src/function/getset.rs | 6 ++++-- vm/src/object/core.rs | 13 +++++++++++++ 4 files changed, 30 insertions(+), 6 deletions(-) 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)) { From dc0a75e903791aef9f8609b68bc74dc3e84fe71d Mon Sep 17 00:00:00 2001 From: Myeongseon Choi Date: Sat, 15 Feb 2025 00:12:19 +0900 Subject: [PATCH 2/3] Refactor object dictionary setter to handle delete and assign operations - Simplify object_set_dict method in object.rs - Update set_dict method in core.rs to handle both assignment and deletion - Consolidate dictionary modification logic --- vm/src/builtins/object.rs | 12 ++---------- vm/src/object/core.rs | 18 +++++++----------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index 679fbf52d4..d247ce9208 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -497,16 +497,8 @@ pub fn object_get_dict(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult, 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())) - } - } + obj.set_dict(dict) + .map_err(|_| vm.new_attribute_error("This object has no __dict__".to_owned())) } pub fn init(ctx: &Context) { diff --git a/vm/src/object/core.rs b/vm/src/object/core.rs index fc0d1e56ff..de469a06ec 100644 --- a/vm/src/object/core.rs +++ b/vm/src/object/core.rs @@ -25,6 +25,7 @@ use crate::{ lock::{PyMutex, PyMutexGuard, PyRwLock}, refcount::RefCount, }, + function::PySetterValue, vm::VirtualMachine, }; use itertools::Itertools; @@ -707,26 +708,21 @@ impl PyObject { /// Set the dict field. Returns `Err(dict)` if this object does not have a dict field /// in the first place. - pub fn set_dict(&self, dict: PyDictRef) -> Result<(), PyDictRef> { - match self.instance_dict() { - Some(d) => { + pub fn set_dict(&self, dict: PySetterValue) -> Result<(), PyDictRef> { + match (self.instance_dict(), dict) { + (Some(d), PySetterValue::Assign(dict)) => { d.set(dict); Ok(()) } - None => Err(dict), - } - } - - pub fn delete_dict(&self) -> Result<(), ()> { - match self.instance_dict() { - Some(_) => { + (None, PySetterValue::Assign(dict)) => Err(dict), + (Some(_), PySetterValue::Delete) => { unsafe { let ptr = self as *const _ as *mut PyObject; (*ptr).0.dict = None; } Ok(()) } - None => Err(()), + (None, PySetterValue::Delete) => Ok(()), } } From b8d6f7b5947aa99a27d429c566749b761b0a2543 Mon Sep 17 00:00:00 2001 From: Myeongseon Choi Date: Sat, 15 Feb 2025 00:56:39 +0900 Subject: [PATCH 3/3] Enhance object dictionary handling in type and object modules - Modify set_dict method to allow assigning dict to objects without existing dict - Update error handling in object_set_dict to provide more precise error message - Refactor type module to correctly handle dictionary assignment --- vm/src/builtins/object.rs | 8 ++++++-- vm/src/builtins/type.rs | 2 +- vm/src/object/core.rs | 12 +++++++++--- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index d247ce9208..970fd6d674 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -496,9 +496,13 @@ pub fn object_get_dict(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult, vm: &VirtualMachine) -> PyResult<()> { +pub fn object_set_dict( + obj: PyObjectRef, + dict: PySetterValue, + vm: &VirtualMachine, +) -> PyResult<()> { obj.set_dict(dict) - .map_err(|_| vm.new_attribute_error("This object has no __dict__".to_owned())) + .map_err(|_| vm.new_attribute_error("This object has no __dict__ to delete".to_owned())) } pub fn init(ctx: &Context) { diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index e1d46bf494..a419263edc 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, PySetterValue::Delete, vm)?; + object::object_set_dict(obj, PySetterValue::Assign(value.try_into_value(vm)?), vm)?; Ok(()) } } diff --git a/vm/src/object/core.rs b/vm/src/object/core.rs index de469a06ec..e60cab8704 100644 --- a/vm/src/object/core.rs +++ b/vm/src/object/core.rs @@ -708,13 +708,19 @@ impl PyObject { /// Set the dict field. Returns `Err(dict)` if this object does not have a dict field /// in the first place. - pub fn set_dict(&self, dict: PySetterValue) -> Result<(), PyDictRef> { + pub fn set_dict(&self, dict: PySetterValue) -> Result<(), PySetterValue> { match (self.instance_dict(), dict) { (Some(d), PySetterValue::Assign(dict)) => { d.set(dict); Ok(()) } - (None, PySetterValue::Assign(dict)) => Err(dict), + (None, PySetterValue::Assign(dict)) => { + unsafe { + let ptr = self as *const _ as *mut PyObject; + (*ptr).0.dict = Some(InstanceDict::new(dict)); + } + Ok(()) + } (Some(_), PySetterValue::Delete) => { unsafe { let ptr = self as *const _ as *mut PyObject; @@ -722,7 +728,7 @@ impl PyObject { } Ok(()) } - (None, PySetterValue::Delete) => Ok(()), + (None, PySetterValue::Delete) => Err(PySetterValue::Delete), } }