diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index cce1422d56..afcebc7584 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -495,9 +495,14 @@ pub fn object_get_dict(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult 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())) + .ok_or_else(|| vm.new_type_error("cannot delete __dict__".to_owned())) } pub fn init(ctx: &Context) { diff --git a/vm/src/builtins/type.rs b/vm/src/builtins/type.rs index e8ad67a666..5345eb93c3 100644 --- a/vm/src/builtins/type.rs +++ b/vm/src/builtins/type.rs @@ -1272,7 +1272,11 @@ fn subtype_get_dict(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { Ok(ret) } -fn subtype_set_dict(obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { +fn subtype_set_dict( + obj: PyObjectRef, + value: PySetterValue, + vm: &VirtualMachine, +) -> PyResult<()> { let cls = obj.class(); match find_base_dict_descr(cls, vm) { Some(descr) => { @@ -1285,10 +1289,11 @@ fn subtype_set_dict(obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) - cls.name() )) })?; - descr_set(&descr, obj, PySetterValue::Assign(value), vm) + descr_set(&descr, obj, value, vm) } None => { - object::object_set_dict(obj, value.try_into_value(vm)?, vm)?; + let dict = value.map(|s| s.try_into_value(vm)).transpose()?; + object::object_set_dict(obj, dict, vm)?; Ok(()) } } diff --git a/vm/src/object/core.rs b/vm/src/object/core.rs index 56ab419c01..e69bd65e80 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; @@ -711,14 +712,37 @@ 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) -> Option<()> { + // NOTE: So far, this is the only error condition that I know of so we can use Option + // for now. + if self.payload_is::() { + return None; + } + + match (self.instance_dict(), dict) { + (Some(d), PySetterValue::Assign(dict)) => { d.set(dict); - Ok(()) } - None => Err(dict), - } + (None, PySetterValue::Assign(dict)) => { + // self.0.dict = Some(InstanceDict::new(dict)); + unsafe { + let ptr = self as *const _ as *mut PyObject; + (*ptr).0.dict = Some(InstanceDict::new(dict)); + } + } + (Some(_), PySetterValue::Delete) => { + // self.0.dict = None; + unsafe { + let ptr = self as *const _ as *mut PyObject; + (*ptr).0.dict = None; + } + } + (None, PySetterValue::Delete) => { + // NOTE(hanif) - noop? + } + }; + + Some(()) } #[inline(always)]