diff --git a/crates/stdlib/src/array.rs b/crates/stdlib/src/array.rs index 878a6ce8fb7..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() } @@ -1177,7 +1176,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/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/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/descriptor.rs b/crates/vm/src/builtins/descriptor.rs index a9218c8d689..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(...)"), @@ -600,10 +604,14 @@ impl SlotFunc { let (index,): (isize,) = args.bind(vm)?; 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)?; + 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) => { @@ -621,10 +629,14 @@ impl SlotFunc { let (key,): (PyObjectRef,) = args.bind(vm)?; 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)?; + 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 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/getset.rs b/crates/vm/src/builtins/getset.rs index a3f0605a473..86f0524b12c 100644 --- a/crates/vm/src/builtins/getset.rs +++ b/crates/vm/src/builtins/getset.rs @@ -118,19 +118,6 @@ impl PyGetSet { ))) } } - #[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 __name__(&self) -> String { 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/property.rs b/crates/vm/src/builtins/property.rs index 3a86867176a..8cc9ba92e92 100644 --- a/crates/vm/src/builtins/property.rs +++ b/crates/vm/src/builtins/property.rs @@ -125,19 +125,6 @@ impl PyProperty { } } } - #[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) - } // Access functions diff --git a/crates/vm/src/builtins/range.rs b/crates/vm/src/builtins/range.rs index fac5206b82d..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() } @@ -342,7 +341,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/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 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) } 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/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/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 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__",