Skip to content

Commit 16113a4

Browse files
committed
Implemented the ability to del __dict__
This PR is based on the work by key262yek. The original PR is here: #5509
1 parent 5619689 commit 16113a4

3 files changed

Lines changed: 45 additions & 11 deletions

File tree

vm/src/builtins/object.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,9 +495,14 @@ pub fn object_get_dict(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyDict
495495
obj.dict()
496496
.ok_or_else(|| vm.new_attribute_error("This object has no __dict__".to_owned()))
497497
}
498-
pub fn object_set_dict(obj: PyObjectRef, dict: PyDictRef, vm: &VirtualMachine) -> PyResult<()> {
498+
499+
pub fn object_set_dict(
500+
obj: PyObjectRef,
501+
dict: PySetterValue<PyDictRef>,
502+
vm: &VirtualMachine,
503+
) -> PyResult<()> {
499504
obj.set_dict(dict)
500-
.map_err(|_| vm.new_attribute_error("This object has no __dict__".to_owned()))
505+
.ok_or_else(|| vm.new_type_error("cannot delete __dict__".to_owned()))
501506
}
502507

503508
pub fn init(ctx: &Context) {

vm/src/builtins/type.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,7 +1272,11 @@ fn subtype_get_dict(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
12721272
Ok(ret)
12731273
}
12741274

1275-
fn subtype_set_dict(obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
1275+
fn subtype_set_dict(
1276+
obj: PyObjectRef,
1277+
value: PySetterValue<PyObjectRef>,
1278+
vm: &VirtualMachine,
1279+
) -> PyResult<()> {
12761280
let cls = obj.class();
12771281
match find_base_dict_descr(cls, vm) {
12781282
Some(descr) => {
@@ -1285,10 +1289,11 @@ fn subtype_set_dict(obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -
12851289
cls.name()
12861290
))
12871291
})?;
1288-
descr_set(&descr, obj, PySetterValue::Assign(value), vm)
1292+
descr_set(&descr, obj, value, vm)
12891293
}
12901294
None => {
1291-
object::object_set_dict(obj, value.try_into_value(vm)?, vm)?;
1295+
let dict = value.map(|s| s.try_into_value(vm)).transpose()?;
1296+
object::object_set_dict(obj, dict, vm)?;
12921297
Ok(())
12931298
}
12941299
}

vm/src/object/core.rs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::{
2525
lock::{PyMutex, PyMutexGuard, PyRwLock},
2626
refcount::RefCount,
2727
},
28+
function::PySetterValue,
2829
vm::VirtualMachine,
2930
};
3031
use itertools::Itertools;
@@ -711,14 +712,37 @@ impl PyObject {
711712

712713
/// Set the dict field. Returns `Err(dict)` if this object does not have a dict field
713714
/// in the first place.
714-
pub fn set_dict(&self, dict: PyDictRef) -> Result<(), PyDictRef> {
715-
match self.instance_dict() {
716-
Some(d) => {
715+
pub fn set_dict(&self, dict: PySetterValue<PyDictRef>) -> Option<()> {
716+
// NOTE(hanif) - So far, this is the only error condition that I know of so we can use Option
717+
// for now.
718+
if self.payload_is::<crate::builtins::function::PyFunction>() {
719+
return None;
720+
}
721+
722+
match (self.instance_dict(), dict) {
723+
(Some(d), PySetterValue::Assign(dict)) => {
717724
d.set(dict);
718-
Ok(())
719725
}
720-
None => Err(dict),
721-
}
726+
(None, PySetterValue::Assign(dict)) => {
727+
// self.0.dict = Some(InstanceDict::new(dict));
728+
unsafe {
729+
let ptr = self as *const _ as *mut PyObject;
730+
(*ptr).0.dict = Some(InstanceDict::new(dict));
731+
}
732+
}
733+
(Some(_), PySetterValue::Delete) => {
734+
// self.0.dict = None;
735+
unsafe {
736+
let ptr = self as *const _ as *mut PyObject;
737+
(*ptr).0.dict = None;
738+
}
739+
}
740+
(None, PySetterValue::Delete) => {
741+
// NOTE(hanif) - noop?
742+
}
743+
};
744+
745+
Some(())
722746
}
723747

724748
#[inline(always)]

0 commit comments

Comments
 (0)