From c7f584117f7cbe03c70e666075d563ec9082d556 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Thu, 1 Jan 2026 22:52:24 +0900 Subject: [PATCH 1/7] fix call --- crates/vm/src/builtins/descriptor.rs | 34 ++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/crates/vm/src/builtins/descriptor.rs b/crates/vm/src/builtins/descriptor.rs index a9218c8d689..f835967adc7 100644 --- a/crates/vm/src/builtins/descriptor.rs +++ b/crates/vm/src/builtins/descriptor.rs @@ -487,7 +487,13 @@ impl core::fmt::Debug for SlotFunc { impl SlotFunc { /// Call the wrapped slot function with proper type handling - pub fn call(&self, obj: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { + pub fn call( + &self, + obj: PyObjectRef, + args: FuncArgs, + name: &str, + vm: &VirtualMachine, + ) -> PyResult { match self { SlotFunc::Init(func) => { func(obj, args, vm)?; @@ -601,9 +607,13 @@ impl SlotFunc { func(obj.sequence_unchecked(), index, vm) } SlotFunc::SeqAssItem(func) => { - let (index, value): (isize, crate::function::OptionalArg) = - args.bind(vm)?; - func(obj.sequence_unchecked(), index, value.into_option(), vm)?; + if name == "__delitem__" { + let (index,): (isize,) = args.bind(vm)?; + func(obj.sequence_unchecked(), index, None, vm)?; + } else { + let (index, value): (isize, PyObjectRef) = args.bind(vm)?; + func(obj.sequence_unchecked(), index, Some(value), vm)?; + } Ok(vm.ctx.none()) } SlotFunc::SeqContains(func) => { @@ -622,9 +632,13 @@ impl SlotFunc { func(obj.mapping_unchecked(), &key, vm) } SlotFunc::MapAssSubscript(func) => { - let (key, value): (PyObjectRef, crate::function::OptionalArg) = - args.bind(vm)?; - func(obj.mapping_unchecked(), &key, value.into_option(), vm)?; + if name == "__delitem__" { + let (key,): (PyObjectRef,) = args.bind(vm)?; + func(obj.mapping_unchecked(), &key, None, vm)?; + } else { + let (key, value): (PyObjectRef, PyObjectRef) = args.bind(vm)?; + func(obj.mapping_unchecked(), &key, Some(value), vm)?; + } Ok(vm.ctx.none()) } // Number sub-slots @@ -711,7 +725,7 @@ impl Callable for PyWrapper { ))); } - zelf.wrapped.call(obj, rest, vm) + zelf.wrapped.call(obj, rest, zelf.name.as_str(), vm) } } @@ -783,7 +797,9 @@ impl Callable for PyMethodWrapper { zelf.obj.class().name() ))); } - zelf.wrapper.wrapped.call(zelf.obj.clone(), args, vm) + zelf.wrapper + .wrapped + .call(zelf.obj.clone(), args, zelf.wrapper.name.as_str(), vm) } } From 015f4b8a9b2169e42000e0918a020d1e88f7bb64 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Thu, 1 Jan 2026 22:54:07 +0900 Subject: [PATCH 2/7] Remove repr pymethod --- crates/vm/src/exception_group.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/crates/vm/src/exception_group.rs b/crates/vm/src/exception_group.rs index b2dee206200..a55273480f6 100644 --- a/crates/vm/src/exception_group.rs +++ b/crates/vm/src/exception_group.rs @@ -202,11 +202,6 @@ pub(super) mod types { ))) } - #[pymethod] - fn __repr__(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult { - Self::slot_repr(&zelf, vm) - } - #[pyslot] fn slot_repr(zelf: &PyObject, vm: &VirtualMachine) -> PyResult { let zelf = zelf From e625cc8252c829b0ae8ebde1a4df271cb7c7b6fb Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Thu, 1 Jan 2026 22:54:43 +0900 Subject: [PATCH 3/7] Remove __get__ and __set__ pymethod --- crates/vm/src/builtins/getset.rs | 3 +-- crates/vm/src/builtins/property.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/vm/src/builtins/getset.rs b/crates/vm/src/builtins/getset.rs index a3f0605a473..bb2a7d8394e 100644 --- a/crates/vm/src/builtins/getset.rs +++ b/crates/vm/src/builtins/getset.rs @@ -118,7 +118,6 @@ impl PyGetSet { ))) } } - #[pymethod] fn __set__( zelf: PyObjectRef, obj: PyObjectRef, @@ -127,7 +126,7 @@ impl PyGetSet { ) -> PyResult<()> { Self::descr_set(&zelf, obj, PySetterValue::Assign(value), vm) } - #[pymethod] + fn __delete__(zelf: PyObjectRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { Self::descr_set(&zelf, obj, PySetterValue::Delete, vm) } diff --git a/crates/vm/src/builtins/property.rs b/crates/vm/src/builtins/property.rs index 3a86867176a..0c6cfda17b5 100644 --- a/crates/vm/src/builtins/property.rs +++ b/crates/vm/src/builtins/property.rs @@ -125,7 +125,6 @@ impl PyProperty { } } } - #[pymethod] fn __set__( zelf: PyObjectRef, obj: PyObjectRef, @@ -134,7 +133,7 @@ impl PyProperty { ) -> PyResult<()> { Self::descr_set(&zelf, obj, PySetterValue::Assign(value), vm) } - #[pymethod] + fn __delete__(zelf: PyObjectRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { Self::descr_set(&zelf, obj, PySetterValue::Delete, vm) } From 76a681359f2d09fbf058baf99091d1c01f79e845 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Thu, 1 Jan 2026 22:56:54 +0900 Subject: [PATCH 4/7] Remove __contains__ pymethod --- crates/stdlib/src/array.rs | 1 - crates/vm/src/builtins/bytearray.rs | 1 - crates/vm/src/builtins/bytes.rs | 1 - crates/vm/src/builtins/dict.rs | 3 --- crates/vm/src/builtins/list.rs | 1 - crates/vm/src/builtins/mappingproxy.rs | 1 - crates/vm/src/builtins/range.rs | 1 - crates/vm/src/builtins/str.rs | 1 - crates/vm/src/builtins/tuple.rs | 1 - crates/vm/src/builtins/weakproxy.rs | 1 - crates/vm/src/stdlib/collections.rs | 1 - 11 files changed, 13 deletions(-) diff --git a/crates/stdlib/src/array.rs b/crates/stdlib/src/array.rs index 878a6ce8fb7..e67d483097d 100644 --- a/crates/stdlib/src/array.rs +++ b/crates/stdlib/src/array.rs @@ -1177,7 +1177,6 @@ mod array { )) } - #[pymethod] fn __contains__(&self, value: PyObjectRef, vm: &VirtualMachine) -> bool { let array = self.array.read(); for element in array diff --git a/crates/vm/src/builtins/bytearray.rs b/crates/vm/src/builtins/bytearray.rs index d3f1b0bd4e8..e1e437310eb 100644 --- a/crates/vm/src/builtins/bytearray.rs +++ b/crates/vm/src/builtins/bytearray.rs @@ -219,7 +219,6 @@ impl PyByteArray { self.inner().add(&other.borrow_buf()).into() } - #[pymethod] fn __contains__( &self, needle: Either, diff --git a/crates/vm/src/builtins/bytes.rs b/crates/vm/src/builtins/bytes.rs index 537a618be3b..57aed481dd4 100644 --- a/crates/vm/src/builtins/bytes.rs +++ b/crates/vm/src/builtins/bytes.rs @@ -228,7 +228,6 @@ impl PyBytes { self.inner.add(&other.borrow_buf()) } - #[pymethod] fn __contains__( &self, needle: Either, diff --git a/crates/vm/src/builtins/dict.rs b/crates/vm/src/builtins/dict.rs index 41f6779c212..19b14688994 100644 --- a/crates/vm/src/builtins/dict.rs +++ b/crates/vm/src/builtins/dict.rs @@ -221,7 +221,6 @@ impl PyDict { core::mem::size_of::() + self.entries.sizeof() } - #[pymethod] fn __contains__(&self, key: PyObjectRef, vm: &VirtualMachine) -> PyResult { self.entries.contains(vm, &*key) } @@ -1130,7 +1129,6 @@ impl ViewSetOps for PyDictKeys {} ) )] impl PyDictKeys { - #[pymethod] fn __contains__(zelf: PyObjectRef, key: PyObjectRef, vm: &VirtualMachine) -> PyResult { zelf.sequence_unchecked().contains(&key, vm) } @@ -1195,7 +1193,6 @@ impl ViewSetOps for PyDictItems {} ) )] impl PyDictItems { - #[pymethod] fn __contains__(zelf: PyObjectRef, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { zelf.sequence_unchecked().contains(&needle, vm) } diff --git a/crates/vm/src/builtins/list.rs b/crates/vm/src/builtins/list.rs index 514b38b6c28..eaff4a54688 100644 --- a/crates/vm/src/builtins/list.rs +++ b/crates/vm/src/builtins/list.rs @@ -251,7 +251,6 @@ impl PyList { self.mut_count(vm, &needle) } - #[pymethod] pub(crate) fn __contains__(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { self.mut_contains(vm, &needle) } diff --git a/crates/vm/src/builtins/mappingproxy.rs b/crates/vm/src/builtins/mappingproxy.rs index 13b0fa32490..c8f77c5c5fc 100644 --- a/crates/vm/src/builtins/mappingproxy.rs +++ b/crates/vm/src/builtins/mappingproxy.rs @@ -128,7 +128,6 @@ impl PyMappingProxy { } } - #[pymethod] pub fn __contains__(&self, key: PyObjectRef, vm: &VirtualMachine) -> PyResult { self._contains(&key, vm) } diff --git a/crates/vm/src/builtins/range.rs b/crates/vm/src/builtins/range.rs index fac5206b82d..ca7aaa9a08c 100644 --- a/crates/vm/src/builtins/range.rs +++ b/crates/vm/src/builtins/range.rs @@ -342,7 +342,6 @@ impl Py { } } - #[pymethod] fn __contains__(&self, needle: PyObjectRef, vm: &VirtualMachine) -> bool { self.contains_inner(&needle, vm) } diff --git a/crates/vm/src/builtins/str.rs b/crates/vm/src/builtins/str.rs index e101ef2a52b..d14bcd92bbe 100644 --- a/crates/vm/src/builtins/str.rs +++ b/crates/vm/src/builtins/str.rs @@ -572,7 +572,6 @@ impl PyStr { } } - #[pymethod] fn __contains__(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { self._contains(&needle, vm) } diff --git a/crates/vm/src/builtins/tuple.rs b/crates/vm/src/builtins/tuple.rs index f3da8b26163..e7271f9b6fd 100644 --- a/crates/vm/src/builtins/tuple.rs +++ b/crates/vm/src/builtins/tuple.rs @@ -345,7 +345,6 @@ impl PyTuple { Ok(false) } - #[pymethod] fn __contains__(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { self._contains(&needle, vm) } diff --git a/crates/vm/src/builtins/weakproxy.rs b/crates/vm/src/builtins/weakproxy.rs index 51120c02c01..0f68e9e9815 100644 --- a/crates/vm/src/builtins/weakproxy.rs +++ b/crates/vm/src/builtins/weakproxy.rs @@ -98,7 +98,6 @@ impl PyWeakProxy { let obj = self.try_upgrade(vm)?; reversed(obj, vm) } - #[pymethod] fn __contains__(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { self.try_upgrade(vm)? .sequence_unchecked() diff --git a/crates/vm/src/stdlib/collections.rs b/crates/vm/src/stdlib/collections.rs index 4688121c9b5..86caef7a25f 100644 --- a/crates/vm/src/stdlib/collections.rs +++ b/crates/vm/src/stdlib/collections.rs @@ -303,7 +303,6 @@ mod _collections { .ok_or_else(|| vm.new_index_error("deque index out of range")) } - #[pymethod] fn __contains__(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { self._contains(&needle, vm) } From 8ffe90e1a782bf953f3ec0d30fbd736a7a924c9d Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Thu, 1 Jan 2026 22:57:16 +0900 Subject: [PATCH 5/7] Remove __len__ pymethod --- crates/stdlib/src/array.rs | 1 - crates/stdlib/src/contextvars.rs | 1 - crates/stdlib/src/mmap.rs | 1 - crates/vm/src/builtins/range.rs | 1 - 4 files changed, 4 deletions(-) diff --git a/crates/stdlib/src/array.rs b/crates/stdlib/src/array.rs index e67d483097d..2e28714611c 100644 --- a/crates/stdlib/src/array.rs +++ b/crates/stdlib/src/array.rs @@ -1102,7 +1102,6 @@ mod array { Ok(zelf) } - #[pymethod] pub(crate) fn __len__(&self) -> usize { self.read().len() } diff --git a/crates/stdlib/src/contextvars.rs b/crates/stdlib/src/contextvars.rs index 731f5d11e0b..658d0906b24 100644 --- a/crates/stdlib/src/contextvars.rs +++ b/crates/stdlib/src/contextvars.rs @@ -202,7 +202,6 @@ mod _contextvars { Ok(item.to_owned()) } - #[pymethod] fn __len__(&self) -> usize { self.borrow_vars().len() } diff --git a/crates/stdlib/src/mmap.rs b/crates/stdlib/src/mmap.rs index b520eb2a1a7..191a330d536 100644 --- a/crates/stdlib/src/mmap.rs +++ b/crates/stdlib/src/mmap.rs @@ -731,7 +731,6 @@ mod mmap { .into() } - #[pymethod] fn __len__(&self) -> usize { self.size.load() } diff --git a/crates/vm/src/builtins/range.rs b/crates/vm/src/builtins/range.rs index ca7aaa9a08c..957a66020c1 100644 --- a/crates/vm/src/builtins/range.rs +++ b/crates/vm/src/builtins/range.rs @@ -265,7 +265,6 @@ impl PyRange { ) } - #[pymethod] fn __len__(&self) -> BigInt { self.compute_length() } From b408ababb31d50a90e2bbc20bb65ce5459039dfa Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Thu, 1 Jan 2026 21:42:40 +0900 Subject: [PATCH 6/7] mapping priors sequence --- crates/vm/src/builtins/descriptor.rs | 58 ++++++++++++------------- crates/vm/src/builtins/getset.rs | 12 ------ crates/vm/src/builtins/property.rs | 12 ------ crates/vm/src/stdlib/ctypes/base.rs | 15 ------- crates/vm/src/types/slot.rs | 61 +++++++++++++++++++++++---- crates/vm/src/types/slot_defs.rs | 63 ++++++++++++++++++---------- 6 files changed, 122 insertions(+), 99 deletions(-) diff --git a/crates/vm/src/builtins/descriptor.rs b/crates/vm/src/builtins/descriptor.rs index f835967adc7..89dafdd14b7 100644 --- a/crates/vm/src/builtins/descriptor.rs +++ b/crates/vm/src/builtins/descriptor.rs @@ -428,13 +428,15 @@ pub enum SlotFunc { SeqConcat(SeqConcatFunc), SeqRepeat(SeqRepeatFunc), SeqItem(SeqItemFunc), - SeqAssItem(SeqAssItemFunc), + SeqSetItem(SeqAssItemFunc), // __setitem__ (same func type, value = Some) + SeqDelItem(SeqAssItemFunc), // __delitem__ (same func type, value = None) SeqContains(SeqContainsFunc), // Mapping sub-slots (mp_*) MapLength(MapLenFunc), MapSubscript(MapSubscriptFunc), - MapAssSubscript(MapAssSubscriptFunc), + MapSetSubscript(MapAssSubscriptFunc), // __setitem__ (same func type, value = Some) + MapDelSubscript(MapAssSubscriptFunc), // __delitem__ (same func type, value = None) // Number sub-slots (nb_*) - grouped by signature NumBoolean(PyNumberUnaryFunc), // __bool__ @@ -468,12 +470,14 @@ impl core::fmt::Debug for SlotFunc { SlotFunc::SeqConcat(_) => write!(f, "SlotFunc::SeqConcat(...)"), SlotFunc::SeqRepeat(_) => write!(f, "SlotFunc::SeqRepeat(...)"), SlotFunc::SeqItem(_) => write!(f, "SlotFunc::SeqItem(...)"), - SlotFunc::SeqAssItem(_) => write!(f, "SlotFunc::SeqAssItem(...)"), + SlotFunc::SeqSetItem(_) => write!(f, "SlotFunc::SeqSetItem(...)"), + SlotFunc::SeqDelItem(_) => write!(f, "SlotFunc::SeqDelItem(...)"), SlotFunc::SeqContains(_) => write!(f, "SlotFunc::SeqContains(...)"), // Mapping sub-slots SlotFunc::MapLength(_) => write!(f, "SlotFunc::MapLength(...)"), SlotFunc::MapSubscript(_) => write!(f, "SlotFunc::MapSubscript(...)"), - SlotFunc::MapAssSubscript(_) => write!(f, "SlotFunc::MapAssSubscript(...)"), + SlotFunc::MapSetSubscript(_) => write!(f, "SlotFunc::MapSetSubscript(...)"), + SlotFunc::MapDelSubscript(_) => write!(f, "SlotFunc::MapDelSubscript(...)"), // Number sub-slots SlotFunc::NumBoolean(_) => write!(f, "SlotFunc::NumBoolean(...)"), SlotFunc::NumUnary(_) => write!(f, "SlotFunc::NumUnary(...)"), @@ -487,13 +491,7 @@ impl core::fmt::Debug for SlotFunc { impl SlotFunc { /// Call the wrapped slot function with proper type handling - pub fn call( - &self, - obj: PyObjectRef, - args: FuncArgs, - name: &str, - vm: &VirtualMachine, - ) -> PyResult { + pub fn call(&self, obj: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult { match self { SlotFunc::Init(func) => { func(obj, args, vm)?; @@ -606,14 +604,14 @@ impl SlotFunc { let (index,): (isize,) = args.bind(vm)?; func(obj.sequence_unchecked(), index, vm) } - SlotFunc::SeqAssItem(func) => { - if name == "__delitem__" { - let (index,): (isize,) = args.bind(vm)?; - func(obj.sequence_unchecked(), index, None, vm)?; - } else { - let (index, value): (isize, PyObjectRef) = args.bind(vm)?; - func(obj.sequence_unchecked(), index, Some(value), vm)?; - } + SlotFunc::SeqSetItem(func) => { + let (index, value): (isize, PyObjectRef) = args.bind(vm)?; + func(obj.sequence_unchecked(), index, Some(value), vm)?; + Ok(vm.ctx.none()) + } + SlotFunc::SeqDelItem(func) => { + let (index,): (isize,) = args.bind(vm)?; + func(obj.sequence_unchecked(), index, None, vm)?; Ok(vm.ctx.none()) } SlotFunc::SeqContains(func) => { @@ -631,14 +629,14 @@ impl SlotFunc { let (key,): (PyObjectRef,) = args.bind(vm)?; func(obj.mapping_unchecked(), &key, vm) } - SlotFunc::MapAssSubscript(func) => { - if name == "__delitem__" { - let (key,): (PyObjectRef,) = args.bind(vm)?; - func(obj.mapping_unchecked(), &key, None, vm)?; - } else { - let (key, value): (PyObjectRef, PyObjectRef) = args.bind(vm)?; - func(obj.mapping_unchecked(), &key, Some(value), vm)?; - } + SlotFunc::MapSetSubscript(func) => { + let (key, value): (PyObjectRef, PyObjectRef) = args.bind(vm)?; + func(obj.mapping_unchecked(), &key, Some(value), vm)?; + Ok(vm.ctx.none()) + } + SlotFunc::MapDelSubscript(func) => { + let (key,): (PyObjectRef,) = args.bind(vm)?; + func(obj.mapping_unchecked(), &key, None, vm)?; Ok(vm.ctx.none()) } // Number sub-slots @@ -725,7 +723,7 @@ impl Callable for PyWrapper { ))); } - zelf.wrapped.call(obj, rest, zelf.name.as_str(), vm) + zelf.wrapped.call(obj, rest, vm) } } @@ -797,9 +795,7 @@ impl Callable for PyMethodWrapper { zelf.obj.class().name() ))); } - zelf.wrapper - .wrapped - .call(zelf.obj.clone(), args, zelf.wrapper.name.as_str(), vm) + zelf.wrapper.wrapped.call(zelf.obj.clone(), args, vm) } } diff --git a/crates/vm/src/builtins/getset.rs b/crates/vm/src/builtins/getset.rs index bb2a7d8394e..86f0524b12c 100644 --- a/crates/vm/src/builtins/getset.rs +++ b/crates/vm/src/builtins/getset.rs @@ -118,18 +118,6 @@ impl PyGetSet { ))) } } - fn __set__( - zelf: PyObjectRef, - obj: PyObjectRef, - value: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult<()> { - Self::descr_set(&zelf, obj, PySetterValue::Assign(value), vm) - } - - fn __delete__(zelf: PyObjectRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - Self::descr_set(&zelf, obj, PySetterValue::Delete, vm) - } #[pygetset] fn __name__(&self) -> String { diff --git a/crates/vm/src/builtins/property.rs b/crates/vm/src/builtins/property.rs index 0c6cfda17b5..8cc9ba92e92 100644 --- a/crates/vm/src/builtins/property.rs +++ b/crates/vm/src/builtins/property.rs @@ -125,18 +125,6 @@ impl PyProperty { } } } - fn __set__( - zelf: PyObjectRef, - obj: PyObjectRef, - value: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult<()> { - Self::descr_set(&zelf, obj, PySetterValue::Assign(value), vm) - } - - fn __delete__(zelf: PyObjectRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - Self::descr_set(&zelf, obj, PySetterValue::Delete, vm) - } // Access functions diff --git a/crates/vm/src/stdlib/ctypes/base.rs b/crates/vm/src/stdlib/ctypes/base.rs index 1f9eaeef56a..58d9466adb2 100644 --- a/crates/vm/src/stdlib/ctypes/base.rs +++ b/crates/vm/src/stdlib/ctypes/base.rs @@ -1650,21 +1650,6 @@ impl PyCField { } } - #[pymethod] - fn __set__( - zelf: PyObjectRef, - obj: PyObjectRef, - value: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult<()> { - Self::descr_set(&zelf, obj, PySetterValue::Assign(value), vm) - } - - #[pymethod] - fn __delete__(zelf: PyObjectRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - Self::descr_set(&zelf, obj, PySetterValue::Delete, vm) - } - #[pygetset] fn offset(&self) -> isize { self.offset diff --git a/crates/vm/src/types/slot.rs b/crates/vm/src/types/slot.rs index 2df440b5b9f..b637bfc40b6 100644 --- a/crates/vm/src/types/slot.rs +++ b/crates/vm/src/types/slot.rs @@ -1319,7 +1319,33 @@ impl PyType { update_sub_slot!(as_sequence, item, sequence_getitem_wrapper, SeqItem) } SlotAccessor::SqAssItem => { - update_sub_slot!(as_sequence, ass_item, sequence_setitem_wrapper, SeqAssItem) + // SqAssItem is shared by __setitem__ (SeqSetItem) and __delitem__ (SeqDelItem) + if ADD { + let has_own = { + let guard = self.attributes.read(); + let setitem = ctx.intern_str("__setitem__"); + let delitem = ctx.intern_str("__delitem__"); + guard.contains_key(setitem) || guard.contains_key(delitem) + }; + if has_own { + self.slots + .as_sequence + .ass_item + .store(Some(sequence_setitem_wrapper)); + } else if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| match sf { + SlotFunc::SeqSetItem(f) | SlotFunc::SeqDelItem(f) => Some(*f), + _ => None, + }) { + self.slots.as_sequence.ass_item.store(Some(func)); + } else { + self.slots + .as_sequence + .ass_item + .store(Some(sequence_setitem_wrapper)); + } + } else { + accessor.inherit_from_mro(self); + } } SlotAccessor::SqContains => { update_sub_slot!( @@ -1338,12 +1364,33 @@ impl PyType { update_sub_slot!(as_mapping, subscript, mapping_getitem_wrapper, MapSubscript) } SlotAccessor::MpAssSubscript => { - update_sub_slot!( - as_mapping, - ass_subscript, - mapping_setitem_wrapper, - MapAssSubscript - ) + // MpAssSubscript is shared by __setitem__ (MapSetSubscript) and __delitem__ (MapDelSubscript) + if ADD { + let has_own = { + let guard = self.attributes.read(); + let setitem = ctx.intern_str("__setitem__"); + let delitem = ctx.intern_str("__delitem__"); + guard.contains_key(setitem) || guard.contains_key(delitem) + }; + if has_own { + self.slots + .as_mapping + .ass_subscript + .store(Some(mapping_setitem_wrapper)); + } else if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| match sf { + SlotFunc::MapSetSubscript(f) | SlotFunc::MapDelSubscript(f) => Some(*f), + _ => None, + }) { + self.slots.as_mapping.ass_subscript.store(Some(func)); + } else { + self.slots + .as_mapping + .ass_subscript + .store(Some(mapping_setitem_wrapper)); + } + } else { + accessor.inherit_from_mro(self); + } } // Reserved slots - no-op diff --git a/crates/vm/src/types/slot_defs.rs b/crates/vm/src/types/slot_defs.rs index 1fd493f685e..024776f7893 100644 --- a/crates/vm/src/types/slot_defs.rs +++ b/crates/vm/src/types/slot_defs.rs @@ -389,13 +389,20 @@ impl SlotAccessor { Self::SqConcat | Self::SqInplaceConcat => matches!(slot_func, SlotFunc::SeqConcat(_)), Self::SqRepeat | Self::SqInplaceRepeat => matches!(slot_func, SlotFunc::SeqRepeat(_)), Self::SqItem => matches!(slot_func, SlotFunc::SeqItem(_)), - Self::SqAssItem => matches!(slot_func, SlotFunc::SeqAssItem(_)), + Self::SqAssItem => { + matches!(slot_func, SlotFunc::SeqSetItem(_) | SlotFunc::SeqDelItem(_)) + } Self::SqContains => matches!(slot_func, SlotFunc::SeqContains(_)), // Mapping Self::MpLength => matches!(slot_func, SlotFunc::MapLength(_)), Self::MpSubscript => matches!(slot_func, SlotFunc::MapSubscript(_)), - Self::MpAssSubscript => matches!(slot_func, SlotFunc::MapAssSubscript(_)), + Self::MpAssSubscript => { + matches!( + slot_func, + SlotFunc::MapSetSubscript(_) | SlotFunc::MapDelSubscript(_) + ) + } // New and reserved slots Self::TpNew => false, @@ -751,7 +758,7 @@ impl SlotAccessor { Self::SqConcat => slots.as_sequence.concat.load().map(SlotFunc::SeqConcat), Self::SqRepeat => slots.as_sequence.repeat.load().map(SlotFunc::SeqRepeat), Self::SqItem => slots.as_sequence.item.load().map(SlotFunc::SeqItem), - Self::SqAssItem => slots.as_sequence.ass_item.load().map(SlotFunc::SeqAssItem), + Self::SqAssItem => slots.as_sequence.ass_item.load().map(SlotFunc::SeqSetItem), Self::SqContains => slots.as_sequence.contains.load().map(SlotFunc::SeqContains), Self::SqInplaceConcat => slots .as_sequence @@ -775,7 +782,7 @@ impl SlotAccessor { .as_mapping .ass_subscript .load() - .map(SlotFunc::MapAssSubscript), + .map(SlotFunc::MapSetSubscript), // Reserved slots _ => None, @@ -793,6 +800,16 @@ impl SlotAccessor { match self { Self::TpSetattro => return slots.setattro.load().map(SlotFunc::DelAttro), Self::TpDescrSet => return slots.descr_set.load().map(SlotFunc::DescrDel), + Self::SqAssItem => { + return slots.as_sequence.ass_item.load().map(SlotFunc::SeqDelItem); + } + Self::MpAssSubscript => { + return slots + .as_mapping + .ass_subscript + .load() + .map(SlotFunc::MapDelSubscript); + } _ => {} } } @@ -1060,62 +1077,64 @@ pub static SLOT_DEFS: &[SlotDef] = &[ op: Some(SlotOp::Delete), doc: "Delete an attribute of instance.", }, - // Sequence protocol (sq_*) + // Mapping protocol (mp_*) - must come before Sequence protocol + // so that mp_subscript wins over sq_item for __getitem__ + // (see CPython typeobject.c:10995-11006) SlotDef { name: "__len__", - accessor: SlotAccessor::SqLength, + accessor: SlotAccessor::MpLength, op: None, doc: "Return len(self).", }, SlotDef { name: "__getitem__", - accessor: SlotAccessor::SqItem, + accessor: SlotAccessor::MpSubscript, op: None, doc: "Return self[key].", }, SlotDef { name: "__setitem__", - accessor: SlotAccessor::SqAssItem, + accessor: SlotAccessor::MpAssSubscript, op: None, doc: "Set self[key] to value.", }, SlotDef { name: "__delitem__", - accessor: SlotAccessor::SqAssItem, - op: None, + accessor: SlotAccessor::MpAssSubscript, + op: Some(SlotOp::Delete), doc: "Delete self[key].", }, - SlotDef { - name: "__contains__", - accessor: SlotAccessor::SqContains, - op: None, - doc: "Return key in self.", - }, - // Mapping protocol (mp_*) + // Sequence protocol (sq_*) SlotDef { name: "__len__", - accessor: SlotAccessor::MpLength, + accessor: SlotAccessor::SqLength, op: None, doc: "Return len(self).", }, SlotDef { name: "__getitem__", - accessor: SlotAccessor::MpSubscript, + accessor: SlotAccessor::SqItem, op: None, doc: "Return self[key].", }, SlotDef { name: "__setitem__", - accessor: SlotAccessor::MpAssSubscript, + accessor: SlotAccessor::SqAssItem, op: None, doc: "Set self[key] to value.", }, SlotDef { name: "__delitem__", - accessor: SlotAccessor::MpAssSubscript, - op: None, + accessor: SlotAccessor::SqAssItem, + op: Some(SlotOp::Delete), doc: "Delete self[key].", }, + SlotDef { + name: "__contains__", + accessor: SlotAccessor::SqContains, + op: None, + doc: "Return key in self.", + }, // Number protocol - binary ops with left/right variants SlotDef { name: "__add__", From ab1cb9ba91d239429aaefde123ce075452128a0a Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Thu, 1 Jan 2026 22:52:34 +0900 Subject: [PATCH 7/7] fix ctypes --- crates/vm/src/stdlib/ctypes/array.rs | 30 +++++++++++++++++++++++--- crates/vm/src/stdlib/ctypes/pointer.rs | 28 +++++++++++++++++++++--- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/crates/vm/src/stdlib/ctypes/array.rs b/crates/vm/src/stdlib/ctypes/array.rs index 63594879878..d808f967a0f 100644 --- a/crates/vm/src/stdlib/ctypes/array.rs +++ b/crates/vm/src/stdlib/ctypes/array.rs @@ -9,8 +9,8 @@ use crate::{ }, class::StaticType, function::{ArgBytesLike, FuncArgs, PySetterValue}, - protocol::{BufferDescriptor, PyBuffer, PyNumberMethods, PySequenceMethods}, - types::{AsBuffer, AsNumber, AsSequence, Constructor, Initializer}, + protocol::{BufferDescriptor, PyBuffer, PyMappingMethods, PyNumberMethods, PySequenceMethods}, + types::{AsBuffer, AsMapping, AsNumber, AsSequence, Constructor, Initializer}, }; use alloc::borrow::Cow; use num_traits::{Signed, ToPrimitive}; @@ -468,9 +468,33 @@ impl AsSequence for PyCArray { } } +impl AsMapping for PyCArray { + fn as_mapping() -> &'static PyMappingMethods { + use std::sync::LazyLock; + static AS_MAPPING: LazyLock = LazyLock::new(|| PyMappingMethods { + length: atomic_func!(|mapping, _vm| { + let zelf = PyCArray::mapping_downcast(mapping); + Ok(zelf.class().stg_info_opt().map_or(0, |i| i.length)) + }), + subscript: atomic_func!(|mapping, needle, vm| { + let zelf = PyCArray::mapping_downcast(mapping); + PyCArray::__getitem__(zelf, needle.to_owned(), vm) + }), + ass_subscript: atomic_func!(|mapping, needle, value, vm| { + let zelf = PyCArray::mapping_downcast(mapping); + match value { + Some(value) => PyCArray::__setitem__(zelf, needle.to_owned(), value, vm), + None => PyCArray::__delitem__(zelf, needle.to_owned(), vm), + } + }), + }); + &AS_MAPPING + } +} + #[pyclass( flags(BASETYPE, IMMUTABLETYPE), - with(Constructor, Initializer, AsSequence, AsBuffer) + with(Constructor, Initializer, AsSequence, AsMapping, AsBuffer) )] impl PyCArray { #[pyclassmethod] diff --git a/crates/vm/src/stdlib/ctypes/pointer.rs b/crates/vm/src/stdlib/ctypes/pointer.rs index 4f935945e88..8a0f7cb0f6a 100644 --- a/crates/vm/src/stdlib/ctypes/pointer.rs +++ b/crates/vm/src/stdlib/ctypes/pointer.rs @@ -1,7 +1,8 @@ use super::base::CDATA_BUFFER_METHODS; use super::{PyCArray, PyCData, PyCSimple, PyCStructure, StgInfo, StgInfoFlags}; -use crate::protocol::{BufferDescriptor, PyBuffer, PyNumberMethods}; -use crate::types::{AsBuffer, AsNumber, Constructor, Initializer}; +use crate::atomic_func; +use crate::protocol::{BufferDescriptor, PyBuffer, PyMappingMethods, PyNumberMethods}; +use crate::types::{AsBuffer, AsMapping, AsNumber, Constructor, Initializer}; use crate::{ AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, builtins::{PyBytes, PyInt, PyList, PySlice, PyStr, PyType, PyTypeRef}, @@ -260,7 +261,7 @@ impl Initializer for PyCPointer { #[pyclass( flags(BASETYPE, IMMUTABLETYPE), - with(Constructor, Initializer, AsNumber, AsBuffer) + with(Constructor, Initializer, AsNumber, AsBuffer, AsMapping) )] impl PyCPointer { /// Get the pointer value stored in buffer as usize @@ -785,6 +786,27 @@ impl AsNumber for PyCPointer { } } +impl AsMapping for PyCPointer { + fn as_mapping() -> &'static PyMappingMethods { + use std::sync::LazyLock; + static AS_MAPPING: LazyLock = LazyLock::new(|| PyMappingMethods { + subscript: atomic_func!(|mapping, needle, vm| { + let zelf = PyCPointer::mapping_downcast(mapping); + PyCPointer::__getitem__(zelf, needle.to_owned(), vm) + }), + ass_subscript: atomic_func!(|mapping, needle, value, vm| { + let zelf = PyCPointer::mapping_downcast(mapping); + match value { + Some(value) => PyCPointer::__setitem__(zelf, needle.to_owned(), value, vm), + None => Err(vm.new_type_error("Pointer does not support item deletion")), + } + }), + ..PyMappingMethods::NOT_IMPLEMENTED + }); + &AS_MAPPING + } +} + impl AsBuffer for PyCPointer { fn as_buffer(zelf: &Py, _vm: &VirtualMachine) -> PyResult { let stg_info = zelf