From da752273f0d20ca50a9c22602d73668873eea153 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 26 Dec 2025 01:38:47 +0900 Subject: [PATCH 1/4] SlotFunc --- crates/vm/src/builtins/descriptor.rs | 102 ++++++++-- crates/vm/src/class.rs | 102 +++++++++- crates/vm/src/types/slot.rs | 271 ++++++++++++++++++--------- crates/vm/src/types/zoo.rs | 2 +- 4 files changed, 374 insertions(+), 103 deletions(-) diff --git a/crates/vm/src/builtins/descriptor.rs b/crates/vm/src/builtins/descriptor.rs index 297199eee1..8fb7dbd216 100644 --- a/crates/vm/src/builtins/descriptor.rs +++ b/crates/vm/src/builtins/descriptor.rs @@ -4,11 +4,12 @@ use crate::{ builtins::{PyTypeRef, builtin_func::PyNativeMethod, type_}, class::PyClassImpl, common::hash::PyHash, - convert::ToPyResult, + convert::{ToPyObject, ToPyResult}, function::{FuncArgs, PyMethodDef, PyMethodFlags, PySetterValue}, types::{ - Callable, Comparable, GetDescriptor, HashFunc, Hashable, InitFunc, IterFunc, IterNextFunc, - PyComparisonOp, Representable, StringifyFunc, + Callable, Comparable, DelFunc, DescrGetFunc, DescrSetFunc, GenericMethod, GetDescriptor, + GetattroFunc, HashFunc, Hashable, InitFunc, IterFunc, IterNextFunc, PyComparisonOp, + Representable, RichCompareFunc, SetattroFunc, StringifyFunc, }, }; use rustpython_common::lock::PyRwLock; @@ -387,22 +388,38 @@ impl GetDescriptor for PyMemberDescriptor { pub fn init(ctx: &Context) { PyMemberDescriptor::extend_class(ctx, ctx.types.member_descriptor_type); PyMethodDescriptor::extend_class(ctx, ctx.types.method_descriptor_type); - PySlotWrapper::extend_class(ctx, ctx.types.wrapper_descriptor_type); + PyWrapper::extend_class(ctx, ctx.types.wrapper_descriptor_type); PyMethodWrapper::extend_class(ctx, ctx.types.method_wrapper_type); } -// PySlotWrapper - wrapper_descriptor +// PyWrapper - wrapper_descriptor /// Type-erased slot function - mirrors CPython's void* d_wrapped /// Each variant knows how to call the wrapped function with proper types #[derive(Clone, Copy)] pub enum SlotFunc { + // Basic slots Init(InitFunc), Hash(HashFunc), Str(StringifyFunc), Repr(StringifyFunc), Iter(IterFunc), IterNext(IterNextFunc), + Call(GenericMethod), + Del(DelFunc), + + // Attribute access slots + GetAttro(GetattroFunc), + SetAttro(SetattroFunc), // __setattr__ + DelAttro(SetattroFunc), // __delattr__ (same func type, different PySetterValue) + + // Rich comparison slots (with comparison op) + RichCompare(RichCompareFunc, PyComparisonOp), + + // Descriptor slots + DescrGet(DescrGetFunc), + DescrSet(DescrSetFunc), // __set__ + DescrDel(DescrSetFunc), // __delete__ (same func type, different PySetterValue) } impl std::fmt::Debug for SlotFunc { @@ -414,6 +431,15 @@ impl std::fmt::Debug for SlotFunc { SlotFunc::Repr(_) => write!(f, "SlotFunc::Repr(...)"), SlotFunc::Iter(_) => write!(f, "SlotFunc::Iter(...)"), SlotFunc::IterNext(_) => write!(f, "SlotFunc::IterNext(...)"), + SlotFunc::Call(_) => write!(f, "SlotFunc::Call(...)"), + SlotFunc::Del(_) => write!(f, "SlotFunc::Del(...)"), + SlotFunc::GetAttro(_) => write!(f, "SlotFunc::GetAttro(...)"), + SlotFunc::SetAttro(_) => write!(f, "SlotFunc::SetAttro(...)"), + SlotFunc::DelAttro(_) => write!(f, "SlotFunc::DelAttro(...)"), + SlotFunc::RichCompare(_, op) => write!(f, "SlotFunc::RichCompare(..., {:?})", op), + SlotFunc::DescrGet(_) => write!(f, "SlotFunc::DescrGet(...)"), + SlotFunc::DescrSet(_) => write!(f, "SlotFunc::DescrSet(...)"), + SlotFunc::DescrDel(_) => write!(f, "SlotFunc::DescrDel(...)"), } } } @@ -463,6 +489,58 @@ impl SlotFunc { } func(&obj, vm).to_pyresult(vm) } + SlotFunc::Call(func) => func(&obj, args, vm), + SlotFunc::Del(func) => { + if !args.args.is_empty() || !args.kwargs.is_empty() { + return Err( + vm.new_type_error("__del__() takes no arguments (1 given)".to_owned()) + ); + } + func(&obj, vm)?; + Ok(vm.ctx.none()) + } + SlotFunc::GetAttro(func) => { + let (name,): (PyRef,) = args.bind(vm)?; + func(&obj, &name, vm) + } + SlotFunc::SetAttro(func) => { + let (name, value): (PyRef, PyObjectRef) = args.bind(vm)?; + func(&obj, &name, PySetterValue::Assign(value), vm)?; + Ok(vm.ctx.none()) + } + SlotFunc::DelAttro(func) => { + let (name,): (PyRef,) = args.bind(vm)?; + func(&obj, &name, PySetterValue::Delete, vm)?; + Ok(vm.ctx.none()) + } + SlotFunc::RichCompare(func, op) => { + let (other,): (PyObjectRef,) = args.bind(vm)?; + func(&obj, &other, *op, vm).map(|r| match r { + crate::function::Either::A(obj) => obj, + crate::function::Either::B(cmp_val) => cmp_val.to_pyobject(vm), + }) + } + SlotFunc::DescrGet(func) => { + let (instance, owner): (PyObjectRef, crate::function::OptionalArg) = + args.bind(vm)?; + let owner = owner.into_option(); + let instance_opt = if vm.is_none(&instance) { + None + } else { + Some(instance) + }; + func(obj, instance_opt, owner, vm) + } + SlotFunc::DescrSet(func) => { + let (instance, value): (PyObjectRef, PyObjectRef) = args.bind(vm)?; + func(&obj, instance, PySetterValue::Assign(value), vm)?; + Ok(vm.ctx.none()) + } + SlotFunc::DescrDel(func) => { + let (instance,): (PyObjectRef,) = args.bind(vm)?; + func(&obj, instance, PySetterValue::Delete, vm)?; + Ok(vm.ctx.none()) + } } } } @@ -471,20 +549,20 @@ impl SlotFunc { // = PyWrapperDescrObject #[pyclass(name = "wrapper_descriptor", module = false)] #[derive(Debug)] -pub struct PySlotWrapper { +pub struct PyWrapper { pub typ: &'static Py, pub name: &'static PyStrInterned, pub wrapped: SlotFunc, pub doc: Option<&'static str>, } -impl PyPayload for PySlotWrapper { +impl PyPayload for PyWrapper { fn class(ctx: &Context) -> &'static Py { ctx.types.wrapper_descriptor_type } } -impl GetDescriptor for PySlotWrapper { +impl GetDescriptor for PyWrapper { fn descr_get( zelf: PyObjectRef, obj: Option, @@ -501,7 +579,7 @@ impl GetDescriptor for PySlotWrapper { } } -impl Callable for PySlotWrapper { +impl Callable for PyWrapper { type Args = FuncArgs; fn call(zelf: &Py, args: FuncArgs, vm: &VirtualMachine) -> PyResult { @@ -525,7 +603,7 @@ impl Callable for PySlotWrapper { with(GetDescriptor, Callable, Representable), flags(DISALLOW_INSTANTIATION) )] -impl PySlotWrapper { +impl PyWrapper { #[pygetset] fn __name__(&self) -> &'static PyStrInterned { self.name @@ -547,7 +625,7 @@ impl PySlotWrapper { } } -impl Representable for PySlotWrapper { +impl Representable for PyWrapper { #[inline] fn repr_str(zelf: &Py, _vm: &VirtualMachine) -> PyResult { Ok(format!( @@ -565,7 +643,7 @@ impl Representable for PySlotWrapper { #[pyclass(name = "method-wrapper", module = false, traverse)] #[derive(Debug)] pub struct PyMethodWrapper { - pub wrapper: PyRef, + pub wrapper: PyRef, #[pytraverse(skip)] pub obj: PyObjectRef, } diff --git a/crates/vm/src/class.rs b/crates/vm/src/class.rs index 577fd7d684..7edbf4373e 100644 --- a/crates/vm/src/class.rs +++ b/crates/vm/src/class.rs @@ -4,11 +4,11 @@ use crate::{ PyPayload, builtins::{ PyBaseObject, PyType, PyTypeRef, - descriptor::{PySlotWrapper, SlotFunc}, + descriptor::{PyWrapper, SlotFunc}, }, function::PyMethodDef, object::Py, - types::{PyTypeFlags, PyTypeSlots, hash_not_implemented}, + types::{PyComparisonOp, PyTypeFlags, PyTypeSlots, hash_not_implemented}, vm::Context, }; use rustpython_common::static_cell; @@ -147,7 +147,7 @@ pub trait PyClassImpl: PyClassDef { if let Some(func) = class.slots.$slot.load() { let attr_name = identifier!(ctx, $name); if !class.attributes.read().contains_key(attr_name) { - let wrapper = PySlotWrapper { + let wrapper = PyWrapper { typ: class, name: ctx.intern_str(stringify!($name)), wrapped: SlotFunc::$variant(func), @@ -177,6 +177,102 @@ pub trait PyClassImpl: PyClassDef { add_slot_wrapper!(hash, __hash__, Hash, "Return hash(self)."); } + add_slot_wrapper!(call, __call__, Call, "Call self as a function."); + add_slot_wrapper!( + del, + __del__, + Del, + "Called when the instance is about to be destroyed." + ); + + // Attribute access slots + add_slot_wrapper!( + getattro, + __getattribute__, + GetAttro, + "Return getattr(self, name)." + ); + // setattro is shared by __setattr__ and __delattr__ + if let Some(func) = class.slots.setattro.load() { + let attr_name = identifier!(ctx, __setattr__); + if !class.attributes.read().contains_key(attr_name) { + let wrapper = PyWrapper { + typ: class, + name: ctx.intern_str("__setattr__"), + wrapped: SlotFunc::SetAttro(func), + doc: Some("Implement setattr(self, name, value)."), + }; + class.set_attr(attr_name, wrapper.into_ref(ctx).into()); + } + let attr_name = identifier!(ctx, __delattr__); + if !class.attributes.read().contains_key(attr_name) { + let wrapper = PyWrapper { + typ: class, + name: ctx.intern_str("__delattr__"), + wrapped: SlotFunc::DelAttro(func), + doc: Some("Implement delattr(self, name)."), + }; + class.set_attr(attr_name, wrapper.into_ref(ctx).into()); + } + } + + // Rich comparison slots + macro_rules! add_richcompare_wrapper { + ($name:ident, $op:expr, $doc:expr) => { + if let Some(func) = class.slots.richcompare.load() { + let attr_name = identifier!(ctx, $name); + if !class.attributes.read().contains_key(attr_name) { + let wrapper = PyWrapper { + typ: class, + name: ctx.intern_str(stringify!($name)), + wrapped: SlotFunc::RichCompare(func, $op), + doc: Some($doc), + }; + class.set_attr(attr_name, wrapper.into_ref(ctx).into()); + } + } + }; + } + add_richcompare_wrapper!(__eq__, PyComparisonOp::Eq, "Return self==value."); + add_richcompare_wrapper!(__ne__, PyComparisonOp::Ne, "Return self!=value."); + add_richcompare_wrapper!(__lt__, PyComparisonOp::Lt, "Return selfvalue."); + add_richcompare_wrapper!(__ge__, PyComparisonOp::Ge, "Return self>=value."); + + // Descriptor slots + add_slot_wrapper!( + descr_get, + __get__, + DescrGet, + "Return an attribute of instance, which is of type owner." + ); + // descr_set is shared by __set__ and __delete__ + if let Some(func) = class.slots.descr_set.load() { + let attr_name = identifier!(ctx, __set__); + if !class.attributes.read().contains_key(attr_name) { + let wrapper = PyWrapper { + typ: class, + name: ctx.intern_str("__set__"), + wrapped: SlotFunc::DescrSet(func), + doc: Some("Set an attribute of instance to value."), + }; + class.set_attr(attr_name, wrapper.into_ref(ctx).into()); + } + let attr_name = identifier!(ctx, __delete__); + if !class.attributes.read().contains_key(attr_name) { + let wrapper = PyWrapper { + typ: class, + name: ctx.intern_str("__delete__"), + wrapped: SlotFunc::DescrDel(func), + doc: Some("Delete an attribute of instance."), + }; + class.set_attr(attr_name, wrapper.into_ref(ctx).into()); + } + } + + // Note: __new__ is handled specially at the beginning of extend_class + // Inherit slots from base types after slots are fully initialized for base in class.bases.read().iter() { class.inherit_slots(base); diff --git a/crates/vm/src/types/slot.rs b/crates/vm/src/types/slot.rs index 0d6b17ae99..6da49f2271 100644 --- a/crates/vm/src/types/slot.rs +++ b/crates/vm/src/types/slot.rs @@ -511,10 +511,10 @@ impl PyType { debug_assert!(name.as_str().starts_with("__")); debug_assert!(name.as_str().ends_with("__")); - macro_rules! toggle_slot { - ($name:ident, $func:expr) => {{ + macro_rules! toggle_sub_slot { + ($group:ident, $name:ident, $func:expr) => {{ if ADD { - self.slots.$name.store(Some($func)); + self.slots.$group.$name.store(Some($func)); } else { // When deleting, re-inherit from MRO (skip self) let inherited = self @@ -522,16 +522,32 @@ impl PyType { .read() .iter() .skip(1) - .find_map(|cls| cls.slots.$name.load()); - self.slots.$name.store(inherited); + .find_map(|cls| cls.slots.$group.$name.load()); + self.slots.$group.$name.store(inherited); } }}; } - macro_rules! toggle_sub_slot { - ($group:ident, $name:ident, $func:expr) => {{ + // If the method is a slot wrapper, extract and use the original slot directly. + // Otherwise use the generic wrapper. + macro_rules! update_one_slot { + ($slot:ident, $wrapper:expr, $variant:ident) => {{ + use crate::builtins::descriptor::SlotFunc; if ADD { - self.slots.$group.$name.store(Some($func)); + // Try to extract the original slot from a slot wrapper + if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| { + if let SlotFunc::$variant(f) = sf { + Some(*f) + } else { + None + } + }) { + // Found slot wrapper - use the original slot directly + self.slots.$slot.store(Some(func)); + } else { + // Real method found or no method - use generic wrapper + self.slots.$slot.store(Some($wrapper)); + } } else { // When deleting, re-inherit from MRO (skip self) let inherited = self @@ -539,15 +555,87 @@ impl PyType { .read() .iter() .skip(1) - .find_map(|cls| cls.slots.$group.$name.load()); - self.slots.$group.$name.store(inherited); + .find_map(|cls| cls.slots.$slot.load()); + self.slots.$slot.store(inherited); + } + }}; + } + + // For setattro slot: matches SetAttro or DelAttro + macro_rules! update_setattro { + ($wrapper:expr) => {{ + use crate::builtins::descriptor::SlotFunc; + if ADD { + if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| match sf { + SlotFunc::SetAttro(f) | SlotFunc::DelAttro(f) => Some(*f), + _ => None, + }) { + self.slots.setattro.store(Some(func)); + } else { + self.slots.setattro.store(Some($wrapper)); + } + } else { + let inherited = self + .mro + .read() + .iter() + .skip(1) + .find_map(|cls| cls.slots.setattro.load()); + self.slots.setattro.store(inherited); } }}; } - macro_rules! update_slot { - ($name:ident, $func:expr) => {{ - self.slots.$name.store(Some($func)); + // For richcompare slot: matches RichCompare with any op + macro_rules! update_richcompare { + ($wrapper:expr) => {{ + use crate::builtins::descriptor::SlotFunc; + if ADD { + if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| { + if let SlotFunc::RichCompare(f, _) = sf { + Some(*f) + } else { + None + } + }) { + self.slots.richcompare.store(Some(func)); + } else { + self.slots.richcompare.store(Some($wrapper)); + } + } else { + let inherited = self + .mro + .read() + .iter() + .skip(1) + .find_map(|cls| cls.slots.richcompare.load()); + self.slots.richcompare.store(inherited); + } + }}; + } + + // For descr_set slot: matches DescrSet or DescrDel + macro_rules! update_descr_set { + ($wrapper:expr) => {{ + use crate::builtins::descriptor::SlotFunc; + if ADD { + if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| match sf { + SlotFunc::DescrSet(f) | SlotFunc::DescrDel(f) => Some(*f), + _ => None, + }) { + self.slots.descr_set.store(Some(func)); + } else { + self.slots.descr_set.store(Some($wrapper)); + } + } else { + let inherited = self + .mro + .read() + .iter() + .skip(1) + .find_map(|cls| cls.slots.descr_set.load()); + self.slots.descr_set.store(inherited); + } }}; } @@ -581,34 +669,55 @@ impl PyType { }); } _ if name == identifier!(ctx, __repr__) => { - update_slot!(repr, repr_wrapper); + update_one_slot!(repr, repr_wrapper, Repr); } _ if name == identifier!(ctx, __str__) => { - update_slot!(str, str_wrapper); + update_one_slot!(str, str_wrapper, Str); } _ if name == identifier!(ctx, __hash__) => { - let is_unhashable = self - .attributes - .read() - .get(identifier!(ctx, __hash__)) - .is_some_and(|a| a.is(&ctx.none)); - let wrapper = if is_unhashable { - hash_not_implemented + use crate::builtins::descriptor::SlotFunc; + if ADD { + // Check for __hash__ = None first (descr == Py_None) + let method = self.attributes.read().get(name).cloned().or_else(|| { + self.mro + .read() + .iter() + .find_map(|cls| cls.attributes.read().get(name).cloned()) + }); + + if method.as_ref().is_some_and(|m| m.is(&ctx.none)) { + self.slots.hash.store(Some(hash_not_implemented)); + } else if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| { + if let SlotFunc::Hash(f) = sf { + Some(*f) + } else { + None + } + }) { + self.slots.hash.store(Some(func)); + } else { + self.slots.hash.store(Some(hash_wrapper)); + } } else { - hash_wrapper - }; - toggle_slot!(hash, wrapper); + let inherited = self + .mro + .read() + .iter() + .skip(1) + .find_map(|cls| cls.slots.hash.load()); + self.slots.hash.store(inherited); + } } _ if name == identifier!(ctx, __call__) => { - toggle_slot!(call, call_wrapper); + update_one_slot!(call, call_wrapper, Call); } _ if name == identifier!(ctx, __getattr__) || name == identifier!(ctx, __getattribute__) => { - update_slot!(getattro, getattro_wrapper); + update_one_slot!(getattro, getattro_wrapper, GetAttro); } _ if name == identifier!(ctx, __setattr__) || name == identifier!(ctx, __delattr__) => { - update_slot!(setattro, setattro_wrapper); + update_setattro!(setattro_wrapper); } _ if name == identifier!(ctx, __eq__) || name == identifier!(ctx, __ne__) @@ -617,64 +726,40 @@ impl PyType { || name == identifier!(ctx, __ge__) || name == identifier!(ctx, __gt__) => { - update_slot!(richcompare, richcompare_wrapper); + update_richcompare!(richcompare_wrapper); } _ if name == identifier!(ctx, __iter__) => { - toggle_slot!(iter, iter_wrapper); + update_one_slot!(iter, iter_wrapper, Iter); } _ if name == identifier!(ctx, __next__) => { - toggle_slot!(iternext, iternext_wrapper); + update_one_slot!(iternext, iternext_wrapper, IterNext); } _ if name == identifier!(ctx, __get__) => { - toggle_slot!(descr_get, descr_get_wrapper); + update_one_slot!(descr_get, descr_get_wrapper, DescrGet); } _ if name == identifier!(ctx, __set__) || name == identifier!(ctx, __delete__) => { - update_slot!(descr_set, descr_set_wrapper); + update_descr_set!(descr_set_wrapper); } _ if name == identifier!(ctx, __init__) => { - // Special handling: check if this type or any base has a real __init__ method - // If only slot wrappers exist, use the inherited slot from copyslot! - if ADD { - // First check if this type has __init__ in its own dict - let has_own_init = self.attributes.read().contains_key(name); - if has_own_init { - // This type defines __init__ - use wrapper - self.slots.init.store(Some(init_wrapper)); - } else if self.has_real_method_in_mro(name, ctx) { - // A base class defines a real __init__ method - use wrapper - self.slots.init.store(Some(init_wrapper)); - } - // else: keep inherited slot from copyslot! - } else { - let inherited = self - .mro - .read() - .iter() - .skip(1) - .find_map(|cls| cls.slots.init.load()); - self.slots.init.store(inherited); - } + update_one_slot!(init, init_wrapper, Init); } _ if name == identifier!(ctx, __new__) => { - toggle_slot!(new, new_wrapper); - } - _ if name == identifier!(ctx, __del__) => { - // Same special handling as __init__ + // __new__ is not wrapped via PyWrapper if ADD { - let has_own_del = self.attributes.read().contains_key(name); - if has_own_del || self.has_real_method_in_mro(name, ctx) { - self.slots.del.store(Some(del_wrapper)); - } + self.slots.new.store(Some(new_wrapper)); } else { let inherited = self .mro .read() .iter() .skip(1) - .find_map(|cls| cls.slots.del.load()); - self.slots.del.store(inherited); + .find_map(|cls| cls.slots.new.load()); + self.slots.new.store(inherited); } } + _ if name == identifier!(ctx, __del__) => { + update_one_slot!(del, del_wrapper, Del); + } _ if name == identifier!(ctx, __bool__) => { toggle_sub_slot!(as_number, boolean, bool_wrapper); } @@ -926,34 +1011,46 @@ impl PyType { } } - /// Check if there's a real method (not a slot wrapper) for `name` anywhere in the MRO. - /// If a real method exists, we should use a wrapper function. Otherwise, use the inherited slot. - fn has_real_method_in_mro(&self, name: &'static PyStrInterned, ctx: &Context) -> bool { - use crate::builtins::descriptor::PySlotWrapper; + /// Look up a method in MRO and extract the slot function if it's a slot wrapper. + /// Returns Some(slot_func) if a matching slot wrapper is found, None if a real method + /// is found or no method exists. + fn lookup_slot_in_mro( + &self, + name: &'static PyStrInterned, + ctx: &Context, + extract: impl Fn(&crate::builtins::descriptor::SlotFunc) -> Option, + ) -> Option { + use crate::builtins::descriptor::PyWrapper; + + // Helper to extract slot from an attribute if it's a wrapper descriptor + let try_extract = |attr: &PyObjectRef| -> Option { + if attr.class().is(ctx.types.wrapper_descriptor_type) { + attr.downcast_ref::() + .and_then(|wrapper| extract(&wrapper.wrapped)) + } else { + None + } + }; + + // Look up in self's dict first + if let Some(attr) = self.attributes.read().get(name).cloned() { + if let Some(func) = try_extract(&attr) { + return Some(func); + } + return None; + } - // Check the entire MRO (including self) for the method + // Look up in MRO for cls in self.mro.read().iter() { if let Some(attr) = cls.attributes.read().get(name).cloned() { - // Found the method - check if it's a slot wrapper - if attr.class().is(ctx.types.wrapper_descriptor_type) { - if let Some(wrapper) = attr.downcast_ref::() { - // It's a slot wrapper - check if it belongs to this class - let wrapper_typ: *const _ = wrapper.typ; - let cls_ptr: *const _ = cls.as_ref(); - if wrapper_typ == cls_ptr { - // Slot wrapper defined on this exact class - use inherited slot - return false; - } - } - // Inherited slot wrapper - continue checking MRO - } else { - // Real method found - use wrapper function - return true; + if let Some(func) = try_extract(&attr) { + return Some(func); } + return None; } } - // No real method found in MRO - use inherited slot - false + // No method found in MRO + None } } diff --git a/crates/vm/src/types/zoo.rs b/crates/vm/src/types/zoo.rs index 9d16424167..c4aa7258c0 100644 --- a/crates/vm/src/types/zoo.rs +++ b/crates/vm/src/types/zoo.rs @@ -189,7 +189,7 @@ impl TypeZoo { generic_alias_type: genericalias::PyGenericAlias::init_builtin_type(), union_type: union_::PyUnion::init_builtin_type(), member_descriptor_type: descriptor::PyMemberDescriptor::init_builtin_type(), - wrapper_descriptor_type: descriptor::PySlotWrapper::init_builtin_type(), + wrapper_descriptor_type: descriptor::PyWrapper::init_builtin_type(), method_wrapper_type: descriptor::PyMethodWrapper::init_builtin_type(), method_def: crate::function::HeapMethodDef::init_builtin_type(), From 0ef02747dc6f8f82e53be6bce70a9448920f1119 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 26 Dec 2025 11:36:43 +0900 Subject: [PATCH 2/4] slotdef --- .cspell.dict/cpython.txt | 1 + Lib/test/test_descr.py | 1 - Lib/test/test_inspect/test_inspect.py | 4 - Lib/test/test_sqlite3/test_factory.py | 2 - .../test_unittest/testmock/testhelpers.py | 2 - crates/vm/src/builtins/descriptor.rs | 108 +- crates/vm/src/builtins/type.rs | 172 +-- crates/vm/src/class.rs | 187 +-- crates/vm/src/protocol/mod.rs | 2 +- crates/vm/src/types/mod.rs | 2 + crates/vm/src/types/slot.rs | 868 +++++++----- crates/vm/src/types/slot_defs.rs | 1235 +++++++++++++++++ 12 files changed, 1913 insertions(+), 671 deletions(-) create mode 100644 crates/vm/src/types/slot_defs.rs diff --git a/.cspell.dict/cpython.txt b/.cspell.dict/cpython.txt index 441e8af5b8..933b6af3fb 100644 --- a/.cspell.dict/cpython.txt +++ b/.cspell.dict/cpython.txt @@ -1,6 +1,7 @@ argtypes asdl asname +attro augassign badcert badsyntax diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 4e04371f62..b3d973237d 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1399,7 +1399,6 @@ class Q2: __qualname__ = object() __slots__ = ["__qualname__"] - @unittest.expectedFailure # TODO: RUSTPYTHON def test_slots_descriptor(self): # Issue2115: slot descriptors did not correctly check # the type of the given object diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 353d7c2e7b..8f87fa8571 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -2126,8 +2126,6 @@ class DataDescriptorSub(DataDescriptorWithNoGet, self.assertFalse(inspect.ismethoddescriptor(MethodDescriptorSub)) self.assertFalse(inspect.ismethoddescriptor(DataDescriptorSub)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_builtin_descriptors(self): builtin_slot_wrapper = int.__add__ # This one is mentioned in docs. class Owner: @@ -2217,8 +2215,6 @@ class DataDescriptor2: self.assertTrue(inspect.isdatadescriptor(DataDescriptor2()), 'class with __set__ = None is a data descriptor') - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_slot(self): class Slotted: __slots__ = 'foo', diff --git a/Lib/test/test_sqlite3/test_factory.py b/Lib/test/test_sqlite3/test_factory.py index e52c10fe94..c13a748152 100644 --- a/Lib/test/test_sqlite3/test_factory.py +++ b/Lib/test/test_sqlite3/test_factory.py @@ -241,8 +241,6 @@ def test_sqlite_row_hash_cmp(self): self.assertEqual(hash(row_1), hash(row_2)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_sqlite_row_as_sequence(self): """ Checks if the row object can act like a sequence """ self.con.row_factory = sqlite.Row diff --git a/Lib/test/test_unittest/testmock/testhelpers.py b/Lib/test/test_unittest/testmock/testhelpers.py index 5facac685f..c83068beb1 100644 --- a/Lib/test/test_unittest/testmock/testhelpers.py +++ b/Lib/test/test_unittest/testmock/testhelpers.py @@ -884,8 +884,6 @@ def f(a, self): pass a.f.assert_called_with(self=10) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_autospec_data_descriptor(self): class Descriptor(object): def __init__(self, value): diff --git a/crates/vm/src/builtins/descriptor.rs b/crates/vm/src/builtins/descriptor.rs index 8fb7dbd216..d42a97d553 100644 --- a/crates/vm/src/builtins/descriptor.rs +++ b/crates/vm/src/builtins/descriptor.rs @@ -6,10 +6,13 @@ use crate::{ common::hash::PyHash, convert::{ToPyObject, ToPyResult}, function::{FuncArgs, PyMethodDef, PyMethodFlags, PySetterValue}, + protocol::{PyNumberBinaryFunc, PyNumberTernaryFunc, PyNumberUnaryFunc}, types::{ Callable, Comparable, DelFunc, DescrGetFunc, DescrSetFunc, GenericMethod, GetDescriptor, - GetattroFunc, HashFunc, Hashable, InitFunc, IterFunc, IterNextFunc, PyComparisonOp, - Representable, RichCompareFunc, SetattroFunc, StringifyFunc, + GetattroFunc, HashFunc, Hashable, InitFunc, IterFunc, IterNextFunc, MapAssSubscriptFunc, + MapLenFunc, MapSubscriptFunc, PyComparisonOp, Representable, RichCompareFunc, + SeqAssItemFunc, SeqConcatFunc, SeqContainsFunc, SeqItemFunc, SeqLenFunc, SeqRepeatFunc, + SetattroFunc, StringifyFunc, }, }; use rustpython_common::lock::PyRwLock; @@ -394,7 +397,6 @@ pub fn init(ctx: &Context) { // PyWrapper - wrapper_descriptor -/// Type-erased slot function - mirrors CPython's void* d_wrapped /// Each variant knows how to call the wrapped function with proper types #[derive(Clone, Copy)] pub enum SlotFunc { @@ -420,6 +422,25 @@ pub enum SlotFunc { DescrGet(DescrGetFunc), DescrSet(DescrSetFunc), // __set__ DescrDel(DescrSetFunc), // __delete__ (same func type, different PySetterValue) + + // Sequence sub-slots (sq_*) + SeqLength(SeqLenFunc), + SeqConcat(SeqConcatFunc), + SeqRepeat(SeqRepeatFunc), + SeqItem(SeqItemFunc), + SeqAssItem(SeqAssItemFunc), + SeqContains(SeqContainsFunc), + + // Mapping sub-slots (mp_*) + MapLength(MapLenFunc), + MapSubscript(MapSubscriptFunc), + MapAssSubscript(MapAssSubscriptFunc), + + // Number sub-slots (nb_*) - grouped by signature + NumBoolean(PyNumberUnaryFunc), // __bool__ + NumUnary(PyNumberUnaryFunc), // __int__, __float__, __index__ + NumBinary(PyNumberBinaryFunc), // __add__, __sub__, __mul__, etc. + NumTernary(PyNumberTernaryFunc), // __pow__ } impl std::fmt::Debug for SlotFunc { @@ -440,6 +461,22 @@ impl std::fmt::Debug for SlotFunc { SlotFunc::DescrGet(_) => write!(f, "SlotFunc::DescrGet(...)"), SlotFunc::DescrSet(_) => write!(f, "SlotFunc::DescrSet(...)"), SlotFunc::DescrDel(_) => write!(f, "SlotFunc::DescrDel(...)"), + // Sequence sub-slots + SlotFunc::SeqLength(_) => write!(f, "SlotFunc::SeqLength(...)"), + 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::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(...)"), + // Number sub-slots + SlotFunc::NumBoolean(_) => write!(f, "SlotFunc::NumBoolean(...)"), + SlotFunc::NumUnary(_) => write!(f, "SlotFunc::NumUnary(...)"), + SlotFunc::NumBinary(_) => write!(f, "SlotFunc::NumBinary(...)"), + SlotFunc::NumTernary(_) => write!(f, "SlotFunc::NumTernary(...)"), } } } @@ -541,6 +578,71 @@ impl SlotFunc { func(&obj, instance, PySetterValue::Delete, vm)?; Ok(vm.ctx.none()) } + // Sequence sub-slots + SlotFunc::SeqLength(func) => { + args.bind::<()>(vm)?; + let len = func(obj.sequence_unchecked(), vm)?; + Ok(vm.ctx.new_int(len).into()) + } + SlotFunc::SeqConcat(func) => { + let (other,): (PyObjectRef,) = args.bind(vm)?; + func(obj.sequence_unchecked(), &other, vm) + } + SlotFunc::SeqRepeat(func) => { + let (n,): (isize,) = args.bind(vm)?; + func(obj.sequence_unchecked(), n, vm) + } + SlotFunc::SeqItem(func) => { + 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)?; + Ok(vm.ctx.none()) + } + SlotFunc::SeqContains(func) => { + let (item,): (PyObjectRef,) = args.bind(vm)?; + let result = func(obj.sequence_unchecked(), &item, vm)?; + Ok(vm.ctx.new_bool(result).into()) + } + // Mapping sub-slots + SlotFunc::MapLength(func) => { + args.bind::<()>(vm)?; + let len = func(obj.mapping_unchecked(), vm)?; + Ok(vm.ctx.new_int(len).into()) + } + SlotFunc::MapSubscript(func) => { + 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)?; + Ok(vm.ctx.none()) + } + // Number sub-slots + SlotFunc::NumBoolean(func) => { + args.bind::<()>(vm)?; + let result = func(obj.number(), vm)?; + Ok(vm.ctx.new_bool(result).into()) + } + SlotFunc::NumUnary(func) => { + args.bind::<()>(vm)?; + func(obj.number(), vm) + } + SlotFunc::NumBinary(func) => { + let (other,): (PyObjectRef,) = args.bind(vm)?; + func(&obj, &other, vm) + } + SlotFunc::NumTernary(func) => { + let (y, z): (PyObjectRef, crate::function::OptionalArg) = + args.bind(vm)?; + let z = z.unwrap_or_else(|| vm.ctx.none()); + func(&obj, &y, &z, vm) + } } } } diff --git a/crates/vm/src/builtins/type.rs b/crates/vm/src/builtins/type.rs index ee07c0db0b..512f9d2894 100644 --- a/crates/vm/src/builtins/type.rs +++ b/crates/vm/src/builtins/type.rs @@ -26,7 +26,7 @@ use crate::{ protocol::{PyIterReturn, PyNumberMethods}, types::{ AsNumber, Callable, Constructor, GetAttr, Initializer, PyTypeFlags, PyTypeSlots, - Representable, SetAttr, TypeDataRef, TypeDataRefMut, TypeDataSlot, + Representable, SLOT_DEFS, SetAttr, TypeDataRef, TypeDataRefMut, TypeDataSlot, }, }; use indexmap::{IndexMap, map::Entry}; @@ -464,173 +464,11 @@ impl PyType { /// Inherit slots from base type. inherit_slots pub(crate) fn inherit_slots(&self, base: &Self) { - macro_rules! copyslot { - ($slot:ident) => { - if self.slots.$slot.load().is_none() { - if let Some(base_val) = base.slots.$slot.load() { - self.slots.$slot.store(Some(base_val)); - } - } - }; - } - - // Copy init slot only if base actually defines it (not just inherited) - // This is needed for multiple inheritance where a later base might - // have a more specific init slot - macro_rules! copyslot_defined { - ($slot:ident) => { - if self.slots.$slot.load().is_none() { - if let Some(base_val) = base.slots.$slot.load() { - // SLOTDEFINED: base->SLOT && (basebase == NULL || base->SLOT != basebase->SLOT) - let basebase = base.base.as_ref(); - let slot_defined = match basebase { - None => true, - Some(bb) => bb.slots.$slot.load().map(|v| v as usize) - != Some(base_val as usize), - }; - if slot_defined { - self.slots.$slot.store(Some(base_val)); - } - } - } - }; - } - - // Core slots - copyslot!(hash); - copyslot!(call); - copyslot!(str); - copyslot!(repr); - copyslot!(getattro); - copyslot!(setattro); - copyslot!(richcompare); - copyslot!(iter); - copyslot!(iternext); - copyslot!(descr_get); - copyslot!(descr_set); - // init uses SLOTDEFINED check for multiple inheritance support - copyslot_defined!(init); - copyslot!(del); - // new is handled by set_new() - // as_buffer is inherited at type creation time (not AtomicCell) - - // Sub-slots (number, sequence, mapping) - self.inherit_number_slots(base); - self.inherit_sequence_slots(base); - self.inherit_mapping_slots(base); - } - - /// Inherit number sub-slots from base type - fn inherit_number_slots(&self, base: &Self) { - macro_rules! copy_num_slot { - ($slot:ident) => { - if self.slots.as_number.$slot.load().is_none() { - if let Some(base_val) = base.slots.as_number.$slot.load() { - self.slots.as_number.$slot.store(Some(base_val)); - } - } - }; + // Use SLOT_DEFS to iterate all slots + // Note: as_buffer is handled in inherit_static_slots (not AtomicCell) + for def in SLOT_DEFS { + def.accessor.copyslot_if_none(self, base); } - - // Binary operations - copy_num_slot!(add); - copy_num_slot!(right_add); - copy_num_slot!(inplace_add); - copy_num_slot!(subtract); - copy_num_slot!(right_subtract); - copy_num_slot!(inplace_subtract); - copy_num_slot!(multiply); - copy_num_slot!(right_multiply); - copy_num_slot!(inplace_multiply); - copy_num_slot!(remainder); - copy_num_slot!(right_remainder); - copy_num_slot!(inplace_remainder); - copy_num_slot!(divmod); - copy_num_slot!(right_divmod); - copy_num_slot!(power); - copy_num_slot!(right_power); - copy_num_slot!(inplace_power); - - // Bitwise operations - copy_num_slot!(lshift); - copy_num_slot!(right_lshift); - copy_num_slot!(inplace_lshift); - copy_num_slot!(rshift); - copy_num_slot!(right_rshift); - copy_num_slot!(inplace_rshift); - copy_num_slot!(and); - copy_num_slot!(right_and); - copy_num_slot!(inplace_and); - copy_num_slot!(xor); - copy_num_slot!(right_xor); - copy_num_slot!(inplace_xor); - copy_num_slot!(or); - copy_num_slot!(right_or); - copy_num_slot!(inplace_or); - - // Division operations - copy_num_slot!(floor_divide); - copy_num_slot!(right_floor_divide); - copy_num_slot!(inplace_floor_divide); - copy_num_slot!(true_divide); - copy_num_slot!(right_true_divide); - copy_num_slot!(inplace_true_divide); - - // Matrix multiplication - copy_num_slot!(matrix_multiply); - copy_num_slot!(right_matrix_multiply); - copy_num_slot!(inplace_matrix_multiply); - - // Unary operations - copy_num_slot!(negative); - copy_num_slot!(positive); - copy_num_slot!(absolute); - copy_num_slot!(boolean); - copy_num_slot!(invert); - - // Conversion - copy_num_slot!(int); - copy_num_slot!(float); - copy_num_slot!(index); - } - - /// Inherit sequence sub-slots from base type - fn inherit_sequence_slots(&self, base: &Self) { - macro_rules! copy_seq_slot { - ($slot:ident) => { - if self.slots.as_sequence.$slot.load().is_none() { - if let Some(base_val) = base.slots.as_sequence.$slot.load() { - self.slots.as_sequence.$slot.store(Some(base_val)); - } - } - }; - } - - copy_seq_slot!(length); - copy_seq_slot!(concat); - copy_seq_slot!(repeat); - copy_seq_slot!(item); - copy_seq_slot!(ass_item); - copy_seq_slot!(contains); - copy_seq_slot!(inplace_concat); - copy_seq_slot!(inplace_repeat); - } - - /// Inherit mapping sub-slots from base type - fn inherit_mapping_slots(&self, base: &Self) { - macro_rules! copy_map_slot { - ($slot:ident) => { - if self.slots.as_mapping.$slot.load().is_none() { - if let Some(base_val) = base.slots.as_mapping.$slot.load() { - self.slots.as_mapping.$slot.store(Some(base_val)); - } - } - }; - } - - copy_map_slot!(length); - copy_map_slot!(subscript); - copy_map_slot!(ass_subscript); } // This is used for class initialization where the vm is not yet available. diff --git a/crates/vm/src/class.rs b/crates/vm/src/class.rs index 7edbf4373e..0039959053 100644 --- a/crates/vm/src/class.rs +++ b/crates/vm/src/class.rs @@ -2,17 +2,60 @@ use crate::{ PyPayload, - builtins::{ - PyBaseObject, PyType, PyTypeRef, - descriptor::{PyWrapper, SlotFunc}, - }, + builtins::{PyBaseObject, PyType, PyTypeRef, descriptor::PyWrapper}, function::PyMethodDef, object::Py, - types::{PyComparisonOp, PyTypeFlags, PyTypeSlots, hash_not_implemented}, + types::{PyTypeFlags, PyTypeSlots, SLOT_DEFS, hash_not_implemented}, vm::Context, }; use rustpython_common::static_cell; +/// Add slot wrapper descriptors to a type's dict +/// +/// Iterates SLOT_DEFS and creates a PyWrapper for each slot that: +/// 1. Has a function set in the type's slots +/// 2. Doesn't already have an attribute in the type's dict +fn add_operators(class: &'static Py, ctx: &Context) { + for def in SLOT_DEFS.iter() { + // Skip __new__ - it has special handling + if def.name == "__new__" { + continue; + } + + // Special handling for __hash__ = None + if def.name == "__hash__" + && class + .slots + .hash + .load() + .is_some_and(|h| h as usize == hash_not_implemented as usize) + { + class.set_attr(ctx.names.__hash__, ctx.none.clone().into()); + continue; + } + + // Get the slot function wrapped in SlotFunc + let Some(slot_func) = def.accessor.get_slot_func(&class.slots) else { + continue; + }; + + // Check if attribute already exists in dict + let attr_name = ctx.intern_str(def.name); + if class.attributes.read().contains_key(attr_name) { + continue; + } + + // Create and add the wrapper + let wrapper = PyWrapper { + typ: class, + name: attr_name, + wrapped: slot_func, + doc: Some(def.doc), + }; + class.set_attr(attr_name, wrapper.into_ref(ctx).into()); + } +} + pub trait StaticType { // Ideally, saving PyType is better than PyTypeRef fn static_cell() -> &'static static_cell::StaticCell; @@ -140,138 +183,8 @@ pub trait PyClassImpl: PyClassDef { } } - // Add slot wrappers for slots that exist and are not already in dict - // This mirrors CPython's add_operators() in typeobject.c - macro_rules! add_slot_wrapper { - ($slot:ident, $name:ident, $variant:ident, $doc:expr) => { - if let Some(func) = class.slots.$slot.load() { - let attr_name = identifier!(ctx, $name); - if !class.attributes.read().contains_key(attr_name) { - let wrapper = PyWrapper { - typ: class, - name: ctx.intern_str(stringify!($name)), - wrapped: SlotFunc::$variant(func), - doc: Some($doc), - }; - class.set_attr(attr_name, wrapper.into_ref(ctx).into()); - } - } - }; - } - - add_slot_wrapper!( - init, - __init__, - Init, - "Initialize self. See help(type(self)) for accurate signature." - ); - add_slot_wrapper!(repr, __repr__, Repr, "Return repr(self)."); - add_slot_wrapper!(str, __str__, Str, "Return str(self)."); - add_slot_wrapper!(iter, __iter__, Iter, "Implement iter(self)."); - add_slot_wrapper!(iternext, __next__, IterNext, "Implement next(self)."); - - // __hash__ needs special handling: hash_not_implemented sets __hash__ = None - if class.slots.hash.load().map_or(0, |h| h as usize) == hash_not_implemented as usize { - class.set_attr(ctx.names.__hash__, ctx.none.clone().into()); - } else { - add_slot_wrapper!(hash, __hash__, Hash, "Return hash(self)."); - } - - add_slot_wrapper!(call, __call__, Call, "Call self as a function."); - add_slot_wrapper!( - del, - __del__, - Del, - "Called when the instance is about to be destroyed." - ); - - // Attribute access slots - add_slot_wrapper!( - getattro, - __getattribute__, - GetAttro, - "Return getattr(self, name)." - ); - // setattro is shared by __setattr__ and __delattr__ - if let Some(func) = class.slots.setattro.load() { - let attr_name = identifier!(ctx, __setattr__); - if !class.attributes.read().contains_key(attr_name) { - let wrapper = PyWrapper { - typ: class, - name: ctx.intern_str("__setattr__"), - wrapped: SlotFunc::SetAttro(func), - doc: Some("Implement setattr(self, name, value)."), - }; - class.set_attr(attr_name, wrapper.into_ref(ctx).into()); - } - let attr_name = identifier!(ctx, __delattr__); - if !class.attributes.read().contains_key(attr_name) { - let wrapper = PyWrapper { - typ: class, - name: ctx.intern_str("__delattr__"), - wrapped: SlotFunc::DelAttro(func), - doc: Some("Implement delattr(self, name)."), - }; - class.set_attr(attr_name, wrapper.into_ref(ctx).into()); - } - } - - // Rich comparison slots - macro_rules! add_richcompare_wrapper { - ($name:ident, $op:expr, $doc:expr) => { - if let Some(func) = class.slots.richcompare.load() { - let attr_name = identifier!(ctx, $name); - if !class.attributes.read().contains_key(attr_name) { - let wrapper = PyWrapper { - typ: class, - name: ctx.intern_str(stringify!($name)), - wrapped: SlotFunc::RichCompare(func, $op), - doc: Some($doc), - }; - class.set_attr(attr_name, wrapper.into_ref(ctx).into()); - } - } - }; - } - add_richcompare_wrapper!(__eq__, PyComparisonOp::Eq, "Return self==value."); - add_richcompare_wrapper!(__ne__, PyComparisonOp::Ne, "Return self!=value."); - add_richcompare_wrapper!(__lt__, PyComparisonOp::Lt, "Return selfvalue."); - add_richcompare_wrapper!(__ge__, PyComparisonOp::Ge, "Return self>=value."); - - // Descriptor slots - add_slot_wrapper!( - descr_get, - __get__, - DescrGet, - "Return an attribute of instance, which is of type owner." - ); - // descr_set is shared by __set__ and __delete__ - if let Some(func) = class.slots.descr_set.load() { - let attr_name = identifier!(ctx, __set__); - if !class.attributes.read().contains_key(attr_name) { - let wrapper = PyWrapper { - typ: class, - name: ctx.intern_str("__set__"), - wrapped: SlotFunc::DescrSet(func), - doc: Some("Set an attribute of instance to value."), - }; - class.set_attr(attr_name, wrapper.into_ref(ctx).into()); - } - let attr_name = identifier!(ctx, __delete__); - if !class.attributes.read().contains_key(attr_name) { - let wrapper = PyWrapper { - typ: class, - name: ctx.intern_str("__delete__"), - wrapped: SlotFunc::DescrDel(func), - doc: Some("Delete an attribute of instance."), - }; - class.set_attr(attr_name, wrapper.into_ref(ctx).into()); - } - } - - // Note: __new__ is handled specially at the beginning of extend_class + // Add slot wrappers using SLOT_DEFS array + add_operators(class, ctx); // Inherit slots from base types after slots are fully initialized for base in class.bases.read().iter() { diff --git a/crates/vm/src/protocol/mod.rs b/crates/vm/src/protocol/mod.rs index e7be286c26..6eb2909f16 100644 --- a/crates/vm/src/protocol/mod.rs +++ b/crates/vm/src/protocol/mod.rs @@ -12,6 +12,6 @@ pub use iter::{PyIter, PyIterIter, PyIterReturn}; pub use mapping::{PyMapping, PyMappingMethods, PyMappingSlots}; pub use number::{ PyNumber, PyNumberBinaryFunc, PyNumberBinaryOp, PyNumberMethods, PyNumberSlots, - PyNumberTernaryOp, PyNumberUnaryFunc, handle_bytes_to_int_err, + PyNumberTernaryFunc, PyNumberTernaryOp, PyNumberUnaryFunc, handle_bytes_to_int_err, }; pub use sequence::{PySequence, PySequenceMethods, PySequenceSlots}; diff --git a/crates/vm/src/types/mod.rs b/crates/vm/src/types/mod.rs index f19328cdd2..b17a737545 100644 --- a/crates/vm/src/types/mod.rs +++ b/crates/vm/src/types/mod.rs @@ -1,7 +1,9 @@ mod slot; +pub mod slot_defs; mod structseq; mod zoo; pub use slot::*; +pub use slot_defs::{SLOT_DEFS, SlotAccessor, SlotDef}; pub use structseq::{PyStructSequence, PyStructSequenceData, struct_sequence_new}; pub(crate) use zoo::TypeZoo; diff --git a/crates/vm/src/types/slot.rs b/crates/vm/src/types/slot.rs index 6da49f2271..5396e09e6e 100644 --- a/crates/vm/src/types/slot.rs +++ b/crates/vm/src/types/slot.rs @@ -14,6 +14,7 @@ use crate::{ PyBuffer, PyIterReturn, PyMapping, PyMappingMethods, PyMappingSlots, PyNumber, PyNumberMethods, PyNumberSlots, PySequence, PySequenceMethods, PySequenceSlots, }, + types::slot_defs::{SlotAccessor, find_slot_defs_by_name}, vm::Context, }; use crossbeam_utils::atomic::AtomicCell; @@ -288,6 +289,21 @@ pub(crate) type NewFunc = fn(PyTypeRef, FuncArgs, &VirtualMachine) -> PyResult; pub(crate) type InitFunc = fn(PyObjectRef, FuncArgs, &VirtualMachine) -> PyResult<()>; pub(crate) type DelFunc = fn(&PyObject, &VirtualMachine) -> PyResult<()>; +// Sequence sub-slot function types (protocol/sequence.rs) +pub(crate) type SeqLenFunc = fn(PySequence<'_>, &VirtualMachine) -> PyResult; +pub(crate) type SeqConcatFunc = fn(PySequence<'_>, &PyObject, &VirtualMachine) -> PyResult; +pub(crate) type SeqRepeatFunc = fn(PySequence<'_>, isize, &VirtualMachine) -> PyResult; +pub(crate) type SeqItemFunc = fn(PySequence<'_>, isize, &VirtualMachine) -> PyResult; +pub(crate) type SeqAssItemFunc = + fn(PySequence<'_>, isize, Option, &VirtualMachine) -> PyResult<()>; +pub(crate) type SeqContainsFunc = fn(PySequence<'_>, &PyObject, &VirtualMachine) -> PyResult; + +// Mapping sub-slot function types (protocol/mapping.rs) +pub(crate) type MapLenFunc = fn(PyMapping<'_>, &VirtualMachine) -> PyResult; +pub(crate) type MapSubscriptFunc = fn(PyMapping<'_>, &PyObject, &VirtualMachine) -> PyResult; +pub(crate) type MapAssSubscriptFunc = + fn(PyMapping<'_>, &PyObject, Option, &VirtualMachine) -> PyResult<()>; + // slot_sq_length pub(crate) fn len_wrapper(obj: &PyObject, vm: &VirtualMachine) -> PyResult { let ret = vm.call_special_method(obj, identifier!(vm, __len__), ())?; @@ -331,6 +347,30 @@ macro_rules! number_binary_right_op_wrapper { |a, b, vm| vm.call_special_method(b, identifier!(vm, $name), (a.to_owned(),)) }; } +macro_rules! number_ternary_op_wrapper { + ($name:ident) => { + |a, b, c, vm: &VirtualMachine| { + let args: Vec = if vm.is_none(c) { + vec![b.to_owned()] + } else { + vec![b.to_owned(), c.to_owned()] + }; + vm.call_special_method(a, identifier!(vm, $name), args) + } + }; +} +macro_rules! number_ternary_right_op_wrapper { + ($name:ident) => { + |a, b, c, vm: &VirtualMachine| { + let args: Vec = if vm.is_none(c) { + vec![a.to_owned()] + } else { + vec![a.to_owned(), c.to_owned()] + }; + vm.call_special_method(b, identifier!(vm, $name), args) + } + }; +} fn getitem_wrapper(obj: &PyObject, needle: K, vm: &VirtualMachine) -> PyResult { vm.call_special_method(obj, identifier!(vm, __getitem__), (needle,)) } @@ -507,34 +547,32 @@ fn del_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<()> { } impl PyType { + /// Update slots based on dunder method changes + /// + /// Iterates SLOT_DEFS to find all slots matching the given name and updates them. pub(crate) fn update_slot(&self, name: &'static PyStrInterned, ctx: &Context) { debug_assert!(name.as_str().starts_with("__")); debug_assert!(name.as_str().ends_with("__")); - macro_rules! toggle_sub_slot { - ($group:ident, $name:ident, $func:expr) => {{ - if ADD { - self.slots.$group.$name.store(Some($func)); - } else { - // When deleting, re-inherit from MRO (skip self) - let inherited = self - .mro - .read() - .iter() - .skip(1) - .find_map(|cls| cls.slots.$group.$name.load()); - self.slots.$group.$name.store(inherited); - } - }}; + // Find all slot_defs matching this name and update each + for def in find_slot_defs_by_name(name.as_str()) { + self.update_one_slot::(&def.accessor, name, ctx); } + } + + /// Update a single slot + fn update_one_slot( + &self, + accessor: &SlotAccessor, + name: &'static PyStrInterned, + ctx: &Context, + ) { + use crate::builtins::descriptor::SlotFunc; - // If the method is a slot wrapper, extract and use the original slot directly. - // Otherwise use the generic wrapper. - macro_rules! update_one_slot { + // Helper macro for main slots + macro_rules! update_main_slot { ($slot:ident, $wrapper:expr, $variant:ident) => {{ - use crate::builtins::descriptor::SlotFunc; if ADD { - // Try to extract the original slot from a slot wrapper if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| { if let SlotFunc::$variant(f) = sf { Some(*f) @@ -542,142 +580,44 @@ impl PyType { None } }) { - // Found slot wrapper - use the original slot directly self.slots.$slot.store(Some(func)); } else { - // Real method found or no method - use generic wrapper self.slots.$slot.store(Some($wrapper)); } } else { - // When deleting, re-inherit from MRO (skip self) - let inherited = self - .mro - .read() - .iter() - .skip(1) - .find_map(|cls| cls.slots.$slot.load()); - self.slots.$slot.store(inherited); - } - }}; - } - - // For setattro slot: matches SetAttro or DelAttro - macro_rules! update_setattro { - ($wrapper:expr) => {{ - use crate::builtins::descriptor::SlotFunc; - if ADD { - if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| match sf { - SlotFunc::SetAttro(f) | SlotFunc::DelAttro(f) => Some(*f), - _ => None, - }) { - self.slots.setattro.store(Some(func)); - } else { - self.slots.setattro.store(Some($wrapper)); - } - } else { - let inherited = self - .mro - .read() - .iter() - .skip(1) - .find_map(|cls| cls.slots.setattro.load()); - self.slots.setattro.store(inherited); + accessor.inherit_from_mro(self); } }}; } - // For richcompare slot: matches RichCompare with any op - macro_rules! update_richcompare { - ($wrapper:expr) => {{ - use crate::builtins::descriptor::SlotFunc; + // Helper macro for number/sequence/mapping sub-slots + macro_rules! update_sub_slot { + ($group:ident, $slot:ident, $wrapper:expr, $variant:ident) => {{ if ADD { if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| { - if let SlotFunc::RichCompare(f, _) = sf { + if let SlotFunc::$variant(f) = sf { Some(*f) } else { None } }) { - self.slots.richcompare.store(Some(func)); - } else { - self.slots.richcompare.store(Some($wrapper)); - } - } else { - let inherited = self - .mro - .read() - .iter() - .skip(1) - .find_map(|cls| cls.slots.richcompare.load()); - self.slots.richcompare.store(inherited); - } - }}; - } - - // For descr_set slot: matches DescrSet or DescrDel - macro_rules! update_descr_set { - ($wrapper:expr) => {{ - use crate::builtins::descriptor::SlotFunc; - if ADD { - if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| match sf { - SlotFunc::DescrSet(f) | SlotFunc::DescrDel(f) => Some(*f), - _ => None, - }) { - self.slots.descr_set.store(Some(func)); + self.slots.$group.$slot.store(Some(func)); } else { - self.slots.descr_set.store(Some($wrapper)); + self.slots.$group.$slot.store(Some($wrapper)); } } else { - let inherited = self - .mro - .read() - .iter() - .skip(1) - .find_map(|cls| cls.slots.descr_set.load()); - self.slots.descr_set.store(inherited); + accessor.inherit_from_mro(self); } }}; } - match name { - _ if name == identifier!(ctx, __len__) => { - toggle_sub_slot!(as_sequence, length, |seq, vm| len_wrapper(seq.obj, vm)); - toggle_sub_slot!(as_mapping, length, |mapping, vm| len_wrapper( - mapping.obj, - vm - )); - } - _ if name == identifier!(ctx, __getitem__) => { - toggle_sub_slot!(as_sequence, item, |seq, i, vm| getitem_wrapper( - seq.obj, i, vm - )); - toggle_sub_slot!(as_mapping, subscript, |mapping, key, vm| { - getitem_wrapper(mapping.obj, key, vm) - }); - } - _ if name == identifier!(ctx, __setitem__) || name == identifier!(ctx, __delitem__) => { - toggle_sub_slot!(as_sequence, ass_item, |seq, i, value, vm| { - setitem_wrapper(seq.obj, i, value, vm) - }); - toggle_sub_slot!(as_mapping, ass_subscript, |mapping, key, value, vm| { - setitem_wrapper(mapping.obj, key, value, vm) - }); - } - _ if name == identifier!(ctx, __contains__) => { - toggle_sub_slot!(as_sequence, contains, |seq, needle, vm| { - contains_wrapper(seq.obj, needle, vm) - }); - } - _ if name == identifier!(ctx, __repr__) => { - update_one_slot!(repr, repr_wrapper, Repr); - } - _ if name == identifier!(ctx, __str__) => { - update_one_slot!(str, str_wrapper, Str); - } - _ if name == identifier!(ctx, __hash__) => { - use crate::builtins::descriptor::SlotFunc; + match accessor { + // === Main slots === + SlotAccessor::Repr => update_main_slot!(repr, repr_wrapper, Repr), + SlotAccessor::Str => update_main_slot!(str, str_wrapper, Str), + SlotAccessor::Hash => { + // Special handling for __hash__ = None if ADD { - // Check for __hash__ = None first (descr == Py_None) let method = self.attributes.read().get(name).cloned().or_else(|| { self.mro .read() @@ -699,315 +639,535 @@ impl PyType { self.slots.hash.store(Some(hash_wrapper)); } } else { - let inherited = self - .mro - .read() - .iter() - .skip(1) - .find_map(|cls| cls.slots.hash.load()); - self.slots.hash.store(inherited); + accessor.inherit_from_mro(self); } } - _ if name == identifier!(ctx, __call__) => { - update_one_slot!(call, call_wrapper, Call); - } - _ if name == identifier!(ctx, __getattr__) - || name == identifier!(ctx, __getattribute__) => - { - update_one_slot!(getattro, getattro_wrapper, GetAttro); - } - _ if name == identifier!(ctx, __setattr__) || name == identifier!(ctx, __delattr__) => { - update_setattro!(setattro_wrapper); - } - _ if name == identifier!(ctx, __eq__) - || name == identifier!(ctx, __ne__) - || name == identifier!(ctx, __le__) - || name == identifier!(ctx, __lt__) - || name == identifier!(ctx, __ge__) - || name == identifier!(ctx, __gt__) => - { - update_richcompare!(richcompare_wrapper); - } - _ if name == identifier!(ctx, __iter__) => { - update_one_slot!(iter, iter_wrapper, Iter); - } - _ if name == identifier!(ctx, __next__) => { - update_one_slot!(iternext, iternext_wrapper, IterNext); - } - _ if name == identifier!(ctx, __get__) => { - update_one_slot!(descr_get, descr_get_wrapper, DescrGet); - } - _ if name == identifier!(ctx, __set__) || name == identifier!(ctx, __delete__) => { - update_descr_set!(descr_set_wrapper); - } - _ if name == identifier!(ctx, __init__) => { - update_one_slot!(init, init_wrapper, Init); - } - _ if name == identifier!(ctx, __new__) => { + SlotAccessor::Call => update_main_slot!(call, call_wrapper, Call), + SlotAccessor::Iter => update_main_slot!(iter, iter_wrapper, Iter), + SlotAccessor::IterNext => update_main_slot!(iternext, iternext_wrapper, IterNext), + SlotAccessor::Init => update_main_slot!(init, init_wrapper, Init), + SlotAccessor::New => { // __new__ is not wrapped via PyWrapper if ADD { self.slots.new.store(Some(new_wrapper)); } else { - let inherited = self - .mro - .read() - .iter() - .skip(1) - .find_map(|cls| cls.slots.new.load()); - self.slots.new.store(inherited); + accessor.inherit_from_mro(self); } } - _ if name == identifier!(ctx, __del__) => { - update_one_slot!(del, del_wrapper, Del); - } - _ if name == identifier!(ctx, __bool__) => { - toggle_sub_slot!(as_number, boolean, bool_wrapper); - } - _ if name == identifier!(ctx, __int__) => { - toggle_sub_slot!(as_number, int, number_unary_op_wrapper!(__int__)); + SlotAccessor::Del => update_main_slot!(del, del_wrapper, Del), + SlotAccessor::GetAttro => update_main_slot!(getattro, getattro_wrapper, GetAttro), + SlotAccessor::SetAttro | SlotAccessor::DelAttro => { + // SetAttro and DelAttro share the same slot + if ADD { + if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| match sf { + SlotFunc::SetAttro(f) | SlotFunc::DelAttro(f) => Some(*f), + _ => None, + }) { + self.slots.setattro.store(Some(func)); + } else { + self.slots.setattro.store(Some(setattro_wrapper)); + } + } else { + accessor.inherit_from_mro(self); + } } - _ if name == identifier!(ctx, __index__) => { - toggle_sub_slot!(as_number, index, number_unary_op_wrapper!(__index__)); + SlotAccessor::DescrGet => update_main_slot!(descr_get, descr_get_wrapper, DescrGet), + SlotAccessor::DescrSet | SlotAccessor::DescrDel => { + // DescrSet and DescrDel share the same slot + if ADD { + if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| match sf { + SlotFunc::DescrSet(f) | SlotFunc::DescrDel(f) => Some(*f), + _ => None, + }) { + self.slots.descr_set.store(Some(func)); + } else { + self.slots.descr_set.store(Some(descr_set_wrapper)); + } + } else { + accessor.inherit_from_mro(self); + } } - _ if name == identifier!(ctx, __float__) => { - toggle_sub_slot!(as_number, float, number_unary_op_wrapper!(__float__)); + + // === Rich compare (all share richcompare slot) === + SlotAccessor::RichCompareLt + | SlotAccessor::RichCompareLe + | SlotAccessor::RichCompareEq + | SlotAccessor::RichCompareNe + | SlotAccessor::RichCompareGt + | SlotAccessor::RichCompareGe => { + if ADD { + if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| { + if let SlotFunc::RichCompare(f, _) = sf { + Some(*f) + } else { + None + } + }) { + self.slots.richcompare.store(Some(func)); + } else { + self.slots.richcompare.store(Some(richcompare_wrapper)); + } + } else { + accessor.inherit_from_mro(self); + } } - _ if name == identifier!(ctx, __add__) => { - toggle_sub_slot!(as_number, add, number_binary_op_wrapper!(__add__)); + + // === Number binary operations === + SlotAccessor::NumAdd => { + update_sub_slot!( + as_number, + add, + number_binary_op_wrapper!(__add__), + NumBinary + ) } - _ if name == identifier!(ctx, __radd__) => { - toggle_sub_slot!( + SlotAccessor::NumRightAdd => { + update_sub_slot!( as_number, right_add, - number_binary_right_op_wrapper!(__radd__) - ); + number_binary_right_op_wrapper!(__radd__), + NumBinary + ) } - _ if name == identifier!(ctx, __iadd__) => { - toggle_sub_slot!(as_number, inplace_add, number_binary_op_wrapper!(__iadd__)); + SlotAccessor::NumInplaceAdd => { + update_sub_slot!( + as_number, + inplace_add, + number_binary_op_wrapper!(__iadd__), + NumBinary + ) } - _ if name == identifier!(ctx, __sub__) => { - toggle_sub_slot!(as_number, subtract, number_binary_op_wrapper!(__sub__)); + SlotAccessor::NumSubtract => { + update_sub_slot!( + as_number, + subtract, + number_binary_op_wrapper!(__sub__), + NumBinary + ) } - _ if name == identifier!(ctx, __rsub__) => { - toggle_sub_slot!( + SlotAccessor::NumRightSubtract => { + update_sub_slot!( as_number, right_subtract, - number_binary_right_op_wrapper!(__rsub__) - ); + number_binary_right_op_wrapper!(__rsub__), + NumBinary + ) } - _ if name == identifier!(ctx, __isub__) => { - toggle_sub_slot!( + SlotAccessor::NumInplaceSubtract => { + update_sub_slot!( as_number, inplace_subtract, - number_binary_op_wrapper!(__isub__) - ); + number_binary_op_wrapper!(__isub__), + NumBinary + ) } - _ if name == identifier!(ctx, __mul__) => { - toggle_sub_slot!(as_number, multiply, number_binary_op_wrapper!(__mul__)); + SlotAccessor::NumMultiply => { + update_sub_slot!( + as_number, + multiply, + number_binary_op_wrapper!(__mul__), + NumBinary + ) } - _ if name == identifier!(ctx, __rmul__) => { - toggle_sub_slot!( + SlotAccessor::NumRightMultiply => { + update_sub_slot!( as_number, right_multiply, - number_binary_right_op_wrapper!(__rmul__) - ); + number_binary_right_op_wrapper!(__rmul__), + NumBinary + ) } - _ if name == identifier!(ctx, __imul__) => { - toggle_sub_slot!( + SlotAccessor::NumInplaceMultiply => { + update_sub_slot!( as_number, inplace_multiply, - number_binary_op_wrapper!(__imul__) - ); + number_binary_op_wrapper!(__imul__), + NumBinary + ) } - _ if name == identifier!(ctx, __mod__) => { - toggle_sub_slot!(as_number, remainder, number_binary_op_wrapper!(__mod__)); + SlotAccessor::NumRemainder => { + update_sub_slot!( + as_number, + remainder, + number_binary_op_wrapper!(__mod__), + NumBinary + ) } - _ if name == identifier!(ctx, __rmod__) => { - toggle_sub_slot!( + SlotAccessor::NumRightRemainder => { + update_sub_slot!( as_number, right_remainder, - number_binary_right_op_wrapper!(__rmod__) - ); + number_binary_right_op_wrapper!(__rmod__), + NumBinary + ) } - _ if name == identifier!(ctx, __imod__) => { - toggle_sub_slot!( + SlotAccessor::NumInplaceRemainder => { + update_sub_slot!( as_number, inplace_remainder, - number_binary_op_wrapper!(__imod__) - ); + number_binary_op_wrapper!(__imod__), + NumBinary + ) } - _ if name == identifier!(ctx, __divmod__) => { - toggle_sub_slot!(as_number, divmod, number_binary_op_wrapper!(__divmod__)); + SlotAccessor::NumDivmod => { + update_sub_slot!( + as_number, + divmod, + number_binary_op_wrapper!(__divmod__), + NumBinary + ) } - _ if name == identifier!(ctx, __rdivmod__) => { - toggle_sub_slot!( + SlotAccessor::NumRightDivmod => { + update_sub_slot!( as_number, right_divmod, - number_binary_right_op_wrapper!(__rdivmod__) - ); + number_binary_right_op_wrapper!(__rdivmod__), + NumBinary + ) } - _ if name == identifier!(ctx, __pow__) => { - toggle_sub_slot!(as_number, power, |a, b, c, vm| { - let args = if vm.is_none(c) { - vec![b.to_owned()] - } else { - vec![b.to_owned(), c.to_owned()] - }; - vm.call_special_method(a, identifier!(vm, __pow__), args) - }); - } - _ if name == identifier!(ctx, __rpow__) => { - toggle_sub_slot!(as_number, right_power, |a, b, c, vm| { - let args = if vm.is_none(c) { - vec![a.to_owned()] - } else { - vec![a.to_owned(), c.to_owned()] - }; - vm.call_special_method(b, identifier!(vm, __rpow__), args) - }); + SlotAccessor::NumPower => { + update_sub_slot!( + as_number, + power, + number_ternary_op_wrapper!(__pow__), + NumTernary + ) + } + SlotAccessor::NumRightPower => { + update_sub_slot!( + as_number, + right_power, + number_ternary_right_op_wrapper!(__rpow__), + NumTernary + ) + } + SlotAccessor::NumInplacePower => { + update_sub_slot!( + as_number, + inplace_power, + number_ternary_op_wrapper!(__ipow__), + NumTernary + ) + } + SlotAccessor::NumFloorDivide => { + update_sub_slot!( + as_number, + floor_divide, + number_binary_op_wrapper!(__floordiv__), + NumBinary + ) + } + SlotAccessor::NumRightFloorDivide => { + update_sub_slot!( + as_number, + right_floor_divide, + number_binary_right_op_wrapper!(__rfloordiv__), + NumBinary + ) + } + SlotAccessor::NumInplaceFloorDivide => { + update_sub_slot!( + as_number, + inplace_floor_divide, + number_binary_op_wrapper!(__ifloordiv__), + NumBinary + ) + } + SlotAccessor::NumTrueDivide => { + update_sub_slot!( + as_number, + true_divide, + number_binary_op_wrapper!(__truediv__), + NumBinary + ) + } + SlotAccessor::NumRightTrueDivide => { + update_sub_slot!( + as_number, + right_true_divide, + number_binary_right_op_wrapper!(__rtruediv__), + NumBinary + ) + } + SlotAccessor::NumInplaceTrueDivide => { + update_sub_slot!( + as_number, + inplace_true_divide, + number_binary_op_wrapper!(__itruediv__), + NumBinary + ) + } + SlotAccessor::NumMatrixMultiply => { + update_sub_slot!( + as_number, + matrix_multiply, + number_binary_op_wrapper!(__matmul__), + NumBinary + ) } - _ if name == identifier!(ctx, __ipow__) => { - toggle_sub_slot!(as_number, inplace_power, |a, b, _, vm| { - vm.call_special_method(a, identifier!(vm, __ipow__), (b.to_owned(),)) - }); + SlotAccessor::NumRightMatrixMultiply => { + update_sub_slot!( + as_number, + right_matrix_multiply, + number_binary_right_op_wrapper!(__rmatmul__), + NumBinary + ) + } + SlotAccessor::NumInplaceMatrixMultiply => { + update_sub_slot!( + as_number, + inplace_matrix_multiply, + number_binary_op_wrapper!(__imatmul__), + NumBinary + ) } - _ if name == identifier!(ctx, __lshift__) => { - toggle_sub_slot!(as_number, lshift, number_binary_op_wrapper!(__lshift__)); + + // === Number bitwise operations === + SlotAccessor::NumLshift => { + update_sub_slot!( + as_number, + lshift, + number_binary_op_wrapper!(__lshift__), + NumBinary + ) } - _ if name == identifier!(ctx, __rlshift__) => { - toggle_sub_slot!( + SlotAccessor::NumRightLshift => { + update_sub_slot!( as_number, right_lshift, - number_binary_right_op_wrapper!(__rlshift__) - ); + number_binary_right_op_wrapper!(__rlshift__), + NumBinary + ) } - _ if name == identifier!(ctx, __ilshift__) => { - toggle_sub_slot!( + SlotAccessor::NumInplaceLshift => { + update_sub_slot!( as_number, inplace_lshift, - number_binary_op_wrapper!(__ilshift__) - ); + number_binary_op_wrapper!(__ilshift__), + NumBinary + ) } - _ if name == identifier!(ctx, __rshift__) => { - toggle_sub_slot!(as_number, rshift, number_binary_op_wrapper!(__rshift__)); + SlotAccessor::NumRshift => { + update_sub_slot!( + as_number, + rshift, + number_binary_op_wrapper!(__rshift__), + NumBinary + ) } - _ if name == identifier!(ctx, __rrshift__) => { - toggle_sub_slot!( + SlotAccessor::NumRightRshift => { + update_sub_slot!( as_number, right_rshift, - number_binary_right_op_wrapper!(__rrshift__) - ); + number_binary_right_op_wrapper!(__rrshift__), + NumBinary + ) } - _ if name == identifier!(ctx, __irshift__) => { - toggle_sub_slot!( + SlotAccessor::NumInplaceRshift => { + update_sub_slot!( as_number, inplace_rshift, - number_binary_op_wrapper!(__irshift__) - ); + number_binary_op_wrapper!(__irshift__), + NumBinary + ) } - _ if name == identifier!(ctx, __and__) => { - toggle_sub_slot!(as_number, and, number_binary_op_wrapper!(__and__)); + SlotAccessor::NumAnd => { + update_sub_slot!( + as_number, + and, + number_binary_op_wrapper!(__and__), + NumBinary + ) } - _ if name == identifier!(ctx, __rand__) => { - toggle_sub_slot!( + SlotAccessor::NumRightAnd => { + update_sub_slot!( as_number, right_and, - number_binary_right_op_wrapper!(__rand__) - ); + number_binary_right_op_wrapper!(__rand__), + NumBinary + ) } - _ if name == identifier!(ctx, __iand__) => { - toggle_sub_slot!(as_number, inplace_and, number_binary_op_wrapper!(__iand__)); + SlotAccessor::NumInplaceAnd => { + update_sub_slot!( + as_number, + inplace_and, + number_binary_op_wrapper!(__iand__), + NumBinary + ) } - _ if name == identifier!(ctx, __xor__) => { - toggle_sub_slot!(as_number, xor, number_binary_op_wrapper!(__xor__)); + SlotAccessor::NumXor => { + update_sub_slot!( + as_number, + xor, + number_binary_op_wrapper!(__xor__), + NumBinary + ) } - _ if name == identifier!(ctx, __rxor__) => { - toggle_sub_slot!( + SlotAccessor::NumRightXor => { + update_sub_slot!( as_number, right_xor, - number_binary_right_op_wrapper!(__rxor__) - ); + number_binary_right_op_wrapper!(__rxor__), + NumBinary + ) } - _ if name == identifier!(ctx, __ixor__) => { - toggle_sub_slot!(as_number, inplace_xor, number_binary_op_wrapper!(__ixor__)); + SlotAccessor::NumInplaceXor => { + update_sub_slot!( + as_number, + inplace_xor, + number_binary_op_wrapper!(__ixor__), + NumBinary + ) } - _ if name == identifier!(ctx, __or__) => { - toggle_sub_slot!(as_number, or, number_binary_op_wrapper!(__or__)); + SlotAccessor::NumOr => { + update_sub_slot!(as_number, or, number_binary_op_wrapper!(__or__), NumBinary) } - _ if name == identifier!(ctx, __ror__) => { - toggle_sub_slot!( + SlotAccessor::NumRightOr => { + update_sub_slot!( as_number, right_or, - number_binary_right_op_wrapper!(__ror__) - ); + number_binary_right_op_wrapper!(__ror__), + NumBinary + ) } - _ if name == identifier!(ctx, __ior__) => { - toggle_sub_slot!(as_number, inplace_or, number_binary_op_wrapper!(__ior__)); - } - _ if name == identifier!(ctx, __floordiv__) => { - toggle_sub_slot!( + SlotAccessor::NumInplaceOr => { + update_sub_slot!( as_number, - floor_divide, - number_binary_op_wrapper!(__floordiv__) - ); + inplace_or, + number_binary_op_wrapper!(__ior__), + NumBinary + ) } - _ if name == identifier!(ctx, __rfloordiv__) => { - toggle_sub_slot!( + + // === Number unary operations === + SlotAccessor::NumNegative => { + update_sub_slot!( as_number, - right_floor_divide, - number_binary_right_op_wrapper!(__rfloordiv__) - ); + negative, + number_unary_op_wrapper!(__neg__), + NumUnary + ) } - _ if name == identifier!(ctx, __ifloordiv__) => { - toggle_sub_slot!( + SlotAccessor::NumPositive => { + update_sub_slot!( as_number, - inplace_floor_divide, - number_binary_op_wrapper!(__ifloordiv__) - ); + positive, + number_unary_op_wrapper!(__pos__), + NumUnary + ) } - _ if name == identifier!(ctx, __truediv__) => { - toggle_sub_slot!( + SlotAccessor::NumAbsolute => { + update_sub_slot!( as_number, - true_divide, - number_binary_op_wrapper!(__truediv__) - ); + absolute, + number_unary_op_wrapper!(__abs__), + NumUnary + ) } - _ if name == identifier!(ctx, __rtruediv__) => { - toggle_sub_slot!( + SlotAccessor::NumInvert => { + update_sub_slot!( as_number, - right_true_divide, - number_binary_right_op_wrapper!(__rtruediv__) - ); + invert, + number_unary_op_wrapper!(__invert__), + NumUnary + ) } - _ if name == identifier!(ctx, __itruediv__) => { - toggle_sub_slot!( - as_number, - inplace_true_divide, - number_binary_op_wrapper!(__itruediv__) - ); + SlotAccessor::NumBoolean => { + update_sub_slot!(as_number, boolean, bool_wrapper, NumBoolean) } - _ if name == identifier!(ctx, __matmul__) => { - toggle_sub_slot!( - as_number, - matrix_multiply, - number_binary_op_wrapper!(__matmul__) - ); + SlotAccessor::NumInt => { + update_sub_slot!(as_number, int, number_unary_op_wrapper!(__int__), NumUnary) } - _ if name == identifier!(ctx, __rmatmul__) => { - toggle_sub_slot!( + SlotAccessor::NumFloat => { + update_sub_slot!( as_number, - right_matrix_multiply, - number_binary_right_op_wrapper!(__rmatmul__) - ); + float, + number_unary_op_wrapper!(__float__), + NumUnary + ) } - _ if name == identifier!(ctx, __imatmul__) => { - toggle_sub_slot!( + SlotAccessor::NumIndex => { + update_sub_slot!( as_number, - inplace_matrix_multiply, - number_binary_op_wrapper!(__imatmul__) - ); + index, + number_unary_op_wrapper!(__index__), + NumUnary + ) + } + + // === Sequence slots === + SlotAccessor::SeqLength => { + update_sub_slot!( + as_sequence, + length, + |seq, vm| len_wrapper(seq.obj, vm), + SeqLength + ) + } + SlotAccessor::SeqConcat | SlotAccessor::SeqInplaceConcat => { + // Sequence concat uses sq_concat slot - no generic wrapper needed + // (handled by number protocol fallback) + if !ADD { + accessor.inherit_from_mro(self); + } + } + SlotAccessor::SeqRepeat | SlotAccessor::SeqInplaceRepeat => { + // Sequence repeat uses sq_repeat slot - no generic wrapper needed + // (handled by number protocol fallback) + if !ADD { + accessor.inherit_from_mro(self); + } + } + SlotAccessor::SeqItem => { + update_sub_slot!( + as_sequence, + item, + |seq, i, vm| getitem_wrapper(seq.obj, i, vm), + SeqItem + ) + } + SlotAccessor::SeqAssItem => { + update_sub_slot!( + as_sequence, + ass_item, + |seq, i, value, vm| setitem_wrapper(seq.obj, i, value, vm), + SeqAssItem + ) + } + SlotAccessor::SeqContains => { + update_sub_slot!( + as_sequence, + contains, + |seq, needle, vm| contains_wrapper(seq.obj, needle, vm), + SeqContains + ) + } + + // === Mapping slots === + SlotAccessor::MapLength => { + update_sub_slot!( + as_mapping, + length, + |mapping, vm| len_wrapper(mapping.obj, vm), + MapLength + ) + } + SlotAccessor::MapSubscript => { + update_sub_slot!( + as_mapping, + subscript, + |mapping, key, vm| getitem_wrapper(mapping.obj, key, vm), + MapSubscript + ) + } + SlotAccessor::MapAssSubscript => { + update_sub_slot!( + as_mapping, + ass_subscript, + |mapping, key, value, vm| setitem_wrapper(mapping.obj, key, value, vm), + MapAssSubscript + ) } - _ => {} } } diff --git a/crates/vm/src/types/slot_defs.rs b/crates/vm/src/types/slot_defs.rs new file mode 100644 index 0000000000..1f6ba64aa6 --- /dev/null +++ b/crates/vm/src/types/slot_defs.rs @@ -0,0 +1,1235 @@ +//! Slot definitions array +//! +//! This module provides a centralized array of all slot definitions, +//! enabling automatic wrapper generation and slot updates. + +use super::{PyComparisonOp, PyTypeSlots}; +use crate::builtins::descriptor::SlotFunc; +use crate::protocol::{PyNumberBinaryFunc, PyNumberSlots}; + +/// Slot definition entry +#[derive(Clone, Copy)] +pub struct SlotDef { + /// Method name ("__init__", "__add__", etc.) + pub name: &'static str, + + /// Slot accessor (which slot field to access) + pub accessor: SlotAccessor, + + /// Documentation string + pub doc: &'static str, +} + +/// Slot accessor +/// +/// Flat enum with all slot types inlined for `#[repr(u8)]` support. +/// Each variant directly corresponds to a slot field in PyTypeSlots. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum SlotAccessor { + // Main slots + Hash, + Repr, + Str, + Call, + Iter, + IterNext, + Init, + New, + Del, + GetAttro, + SetAttro, + DelAttro, + DescrGet, + DescrSet, + DescrDel, + + // Rich compare - tp_richcompare with different ops + RichCompareLt, + RichCompareLe, + RichCompareEq, + RichCompareNe, + RichCompareGt, + RichCompareGe, + + // Number binary operations + NumAdd, + NumRightAdd, + NumInplaceAdd, + NumSubtract, + NumRightSubtract, + NumInplaceSubtract, + NumMultiply, + NumRightMultiply, + NumInplaceMultiply, + NumRemainder, + NumRightRemainder, + NumInplaceRemainder, + NumDivmod, + NumRightDivmod, + NumPower, + NumRightPower, + NumInplacePower, + NumFloorDivide, + NumRightFloorDivide, + NumInplaceFloorDivide, + NumTrueDivide, + NumRightTrueDivide, + NumInplaceTrueDivide, + NumMatrixMultiply, + NumRightMatrixMultiply, + NumInplaceMatrixMultiply, + + // Bitwise operations + NumLshift, + NumRightLshift, + NumInplaceLshift, + NumRshift, + NumRightRshift, + NumInplaceRshift, + NumAnd, + NumRightAnd, + NumInplaceAnd, + NumXor, + NumRightXor, + NumInplaceXor, + NumOr, + NumRightOr, + NumInplaceOr, + + // Number unary operations + NumNegative, + NumPositive, + NumAbsolute, + NumInvert, + NumBoolean, + NumInt, + NumFloat, + NumIndex, + + // Sequence slots + SeqLength, + SeqConcat, + SeqRepeat, + SeqItem, + SeqAssItem, + SeqContains, + SeqInplaceConcat, + SeqInplaceRepeat, + + // Mapping slots + MapLength, + MapSubscript, + MapAssSubscript, +} + +// SlotAccessor implementation + +impl SlotAccessor { + /// Get the PyComparisonOp for RichCompare variants + pub fn rich_compare_op(&self) -> Option { + match self { + Self::RichCompareLt => Some(PyComparisonOp::Lt), + Self::RichCompareLe => Some(PyComparisonOp::Le), + Self::RichCompareEq => Some(PyComparisonOp::Eq), + Self::RichCompareNe => Some(PyComparisonOp::Ne), + Self::RichCompareGt => Some(PyComparisonOp::Gt), + Self::RichCompareGe => Some(PyComparisonOp::Ge), + _ => None, + } + } + + /// Check if this accessor refers to a shared slot + /// + /// Shared slots are used by multiple dunder methods: + /// - SetAttro/DelAttro share setattro slot + /// - RichCompare variants share richcompare slot + /// - DescrSet/DescrDel share descr_set slot + /// - SeqAssItem is used by __setitem__ and __delitem__ + /// - MapAssSubscript is used by __setitem__ and __delitem__ + pub fn is_shared_slot(&self) -> bool { + matches!( + self, + Self::SetAttro + | Self::DelAttro + | Self::RichCompareLt + | Self::RichCompareLe + | Self::RichCompareEq + | Self::RichCompareNe + | Self::RichCompareGt + | Self::RichCompareGe + | Self::DescrSet + | Self::DescrDel + | Self::SeqAssItem + | Self::MapAssSubscript + ) + } + + /// Get the underlying slot accessor for shared slots + /// + /// For SetAttro/DelAttro, returns SetAttro (they share the same slot). + /// For DescrSet/DescrDel, returns DescrSet (they share the same slot). + pub fn canonical(&self) -> SlotAccessor { + match self { + Self::DelAttro => Self::SetAttro, + Self::DescrDel => Self::DescrSet, + _ => *self, + } + } + + /// Extract the raw function pointer from a SlotFunc if it matches this accessor's type + pub fn extract_from_slot_func(&self, slot_func: &SlotFunc) -> bool { + match self { + // Main slots + Self::Hash => matches!(slot_func, SlotFunc::Hash(_)), + Self::Repr => matches!(slot_func, SlotFunc::Repr(_)), + Self::Str => matches!(slot_func, SlotFunc::Str(_)), + Self::Call => matches!(slot_func, SlotFunc::Call(_)), + Self::Iter => matches!(slot_func, SlotFunc::Iter(_)), + Self::IterNext => matches!(slot_func, SlotFunc::IterNext(_)), + Self::Init => matches!(slot_func, SlotFunc::Init(_)), + Self::Del => matches!(slot_func, SlotFunc::Del(_)), + Self::GetAttro => matches!(slot_func, SlotFunc::GetAttro(_)), + Self::SetAttro | Self::DelAttro => { + matches!(slot_func, SlotFunc::SetAttro(_) | SlotFunc::DelAttro(_)) + } + Self::DescrGet => matches!(slot_func, SlotFunc::DescrGet(_)), + Self::DescrSet | Self::DescrDel => { + matches!(slot_func, SlotFunc::DescrSet(_) | SlotFunc::DescrDel(_)) + } + // RichCompare + Self::RichCompareLt + | Self::RichCompareLe + | Self::RichCompareEq + | Self::RichCompareNe + | Self::RichCompareGt + | Self::RichCompareGe => matches!(slot_func, SlotFunc::RichCompare(_, _)), + // Number - Power (ternary) + Self::NumPower | Self::NumRightPower | Self::NumInplacePower => { + matches!(slot_func, SlotFunc::NumTernary(_)) + } + // Number - Boolean + Self::NumBoolean => matches!(slot_func, SlotFunc::NumBoolean(_)), + // Number - Unary + Self::NumNegative + | Self::NumPositive + | Self::NumAbsolute + | Self::NumInvert + | Self::NumInt + | Self::NumFloat + | Self::NumIndex => matches!(slot_func, SlotFunc::NumUnary(_)), + // Number - Binary (all others) + Self::NumAdd + | Self::NumRightAdd + | Self::NumInplaceAdd + | Self::NumSubtract + | Self::NumRightSubtract + | Self::NumInplaceSubtract + | Self::NumMultiply + | Self::NumRightMultiply + | Self::NumInplaceMultiply + | Self::NumRemainder + | Self::NumRightRemainder + | Self::NumInplaceRemainder + | Self::NumDivmod + | Self::NumRightDivmod + | Self::NumFloorDivide + | Self::NumRightFloorDivide + | Self::NumInplaceFloorDivide + | Self::NumTrueDivide + | Self::NumRightTrueDivide + | Self::NumInplaceTrueDivide + | Self::NumMatrixMultiply + | Self::NumRightMatrixMultiply + | Self::NumInplaceMatrixMultiply + | Self::NumLshift + | Self::NumRightLshift + | Self::NumInplaceLshift + | Self::NumRshift + | Self::NumRightRshift + | Self::NumInplaceRshift + | Self::NumAnd + | Self::NumRightAnd + | Self::NumInplaceAnd + | Self::NumXor + | Self::NumRightXor + | Self::NumInplaceXor + | Self::NumOr + | Self::NumRightOr + | Self::NumInplaceOr => matches!(slot_func, SlotFunc::NumBinary(_)), + // Sequence + Self::SeqLength => matches!(slot_func, SlotFunc::SeqLength(_)), + Self::SeqConcat | Self::SeqInplaceConcat => matches!(slot_func, SlotFunc::SeqConcat(_)), + Self::SeqRepeat | Self::SeqInplaceRepeat => matches!(slot_func, SlotFunc::SeqRepeat(_)), + Self::SeqItem => matches!(slot_func, SlotFunc::SeqItem(_)), + Self::SeqAssItem => matches!(slot_func, SlotFunc::SeqAssItem(_)), + Self::SeqContains => matches!(slot_func, SlotFunc::SeqContains(_)), + // Mapping + Self::MapLength => matches!(slot_func, SlotFunc::MapLength(_)), + Self::MapSubscript => matches!(slot_func, SlotFunc::MapSubscript(_)), + Self::MapAssSubscript => matches!(slot_func, SlotFunc::MapAssSubscript(_)), + // New has no wrapper + Self::New => false, + } + } + + /// Inherit slot value from MRO + pub fn inherit_from_mro(&self, typ: &crate::builtins::PyType) { + // Note: typ.mro does NOT include typ itself, so we iterate all elements + let mro = typ.mro.read(); + + macro_rules! inherit_main { + ($slot:ident) => {{ + let inherited = mro.iter().find_map(|cls| cls.slots.$slot.load()); + typ.slots.$slot.store(inherited); + }}; + } + + macro_rules! inherit_number { + ($slot:ident) => {{ + let inherited = mro.iter().find_map(|cls| cls.slots.as_number.$slot.load()); + typ.slots.as_number.$slot.store(inherited); + }}; + } + + macro_rules! inherit_sequence { + ($slot:ident) => {{ + let inherited = mro + .iter() + .find_map(|cls| cls.slots.as_sequence.$slot.load()); + typ.slots.as_sequence.$slot.store(inherited); + }}; + } + + macro_rules! inherit_mapping { + ($slot:ident) => {{ + let inherited = mro.iter().find_map(|cls| cls.slots.as_mapping.$slot.load()); + typ.slots.as_mapping.$slot.store(inherited); + }}; + } + + match self { + // Main slots + Self::Hash => inherit_main!(hash), + Self::Repr => inherit_main!(repr), + Self::Str => inherit_main!(str), + Self::Call => inherit_main!(call), + Self::Iter => inherit_main!(iter), + Self::IterNext => inherit_main!(iternext), + Self::Init => inherit_main!(init), + Self::New => inherit_main!(new), + Self::Del => inherit_main!(del), + Self::GetAttro => inherit_main!(getattro), + Self::SetAttro | Self::DelAttro => inherit_main!(setattro), + Self::DescrGet => inherit_main!(descr_get), + Self::DescrSet | Self::DescrDel => inherit_main!(descr_set), + + // RichCompare + Self::RichCompareLt + | Self::RichCompareLe + | Self::RichCompareEq + | Self::RichCompareNe + | Self::RichCompareGt + | Self::RichCompareGe => inherit_main!(richcompare), + + // Number binary + Self::NumAdd => inherit_number!(add), + Self::NumRightAdd => inherit_number!(right_add), + Self::NumInplaceAdd => inherit_number!(inplace_add), + Self::NumSubtract => inherit_number!(subtract), + Self::NumRightSubtract => inherit_number!(right_subtract), + Self::NumInplaceSubtract => inherit_number!(inplace_subtract), + Self::NumMultiply => inherit_number!(multiply), + Self::NumRightMultiply => inherit_number!(right_multiply), + Self::NumInplaceMultiply => inherit_number!(inplace_multiply), + Self::NumRemainder => inherit_number!(remainder), + Self::NumRightRemainder => inherit_number!(right_remainder), + Self::NumInplaceRemainder => inherit_number!(inplace_remainder), + Self::NumDivmod => inherit_number!(divmod), + Self::NumRightDivmod => inherit_number!(right_divmod), + Self::NumPower => inherit_number!(power), + Self::NumRightPower => inherit_number!(right_power), + Self::NumInplacePower => inherit_number!(inplace_power), + Self::NumFloorDivide => inherit_number!(floor_divide), + Self::NumRightFloorDivide => inherit_number!(right_floor_divide), + Self::NumInplaceFloorDivide => inherit_number!(inplace_floor_divide), + Self::NumTrueDivide => inherit_number!(true_divide), + Self::NumRightTrueDivide => inherit_number!(right_true_divide), + Self::NumInplaceTrueDivide => inherit_number!(inplace_true_divide), + Self::NumMatrixMultiply => inherit_number!(matrix_multiply), + Self::NumRightMatrixMultiply => inherit_number!(right_matrix_multiply), + Self::NumInplaceMatrixMultiply => inherit_number!(inplace_matrix_multiply), + Self::NumLshift => inherit_number!(lshift), + Self::NumRightLshift => inherit_number!(right_lshift), + Self::NumInplaceLshift => inherit_number!(inplace_lshift), + Self::NumRshift => inherit_number!(rshift), + Self::NumRightRshift => inherit_number!(right_rshift), + Self::NumInplaceRshift => inherit_number!(inplace_rshift), + Self::NumAnd => inherit_number!(and), + Self::NumRightAnd => inherit_number!(right_and), + Self::NumInplaceAnd => inherit_number!(inplace_and), + Self::NumXor => inherit_number!(xor), + Self::NumRightXor => inherit_number!(right_xor), + Self::NumInplaceXor => inherit_number!(inplace_xor), + Self::NumOr => inherit_number!(or), + Self::NumRightOr => inherit_number!(right_or), + Self::NumInplaceOr => inherit_number!(inplace_or), + + // Number unary + Self::NumNegative => inherit_number!(negative), + Self::NumPositive => inherit_number!(positive), + Self::NumAbsolute => inherit_number!(absolute), + Self::NumInvert => inherit_number!(invert), + Self::NumBoolean => inherit_number!(boolean), + Self::NumInt => inherit_number!(int), + Self::NumFloat => inherit_number!(float), + Self::NumIndex => inherit_number!(index), + + // Sequence + Self::SeqLength => inherit_sequence!(length), + Self::SeqConcat => inherit_sequence!(concat), + Self::SeqRepeat => inherit_sequence!(repeat), + Self::SeqItem => inherit_sequence!(item), + Self::SeqAssItem => inherit_sequence!(ass_item), + Self::SeqContains => inherit_sequence!(contains), + Self::SeqInplaceConcat => inherit_sequence!(inplace_concat), + Self::SeqInplaceRepeat => inherit_sequence!(inplace_repeat), + + // Mapping + Self::MapLength => inherit_mapping!(length), + Self::MapSubscript => inherit_mapping!(subscript), + Self::MapAssSubscript => inherit_mapping!(ass_subscript), + } + } + + /// Copy slot from base type if self's slot is None + /// + /// Used by inherit_slots() for slot inheritance from base classes. + pub fn copyslot_if_none(&self, typ: &crate::builtins::PyType, base: &crate::builtins::PyType) { + macro_rules! copy_main { + ($slot:ident) => {{ + if typ.slots.$slot.load().is_none() { + if let Some(base_val) = base.slots.$slot.load() { + typ.slots.$slot.store(Some(base_val)); + } + } + }}; + } + + macro_rules! copy_number { + ($slot:ident) => {{ + if typ.slots.as_number.$slot.load().is_none() { + if let Some(base_val) = base.slots.as_number.$slot.load() { + typ.slots.as_number.$slot.store(Some(base_val)); + } + } + }}; + } + + macro_rules! copy_sequence { + ($slot:ident) => {{ + if typ.slots.as_sequence.$slot.load().is_none() { + if let Some(base_val) = base.slots.as_sequence.$slot.load() { + typ.slots.as_sequence.$slot.store(Some(base_val)); + } + } + }}; + } + + macro_rules! copy_mapping { + ($slot:ident) => {{ + if typ.slots.as_mapping.$slot.load().is_none() { + if let Some(base_val) = base.slots.as_mapping.$slot.load() { + typ.slots.as_mapping.$slot.store(Some(base_val)); + } + } + }}; + } + + match self { + // Main slots + Self::Hash => copy_main!(hash), + Self::Repr => copy_main!(repr), + Self::Str => copy_main!(str), + Self::Call => copy_main!(call), + Self::Iter => copy_main!(iter), + Self::IterNext => copy_main!(iternext), + Self::Init => { + // SLOTDEFINED check for multiple inheritance support + if typ.slots.init.load().is_none() + && let Some(base_val) = base.slots.init.load() + { + let slot_defined = base.base.as_ref().is_none_or(|bb| { + bb.slots.init.load().map(|v| v as usize) != Some(base_val as usize) + }); + if slot_defined { + typ.slots.init.store(Some(base_val)); + } + } + } + Self::New => {} // handled by set_new() + Self::Del => copy_main!(del), + Self::GetAttro => copy_main!(getattro), + Self::SetAttro | Self::DelAttro => copy_main!(setattro), + Self::DescrGet => copy_main!(descr_get), + Self::DescrSet | Self::DescrDel => copy_main!(descr_set), + + // RichCompare + Self::RichCompareLt + | Self::RichCompareLe + | Self::RichCompareEq + | Self::RichCompareNe + | Self::RichCompareGt + | Self::RichCompareGe => copy_main!(richcompare), + + // Number binary + Self::NumAdd => copy_number!(add), + Self::NumRightAdd => copy_number!(right_add), + Self::NumInplaceAdd => copy_number!(inplace_add), + Self::NumSubtract => copy_number!(subtract), + Self::NumRightSubtract => copy_number!(right_subtract), + Self::NumInplaceSubtract => copy_number!(inplace_subtract), + Self::NumMultiply => copy_number!(multiply), + Self::NumRightMultiply => copy_number!(right_multiply), + Self::NumInplaceMultiply => copy_number!(inplace_multiply), + Self::NumRemainder => copy_number!(remainder), + Self::NumRightRemainder => copy_number!(right_remainder), + Self::NumInplaceRemainder => copy_number!(inplace_remainder), + Self::NumDivmod => copy_number!(divmod), + Self::NumRightDivmod => copy_number!(right_divmod), + Self::NumPower => copy_number!(power), + Self::NumRightPower => copy_number!(right_power), + Self::NumInplacePower => copy_number!(inplace_power), + Self::NumFloorDivide => copy_number!(floor_divide), + Self::NumRightFloorDivide => copy_number!(right_floor_divide), + Self::NumInplaceFloorDivide => copy_number!(inplace_floor_divide), + Self::NumTrueDivide => copy_number!(true_divide), + Self::NumRightTrueDivide => copy_number!(right_true_divide), + Self::NumInplaceTrueDivide => copy_number!(inplace_true_divide), + Self::NumMatrixMultiply => copy_number!(matrix_multiply), + Self::NumRightMatrixMultiply => copy_number!(right_matrix_multiply), + Self::NumInplaceMatrixMultiply => copy_number!(inplace_matrix_multiply), + Self::NumLshift => copy_number!(lshift), + Self::NumRightLshift => copy_number!(right_lshift), + Self::NumInplaceLshift => copy_number!(inplace_lshift), + Self::NumRshift => copy_number!(rshift), + Self::NumRightRshift => copy_number!(right_rshift), + Self::NumInplaceRshift => copy_number!(inplace_rshift), + Self::NumAnd => copy_number!(and), + Self::NumRightAnd => copy_number!(right_and), + Self::NumInplaceAnd => copy_number!(inplace_and), + Self::NumXor => copy_number!(xor), + Self::NumRightXor => copy_number!(right_xor), + Self::NumInplaceXor => copy_number!(inplace_xor), + Self::NumOr => copy_number!(or), + Self::NumRightOr => copy_number!(right_or), + Self::NumInplaceOr => copy_number!(inplace_or), + + // Number unary + Self::NumNegative => copy_number!(negative), + Self::NumPositive => copy_number!(positive), + Self::NumAbsolute => copy_number!(absolute), + Self::NumInvert => copy_number!(invert), + Self::NumBoolean => copy_number!(boolean), + Self::NumInt => copy_number!(int), + Self::NumFloat => copy_number!(float), + Self::NumIndex => copy_number!(index), + + // Sequence + Self::SeqLength => copy_sequence!(length), + Self::SeqConcat => copy_sequence!(concat), + Self::SeqRepeat => copy_sequence!(repeat), + Self::SeqItem => copy_sequence!(item), + Self::SeqAssItem => copy_sequence!(ass_item), + Self::SeqContains => copy_sequence!(contains), + Self::SeqInplaceConcat => copy_sequence!(inplace_concat), + Self::SeqInplaceRepeat => copy_sequence!(inplace_repeat), + + // Mapping + Self::MapLength => copy_mapping!(length), + Self::MapSubscript => copy_mapping!(subscript), + Self::MapAssSubscript => copy_mapping!(ass_subscript), + } + } + + /// Get the slot function from PyTypeSlots, wrapped in SlotFunc + /// + /// Returns None if the slot is not set. + pub fn get_slot_func(&self, slots: &PyTypeSlots) -> Option { + match self { + // Main slots + Self::Hash => slots.hash.load().map(SlotFunc::Hash), + Self::Repr => slots.repr.load().map(SlotFunc::Repr), + Self::Str => slots.str.load().map(SlotFunc::Str), + Self::Call => slots.call.load().map(SlotFunc::Call), + Self::Iter => slots.iter.load().map(SlotFunc::Iter), + Self::IterNext => slots.iternext.load().map(SlotFunc::IterNext), + Self::Init => slots.init.load().map(SlotFunc::Init), + Self::New => None, // __new__ has special handling, no wrapper + Self::Del => slots.del.load().map(SlotFunc::Del), + Self::GetAttro => slots.getattro.load().map(SlotFunc::GetAttro), + Self::SetAttro => slots.setattro.load().map(SlotFunc::SetAttro), + Self::DelAttro => slots.setattro.load().map(SlotFunc::DelAttro), + Self::DescrGet => slots.descr_get.load().map(SlotFunc::DescrGet), + Self::DescrSet => slots.descr_set.load().map(SlotFunc::DescrSet), + Self::DescrDel => slots.descr_set.load().map(SlotFunc::DescrDel), + + // RichCompare + Self::RichCompareLt => slots + .richcompare + .load() + .map(|f| SlotFunc::RichCompare(f, PyComparisonOp::Lt)), + Self::RichCompareLe => slots + .richcompare + .load() + .map(|f| SlotFunc::RichCompare(f, PyComparisonOp::Le)), + Self::RichCompareEq => slots + .richcompare + .load() + .map(|f| SlotFunc::RichCompare(f, PyComparisonOp::Eq)), + Self::RichCompareNe => slots + .richcompare + .load() + .map(|f| SlotFunc::RichCompare(f, PyComparisonOp::Ne)), + Self::RichCompareGt => slots + .richcompare + .load() + .map(|f| SlotFunc::RichCompare(f, PyComparisonOp::Gt)), + Self::RichCompareGe => slots + .richcompare + .load() + .map(|f| SlotFunc::RichCompare(f, PyComparisonOp::Ge)), + + // Number - binary + Self::NumAdd => Self::get_number_slot(&slots.as_number, |s| s.add.load()), + Self::NumRightAdd => Self::get_number_slot(&slots.as_number, |s| s.right_add.load()), + Self::NumInplaceAdd => { + Self::get_number_slot(&slots.as_number, |s| s.inplace_add.load()) + } + Self::NumSubtract => Self::get_number_slot(&slots.as_number, |s| s.subtract.load()), + Self::NumRightSubtract => { + Self::get_number_slot(&slots.as_number, |s| s.right_subtract.load()) + } + Self::NumInplaceSubtract => { + Self::get_number_slot(&slots.as_number, |s| s.inplace_subtract.load()) + } + Self::NumMultiply => Self::get_number_slot(&slots.as_number, |s| s.multiply.load()), + Self::NumRightMultiply => { + Self::get_number_slot(&slots.as_number, |s| s.right_multiply.load()) + } + Self::NumInplaceMultiply => { + Self::get_number_slot(&slots.as_number, |s| s.inplace_multiply.load()) + } + Self::NumRemainder => Self::get_number_slot(&slots.as_number, |s| s.remainder.load()), + Self::NumRightRemainder => { + Self::get_number_slot(&slots.as_number, |s| s.right_remainder.load()) + } + Self::NumInplaceRemainder => { + Self::get_number_slot(&slots.as_number, |s| s.inplace_remainder.load()) + } + Self::NumDivmod => Self::get_number_slot(&slots.as_number, |s| s.divmod.load()), + Self::NumRightDivmod => { + Self::get_number_slot(&slots.as_number, |s| s.right_divmod.load()) + } + Self::NumFloorDivide => { + Self::get_number_slot(&slots.as_number, |s| s.floor_divide.load()) + } + Self::NumRightFloorDivide => { + Self::get_number_slot(&slots.as_number, |s| s.right_floor_divide.load()) + } + Self::NumInplaceFloorDivide => { + Self::get_number_slot(&slots.as_number, |s| s.inplace_floor_divide.load()) + } + Self::NumTrueDivide => { + Self::get_number_slot(&slots.as_number, |s| s.true_divide.load()) + } + Self::NumRightTrueDivide => { + Self::get_number_slot(&slots.as_number, |s| s.right_true_divide.load()) + } + Self::NumInplaceTrueDivide => { + Self::get_number_slot(&slots.as_number, |s| s.inplace_true_divide.load()) + } + Self::NumMatrixMultiply => { + Self::get_number_slot(&slots.as_number, |s| s.matrix_multiply.load()) + } + Self::NumRightMatrixMultiply => { + Self::get_number_slot(&slots.as_number, |s| s.right_matrix_multiply.load()) + } + Self::NumInplaceMatrixMultiply => { + Self::get_number_slot(&slots.as_number, |s| s.inplace_matrix_multiply.load()) + } + Self::NumLshift => Self::get_number_slot(&slots.as_number, |s| s.lshift.load()), + Self::NumRightLshift => { + Self::get_number_slot(&slots.as_number, |s| s.right_lshift.load()) + } + Self::NumInplaceLshift => { + Self::get_number_slot(&slots.as_number, |s| s.inplace_lshift.load()) + } + Self::NumRshift => Self::get_number_slot(&slots.as_number, |s| s.rshift.load()), + Self::NumRightRshift => { + Self::get_number_slot(&slots.as_number, |s| s.right_rshift.load()) + } + Self::NumInplaceRshift => { + Self::get_number_slot(&slots.as_number, |s| s.inplace_rshift.load()) + } + Self::NumAnd => Self::get_number_slot(&slots.as_number, |s| s.and.load()), + Self::NumRightAnd => Self::get_number_slot(&slots.as_number, |s| s.right_and.load()), + Self::NumInplaceAnd => { + Self::get_number_slot(&slots.as_number, |s| s.inplace_and.load()) + } + Self::NumXor => Self::get_number_slot(&slots.as_number, |s| s.xor.load()), + Self::NumRightXor => Self::get_number_slot(&slots.as_number, |s| s.right_xor.load()), + Self::NumInplaceXor => { + Self::get_number_slot(&slots.as_number, |s| s.inplace_xor.load()) + } + Self::NumOr => Self::get_number_slot(&slots.as_number, |s| s.or.load()), + Self::NumRightOr => Self::get_number_slot(&slots.as_number, |s| s.right_or.load()), + Self::NumInplaceOr => Self::get_number_slot(&slots.as_number, |s| s.inplace_or.load()), + + // Number - power (ternary) + Self::NumPower => slots.as_number.power.load().map(SlotFunc::NumTernary), + Self::NumRightPower => slots.as_number.right_power.load().map(SlotFunc::NumTernary), + Self::NumInplacePower => slots + .as_number + .inplace_power + .load() + .map(SlotFunc::NumTernary), + + // Number - unary + Self::NumNegative => slots.as_number.negative.load().map(SlotFunc::NumUnary), + Self::NumPositive => slots.as_number.positive.load().map(SlotFunc::NumUnary), + Self::NumAbsolute => slots.as_number.absolute.load().map(SlotFunc::NumUnary), + Self::NumInvert => slots.as_number.invert.load().map(SlotFunc::NumUnary), + Self::NumBoolean => slots.as_number.boolean.load().map(SlotFunc::NumBoolean), + Self::NumInt => slots.as_number.int.load().map(SlotFunc::NumUnary), + Self::NumFloat => slots.as_number.float.load().map(SlotFunc::NumUnary), + Self::NumIndex => slots.as_number.index.load().map(SlotFunc::NumUnary), + + // Sequence + Self::SeqLength => slots.as_sequence.length.load().map(SlotFunc::SeqLength), + Self::SeqConcat => slots.as_sequence.concat.load().map(SlotFunc::SeqConcat), + Self::SeqRepeat => slots.as_sequence.repeat.load().map(SlotFunc::SeqRepeat), + Self::SeqItem => slots.as_sequence.item.load().map(SlotFunc::SeqItem), + Self::SeqAssItem => slots.as_sequence.ass_item.load().map(SlotFunc::SeqAssItem), + Self::SeqContains => slots.as_sequence.contains.load().map(SlotFunc::SeqContains), + Self::SeqInplaceConcat => slots + .as_sequence + .inplace_concat + .load() + .map(SlotFunc::SeqConcat), + Self::SeqInplaceRepeat => slots + .as_sequence + .inplace_repeat + .load() + .map(SlotFunc::SeqRepeat), + + // Mapping + Self::MapLength => slots.as_mapping.length.load().map(SlotFunc::MapLength), + Self::MapSubscript => slots + .as_mapping + .subscript + .load() + .map(SlotFunc::MapSubscript), + Self::MapAssSubscript => slots + .as_mapping + .ass_subscript + .load() + .map(SlotFunc::MapAssSubscript), + } + } + + /// Helper for number binary slots + fn get_number_slot(slots: &PyNumberSlots, getter: F) -> Option + where + F: FnOnce(&PyNumberSlots) -> Option, + { + getter(slots).map(SlotFunc::NumBinary) + } +} + +/// All slot definitions in a single static array +/// +/// Adding a new slot: just add one entry here, and implement the +/// accessor methods - everything else is automatic. +pub static SLOT_DEFS: &[SlotDef] = &[ + // Main slots (tp_*) + SlotDef { + name: "__init__", + accessor: SlotAccessor::Init, + doc: "Initialize self. See help(type(self)) for accurate signature.", + }, + SlotDef { + name: "__new__", + accessor: SlotAccessor::New, + doc: "Create and return a new object. See help(type) for accurate signature.", + }, + SlotDef { + name: "__del__", + accessor: SlotAccessor::Del, + doc: "Called when the instance is about to be destroyed.", + }, + SlotDef { + name: "__repr__", + accessor: SlotAccessor::Repr, + doc: "Return repr(self).", + }, + SlotDef { + name: "__str__", + accessor: SlotAccessor::Str, + doc: "Return str(self).", + }, + SlotDef { + name: "__hash__", + accessor: SlotAccessor::Hash, + doc: "Return hash(self).", + }, + SlotDef { + name: "__call__", + accessor: SlotAccessor::Call, + doc: "Call self as a function.", + }, + SlotDef { + name: "__iter__", + accessor: SlotAccessor::Iter, + doc: "Implement iter(self).", + }, + SlotDef { + name: "__next__", + accessor: SlotAccessor::IterNext, + doc: "Implement next(self).", + }, + // Attribute access + SlotDef { + name: "__getattribute__", + accessor: SlotAccessor::GetAttro, + doc: "Return getattr(self, name).", + }, + SlotDef { + name: "__setattr__", + accessor: SlotAccessor::SetAttro, + doc: "Implement setattr(self, name, value).", + }, + SlotDef { + name: "__delattr__", + accessor: SlotAccessor::DelAttro, + doc: "Implement delattr(self, name).", + }, + // Rich comparison (all map to richcompare slot with different op) + SlotDef { + name: "__eq__", + accessor: SlotAccessor::RichCompareEq, + doc: "Return self==value.", + }, + SlotDef { + name: "__ne__", + accessor: SlotAccessor::RichCompareNe, + doc: "Return self!=value.", + }, + SlotDef { + name: "__lt__", + accessor: SlotAccessor::RichCompareLt, + doc: "Return selfvalue.", + }, + SlotDef { + name: "__ge__", + accessor: SlotAccessor::RichCompareGe, + doc: "Return self>=value.", + }, + // Descriptor protocol + SlotDef { + name: "__get__", + accessor: SlotAccessor::DescrGet, + doc: "Return an attribute of instance, which is of type owner.", + }, + SlotDef { + name: "__set__", + accessor: SlotAccessor::DescrSet, + doc: "Set an attribute of instance to value.", + }, + SlotDef { + name: "__delete__", + accessor: SlotAccessor::DescrDel, + doc: "Delete an attribute of instance.", + }, + // Sequence protocol (sq_*) + SlotDef { + name: "__len__", + accessor: SlotAccessor::SeqLength, + doc: "Return len(self).", + }, + SlotDef { + name: "__getitem__", + accessor: SlotAccessor::SeqItem, + doc: "Return self[key].", + }, + SlotDef { + name: "__setitem__", + accessor: SlotAccessor::SeqAssItem, + doc: "Set self[key] to value.", + }, + SlotDef { + name: "__delitem__", + accessor: SlotAccessor::SeqAssItem, + doc: "Delete self[key].", + }, + SlotDef { + name: "__contains__", + accessor: SlotAccessor::SeqContains, + doc: "Return key in self.", + }, + SlotDef { + name: "__add__", + accessor: SlotAccessor::SeqConcat, + doc: "Return self+value.", + }, + SlotDef { + name: "__mul__", + accessor: SlotAccessor::SeqRepeat, + doc: "Return self*value.", + }, + SlotDef { + name: "__iadd__", + accessor: SlotAccessor::SeqInplaceConcat, + doc: "Implement self+=value.", + }, + SlotDef { + name: "__imul__", + accessor: SlotAccessor::SeqInplaceRepeat, + doc: "Implement self*=value.", + }, + // Mapping protocol (mp_*) + SlotDef { + name: "__len__", + accessor: SlotAccessor::MapLength, + doc: "Return len(self).", + }, + SlotDef { + name: "__getitem__", + accessor: SlotAccessor::MapSubscript, + doc: "Return self[key].", + }, + SlotDef { + name: "__setitem__", + accessor: SlotAccessor::MapAssSubscript, + doc: "Set self[key] to value.", + }, + SlotDef { + name: "__delitem__", + accessor: SlotAccessor::MapAssSubscript, + doc: "Delete self[key].", + }, + // Number protocol - Binary operations (nb_*) + SlotDef { + name: "__add__", + accessor: SlotAccessor::NumAdd, + doc: "Return self+value.", + }, + SlotDef { + name: "__radd__", + accessor: SlotAccessor::NumRightAdd, + doc: "Return value+self.", + }, + SlotDef { + name: "__iadd__", + accessor: SlotAccessor::NumInplaceAdd, + doc: "Implement self+=value.", + }, + SlotDef { + name: "__sub__", + accessor: SlotAccessor::NumSubtract, + doc: "Return self-value.", + }, + SlotDef { + name: "__rsub__", + accessor: SlotAccessor::NumRightSubtract, + doc: "Return value-self.", + }, + SlotDef { + name: "__isub__", + accessor: SlotAccessor::NumInplaceSubtract, + doc: "Implement self-=value.", + }, + SlotDef { + name: "__mul__", + accessor: SlotAccessor::NumMultiply, + doc: "Return self*value.", + }, + SlotDef { + name: "__rmul__", + accessor: SlotAccessor::NumRightMultiply, + doc: "Return value*self.", + }, + SlotDef { + name: "__imul__", + accessor: SlotAccessor::NumInplaceMultiply, + doc: "Implement self*=value.", + }, + SlotDef { + name: "__mod__", + accessor: SlotAccessor::NumRemainder, + doc: "Return self%value.", + }, + SlotDef { + name: "__rmod__", + accessor: SlotAccessor::NumRightRemainder, + doc: "Return value%self.", + }, + SlotDef { + name: "__imod__", + accessor: SlotAccessor::NumInplaceRemainder, + doc: "Implement self%=value.", + }, + SlotDef { + name: "__divmod__", + accessor: SlotAccessor::NumDivmod, + doc: "Return divmod(self, value).", + }, + SlotDef { + name: "__rdivmod__", + accessor: SlotAccessor::NumRightDivmod, + doc: "Return divmod(value, self).", + }, + SlotDef { + name: "__pow__", + accessor: SlotAccessor::NumPower, + doc: "Return pow(self, value, mod).", + }, + SlotDef { + name: "__rpow__", + accessor: SlotAccessor::NumRightPower, + doc: "Return pow(value, self, mod).", + }, + SlotDef { + name: "__ipow__", + accessor: SlotAccessor::NumInplacePower, + doc: "Implement self**=value.", + }, + SlotDef { + name: "__floordiv__", + accessor: SlotAccessor::NumFloorDivide, + doc: "Return self//value.", + }, + SlotDef { + name: "__rfloordiv__", + accessor: SlotAccessor::NumRightFloorDivide, + doc: "Return value//self.", + }, + SlotDef { + name: "__ifloordiv__", + accessor: SlotAccessor::NumInplaceFloorDivide, + doc: "Implement self//=value.", + }, + SlotDef { + name: "__truediv__", + accessor: SlotAccessor::NumTrueDivide, + doc: "Return self/value.", + }, + SlotDef { + name: "__rtruediv__", + accessor: SlotAccessor::NumRightTrueDivide, + doc: "Return value/self.", + }, + SlotDef { + name: "__itruediv__", + accessor: SlotAccessor::NumInplaceTrueDivide, + doc: "Implement self/=value.", + }, + SlotDef { + name: "__matmul__", + accessor: SlotAccessor::NumMatrixMultiply, + doc: "Return self@value.", + }, + SlotDef { + name: "__rmatmul__", + accessor: SlotAccessor::NumRightMatrixMultiply, + doc: "Return value@self.", + }, + SlotDef { + name: "__imatmul__", + accessor: SlotAccessor::NumInplaceMatrixMultiply, + doc: "Implement self@=value.", + }, + // Bitwise operations + SlotDef { + name: "__lshift__", + accessor: SlotAccessor::NumLshift, + doc: "Return self<>value.", + }, + SlotDef { + name: "__rrshift__", + accessor: SlotAccessor::NumRightRshift, + doc: "Return value>>self.", + }, + SlotDef { + name: "__irshift__", + accessor: SlotAccessor::NumInplaceRshift, + doc: "Implement self>>=value.", + }, + SlotDef { + name: "__and__", + accessor: SlotAccessor::NumAnd, + doc: "Return self&value.", + }, + SlotDef { + name: "__rand__", + accessor: SlotAccessor::NumRightAnd, + doc: "Return value&self.", + }, + SlotDef { + name: "__iand__", + accessor: SlotAccessor::NumInplaceAnd, + doc: "Implement self&=value.", + }, + SlotDef { + name: "__xor__", + accessor: SlotAccessor::NumXor, + doc: "Return self^value.", + }, + SlotDef { + name: "__rxor__", + accessor: SlotAccessor::NumRightXor, + doc: "Return value^self.", + }, + SlotDef { + name: "__ixor__", + accessor: SlotAccessor::NumInplaceXor, + doc: "Implement self^=value.", + }, + SlotDef { + name: "__or__", + accessor: SlotAccessor::NumOr, + doc: "Return self|value.", + }, + SlotDef { + name: "__ror__", + accessor: SlotAccessor::NumRightOr, + doc: "Return value|self.", + }, + SlotDef { + name: "__ior__", + accessor: SlotAccessor::NumInplaceOr, + doc: "Implement self|=value.", + }, + // Number protocol - Unary operations + SlotDef { + name: "__neg__", + accessor: SlotAccessor::NumNegative, + doc: "Return -self.", + }, + SlotDef { + name: "__pos__", + accessor: SlotAccessor::NumPositive, + doc: "Return +self.", + }, + SlotDef { + name: "__abs__", + accessor: SlotAccessor::NumAbsolute, + doc: "Return abs(self).", + }, + SlotDef { + name: "__invert__", + accessor: SlotAccessor::NumInvert, + doc: "Return ~self.", + }, + SlotDef { + name: "__bool__", + accessor: SlotAccessor::NumBoolean, + doc: "Return self != 0.", + }, + SlotDef { + name: "__int__", + accessor: SlotAccessor::NumInt, + doc: "int(self)", + }, + SlotDef { + name: "__float__", + accessor: SlotAccessor::NumFloat, + doc: "float(self)", + }, + SlotDef { + name: "__index__", + accessor: SlotAccessor::NumIndex, + doc: "Return self converted to an integer, if self is suitable for use as an index into a list.", + }, +]; + +/// Find all slot definitions with a given name +pub fn find_slot_defs_by_name(name: &str) -> impl Iterator { + SLOT_DEFS.iter().filter(move |def| def.name == name) +} + +/// Total number of slot definitions +pub const SLOT_DEFS_COUNT: usize = SLOT_DEFS.len(); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_slot_defs_count() { + // Should have a reasonable number of entries + assert!( + SLOT_DEFS.len() > 60, + "Expected at least 60 slot definitions" + ); + assert!(SLOT_DEFS.len() < 150, "Too many slot definitions"); + } + + #[test] + fn test_find_by_name() { + // __len__ appears in both sequence and mapping + let len_defs: Vec<_> = find_slot_defs_by_name("__len__").collect(); + assert_eq!(len_defs.len(), 2); + + // __init__ appears once + let init_defs: Vec<_> = find_slot_defs_by_name("__init__").collect(); + assert_eq!(init_defs.len(), 1); + + // __add__ appears in sequence and number + let add_defs: Vec<_> = find_slot_defs_by_name("__add__").collect(); + assert_eq!(add_defs.len(), 2); + } + + #[test] + fn test_repr_u8() { + // Verify that SlotAccessor fits in u8 + assert!(std::mem::size_of::() == 1); + } + + #[test] + fn test_rich_compare_op() { + assert_eq!( + SlotAccessor::RichCompareLt.rich_compare_op(), + Some(PyComparisonOp::Lt) + ); + assert_eq!( + SlotAccessor::RichCompareEq.rich_compare_op(), + Some(PyComparisonOp::Eq) + ); + assert_eq!(SlotAccessor::Hash.rich_compare_op(), None); + } +} From a03d228c250491f1b1a9855fff7e27f502e427e6 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 27 Dec 2025 00:11:25 +0900 Subject: [PATCH 3/4] unify slots --- .cspell.dict/cpython.txt | 1 + crates/vm/src/builtins/complex.rs | 13 +- crates/vm/src/builtins/descriptor.rs | 22 +- crates/vm/src/builtins/float.rs | 3 +- crates/vm/src/builtins/int.rs | 3 +- crates/vm/src/builtins/type.rs | 2 +- crates/vm/src/class.rs | 4 +- crates/vm/src/protocol/number.rs | 113 +- crates/vm/src/types/slot.rs | 645 +++++----- crates/vm/src/types/slot_defs.rs | 1678 +++++++++++++++----------- 10 files changed, 1417 insertions(+), 1067 deletions(-) diff --git a/.cspell.dict/cpython.txt b/.cspell.dict/cpython.txt index 933b6af3fb..cb6f774ed1 100644 --- a/.cspell.dict/cpython.txt +++ b/.cspell.dict/cpython.txt @@ -51,6 +51,7 @@ prec preinitialized pythonw PYTHREAD_NAME +releasebuffer SA_ONSTACK SOABI stackdepth diff --git a/crates/vm/src/builtins/complex.rs b/crates/vm/src/builtins/complex.rs index 8bf46cfdd5..83021a7b4f 100644 --- a/crates/vm/src/builtins/complex.rs +++ b/crates/vm/src/builtins/complex.rs @@ -5,11 +5,7 @@ use crate::{ class::PyClassImpl, common::format::FormatSpec, convert::{IntoPyException, ToPyObject, ToPyResult}, - function::{ - FuncArgs, OptionalArg, OptionalOption, - PyArithmeticValue::{self, *}, - PyComparisonValue, - }, + function::{FuncArgs, OptionalArg, PyComparisonValue}, protocol::PyNumberMethods, stdlib::warnings, types::{AsNumber, Comparable, Constructor, Hashable, PyComparisonOp, Representable}, @@ -489,7 +485,12 @@ impl AsNumber for PyComplex { }), absolute: Some(|number, vm| { let value = PyComplex::number_downcast(number).value; - value.norm().to_pyresult(vm) + let result = value.norm(); + // Check for overflow: hypot returns inf for finite inputs that overflow + if result.is_infinite() && value.re.is_finite() && value.im.is_finite() { + return Err(vm.new_overflow_error("absolute value too large".to_owned())); + } + result.to_pyresult(vm) }), boolean: Some(|number, _vm| Ok(!PyComplex::number_downcast(number).value.is_zero())), true_divide: Some(|a, b, vm| PyComplex::number_op(a, b, inner_div, vm)), diff --git a/crates/vm/src/builtins/descriptor.rs b/crates/vm/src/builtins/descriptor.rs index d42a97d553..802b81f6d7 100644 --- a/crates/vm/src/builtins/descriptor.rs +++ b/crates/vm/src/builtins/descriptor.rs @@ -437,10 +437,12 @@ pub enum SlotFunc { MapAssSubscript(MapAssSubscriptFunc), // Number sub-slots (nb_*) - grouped by signature - NumBoolean(PyNumberUnaryFunc), // __bool__ - NumUnary(PyNumberUnaryFunc), // __int__, __float__, __index__ - NumBinary(PyNumberBinaryFunc), // __add__, __sub__, __mul__, etc. - NumTernary(PyNumberTernaryFunc), // __pow__ + NumBoolean(PyNumberUnaryFunc), // __bool__ + NumUnary(PyNumberUnaryFunc), // __int__, __float__, __index__ + NumBinary(PyNumberBinaryFunc), // __add__, __sub__, __mul__, etc. + NumBinaryRight(PyNumberBinaryFunc), // __radd__, __rsub__, etc. (swapped args) + NumTernary(PyNumberTernaryFunc), // __pow__ + NumTernaryRight(PyNumberTernaryFunc), // __rpow__ (swapped first two args) } impl std::fmt::Debug for SlotFunc { @@ -476,7 +478,9 @@ impl std::fmt::Debug for SlotFunc { SlotFunc::NumBoolean(_) => write!(f, "SlotFunc::NumBoolean(...)"), SlotFunc::NumUnary(_) => write!(f, "SlotFunc::NumUnary(...)"), SlotFunc::NumBinary(_) => write!(f, "SlotFunc::NumBinary(...)"), + SlotFunc::NumBinaryRight(_) => write!(f, "SlotFunc::NumBinaryRight(...)"), SlotFunc::NumTernary(_) => write!(f, "SlotFunc::NumTernary(...)"), + SlotFunc::NumTernaryRight(_) => write!(f, "SlotFunc::NumTernaryRight(...)"), } } } @@ -637,12 +641,22 @@ impl SlotFunc { let (other,): (PyObjectRef,) = args.bind(vm)?; func(&obj, &other, vm) } + SlotFunc::NumBinaryRight(func) => { + let (other,): (PyObjectRef,) = args.bind(vm)?; + func(&other, &obj, vm) // Swapped: other op obj + } SlotFunc::NumTernary(func) => { let (y, z): (PyObjectRef, crate::function::OptionalArg) = args.bind(vm)?; let z = z.unwrap_or_else(|| vm.ctx.none()); func(&obj, &y, &z, vm) } + SlotFunc::NumTernaryRight(func) => { + let (y, z): (PyObjectRef, crate::function::OptionalArg) = + args.bind(vm)?; + let z = z.unwrap_or_else(|| vm.ctx.none()); + func(&y, &obj, &z, vm) // Swapped: y ** obj % z + } } } } diff --git a/crates/vm/src/builtins/float.rs b/crates/vm/src/builtins/float.rs index 26182d748a..9ce0c8953f 100644 --- a/crates/vm/src/builtins/float.rs +++ b/crates/vm/src/builtins/float.rs @@ -8,8 +8,7 @@ use crate::{ common::{float_ops, format::FormatSpec, hash}, convert::{IntoPyException, ToPyObject, ToPyResult}, function::{ - ArgBytesLike, FuncArgs, OptionalArg, OptionalOption, - PyArithmeticValue::{self, *}, + ArgBytesLike, FuncArgs, OptionalArg, OptionalOption, PyArithmeticValue::*, PyComparisonValue, }, protocol::PyNumberMethods, diff --git a/crates/vm/src/builtins/int.rs b/crates/vm/src/builtins/int.rs index 46a0ff4774..0a406abd78 100644 --- a/crates/vm/src/builtins/int.rs +++ b/crates/vm/src/builtins/int.rs @@ -12,8 +12,7 @@ use crate::{ }, convert::{IntoPyException, ToPyObject, ToPyResult}, function::{ - ArgByteOrder, ArgIntoBool, FuncArgs, OptionalArg, OptionalOption, PyArithmeticValue, - PyComparisonValue, + ArgByteOrder, ArgIntoBool, FuncArgs, OptionalArg, PyArithmeticValue, PyComparisonValue, }, protocol::{PyNumberMethods, handle_bytes_to_int_err}, types::{AsNumber, Comparable, Constructor, Hashable, PyComparisonOp, Representable}, diff --git a/crates/vm/src/builtins/type.rs b/crates/vm/src/builtins/type.rs index 512f9d2894..f74095a8c8 100644 --- a/crates/vm/src/builtins/type.rs +++ b/crates/vm/src/builtins/type.rs @@ -465,7 +465,7 @@ impl PyType { /// Inherit slots from base type. inherit_slots pub(crate) fn inherit_slots(&self, base: &Self) { // Use SLOT_DEFS to iterate all slots - // Note: as_buffer is handled in inherit_static_slots (not AtomicCell) + // Note: as_buffer is handled in inherit_readonly_slots (not AtomicCell) for def in SLOT_DEFS { def.accessor.copyslot_if_none(self, base); } diff --git a/crates/vm/src/class.rs b/crates/vm/src/class.rs index 0039959053..ce41abcc60 100644 --- a/crates/vm/src/class.rs +++ b/crates/vm/src/class.rs @@ -15,7 +15,7 @@ use rustpython_common::static_cell; /// Iterates SLOT_DEFS and creates a PyWrapper for each slot that: /// 1. Has a function set in the type's slots /// 2. Doesn't already have an attribute in the type's dict -fn add_operators(class: &'static Py, ctx: &Context) { +pub fn add_operators(class: &'static Py, ctx: &Context) { for def in SLOT_DEFS.iter() { // Skip __new__ - it has special handling if def.name == "__new__" { @@ -35,7 +35,7 @@ fn add_operators(class: &'static Py, ctx: &Context) { } // Get the slot function wrapped in SlotFunc - let Some(slot_func) = def.accessor.get_slot_func(&class.slots) else { + let Some(slot_func) = def.accessor.get_slot_func_with_op(&class.slots, def.op) else { continue; }; diff --git a/crates/vm/src/protocol/number.rs b/crates/vm/src/protocol/number.rs index 4f21a1e64f..c208bf26de 100644 --- a/crates/vm/src/protocol/number.rs +++ b/crates/vm/src/protocol/number.rs @@ -256,6 +256,7 @@ pub struct PyNumberSlots { pub int: AtomicCell>, pub float: AtomicCell>, + // Right variants (internal - not exposed in SlotAccessor) pub right_add: AtomicCell>, pub right_subtract: AtomicCell>, pub right_multiply: AtomicCell>, @@ -295,8 +296,7 @@ pub struct PyNumberSlots { impl From<&PyNumberMethods> for PyNumberSlots { fn from(value: &PyNumberMethods) -> Self { - // right_* functions will use the same left function as PyNumberMethods - // allows both f(self, other) and f(other, self) + // right_* slots use the same function as left ops for native types Self { add: AtomicCell::new(value.add), subtract: AtomicCell::new(value.subtract), @@ -352,6 +352,115 @@ impl From<&PyNumberMethods> for PyNumberSlots { } impl PyNumberSlots { + /// Copy from static PyNumberMethods + pub fn copy_from(&self, methods: &PyNumberMethods) { + if let Some(f) = methods.add { + self.add.store(Some(f)); + } + if let Some(f) = methods.subtract { + self.subtract.store(Some(f)); + } + if let Some(f) = methods.multiply { + self.multiply.store(Some(f)); + } + if let Some(f) = methods.remainder { + self.remainder.store(Some(f)); + } + if let Some(f) = methods.divmod { + self.divmod.store(Some(f)); + } + if let Some(f) = methods.power { + self.power.store(Some(f)); + } + if let Some(f) = methods.negative { + self.negative.store(Some(f)); + } + if let Some(f) = methods.positive { + self.positive.store(Some(f)); + } + if let Some(f) = methods.absolute { + self.absolute.store(Some(f)); + } + if let Some(f) = methods.boolean { + self.boolean.store(Some(f)); + } + if let Some(f) = methods.invert { + self.invert.store(Some(f)); + } + if let Some(f) = methods.lshift { + self.lshift.store(Some(f)); + } + if let Some(f) = methods.rshift { + self.rshift.store(Some(f)); + } + if let Some(f) = methods.and { + self.and.store(Some(f)); + } + if let Some(f) = methods.xor { + self.xor.store(Some(f)); + } + if let Some(f) = methods.or { + self.or.store(Some(f)); + } + if let Some(f) = methods.int { + self.int.store(Some(f)); + } + if let Some(f) = methods.float { + self.float.store(Some(f)); + } + if let Some(f) = methods.inplace_add { + self.inplace_add.store(Some(f)); + } + if let Some(f) = methods.inplace_subtract { + self.inplace_subtract.store(Some(f)); + } + if let Some(f) = methods.inplace_multiply { + self.inplace_multiply.store(Some(f)); + } + if let Some(f) = methods.inplace_remainder { + self.inplace_remainder.store(Some(f)); + } + if let Some(f) = methods.inplace_power { + self.inplace_power.store(Some(f)); + } + if let Some(f) = methods.inplace_lshift { + self.inplace_lshift.store(Some(f)); + } + if let Some(f) = methods.inplace_rshift { + self.inplace_rshift.store(Some(f)); + } + if let Some(f) = methods.inplace_and { + self.inplace_and.store(Some(f)); + } + if let Some(f) = methods.inplace_xor { + self.inplace_xor.store(Some(f)); + } + if let Some(f) = methods.inplace_or { + self.inplace_or.store(Some(f)); + } + if let Some(f) = methods.floor_divide { + self.floor_divide.store(Some(f)); + } + if let Some(f) = methods.true_divide { + self.true_divide.store(Some(f)); + } + if let Some(f) = methods.inplace_floor_divide { + self.inplace_floor_divide.store(Some(f)); + } + if let Some(f) = methods.inplace_true_divide { + self.inplace_true_divide.store(Some(f)); + } + if let Some(f) = methods.index { + self.index.store(Some(f)); + } + if let Some(f) = methods.matrix_multiply { + self.matrix_multiply.store(Some(f)); + } + if let Some(f) = methods.inplace_matrix_multiply { + self.inplace_matrix_multiply.store(Some(f)); + } + } + pub fn left_binary_op(&self, op_slot: PyNumberBinaryOp) -> Option { use PyNumberBinaryOp::*; match op_slot { diff --git a/crates/vm/src/types/slot.rs b/crates/vm/src/types/slot.rs index 5396e09e6e..b7c20041d0 100644 --- a/crates/vm/src/types/slot.rs +++ b/crates/vm/src/types/slot.rs @@ -289,7 +289,7 @@ pub(crate) type NewFunc = fn(PyTypeRef, FuncArgs, &VirtualMachine) -> PyResult; pub(crate) type InitFunc = fn(PyObjectRef, FuncArgs, &VirtualMachine) -> PyResult<()>; pub(crate) type DelFunc = fn(&PyObject, &VirtualMachine) -> PyResult<()>; -// Sequence sub-slot function types (protocol/sequence.rs) +// Sequence sub-slot function types pub(crate) type SeqLenFunc = fn(PySequence<'_>, &VirtualMachine) -> PyResult; pub(crate) type SeqConcatFunc = fn(PySequence<'_>, &PyObject, &VirtualMachine) -> PyResult; pub(crate) type SeqRepeatFunc = fn(PySequence<'_>, isize, &VirtualMachine) -> PyResult; @@ -298,7 +298,7 @@ pub(crate) type SeqAssItemFunc = fn(PySequence<'_>, isize, Option, &VirtualMachine) -> PyResult<()>; pub(crate) type SeqContainsFunc = fn(PySequence<'_>, &PyObject, &VirtualMachine) -> PyResult; -// Mapping sub-slot function types (protocol/mapping.rs) +// Mapping sub-slot function types pub(crate) type MapLenFunc = fn(PyMapping<'_>, &VirtualMachine) -> PyResult; pub(crate) type MapSubscriptFunc = fn(PyMapping<'_>, &PyObject, &VirtualMachine) -> PyResult; pub(crate) type MapAssSubscriptFunc = @@ -350,24 +350,22 @@ macro_rules! number_binary_right_op_wrapper { macro_rules! number_ternary_op_wrapper { ($name:ident) => { |a, b, c, vm: &VirtualMachine| { - let args: Vec = if vm.is_none(c) { - vec![b.to_owned()] + if vm.is_none(c) { + vm.call_special_method(a, identifier!(vm, $name), (b.to_owned(),)) } else { - vec![b.to_owned(), c.to_owned()] - }; - vm.call_special_method(a, identifier!(vm, $name), args) + vm.call_special_method(a, identifier!(vm, $name), (b.to_owned(), c.to_owned())) + } } }; } macro_rules! number_ternary_right_op_wrapper { ($name:ident) => { |a, b, c, vm: &VirtualMachine| { - let args: Vec = if vm.is_none(c) { - vec![a.to_owned()] + if vm.is_none(c) { + vm.call_special_method(b, identifier!(vm, $name), (a.to_owned(),)) } else { - vec![a.to_owned(), c.to_owned()] - }; - vm.call_special_method(b, identifier!(vm, $name), args) + vm.call_special_method(b, identifier!(vm, $name), (a.to_owned(), c.to_owned())) + } } }; } @@ -613,9 +611,9 @@ impl PyType { match accessor { // === Main slots === - SlotAccessor::Repr => update_main_slot!(repr, repr_wrapper, Repr), - SlotAccessor::Str => update_main_slot!(str, str_wrapper, Str), - SlotAccessor::Hash => { + SlotAccessor::TpRepr => update_main_slot!(repr, repr_wrapper, Repr), + SlotAccessor::TpStr => update_main_slot!(str, str_wrapper, Str), + SlotAccessor::TpHash => { // Special handling for __hash__ = None if ADD { let method = self.attributes.read().get(name).cloned().or_else(|| { @@ -642,11 +640,11 @@ impl PyType { accessor.inherit_from_mro(self); } } - SlotAccessor::Call => update_main_slot!(call, call_wrapper, Call), - SlotAccessor::Iter => update_main_slot!(iter, iter_wrapper, Iter), - SlotAccessor::IterNext => update_main_slot!(iternext, iternext_wrapper, IterNext), - SlotAccessor::Init => update_main_slot!(init, init_wrapper, Init), - SlotAccessor::New => { + SlotAccessor::TpCall => update_main_slot!(call, call_wrapper, Call), + SlotAccessor::TpIter => update_main_slot!(iter, iter_wrapper, Iter), + SlotAccessor::TpIternext => update_main_slot!(iternext, iternext_wrapper, IterNext), + SlotAccessor::TpInit => update_main_slot!(init, init_wrapper, Init), + SlotAccessor::TpNew => { // __new__ is not wrapped via PyWrapper if ADD { self.slots.new.store(Some(new_wrapper)); @@ -654,10 +652,10 @@ impl PyType { accessor.inherit_from_mro(self); } } - SlotAccessor::Del => update_main_slot!(del, del_wrapper, Del), - SlotAccessor::GetAttro => update_main_slot!(getattro, getattro_wrapper, GetAttro), - SlotAccessor::SetAttro | SlotAccessor::DelAttro => { - // SetAttro and DelAttro share the same slot + SlotAccessor::TpDel => update_main_slot!(del, del_wrapper, Del), + SlotAccessor::TpGetattro => update_main_slot!(getattro, getattro_wrapper, GetAttro), + SlotAccessor::TpSetattro => { + // __setattr__ and __delattr__ share the same slot if ADD { if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| match sf { SlotFunc::SetAttro(f) | SlotFunc::DelAttro(f) => Some(*f), @@ -671,9 +669,9 @@ impl PyType { accessor.inherit_from_mro(self); } } - SlotAccessor::DescrGet => update_main_slot!(descr_get, descr_get_wrapper, DescrGet), - SlotAccessor::DescrSet | SlotAccessor::DescrDel => { - // DescrSet and DescrDel share the same slot + SlotAccessor::TpDescrGet => update_main_slot!(descr_get, descr_get_wrapper, DescrGet), + SlotAccessor::TpDescrSet => { + // __set__ and __delete__ share the same slot if ADD { if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| match sf { SlotFunc::DescrSet(f) | SlotFunc::DescrDel(f) => Some(*f), @@ -688,15 +686,45 @@ impl PyType { } } - // === Rich compare (all share richcompare slot) === - SlotAccessor::RichCompareLt - | SlotAccessor::RichCompareLe - | SlotAccessor::RichCompareEq - | SlotAccessor::RichCompareNe - | SlotAccessor::RichCompareGt - | SlotAccessor::RichCompareGe => { + // === Rich compare (__lt__, __le__, __eq__, __ne__, __gt__, __ge__) === + SlotAccessor::TpRichcompare => { if ADD { - if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| { + // Check if self or any class in MRO has a Python-defined comparison method + // All comparison ops share the same slot, so if any is overridden anywhere + // in the hierarchy with a Python function, we need to use the wrapper + let cmp_names = [ + identifier!(ctx, __eq__), + identifier!(ctx, __ne__), + identifier!(ctx, __lt__), + identifier!(ctx, __le__), + identifier!(ctx, __gt__), + identifier!(ctx, __ge__), + ]; + + let has_python_cmp = { + // Check self first + let attrs = self.attributes.read(); + let in_self = cmp_names.iter().any(|n| attrs.contains_key(*n)); + drop(attrs); + + in_self + || self.mro.read().iter().any(|cls| { + let attrs = cls.attributes.read(); + cmp_names.iter().any(|n| { + if let Some(attr) = attrs.get(*n) { + // Check if it's a Python function (not wrapper_descriptor) + !attr.class().is(ctx.types.wrapper_descriptor_type) + } else { + false + } + }) + }) + }; + + if has_python_cmp { + // Use wrapper to call the Python method + self.slots.richcompare.store(Some(richcompare_wrapper)); + } else if let Some(func) = self.lookup_slot_in_mro(name, ctx, |sf| { if let SlotFunc::RichCompare(f, _) = sf { Some(*f) } else { @@ -713,23 +741,24 @@ impl PyType { } // === Number binary operations === - SlotAccessor::NumAdd => { - update_sub_slot!( - as_number, - add, - number_binary_op_wrapper!(__add__), - NumBinary - ) - } - SlotAccessor::NumRightAdd => { - update_sub_slot!( - as_number, - right_add, - number_binary_right_op_wrapper!(__radd__), - NumBinary - ) + SlotAccessor::NbAdd => { + if name.as_str() == "__radd__" { + update_sub_slot!( + as_number, + right_add, + number_binary_right_op_wrapper!(__radd__), + NumBinary + ) + } else { + update_sub_slot!( + as_number, + add, + number_binary_op_wrapper!(__add__), + NumBinary + ) + } } - SlotAccessor::NumInplaceAdd => { + SlotAccessor::NbInplaceAdd => { update_sub_slot!( as_number, inplace_add, @@ -737,23 +766,24 @@ impl PyType { NumBinary ) } - SlotAccessor::NumSubtract => { - update_sub_slot!( - as_number, - subtract, - number_binary_op_wrapper!(__sub__), - NumBinary - ) - } - SlotAccessor::NumRightSubtract => { - update_sub_slot!( - as_number, - right_subtract, - number_binary_right_op_wrapper!(__rsub__), - NumBinary - ) + SlotAccessor::NbSubtract => { + if name.as_str() == "__rsub__" { + update_sub_slot!( + as_number, + right_subtract, + number_binary_right_op_wrapper!(__rsub__), + NumBinary + ) + } else { + update_sub_slot!( + as_number, + subtract, + number_binary_op_wrapper!(__sub__), + NumBinary + ) + } } - SlotAccessor::NumInplaceSubtract => { + SlotAccessor::NbInplaceSubtract => { update_sub_slot!( as_number, inplace_subtract, @@ -761,23 +791,24 @@ impl PyType { NumBinary ) } - SlotAccessor::NumMultiply => { - update_sub_slot!( - as_number, - multiply, - number_binary_op_wrapper!(__mul__), - NumBinary - ) - } - SlotAccessor::NumRightMultiply => { - update_sub_slot!( - as_number, - right_multiply, - number_binary_right_op_wrapper!(__rmul__), - NumBinary - ) + SlotAccessor::NbMultiply => { + if name.as_str() == "__rmul__" { + update_sub_slot!( + as_number, + right_multiply, + number_binary_right_op_wrapper!(__rmul__), + NumBinary + ) + } else { + update_sub_slot!( + as_number, + multiply, + number_binary_op_wrapper!(__mul__), + NumBinary + ) + } } - SlotAccessor::NumInplaceMultiply => { + SlotAccessor::NbInplaceMultiply => { update_sub_slot!( as_number, inplace_multiply, @@ -785,23 +816,24 @@ impl PyType { NumBinary ) } - SlotAccessor::NumRemainder => { - update_sub_slot!( - as_number, - remainder, - number_binary_op_wrapper!(__mod__), - NumBinary - ) - } - SlotAccessor::NumRightRemainder => { - update_sub_slot!( - as_number, - right_remainder, - number_binary_right_op_wrapper!(__rmod__), - NumBinary - ) + SlotAccessor::NbRemainder => { + if name.as_str() == "__rmod__" { + update_sub_slot!( + as_number, + right_remainder, + number_binary_right_op_wrapper!(__rmod__), + NumBinary + ) + } else { + update_sub_slot!( + as_number, + remainder, + number_binary_op_wrapper!(__mod__), + NumBinary + ) + } } - SlotAccessor::NumInplaceRemainder => { + SlotAccessor::NbInplaceRemainder => { update_sub_slot!( as_number, inplace_remainder, @@ -809,39 +841,41 @@ impl PyType { NumBinary ) } - SlotAccessor::NumDivmod => { - update_sub_slot!( - as_number, - divmod, - number_binary_op_wrapper!(__divmod__), - NumBinary - ) - } - SlotAccessor::NumRightDivmod => { - update_sub_slot!( - as_number, - right_divmod, - number_binary_right_op_wrapper!(__rdivmod__), - NumBinary - ) - } - SlotAccessor::NumPower => { - update_sub_slot!( - as_number, - power, - number_ternary_op_wrapper!(__pow__), - NumTernary - ) + SlotAccessor::NbDivmod => { + if name.as_str() == "__rdivmod__" { + update_sub_slot!( + as_number, + right_divmod, + number_binary_right_op_wrapper!(__rdivmod__), + NumBinary + ) + } else { + update_sub_slot!( + as_number, + divmod, + number_binary_op_wrapper!(__divmod__), + NumBinary + ) + } } - SlotAccessor::NumRightPower => { - update_sub_slot!( - as_number, - right_power, - number_ternary_right_op_wrapper!(__rpow__), - NumTernary - ) + SlotAccessor::NbPower => { + if name.as_str() == "__rpow__" { + update_sub_slot!( + as_number, + right_power, + number_ternary_right_op_wrapper!(__rpow__), + NumTernary + ) + } else { + update_sub_slot!( + as_number, + power, + number_ternary_op_wrapper!(__pow__), + NumTernary + ) + } } - SlotAccessor::NumInplacePower => { + SlotAccessor::NbInplacePower => { update_sub_slot!( as_number, inplace_power, @@ -849,23 +883,24 @@ impl PyType { NumTernary ) } - SlotAccessor::NumFloorDivide => { - update_sub_slot!( - as_number, - floor_divide, - number_binary_op_wrapper!(__floordiv__), - NumBinary - ) - } - SlotAccessor::NumRightFloorDivide => { - update_sub_slot!( - as_number, - right_floor_divide, - number_binary_right_op_wrapper!(__rfloordiv__), - NumBinary - ) + SlotAccessor::NbFloorDivide => { + if name.as_str() == "__rfloordiv__" { + update_sub_slot!( + as_number, + right_floor_divide, + number_binary_right_op_wrapper!(__rfloordiv__), + NumBinary + ) + } else { + update_sub_slot!( + as_number, + floor_divide, + number_binary_op_wrapper!(__floordiv__), + NumBinary + ) + } } - SlotAccessor::NumInplaceFloorDivide => { + SlotAccessor::NbInplaceFloorDivide => { update_sub_slot!( as_number, inplace_floor_divide, @@ -873,23 +908,24 @@ impl PyType { NumBinary ) } - SlotAccessor::NumTrueDivide => { - update_sub_slot!( - as_number, - true_divide, - number_binary_op_wrapper!(__truediv__), - NumBinary - ) - } - SlotAccessor::NumRightTrueDivide => { - update_sub_slot!( - as_number, - right_true_divide, - number_binary_right_op_wrapper!(__rtruediv__), - NumBinary - ) + SlotAccessor::NbTrueDivide => { + if name.as_str() == "__rtruediv__" { + update_sub_slot!( + as_number, + right_true_divide, + number_binary_right_op_wrapper!(__rtruediv__), + NumBinary + ) + } else { + update_sub_slot!( + as_number, + true_divide, + number_binary_op_wrapper!(__truediv__), + NumBinary + ) + } } - SlotAccessor::NumInplaceTrueDivide => { + SlotAccessor::NbInplaceTrueDivide => { update_sub_slot!( as_number, inplace_true_divide, @@ -897,23 +933,24 @@ impl PyType { NumBinary ) } - SlotAccessor::NumMatrixMultiply => { - update_sub_slot!( - as_number, - matrix_multiply, - number_binary_op_wrapper!(__matmul__), - NumBinary - ) - } - SlotAccessor::NumRightMatrixMultiply => { - update_sub_slot!( - as_number, - right_matrix_multiply, - number_binary_right_op_wrapper!(__rmatmul__), - NumBinary - ) + SlotAccessor::NbMatrixMultiply => { + if name.as_str() == "__rmatmul__" { + update_sub_slot!( + as_number, + right_matrix_multiply, + number_binary_right_op_wrapper!(__rmatmul__), + NumBinary + ) + } else { + update_sub_slot!( + as_number, + matrix_multiply, + number_binary_op_wrapper!(__matmul__), + NumBinary + ) + } } - SlotAccessor::NumInplaceMatrixMultiply => { + SlotAccessor::NbInplaceMatrixMultiply => { update_sub_slot!( as_number, inplace_matrix_multiply, @@ -923,23 +960,24 @@ impl PyType { } // === Number bitwise operations === - SlotAccessor::NumLshift => { - update_sub_slot!( - as_number, - lshift, - number_binary_op_wrapper!(__lshift__), - NumBinary - ) - } - SlotAccessor::NumRightLshift => { - update_sub_slot!( - as_number, - right_lshift, - number_binary_right_op_wrapper!(__rlshift__), - NumBinary - ) + SlotAccessor::NbLshift => { + if name.as_str() == "__rlshift__" { + update_sub_slot!( + as_number, + right_lshift, + number_binary_right_op_wrapper!(__rlshift__), + NumBinary + ) + } else { + update_sub_slot!( + as_number, + lshift, + number_binary_op_wrapper!(__lshift__), + NumBinary + ) + } } - SlotAccessor::NumInplaceLshift => { + SlotAccessor::NbInplaceLshift => { update_sub_slot!( as_number, inplace_lshift, @@ -947,23 +985,24 @@ impl PyType { NumBinary ) } - SlotAccessor::NumRshift => { - update_sub_slot!( - as_number, - rshift, - number_binary_op_wrapper!(__rshift__), - NumBinary - ) - } - SlotAccessor::NumRightRshift => { - update_sub_slot!( - as_number, - right_rshift, - number_binary_right_op_wrapper!(__rrshift__), - NumBinary - ) + SlotAccessor::NbRshift => { + if name.as_str() == "__rrshift__" { + update_sub_slot!( + as_number, + right_rshift, + number_binary_right_op_wrapper!(__rrshift__), + NumBinary + ) + } else { + update_sub_slot!( + as_number, + rshift, + number_binary_op_wrapper!(__rshift__), + NumBinary + ) + } } - SlotAccessor::NumInplaceRshift => { + SlotAccessor::NbInplaceRshift => { update_sub_slot!( as_number, inplace_rshift, @@ -971,23 +1010,24 @@ impl PyType { NumBinary ) } - SlotAccessor::NumAnd => { - update_sub_slot!( - as_number, - and, - number_binary_op_wrapper!(__and__), - NumBinary - ) - } - SlotAccessor::NumRightAnd => { - update_sub_slot!( - as_number, - right_and, - number_binary_right_op_wrapper!(__rand__), - NumBinary - ) + SlotAccessor::NbAnd => { + if name.as_str() == "__rand__" { + update_sub_slot!( + as_number, + right_and, + number_binary_right_op_wrapper!(__rand__), + NumBinary + ) + } else { + update_sub_slot!( + as_number, + and, + number_binary_op_wrapper!(__and__), + NumBinary + ) + } } - SlotAccessor::NumInplaceAnd => { + SlotAccessor::NbInplaceAnd => { update_sub_slot!( as_number, inplace_and, @@ -995,23 +1035,24 @@ impl PyType { NumBinary ) } - SlotAccessor::NumXor => { - update_sub_slot!( - as_number, - xor, - number_binary_op_wrapper!(__xor__), - NumBinary - ) - } - SlotAccessor::NumRightXor => { - update_sub_slot!( - as_number, - right_xor, - number_binary_right_op_wrapper!(__rxor__), - NumBinary - ) + SlotAccessor::NbXor => { + if name.as_str() == "__rxor__" { + update_sub_slot!( + as_number, + right_xor, + number_binary_right_op_wrapper!(__rxor__), + NumBinary + ) + } else { + update_sub_slot!( + as_number, + xor, + number_binary_op_wrapper!(__xor__), + NumBinary + ) + } } - SlotAccessor::NumInplaceXor => { + SlotAccessor::NbInplaceXor => { update_sub_slot!( as_number, inplace_xor, @@ -1019,18 +1060,19 @@ impl PyType { NumBinary ) } - SlotAccessor::NumOr => { - update_sub_slot!(as_number, or, number_binary_op_wrapper!(__or__), NumBinary) - } - SlotAccessor::NumRightOr => { - update_sub_slot!( - as_number, - right_or, - number_binary_right_op_wrapper!(__ror__), - NumBinary - ) + SlotAccessor::NbOr => { + if name.as_str() == "__ror__" { + update_sub_slot!( + as_number, + right_or, + number_binary_right_op_wrapper!(__ror__), + NumBinary + ) + } else { + update_sub_slot!(as_number, or, number_binary_op_wrapper!(__or__), NumBinary) + } } - SlotAccessor::NumInplaceOr => { + SlotAccessor::NbInplaceOr => { update_sub_slot!( as_number, inplace_or, @@ -1040,7 +1082,7 @@ impl PyType { } // === Number unary operations === - SlotAccessor::NumNegative => { + SlotAccessor::NbNegative => { update_sub_slot!( as_number, negative, @@ -1048,7 +1090,7 @@ impl PyType { NumUnary ) } - SlotAccessor::NumPositive => { + SlotAccessor::NbPositive => { update_sub_slot!( as_number, positive, @@ -1056,7 +1098,7 @@ impl PyType { NumUnary ) } - SlotAccessor::NumAbsolute => { + SlotAccessor::NbAbsolute => { update_sub_slot!( as_number, absolute, @@ -1064,7 +1106,7 @@ impl PyType { NumUnary ) } - SlotAccessor::NumInvert => { + SlotAccessor::NbInvert => { update_sub_slot!( as_number, invert, @@ -1072,13 +1114,13 @@ impl PyType { NumUnary ) } - SlotAccessor::NumBoolean => { + SlotAccessor::NbBool => { update_sub_slot!(as_number, boolean, bool_wrapper, NumBoolean) } - SlotAccessor::NumInt => { + SlotAccessor::NbInt => { update_sub_slot!(as_number, int, number_unary_op_wrapper!(__int__), NumUnary) } - SlotAccessor::NumFloat => { + SlotAccessor::NbFloat => { update_sub_slot!( as_number, float, @@ -1086,7 +1128,7 @@ impl PyType { NumUnary ) } - SlotAccessor::NumIndex => { + SlotAccessor::NbIndex => { update_sub_slot!( as_number, index, @@ -1096,7 +1138,7 @@ impl PyType { } // === Sequence slots === - SlotAccessor::SeqLength => { + SlotAccessor::SqLength => { update_sub_slot!( as_sequence, length, @@ -1104,21 +1146,21 @@ impl PyType { SeqLength ) } - SlotAccessor::SeqConcat | SlotAccessor::SeqInplaceConcat => { + SlotAccessor::SqConcat | SlotAccessor::SqInplaceConcat => { // Sequence concat uses sq_concat slot - no generic wrapper needed // (handled by number protocol fallback) if !ADD { accessor.inherit_from_mro(self); } } - SlotAccessor::SeqRepeat | SlotAccessor::SeqInplaceRepeat => { + SlotAccessor::SqRepeat | SlotAccessor::SqInplaceRepeat => { // Sequence repeat uses sq_repeat slot - no generic wrapper needed // (handled by number protocol fallback) if !ADD { accessor.inherit_from_mro(self); } } - SlotAccessor::SeqItem => { + SlotAccessor::SqItem => { update_sub_slot!( as_sequence, item, @@ -1126,7 +1168,7 @@ impl PyType { SeqItem ) } - SlotAccessor::SeqAssItem => { + SlotAccessor::SqAssItem => { update_sub_slot!( as_sequence, ass_item, @@ -1134,7 +1176,7 @@ impl PyType { SeqAssItem ) } - SlotAccessor::SeqContains => { + SlotAccessor::SqContains => { update_sub_slot!( as_sequence, contains, @@ -1144,7 +1186,7 @@ impl PyType { } // === Mapping slots === - SlotAccessor::MapLength => { + SlotAccessor::MpLength => { update_sub_slot!( as_mapping, length, @@ -1152,7 +1194,7 @@ impl PyType { MapLength ) } - SlotAccessor::MapSubscript => { + SlotAccessor::MpSubscript => { update_sub_slot!( as_mapping, subscript, @@ -1160,7 +1202,7 @@ impl PyType { MapSubscript ) } - SlotAccessor::MapAssSubscript => { + SlotAccessor::MpAssSubscript => { update_sub_slot!( as_mapping, ass_subscript, @@ -1168,6 +1210,9 @@ impl PyType { MapAssSubscript ) } + + // Reserved slots - no-op + _ => {} } } @@ -1490,60 +1535,8 @@ pub trait Comparable: PyPayload { vm: &VirtualMachine, ) -> PyResult; - #[inline] - #[pymethod] - fn __eq__( - zelf: &Py, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult { - Self::cmp(zelf, &other, PyComparisonOp::Eq, vm) - } - #[inline] - #[pymethod] - fn __ne__( - zelf: &Py, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult { - Self::cmp(zelf, &other, PyComparisonOp::Ne, vm) - } - #[inline] - #[pymethod] - fn __lt__( - zelf: &Py, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult { - Self::cmp(zelf, &other, PyComparisonOp::Lt, vm) - } - #[inline] - #[pymethod] - fn __le__( - zelf: &Py, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult { - Self::cmp(zelf, &other, PyComparisonOp::Le, vm) - } - #[inline] - #[pymethod] - fn __ge__( - zelf: &Py, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult { - Self::cmp(zelf, &other, PyComparisonOp::Ge, vm) - } - #[inline] - #[pymethod] - fn __gt__( - zelf: &Py, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult { - Self::cmp(zelf, &other, PyComparisonOp::Gt, vm) - } + // Comparison methods are exposed as wrapper_descriptor via slot_richcompare + // No #[pymethod] - add_operators creates wrapper from SLOT_DEFS } #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -1752,6 +1745,10 @@ pub trait AsNumber: PyPayload { #[pyslot] fn as_number() -> &'static PyNumberMethods; + fn extend_slots(slots: &mut PyTypeSlots) { + slots.as_number.copy_from(Self::as_number()); + } + fn clone_exact(_zelf: &Py, _vm: &VirtualMachine) -> PyRef { // not all AsNumber requires this implementation. unimplemented!() diff --git a/crates/vm/src/types/slot_defs.rs b/crates/vm/src/types/slot_defs.rs index 1f6ba64aa6..0d8dbf4b0c 100644 --- a/crates/vm/src/types/slot_defs.rs +++ b/crates/vm/src/types/slot_defs.rs @@ -1,11 +1,50 @@ //! Slot definitions array //! //! This module provides a centralized array of all slot definitions, -//! enabling automatic wrapper generation and slot updates. use super::{PyComparisonOp, PyTypeSlots}; use crate::builtins::descriptor::SlotFunc; -use crate::protocol::{PyNumberBinaryFunc, PyNumberSlots}; + +/// Slot operation type +/// +/// Used to distinguish between different operations that share the same slot: +/// - RichCompare: Lt, Le, Eq, Ne, Gt, Ge +/// - Binary ops: Left (__add__) vs Right (__radd__) +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum SlotOp { + // RichCompare operations + Lt, + Le, + Eq, + Ne, + Gt, + Ge, + // Binary operation direction + Left, + Right, + // Setter vs Deleter + Delete, +} + +impl SlotOp { + /// Convert to PyComparisonOp if this is a comparison operation + pub fn as_compare_op(&self) -> Option { + match self { + Self::Lt => Some(PyComparisonOp::Lt), + Self::Le => Some(PyComparisonOp::Le), + Self::Eq => Some(PyComparisonOp::Eq), + Self::Ne => Some(PyComparisonOp::Ne), + Self::Gt => Some(PyComparisonOp::Gt), + Self::Ge => Some(PyComparisonOp::Ge), + _ => None, + } + } + + /// Check if this is a right operation (__radd__, __rsub__, etc.) + pub fn is_right(&self) -> bool { + matches!(self, Self::Right) + } +} /// Slot definition entry #[derive(Clone, Copy)] @@ -16,265 +55,357 @@ pub struct SlotDef { /// Slot accessor (which slot field to access) pub accessor: SlotAccessor, + /// Operation type (for shared slots like RichCompare, binary ops) + pub op: Option, + /// Documentation string pub doc: &'static str, } /// Slot accessor /// -/// Flat enum with all slot types inlined for `#[repr(u8)]` support. -/// Each variant directly corresponds to a slot field in PyTypeSlots. +/// Values match CPython's Py_* slot IDs from typeslots.h. +/// Unused slots are included for value reservation. #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u8)] pub enum SlotAccessor { - // Main slots - Hash, - Repr, - Str, - Call, - Iter, - IterNext, - Init, - New, - Del, - GetAttro, - SetAttro, - DelAttro, - DescrGet, - DescrSet, - DescrDel, + // Buffer protocol (1-2) - Reserved, not used in RustPython + BfGetBuffer = 1, + BfReleaseBuffer = 2, - // Rich compare - tp_richcompare with different ops - RichCompareLt, - RichCompareLe, - RichCompareEq, - RichCompareNe, - RichCompareGt, - RichCompareGe, + // Mapping protocol (3-5) + MpAssSubscript = 3, + MpLength = 4, + MpSubscript = 5, - // Number binary operations - NumAdd, - NumRightAdd, - NumInplaceAdd, - NumSubtract, - NumRightSubtract, - NumInplaceSubtract, - NumMultiply, - NumRightMultiply, - NumInplaceMultiply, - NumRemainder, - NumRightRemainder, - NumInplaceRemainder, - NumDivmod, - NumRightDivmod, - NumPower, - NumRightPower, - NumInplacePower, - NumFloorDivide, - NumRightFloorDivide, - NumInplaceFloorDivide, - NumTrueDivide, - NumRightTrueDivide, - NumInplaceTrueDivide, - NumMatrixMultiply, - NumRightMatrixMultiply, - NumInplaceMatrixMultiply, + // Number protocol (6-38) + NbAbsolute = 6, + NbAdd = 7, + NbAnd = 8, + NbBool = 9, + NbDivmod = 10, + NbFloat = 11, + NbFloorDivide = 12, + NbIndex = 13, + NbInplaceAdd = 14, + NbInplaceAnd = 15, + NbInplaceFloorDivide = 16, + NbInplaceLshift = 17, + NbInplaceMultiply = 18, + NbInplaceOr = 19, + NbInplacePower = 20, + NbInplaceRemainder = 21, + NbInplaceRshift = 22, + NbInplaceSubtract = 23, + NbInplaceTrueDivide = 24, + NbInplaceXor = 25, + NbInt = 26, + NbInvert = 27, + NbLshift = 28, + NbMultiply = 29, + NbNegative = 30, + NbOr = 31, + NbPositive = 32, + NbPower = 33, + NbRemainder = 34, + NbRshift = 35, + NbSubtract = 36, + NbTrueDivide = 37, + NbXor = 38, - // Bitwise operations - NumLshift, - NumRightLshift, - NumInplaceLshift, - NumRshift, - NumRightRshift, - NumInplaceRshift, - NumAnd, - NumRightAnd, - NumInplaceAnd, - NumXor, - NumRightXor, - NumInplaceXor, - NumOr, - NumRightOr, - NumInplaceOr, + // Sequence protocol (39-46) + SqAssItem = 39, + SqConcat = 40, + SqContains = 41, + SqInplaceConcat = 42, + SqInplaceRepeat = 43, + SqItem = 44, + SqLength = 45, + SqRepeat = 46, - // Number unary operations - NumNegative, - NumPositive, - NumAbsolute, - NumInvert, - NumBoolean, - NumInt, - NumFloat, - NumIndex, + // Type slots (47-74) + TpAlloc = 47, // Reserved + TpBase = 48, // Reserved + TpBases = 49, // Reserved + TpCall = 50, + TpClear = 51, // Reserved + TpDealloc = 52, // Reserved + TpDel = 53, + TpDescrGet = 54, + TpDescrSet = 55, + TpDoc = 56, // Reserved + TpGetattr = 57, // Reserved (use TpGetattro) + TpGetattro = 58, + TpHash = 59, + TpInit = 60, + TpIsGc = 61, // Reserved + TpIter = 62, + TpIternext = 63, + TpMethods = 64, // Reserved + TpNew = 65, + TpRepr = 66, + TpRichcompare = 67, + TpSetattr = 68, // Reserved (use TpSetattro) + TpSetattro = 69, + TpStr = 70, + TpTraverse = 71, // Reserved + TpMembers = 72, // Reserved + TpGetset = 73, // Reserved + TpFree = 74, // Reserved - // Sequence slots - SeqLength, - SeqConcat, - SeqRepeat, - SeqItem, - SeqAssItem, - SeqContains, - SeqInplaceConcat, - SeqInplaceRepeat, + // Number protocol additions (75-76) + NbMatrixMultiply = 75, + NbInplaceMatrixMultiply = 76, - // Mapping slots - MapLength, - MapSubscript, - MapAssSubscript, + // Async protocol (77-81) - Reserved for future + AmAwait = 77, + AmAiter = 78, + AmAnext = 79, + TpFinalize = 80, + AmSend = 81, } -// SlotAccessor implementation - impl SlotAccessor { - /// Get the PyComparisonOp for RichCompare variants - pub fn rich_compare_op(&self) -> Option { - match self { - Self::RichCompareLt => Some(PyComparisonOp::Lt), - Self::RichCompareLe => Some(PyComparisonOp::Le), - Self::RichCompareEq => Some(PyComparisonOp::Eq), - Self::RichCompareNe => Some(PyComparisonOp::Ne), - Self::RichCompareGt => Some(PyComparisonOp::Gt), - Self::RichCompareGe => Some(PyComparisonOp::Ge), - _ => None, - } + /// Check if this accessor is for a reserved/unused slot + pub fn is_reserved(&self) -> bool { + matches!( + self, + Self::BfGetBuffer + | Self::BfReleaseBuffer + | Self::TpAlloc + | Self::TpBase + | Self::TpBases + | Self::TpClear + | Self::TpDealloc + | Self::TpDoc + | Self::TpGetattr + | Self::TpIsGc + | Self::TpMethods + | Self::TpSetattr + | Self::TpTraverse + | Self::TpMembers + | Self::TpGetset + | Self::TpFree + | Self::TpFinalize + | Self::AmAwait + | Self::AmAiter + | Self::AmAnext + | Self::AmSend + ) + } + + /// Check if this is a number binary operation slot + pub fn is_number_binary(&self) -> bool { + matches!( + self, + Self::NbAdd + | Self::NbSubtract + | Self::NbMultiply + | Self::NbRemainder + | Self::NbDivmod + | Self::NbPower + | Self::NbLshift + | Self::NbRshift + | Self::NbAnd + | Self::NbXor + | Self::NbOr + | Self::NbFloorDivide + | Self::NbTrueDivide + | Self::NbMatrixMultiply + ) } /// Check if this accessor refers to a shared slot /// /// Shared slots are used by multiple dunder methods: - /// - SetAttro/DelAttro share setattro slot - /// - RichCompare variants share richcompare slot - /// - DescrSet/DescrDel share descr_set slot - /// - SeqAssItem is used by __setitem__ and __delitem__ - /// - MapAssSubscript is used by __setitem__ and __delitem__ + /// - TpSetattro: __setattr__ and __delattr__ + /// - TpRichcompare: __lt__, __le__, __eq__, __ne__, __gt__, __ge__ + /// - TpDescrSet: __set__ and __delete__ + /// - SqAssItem/MpAssSubscript: __setitem__ and __delitem__ + /// - Number binaries: __add__ and __radd__, etc. pub fn is_shared_slot(&self) -> bool { matches!( self, - Self::SetAttro - | Self::DelAttro - | Self::RichCompareLt - | Self::RichCompareLe - | Self::RichCompareEq - | Self::RichCompareNe - | Self::RichCompareGt - | Self::RichCompareGe - | Self::DescrSet - | Self::DescrDel - | Self::SeqAssItem - | Self::MapAssSubscript - ) + Self::TpSetattro + | Self::TpRichcompare + | Self::TpDescrSet + | Self::SqAssItem + | Self::MpAssSubscript + ) || self.is_number_binary() } - /// Get the underlying slot accessor for shared slots - /// - /// For SetAttro/DelAttro, returns SetAttro (they share the same slot). - /// For DescrSet/DescrDel, returns DescrSet (they share the same slot). - pub fn canonical(&self) -> SlotAccessor { + /// Get underlying slot field name for debugging + pub fn slot_name(&self) -> &'static str { match self { - Self::DelAttro => Self::SetAttro, - Self::DescrDel => Self::DescrSet, - _ => *self, + Self::BfGetBuffer => "bf_getbuffer", + Self::BfReleaseBuffer => "bf_releasebuffer", + Self::MpAssSubscript => "mp_ass_subscript", + Self::MpLength => "mp_length", + Self::MpSubscript => "mp_subscript", + Self::NbAbsolute => "nb_absolute", + Self::NbAdd => "nb_add", + Self::NbAnd => "nb_and", + Self::NbBool => "nb_bool", + Self::NbDivmod => "nb_divmod", + Self::NbFloat => "nb_float", + Self::NbFloorDivide => "nb_floor_divide", + Self::NbIndex => "nb_index", + Self::NbInplaceAdd => "nb_inplace_add", + Self::NbInplaceAnd => "nb_inplace_and", + Self::NbInplaceFloorDivide => "nb_inplace_floor_divide", + Self::NbInplaceLshift => "nb_inplace_lshift", + Self::NbInplaceMultiply => "nb_inplace_multiply", + Self::NbInplaceOr => "nb_inplace_or", + Self::NbInplacePower => "nb_inplace_power", + Self::NbInplaceRemainder => "nb_inplace_remainder", + Self::NbInplaceRshift => "nb_inplace_rshift", + Self::NbInplaceSubtract => "nb_inplace_subtract", + Self::NbInplaceTrueDivide => "nb_inplace_true_divide", + Self::NbInplaceXor => "nb_inplace_xor", + Self::NbInt => "nb_int", + Self::NbInvert => "nb_invert", + Self::NbLshift => "nb_lshift", + Self::NbMultiply => "nb_multiply", + Self::NbNegative => "nb_negative", + Self::NbOr => "nb_or", + Self::NbPositive => "nb_positive", + Self::NbPower => "nb_power", + Self::NbRemainder => "nb_remainder", + Self::NbRshift => "nb_rshift", + Self::NbSubtract => "nb_subtract", + Self::NbTrueDivide => "nb_true_divide", + Self::NbXor => "nb_xor", + Self::SqAssItem => "sq_ass_item", + Self::SqConcat => "sq_concat", + Self::SqContains => "sq_contains", + Self::SqInplaceConcat => "sq_inplace_concat", + Self::SqInplaceRepeat => "sq_inplace_repeat", + Self::SqItem => "sq_item", + Self::SqLength => "sq_length", + Self::SqRepeat => "sq_repeat", + Self::TpAlloc => "tp_alloc", + Self::TpBase => "tp_base", + Self::TpBases => "tp_bases", + Self::TpCall => "tp_call", + Self::TpClear => "tp_clear", + Self::TpDealloc => "tp_dealloc", + Self::TpDel => "tp_del", + Self::TpDescrGet => "tp_descr_get", + Self::TpDescrSet => "tp_descr_set", + Self::TpDoc => "tp_doc", + Self::TpGetattr => "tp_getattr", + Self::TpGetattro => "tp_getattro", + Self::TpHash => "tp_hash", + Self::TpInit => "tp_init", + Self::TpIsGc => "tp_is_gc", + Self::TpIter => "tp_iter", + Self::TpIternext => "tp_iternext", + Self::TpMethods => "tp_methods", + Self::TpNew => "tp_new", + Self::TpRepr => "tp_repr", + Self::TpRichcompare => "tp_richcompare", + Self::TpSetattr => "tp_setattr", + Self::TpSetattro => "tp_setattro", + Self::TpStr => "tp_str", + Self::TpTraverse => "tp_traverse", + Self::TpMembers => "tp_members", + Self::TpGetset => "tp_getset", + Self::TpFree => "tp_free", + Self::NbMatrixMultiply => "nb_matrix_multiply", + Self::NbInplaceMatrixMultiply => "nb_inplace_matrix_multiply", + Self::AmAwait => "am_await", + Self::AmAiter => "am_aiter", + Self::AmAnext => "am_anext", + Self::TpFinalize => "tp_finalize", + Self::AmSend => "am_send", } } /// Extract the raw function pointer from a SlotFunc if it matches this accessor's type pub fn extract_from_slot_func(&self, slot_func: &SlotFunc) -> bool { match self { - // Main slots - Self::Hash => matches!(slot_func, SlotFunc::Hash(_)), - Self::Repr => matches!(slot_func, SlotFunc::Repr(_)), - Self::Str => matches!(slot_func, SlotFunc::Str(_)), - Self::Call => matches!(slot_func, SlotFunc::Call(_)), - Self::Iter => matches!(slot_func, SlotFunc::Iter(_)), - Self::IterNext => matches!(slot_func, SlotFunc::IterNext(_)), - Self::Init => matches!(slot_func, SlotFunc::Init(_)), - Self::Del => matches!(slot_func, SlotFunc::Del(_)), - Self::GetAttro => matches!(slot_func, SlotFunc::GetAttro(_)), - Self::SetAttro | Self::DelAttro => { + // Type slots + Self::TpHash => matches!(slot_func, SlotFunc::Hash(_)), + Self::TpRepr => matches!(slot_func, SlotFunc::Repr(_)), + Self::TpStr => matches!(slot_func, SlotFunc::Str(_)), + Self::TpCall => matches!(slot_func, SlotFunc::Call(_)), + Self::TpIter => matches!(slot_func, SlotFunc::Iter(_)), + Self::TpIternext => matches!(slot_func, SlotFunc::IterNext(_)), + Self::TpInit => matches!(slot_func, SlotFunc::Init(_)), + Self::TpDel => matches!(slot_func, SlotFunc::Del(_)), + Self::TpGetattro => matches!(slot_func, SlotFunc::GetAttro(_)), + Self::TpSetattro => { matches!(slot_func, SlotFunc::SetAttro(_) | SlotFunc::DelAttro(_)) } - Self::DescrGet => matches!(slot_func, SlotFunc::DescrGet(_)), - Self::DescrSet | Self::DescrDel => { + Self::TpDescrGet => matches!(slot_func, SlotFunc::DescrGet(_)), + Self::TpDescrSet => { matches!(slot_func, SlotFunc::DescrSet(_) | SlotFunc::DescrDel(_)) } - // RichCompare - Self::RichCompareLt - | Self::RichCompareLe - | Self::RichCompareEq - | Self::RichCompareNe - | Self::RichCompareGt - | Self::RichCompareGe => matches!(slot_func, SlotFunc::RichCompare(_, _)), + Self::TpRichcompare => matches!(slot_func, SlotFunc::RichCompare(_, _)), + // Number - Power (ternary) - Self::NumPower | Self::NumRightPower | Self::NumInplacePower => { + Self::NbPower | Self::NbInplacePower => { matches!(slot_func, SlotFunc::NumTernary(_)) } // Number - Boolean - Self::NumBoolean => matches!(slot_func, SlotFunc::NumBoolean(_)), + Self::NbBool => matches!(slot_func, SlotFunc::NumBoolean(_)), // Number - Unary - Self::NumNegative - | Self::NumPositive - | Self::NumAbsolute - | Self::NumInvert - | Self::NumInt - | Self::NumFloat - | Self::NumIndex => matches!(slot_func, SlotFunc::NumUnary(_)), - // Number - Binary (all others) - Self::NumAdd - | Self::NumRightAdd - | Self::NumInplaceAdd - | Self::NumSubtract - | Self::NumRightSubtract - | Self::NumInplaceSubtract - | Self::NumMultiply - | Self::NumRightMultiply - | Self::NumInplaceMultiply - | Self::NumRemainder - | Self::NumRightRemainder - | Self::NumInplaceRemainder - | Self::NumDivmod - | Self::NumRightDivmod - | Self::NumFloorDivide - | Self::NumRightFloorDivide - | Self::NumInplaceFloorDivide - | Self::NumTrueDivide - | Self::NumRightTrueDivide - | Self::NumInplaceTrueDivide - | Self::NumMatrixMultiply - | Self::NumRightMatrixMultiply - | Self::NumInplaceMatrixMultiply - | Self::NumLshift - | Self::NumRightLshift - | Self::NumInplaceLshift - | Self::NumRshift - | Self::NumRightRshift - | Self::NumInplaceRshift - | Self::NumAnd - | Self::NumRightAnd - | Self::NumInplaceAnd - | Self::NumXor - | Self::NumRightXor - | Self::NumInplaceXor - | Self::NumOr - | Self::NumRightOr - | Self::NumInplaceOr => matches!(slot_func, SlotFunc::NumBinary(_)), + Self::NbNegative + | Self::NbPositive + | Self::NbAbsolute + | Self::NbInvert + | Self::NbInt + | Self::NbFloat + | Self::NbIndex => matches!(slot_func, SlotFunc::NumUnary(_)), + // Number - Binary + Self::NbAdd + | Self::NbSubtract + | Self::NbMultiply + | Self::NbRemainder + | Self::NbDivmod + | Self::NbLshift + | Self::NbRshift + | Self::NbAnd + | Self::NbXor + | Self::NbOr + | Self::NbFloorDivide + | Self::NbTrueDivide + | Self::NbMatrixMultiply + | Self::NbInplaceAdd + | Self::NbInplaceSubtract + | Self::NbInplaceMultiply + | Self::NbInplaceRemainder + | Self::NbInplaceLshift + | Self::NbInplaceRshift + | Self::NbInplaceAnd + | Self::NbInplaceXor + | Self::NbInplaceOr + | Self::NbInplaceFloorDivide + | Self::NbInplaceTrueDivide + | Self::NbInplaceMatrixMultiply => matches!(slot_func, SlotFunc::NumBinary(_)), + // Sequence - Self::SeqLength => matches!(slot_func, SlotFunc::SeqLength(_)), - Self::SeqConcat | Self::SeqInplaceConcat => matches!(slot_func, SlotFunc::SeqConcat(_)), - Self::SeqRepeat | Self::SeqInplaceRepeat => matches!(slot_func, SlotFunc::SeqRepeat(_)), - Self::SeqItem => matches!(slot_func, SlotFunc::SeqItem(_)), - Self::SeqAssItem => matches!(slot_func, SlotFunc::SeqAssItem(_)), - Self::SeqContains => matches!(slot_func, SlotFunc::SeqContains(_)), + Self::SqLength => matches!(slot_func, SlotFunc::SeqLength(_)), + 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::SqContains => matches!(slot_func, SlotFunc::SeqContains(_)), + // Mapping - Self::MapLength => matches!(slot_func, SlotFunc::MapLength(_)), - Self::MapSubscript => matches!(slot_func, SlotFunc::MapSubscript(_)), - Self::MapAssSubscript => matches!(slot_func, SlotFunc::MapAssSubscript(_)), - // New has no wrapper - Self::New => false, + Self::MpLength => matches!(slot_func, SlotFunc::MapLength(_)), + Self::MpSubscript => matches!(slot_func, SlotFunc::MapSubscript(_)), + Self::MpAssSubscript => matches!(slot_func, SlotFunc::MapAssSubscript(_)), + + // New and reserved slots + Self::TpNew => false, + _ => false, // Reserved slots } } /// Inherit slot value from MRO pub fn inherit_from_mro(&self, typ: &crate::builtins::PyType) { - // Note: typ.mro does NOT include typ itself, so we iterate all elements + // Note: typ.mro does NOT include typ itself let mro = typ.mro.read(); macro_rules! inherit_main { @@ -308,102 +439,81 @@ impl SlotAccessor { } match self { - // Main slots - Self::Hash => inherit_main!(hash), - Self::Repr => inherit_main!(repr), - Self::Str => inherit_main!(str), - Self::Call => inherit_main!(call), - Self::Iter => inherit_main!(iter), - Self::IterNext => inherit_main!(iternext), - Self::Init => inherit_main!(init), - Self::New => inherit_main!(new), - Self::Del => inherit_main!(del), - Self::GetAttro => inherit_main!(getattro), - Self::SetAttro | Self::DelAttro => inherit_main!(setattro), - Self::DescrGet => inherit_main!(descr_get), - Self::DescrSet | Self::DescrDel => inherit_main!(descr_set), - - // RichCompare - Self::RichCompareLt - | Self::RichCompareLe - | Self::RichCompareEq - | Self::RichCompareNe - | Self::RichCompareGt - | Self::RichCompareGe => inherit_main!(richcompare), - - // Number binary - Self::NumAdd => inherit_number!(add), - Self::NumRightAdd => inherit_number!(right_add), - Self::NumInplaceAdd => inherit_number!(inplace_add), - Self::NumSubtract => inherit_number!(subtract), - Self::NumRightSubtract => inherit_number!(right_subtract), - Self::NumInplaceSubtract => inherit_number!(inplace_subtract), - Self::NumMultiply => inherit_number!(multiply), - Self::NumRightMultiply => inherit_number!(right_multiply), - Self::NumInplaceMultiply => inherit_number!(inplace_multiply), - Self::NumRemainder => inherit_number!(remainder), - Self::NumRightRemainder => inherit_number!(right_remainder), - Self::NumInplaceRemainder => inherit_number!(inplace_remainder), - Self::NumDivmod => inherit_number!(divmod), - Self::NumRightDivmod => inherit_number!(right_divmod), - Self::NumPower => inherit_number!(power), - Self::NumRightPower => inherit_number!(right_power), - Self::NumInplacePower => inherit_number!(inplace_power), - Self::NumFloorDivide => inherit_number!(floor_divide), - Self::NumRightFloorDivide => inherit_number!(right_floor_divide), - Self::NumInplaceFloorDivide => inherit_number!(inplace_floor_divide), - Self::NumTrueDivide => inherit_number!(true_divide), - Self::NumRightTrueDivide => inherit_number!(right_true_divide), - Self::NumInplaceTrueDivide => inherit_number!(inplace_true_divide), - Self::NumMatrixMultiply => inherit_number!(matrix_multiply), - Self::NumRightMatrixMultiply => inherit_number!(right_matrix_multiply), - Self::NumInplaceMatrixMultiply => inherit_number!(inplace_matrix_multiply), - Self::NumLshift => inherit_number!(lshift), - Self::NumRightLshift => inherit_number!(right_lshift), - Self::NumInplaceLshift => inherit_number!(inplace_lshift), - Self::NumRshift => inherit_number!(rshift), - Self::NumRightRshift => inherit_number!(right_rshift), - Self::NumInplaceRshift => inherit_number!(inplace_rshift), - Self::NumAnd => inherit_number!(and), - Self::NumRightAnd => inherit_number!(right_and), - Self::NumInplaceAnd => inherit_number!(inplace_and), - Self::NumXor => inherit_number!(xor), - Self::NumRightXor => inherit_number!(right_xor), - Self::NumInplaceXor => inherit_number!(inplace_xor), - Self::NumOr => inherit_number!(or), - Self::NumRightOr => inherit_number!(right_or), - Self::NumInplaceOr => inherit_number!(inplace_or), + // Type slots + Self::TpHash => inherit_main!(hash), + Self::TpRepr => inherit_main!(repr), + Self::TpStr => inherit_main!(str), + Self::TpCall => inherit_main!(call), + Self::TpIter => inherit_main!(iter), + Self::TpIternext => inherit_main!(iternext), + Self::TpInit => inherit_main!(init), + Self::TpNew => inherit_main!(new), + Self::TpDel => inherit_main!(del), + Self::TpGetattro => inherit_main!(getattro), + Self::TpSetattro => inherit_main!(setattro), + Self::TpDescrGet => inherit_main!(descr_get), + Self::TpDescrSet => inherit_main!(descr_set), + Self::TpRichcompare => inherit_main!(richcompare), + // Number slots + Self::NbAdd => inherit_number!(add), + Self::NbSubtract => inherit_number!(subtract), + Self::NbMultiply => inherit_number!(multiply), + Self::NbRemainder => inherit_number!(remainder), + Self::NbDivmod => inherit_number!(divmod), + Self::NbPower => inherit_number!(power), + Self::NbLshift => inherit_number!(lshift), + Self::NbRshift => inherit_number!(rshift), + Self::NbAnd => inherit_number!(and), + Self::NbXor => inherit_number!(xor), + Self::NbOr => inherit_number!(or), + Self::NbFloorDivide => inherit_number!(floor_divide), + Self::NbTrueDivide => inherit_number!(true_divide), + Self::NbMatrixMultiply => inherit_number!(matrix_multiply), + Self::NbInplaceAdd => inherit_number!(inplace_add), + Self::NbInplaceSubtract => inherit_number!(inplace_subtract), + Self::NbInplaceMultiply => inherit_number!(inplace_multiply), + Self::NbInplaceRemainder => inherit_number!(inplace_remainder), + Self::NbInplacePower => inherit_number!(inplace_power), + Self::NbInplaceLshift => inherit_number!(inplace_lshift), + Self::NbInplaceRshift => inherit_number!(inplace_rshift), + Self::NbInplaceAnd => inherit_number!(inplace_and), + Self::NbInplaceXor => inherit_number!(inplace_xor), + Self::NbInplaceOr => inherit_number!(inplace_or), + Self::NbInplaceFloorDivide => inherit_number!(inplace_floor_divide), + Self::NbInplaceTrueDivide => inherit_number!(inplace_true_divide), + Self::NbInplaceMatrixMultiply => inherit_number!(inplace_matrix_multiply), // Number unary - Self::NumNegative => inherit_number!(negative), - Self::NumPositive => inherit_number!(positive), - Self::NumAbsolute => inherit_number!(absolute), - Self::NumInvert => inherit_number!(invert), - Self::NumBoolean => inherit_number!(boolean), - Self::NumInt => inherit_number!(int), - Self::NumFloat => inherit_number!(float), - Self::NumIndex => inherit_number!(index), + Self::NbNegative => inherit_number!(negative), + Self::NbPositive => inherit_number!(positive), + Self::NbAbsolute => inherit_number!(absolute), + Self::NbInvert => inherit_number!(invert), + Self::NbBool => inherit_number!(boolean), + Self::NbInt => inherit_number!(int), + Self::NbFloat => inherit_number!(float), + Self::NbIndex => inherit_number!(index), - // Sequence - Self::SeqLength => inherit_sequence!(length), - Self::SeqConcat => inherit_sequence!(concat), - Self::SeqRepeat => inherit_sequence!(repeat), - Self::SeqItem => inherit_sequence!(item), - Self::SeqAssItem => inherit_sequence!(ass_item), - Self::SeqContains => inherit_sequence!(contains), - Self::SeqInplaceConcat => inherit_sequence!(inplace_concat), - Self::SeqInplaceRepeat => inherit_sequence!(inplace_repeat), + // Sequence slots + Self::SqLength => inherit_sequence!(length), + Self::SqConcat => inherit_sequence!(concat), + Self::SqRepeat => inherit_sequence!(repeat), + Self::SqItem => inherit_sequence!(item), + Self::SqAssItem => inherit_sequence!(ass_item), + Self::SqContains => inherit_sequence!(contains), + Self::SqInplaceConcat => inherit_sequence!(inplace_concat), + Self::SqInplaceRepeat => inherit_sequence!(inplace_repeat), - // Mapping - Self::MapLength => inherit_mapping!(length), - Self::MapSubscript => inherit_mapping!(subscript), - Self::MapAssSubscript => inherit_mapping!(ass_subscript), + // Mapping slots + Self::MpLength => inherit_mapping!(length), + Self::MpSubscript => inherit_mapping!(subscript), + Self::MpAssSubscript => inherit_mapping!(ass_subscript), + + // Reserved slots - no-op + _ => {} } } /// Copy slot from base type if self's slot is None - /// - /// Used by inherit_slots() for slot inheritance from base classes. pub fn copyslot_if_none(&self, typ: &crate::builtins::PyType, base: &crate::builtins::PyType) { macro_rules! copy_main { ($slot:ident) => {{ @@ -446,14 +556,14 @@ impl SlotAccessor { } match self { - // Main slots - Self::Hash => copy_main!(hash), - Self::Repr => copy_main!(repr), - Self::Str => copy_main!(str), - Self::Call => copy_main!(call), - Self::Iter => copy_main!(iter), - Self::IterNext => copy_main!(iternext), - Self::Init => { + // Type slots + Self::TpHash => copy_main!(hash), + Self::TpRepr => copy_main!(repr), + Self::TpStr => copy_main!(str), + Self::TpCall => copy_main!(call), + Self::TpIter => copy_main!(iter), + Self::TpIternext => copy_main!(iternext), + Self::TpInit => { // SLOTDEFINED check for multiple inheritance support if typ.slots.init.load().is_none() && let Some(base_val) = base.slots.init.load() @@ -466,739 +576,866 @@ impl SlotAccessor { } } } - Self::New => {} // handled by set_new() - Self::Del => copy_main!(del), - Self::GetAttro => copy_main!(getattro), - Self::SetAttro | Self::DelAttro => copy_main!(setattro), - Self::DescrGet => copy_main!(descr_get), - Self::DescrSet | Self::DescrDel => copy_main!(descr_set), - - // RichCompare - Self::RichCompareLt - | Self::RichCompareLe - | Self::RichCompareEq - | Self::RichCompareNe - | Self::RichCompareGt - | Self::RichCompareGe => copy_main!(richcompare), - - // Number binary - Self::NumAdd => copy_number!(add), - Self::NumRightAdd => copy_number!(right_add), - Self::NumInplaceAdd => copy_number!(inplace_add), - Self::NumSubtract => copy_number!(subtract), - Self::NumRightSubtract => copy_number!(right_subtract), - Self::NumInplaceSubtract => copy_number!(inplace_subtract), - Self::NumMultiply => copy_number!(multiply), - Self::NumRightMultiply => copy_number!(right_multiply), - Self::NumInplaceMultiply => copy_number!(inplace_multiply), - Self::NumRemainder => copy_number!(remainder), - Self::NumRightRemainder => copy_number!(right_remainder), - Self::NumInplaceRemainder => copy_number!(inplace_remainder), - Self::NumDivmod => copy_number!(divmod), - Self::NumRightDivmod => copy_number!(right_divmod), - Self::NumPower => copy_number!(power), - Self::NumRightPower => copy_number!(right_power), - Self::NumInplacePower => copy_number!(inplace_power), - Self::NumFloorDivide => copy_number!(floor_divide), - Self::NumRightFloorDivide => copy_number!(right_floor_divide), - Self::NumInplaceFloorDivide => copy_number!(inplace_floor_divide), - Self::NumTrueDivide => copy_number!(true_divide), - Self::NumRightTrueDivide => copy_number!(right_true_divide), - Self::NumInplaceTrueDivide => copy_number!(inplace_true_divide), - Self::NumMatrixMultiply => copy_number!(matrix_multiply), - Self::NumRightMatrixMultiply => copy_number!(right_matrix_multiply), - Self::NumInplaceMatrixMultiply => copy_number!(inplace_matrix_multiply), - Self::NumLshift => copy_number!(lshift), - Self::NumRightLshift => copy_number!(right_lshift), - Self::NumInplaceLshift => copy_number!(inplace_lshift), - Self::NumRshift => copy_number!(rshift), - Self::NumRightRshift => copy_number!(right_rshift), - Self::NumInplaceRshift => copy_number!(inplace_rshift), - Self::NumAnd => copy_number!(and), - Self::NumRightAnd => copy_number!(right_and), - Self::NumInplaceAnd => copy_number!(inplace_and), - Self::NumXor => copy_number!(xor), - Self::NumRightXor => copy_number!(right_xor), - Self::NumInplaceXor => copy_number!(inplace_xor), - Self::NumOr => copy_number!(or), - Self::NumRightOr => copy_number!(right_or), - Self::NumInplaceOr => copy_number!(inplace_or), + Self::TpNew => {} // handled by set_new() + Self::TpDel => copy_main!(del), + Self::TpGetattro => copy_main!(getattro), + Self::TpSetattro => copy_main!(setattro), + Self::TpDescrGet => copy_main!(descr_get), + Self::TpDescrSet => copy_main!(descr_set), + Self::TpRichcompare => copy_main!(richcompare), + // Number slots + Self::NbAdd => copy_number!(add), + Self::NbSubtract => copy_number!(subtract), + Self::NbMultiply => copy_number!(multiply), + Self::NbRemainder => copy_number!(remainder), + Self::NbDivmod => copy_number!(divmod), + Self::NbPower => copy_number!(power), + Self::NbLshift => copy_number!(lshift), + Self::NbRshift => copy_number!(rshift), + Self::NbAnd => copy_number!(and), + Self::NbXor => copy_number!(xor), + Self::NbOr => copy_number!(or), + Self::NbFloorDivide => copy_number!(floor_divide), + Self::NbTrueDivide => copy_number!(true_divide), + Self::NbMatrixMultiply => copy_number!(matrix_multiply), + Self::NbInplaceAdd => copy_number!(inplace_add), + Self::NbInplaceSubtract => copy_number!(inplace_subtract), + Self::NbInplaceMultiply => copy_number!(inplace_multiply), + Self::NbInplaceRemainder => copy_number!(inplace_remainder), + Self::NbInplacePower => copy_number!(inplace_power), + Self::NbInplaceLshift => copy_number!(inplace_lshift), + Self::NbInplaceRshift => copy_number!(inplace_rshift), + Self::NbInplaceAnd => copy_number!(inplace_and), + Self::NbInplaceXor => copy_number!(inplace_xor), + Self::NbInplaceOr => copy_number!(inplace_or), + Self::NbInplaceFloorDivide => copy_number!(inplace_floor_divide), + Self::NbInplaceTrueDivide => copy_number!(inplace_true_divide), + Self::NbInplaceMatrixMultiply => copy_number!(inplace_matrix_multiply), // Number unary - Self::NumNegative => copy_number!(negative), - Self::NumPositive => copy_number!(positive), - Self::NumAbsolute => copy_number!(absolute), - Self::NumInvert => copy_number!(invert), - Self::NumBoolean => copy_number!(boolean), - Self::NumInt => copy_number!(int), - Self::NumFloat => copy_number!(float), - Self::NumIndex => copy_number!(index), + Self::NbNegative => copy_number!(negative), + Self::NbPositive => copy_number!(positive), + Self::NbAbsolute => copy_number!(absolute), + Self::NbInvert => copy_number!(invert), + Self::NbBool => copy_number!(boolean), + Self::NbInt => copy_number!(int), + Self::NbFloat => copy_number!(float), + Self::NbIndex => copy_number!(index), - // Sequence - Self::SeqLength => copy_sequence!(length), - Self::SeqConcat => copy_sequence!(concat), - Self::SeqRepeat => copy_sequence!(repeat), - Self::SeqItem => copy_sequence!(item), - Self::SeqAssItem => copy_sequence!(ass_item), - Self::SeqContains => copy_sequence!(contains), - Self::SeqInplaceConcat => copy_sequence!(inplace_concat), - Self::SeqInplaceRepeat => copy_sequence!(inplace_repeat), + // Sequence slots + Self::SqLength => copy_sequence!(length), + Self::SqConcat => copy_sequence!(concat), + Self::SqRepeat => copy_sequence!(repeat), + Self::SqItem => copy_sequence!(item), + Self::SqAssItem => copy_sequence!(ass_item), + Self::SqContains => copy_sequence!(contains), + Self::SqInplaceConcat => copy_sequence!(inplace_concat), + Self::SqInplaceRepeat => copy_sequence!(inplace_repeat), - // Mapping - Self::MapLength => copy_mapping!(length), - Self::MapSubscript => copy_mapping!(subscript), - Self::MapAssSubscript => copy_mapping!(ass_subscript), + // Mapping slots + Self::MpLength => copy_mapping!(length), + Self::MpSubscript => copy_mapping!(subscript), + Self::MpAssSubscript => copy_mapping!(ass_subscript), + + // Reserved slots - no-op + _ => {} } } - /// Get the slot function from PyTypeSlots, wrapped in SlotFunc - /// - /// Returns None if the slot is not set. + /// Get the SlotFunc from type slots for this accessor pub fn get_slot_func(&self, slots: &PyTypeSlots) -> Option { match self { - // Main slots - Self::Hash => slots.hash.load().map(SlotFunc::Hash), - Self::Repr => slots.repr.load().map(SlotFunc::Repr), - Self::Str => slots.str.load().map(SlotFunc::Str), - Self::Call => slots.call.load().map(SlotFunc::Call), - Self::Iter => slots.iter.load().map(SlotFunc::Iter), - Self::IterNext => slots.iternext.load().map(SlotFunc::IterNext), - Self::Init => slots.init.load().map(SlotFunc::Init), - Self::New => None, // __new__ has special handling, no wrapper - Self::Del => slots.del.load().map(SlotFunc::Del), - Self::GetAttro => slots.getattro.load().map(SlotFunc::GetAttro), - Self::SetAttro => slots.setattro.load().map(SlotFunc::SetAttro), - Self::DelAttro => slots.setattro.load().map(SlotFunc::DelAttro), - Self::DescrGet => slots.descr_get.load().map(SlotFunc::DescrGet), - Self::DescrSet => slots.descr_set.load().map(SlotFunc::DescrSet), - Self::DescrDel => slots.descr_set.load().map(SlotFunc::DescrDel), - - // RichCompare - Self::RichCompareLt => slots - .richcompare - .load() - .map(|f| SlotFunc::RichCompare(f, PyComparisonOp::Lt)), - Self::RichCompareLe => slots - .richcompare - .load() - .map(|f| SlotFunc::RichCompare(f, PyComparisonOp::Le)), - Self::RichCompareEq => slots + // Type slots + Self::TpHash => slots.hash.load().map(SlotFunc::Hash), + Self::TpRepr => slots.repr.load().map(SlotFunc::Repr), + Self::TpStr => slots.str.load().map(SlotFunc::Str), + Self::TpCall => slots.call.load().map(SlotFunc::Call), + Self::TpIter => slots.iter.load().map(SlotFunc::Iter), + Self::TpIternext => slots.iternext.load().map(SlotFunc::IterNext), + Self::TpInit => slots.init.load().map(SlotFunc::Init), + Self::TpNew => None, // __new__ handled separately + Self::TpDel => slots.del.load().map(SlotFunc::Del), + Self::TpGetattro => slots.getattro.load().map(SlotFunc::GetAttro), + Self::TpSetattro => slots.setattro.load().map(SlotFunc::SetAttro), + Self::TpDescrGet => slots.descr_get.load().map(SlotFunc::DescrGet), + Self::TpDescrSet => slots.descr_set.load().map(SlotFunc::DescrSet), + Self::TpRichcompare => slots .richcompare .load() .map(|f| SlotFunc::RichCompare(f, PyComparisonOp::Eq)), - Self::RichCompareNe => slots - .richcompare + + // Number binary slots + Self::NbAdd => slots.as_number.add.load().map(SlotFunc::NumBinary), + Self::NbSubtract => slots.as_number.subtract.load().map(SlotFunc::NumBinary), + Self::NbMultiply => slots.as_number.multiply.load().map(SlotFunc::NumBinary), + Self::NbRemainder => slots.as_number.remainder.load().map(SlotFunc::NumBinary), + Self::NbDivmod => slots.as_number.divmod.load().map(SlotFunc::NumBinary), + Self::NbPower => slots.as_number.power.load().map(SlotFunc::NumTernary), + Self::NbLshift => slots.as_number.lshift.load().map(SlotFunc::NumBinary), + Self::NbRshift => slots.as_number.rshift.load().map(SlotFunc::NumBinary), + Self::NbAnd => slots.as_number.and.load().map(SlotFunc::NumBinary), + Self::NbXor => slots.as_number.xor.load().map(SlotFunc::NumBinary), + Self::NbOr => slots.as_number.or.load().map(SlotFunc::NumBinary), + Self::NbFloorDivide => slots.as_number.floor_divide.load().map(SlotFunc::NumBinary), + Self::NbTrueDivide => slots.as_number.true_divide.load().map(SlotFunc::NumBinary), + Self::NbMatrixMultiply => slots + .as_number + .matrix_multiply .load() - .map(|f| SlotFunc::RichCompare(f, PyComparisonOp::Ne)), - Self::RichCompareGt => slots - .richcompare + .map(SlotFunc::NumBinary), + + // Number inplace slots + Self::NbInplaceAdd => slots.as_number.inplace_add.load().map(SlotFunc::NumBinary), + Self::NbInplaceSubtract => slots + .as_number + .inplace_subtract .load() - .map(|f| SlotFunc::RichCompare(f, PyComparisonOp::Gt)), - Self::RichCompareGe => slots - .richcompare + .map(SlotFunc::NumBinary), + Self::NbInplaceMultiply => slots + .as_number + .inplace_multiply .load() - .map(|f| SlotFunc::RichCompare(f, PyComparisonOp::Ge)), - - // Number - binary - Self::NumAdd => Self::get_number_slot(&slots.as_number, |s| s.add.load()), - Self::NumRightAdd => Self::get_number_slot(&slots.as_number, |s| s.right_add.load()), - Self::NumInplaceAdd => { - Self::get_number_slot(&slots.as_number, |s| s.inplace_add.load()) - } - Self::NumSubtract => Self::get_number_slot(&slots.as_number, |s| s.subtract.load()), - Self::NumRightSubtract => { - Self::get_number_slot(&slots.as_number, |s| s.right_subtract.load()) - } - Self::NumInplaceSubtract => { - Self::get_number_slot(&slots.as_number, |s| s.inplace_subtract.load()) - } - Self::NumMultiply => Self::get_number_slot(&slots.as_number, |s| s.multiply.load()), - Self::NumRightMultiply => { - Self::get_number_slot(&slots.as_number, |s| s.right_multiply.load()) - } - Self::NumInplaceMultiply => { - Self::get_number_slot(&slots.as_number, |s| s.inplace_multiply.load()) - } - Self::NumRemainder => Self::get_number_slot(&slots.as_number, |s| s.remainder.load()), - Self::NumRightRemainder => { - Self::get_number_slot(&slots.as_number, |s| s.right_remainder.load()) - } - Self::NumInplaceRemainder => { - Self::get_number_slot(&slots.as_number, |s| s.inplace_remainder.load()) - } - Self::NumDivmod => Self::get_number_slot(&slots.as_number, |s| s.divmod.load()), - Self::NumRightDivmod => { - Self::get_number_slot(&slots.as_number, |s| s.right_divmod.load()) - } - Self::NumFloorDivide => { - Self::get_number_slot(&slots.as_number, |s| s.floor_divide.load()) - } - Self::NumRightFloorDivide => { - Self::get_number_slot(&slots.as_number, |s| s.right_floor_divide.load()) - } - Self::NumInplaceFloorDivide => { - Self::get_number_slot(&slots.as_number, |s| s.inplace_floor_divide.load()) - } - Self::NumTrueDivide => { - Self::get_number_slot(&slots.as_number, |s| s.true_divide.load()) - } - Self::NumRightTrueDivide => { - Self::get_number_slot(&slots.as_number, |s| s.right_true_divide.load()) - } - Self::NumInplaceTrueDivide => { - Self::get_number_slot(&slots.as_number, |s| s.inplace_true_divide.load()) - } - Self::NumMatrixMultiply => { - Self::get_number_slot(&slots.as_number, |s| s.matrix_multiply.load()) - } - Self::NumRightMatrixMultiply => { - Self::get_number_slot(&slots.as_number, |s| s.right_matrix_multiply.load()) - } - Self::NumInplaceMatrixMultiply => { - Self::get_number_slot(&slots.as_number, |s| s.inplace_matrix_multiply.load()) - } - Self::NumLshift => Self::get_number_slot(&slots.as_number, |s| s.lshift.load()), - Self::NumRightLshift => { - Self::get_number_slot(&slots.as_number, |s| s.right_lshift.load()) - } - Self::NumInplaceLshift => { - Self::get_number_slot(&slots.as_number, |s| s.inplace_lshift.load()) - } - Self::NumRshift => Self::get_number_slot(&slots.as_number, |s| s.rshift.load()), - Self::NumRightRshift => { - Self::get_number_slot(&slots.as_number, |s| s.right_rshift.load()) - } - Self::NumInplaceRshift => { - Self::get_number_slot(&slots.as_number, |s| s.inplace_rshift.load()) - } - Self::NumAnd => Self::get_number_slot(&slots.as_number, |s| s.and.load()), - Self::NumRightAnd => Self::get_number_slot(&slots.as_number, |s| s.right_and.load()), - Self::NumInplaceAnd => { - Self::get_number_slot(&slots.as_number, |s| s.inplace_and.load()) - } - Self::NumXor => Self::get_number_slot(&slots.as_number, |s| s.xor.load()), - Self::NumRightXor => Self::get_number_slot(&slots.as_number, |s| s.right_xor.load()), - Self::NumInplaceXor => { - Self::get_number_slot(&slots.as_number, |s| s.inplace_xor.load()) - } - Self::NumOr => Self::get_number_slot(&slots.as_number, |s| s.or.load()), - Self::NumRightOr => Self::get_number_slot(&slots.as_number, |s| s.right_or.load()), - Self::NumInplaceOr => Self::get_number_slot(&slots.as_number, |s| s.inplace_or.load()), - - // Number - power (ternary) - Self::NumPower => slots.as_number.power.load().map(SlotFunc::NumTernary), - Self::NumRightPower => slots.as_number.right_power.load().map(SlotFunc::NumTernary), - Self::NumInplacePower => slots + .map(SlotFunc::NumBinary), + Self::NbInplaceRemainder => slots + .as_number + .inplace_remainder + .load() + .map(SlotFunc::NumBinary), + Self::NbInplacePower => slots .as_number .inplace_power .load() .map(SlotFunc::NumTernary), + Self::NbInplaceLshift => slots + .as_number + .inplace_lshift + .load() + .map(SlotFunc::NumBinary), + Self::NbInplaceRshift => slots + .as_number + .inplace_rshift + .load() + .map(SlotFunc::NumBinary), + Self::NbInplaceAnd => slots.as_number.inplace_and.load().map(SlotFunc::NumBinary), + Self::NbInplaceXor => slots.as_number.inplace_xor.load().map(SlotFunc::NumBinary), + Self::NbInplaceOr => slots.as_number.inplace_or.load().map(SlotFunc::NumBinary), + Self::NbInplaceFloorDivide => slots + .as_number + .inplace_floor_divide + .load() + .map(SlotFunc::NumBinary), + Self::NbInplaceTrueDivide => slots + .as_number + .inplace_true_divide + .load() + .map(SlotFunc::NumBinary), + Self::NbInplaceMatrixMultiply => slots + .as_number + .inplace_matrix_multiply + .load() + .map(SlotFunc::NumBinary), - // Number - unary - Self::NumNegative => slots.as_number.negative.load().map(SlotFunc::NumUnary), - Self::NumPositive => slots.as_number.positive.load().map(SlotFunc::NumUnary), - Self::NumAbsolute => slots.as_number.absolute.load().map(SlotFunc::NumUnary), - Self::NumInvert => slots.as_number.invert.load().map(SlotFunc::NumUnary), - Self::NumBoolean => slots.as_number.boolean.load().map(SlotFunc::NumBoolean), - Self::NumInt => slots.as_number.int.load().map(SlotFunc::NumUnary), - Self::NumFloat => slots.as_number.float.load().map(SlotFunc::NumUnary), - Self::NumIndex => slots.as_number.index.load().map(SlotFunc::NumUnary), + // Number unary slots + Self::NbNegative => slots.as_number.negative.load().map(SlotFunc::NumUnary), + Self::NbPositive => slots.as_number.positive.load().map(SlotFunc::NumUnary), + Self::NbAbsolute => slots.as_number.absolute.load().map(SlotFunc::NumUnary), + Self::NbInvert => slots.as_number.invert.load().map(SlotFunc::NumUnary), + Self::NbBool => slots.as_number.boolean.load().map(SlotFunc::NumBoolean), + Self::NbInt => slots.as_number.int.load().map(SlotFunc::NumUnary), + Self::NbFloat => slots.as_number.float.load().map(SlotFunc::NumUnary), + Self::NbIndex => slots.as_number.index.load().map(SlotFunc::NumUnary), - // Sequence - Self::SeqLength => slots.as_sequence.length.load().map(SlotFunc::SeqLength), - Self::SeqConcat => slots.as_sequence.concat.load().map(SlotFunc::SeqConcat), - Self::SeqRepeat => slots.as_sequence.repeat.load().map(SlotFunc::SeqRepeat), - Self::SeqItem => slots.as_sequence.item.load().map(SlotFunc::SeqItem), - Self::SeqAssItem => slots.as_sequence.ass_item.load().map(SlotFunc::SeqAssItem), - Self::SeqContains => slots.as_sequence.contains.load().map(SlotFunc::SeqContains), - Self::SeqInplaceConcat => slots + // Sequence slots + Self::SqLength => slots.as_sequence.length.load().map(SlotFunc::SeqLength), + 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::SqContains => slots.as_sequence.contains.load().map(SlotFunc::SeqContains), + Self::SqInplaceConcat => slots .as_sequence .inplace_concat .load() .map(SlotFunc::SeqConcat), - Self::SeqInplaceRepeat => slots + Self::SqInplaceRepeat => slots .as_sequence .inplace_repeat .load() .map(SlotFunc::SeqRepeat), - // Mapping - Self::MapLength => slots.as_mapping.length.load().map(SlotFunc::MapLength), - Self::MapSubscript => slots + // Mapping slots + Self::MpLength => slots.as_mapping.length.load().map(SlotFunc::MapLength), + Self::MpSubscript => slots .as_mapping .subscript .load() .map(SlotFunc::MapSubscript), - Self::MapAssSubscript => slots + Self::MpAssSubscript => slots .as_mapping .ass_subscript .load() .map(SlotFunc::MapAssSubscript), + + // Reserved slots + _ => None, } } - /// Helper for number binary slots - fn get_number_slot(slots: &PyNumberSlots, getter: F) -> Option - where - F: FnOnce(&PyNumberSlots) -> Option, - { - getter(slots).map(SlotFunc::NumBinary) + /// Get slot function considering SlotOp for right-hand and delete operations + pub fn get_slot_func_with_op( + &self, + slots: &PyTypeSlots, + op: Option, + ) -> Option { + // For Delete operations, return the delete variant + if op == Some(SlotOp::Delete) { + match self { + Self::TpSetattro => return slots.setattro.load().map(SlotFunc::DelAttro), + Self::TpDescrSet => return slots.descr_set.load().map(SlotFunc::DescrDel), + _ => {} + } + } + // For Right operations on binary number slots, use right_* fields with swapped args + if op == Some(SlotOp::Right) { + match self { + Self::NbAdd => { + return slots + .as_number + .right_add + .load() + .map(SlotFunc::NumBinaryRight); + } + Self::NbSubtract => { + return slots + .as_number + .right_subtract + .load() + .map(SlotFunc::NumBinaryRight); + } + Self::NbMultiply => { + return slots + .as_number + .right_multiply + .load() + .map(SlotFunc::NumBinaryRight); + } + Self::NbRemainder => { + return slots + .as_number + .right_remainder + .load() + .map(SlotFunc::NumBinaryRight); + } + Self::NbDivmod => { + return slots + .as_number + .right_divmod + .load() + .map(SlotFunc::NumBinaryRight); + } + Self::NbPower => { + return slots + .as_number + .right_power + .load() + .map(SlotFunc::NumTernaryRight); + } + Self::NbLshift => { + return slots + .as_number + .right_lshift + .load() + .map(SlotFunc::NumBinaryRight); + } + Self::NbRshift => { + return slots + .as_number + .right_rshift + .load() + .map(SlotFunc::NumBinaryRight); + } + Self::NbAnd => { + return slots + .as_number + .right_and + .load() + .map(SlotFunc::NumBinaryRight); + } + Self::NbXor => { + return slots + .as_number + .right_xor + .load() + .map(SlotFunc::NumBinaryRight); + } + Self::NbOr => { + return slots + .as_number + .right_or + .load() + .map(SlotFunc::NumBinaryRight); + } + Self::NbFloorDivide => { + return slots + .as_number + .right_floor_divide + .load() + .map(SlotFunc::NumBinaryRight); + } + Self::NbTrueDivide => { + return slots + .as_number + .right_true_divide + .load() + .map(SlotFunc::NumBinaryRight); + } + Self::NbMatrixMultiply => { + return slots + .as_number + .right_matrix_multiply + .load() + .map(SlotFunc::NumBinaryRight); + } + _ => {} + } + } + // For comparison operations, use the appropriate PyComparisonOp + if let Self::TpRichcompare = self + && let Some(cmp_op) = op.and_then(|o| o.as_compare_op()) + { + return slots + .richcompare + .load() + .map(|f| SlotFunc::RichCompare(f, cmp_op)); + } + // Fall back to existing get_slot_func for left/other operations + self.get_slot_func(slots) } } -/// All slot definitions in a single static array -/// -/// Adding a new slot: just add one entry here, and implement the -/// accessor methods - everything else is automatic. +/// Find all slot definitions with a given name +pub fn find_slot_defs_by_name(name: &str) -> impl Iterator { + SLOT_DEFS.iter().filter(move |def| def.name == name) +} + +/// Total number of slot definitions +pub const SLOT_DEFS_COUNT: usize = SLOT_DEFS.len(); + +/// All slot definitions pub static SLOT_DEFS: &[SlotDef] = &[ - // Main slots (tp_*) + // Type slots (tp_*) SlotDef { name: "__init__", - accessor: SlotAccessor::Init, + accessor: SlotAccessor::TpInit, + op: None, doc: "Initialize self. See help(type(self)) for accurate signature.", }, SlotDef { name: "__new__", - accessor: SlotAccessor::New, + accessor: SlotAccessor::TpNew, + op: None, doc: "Create and return a new object. See help(type) for accurate signature.", }, SlotDef { name: "__del__", - accessor: SlotAccessor::Del, + accessor: SlotAccessor::TpDel, + op: None, doc: "Called when the instance is about to be destroyed.", }, SlotDef { name: "__repr__", - accessor: SlotAccessor::Repr, + accessor: SlotAccessor::TpRepr, + op: None, doc: "Return repr(self).", }, SlotDef { name: "__str__", - accessor: SlotAccessor::Str, + accessor: SlotAccessor::TpStr, + op: None, doc: "Return str(self).", }, SlotDef { name: "__hash__", - accessor: SlotAccessor::Hash, + accessor: SlotAccessor::TpHash, + op: None, doc: "Return hash(self).", }, SlotDef { name: "__call__", - accessor: SlotAccessor::Call, + accessor: SlotAccessor::TpCall, + op: None, doc: "Call self as a function.", }, SlotDef { name: "__iter__", - accessor: SlotAccessor::Iter, + accessor: SlotAccessor::TpIter, + op: None, doc: "Implement iter(self).", }, SlotDef { name: "__next__", - accessor: SlotAccessor::IterNext, + accessor: SlotAccessor::TpIternext, + op: None, doc: "Implement next(self).", }, // Attribute access SlotDef { name: "__getattribute__", - accessor: SlotAccessor::GetAttro, + accessor: SlotAccessor::TpGetattro, + op: None, doc: "Return getattr(self, name).", }, SlotDef { name: "__setattr__", - accessor: SlotAccessor::SetAttro, + accessor: SlotAccessor::TpSetattro, + op: None, doc: "Implement setattr(self, name, value).", }, SlotDef { name: "__delattr__", - accessor: SlotAccessor::DelAttro, + accessor: SlotAccessor::TpSetattro, + op: Some(SlotOp::Delete), doc: "Implement delattr(self, name).", }, - // Rich comparison (all map to richcompare slot with different op) + // Rich comparison - all map to TpRichcompare with different op SlotDef { name: "__eq__", - accessor: SlotAccessor::RichCompareEq, + accessor: SlotAccessor::TpRichcompare, + op: Some(SlotOp::Eq), doc: "Return self==value.", }, SlotDef { name: "__ne__", - accessor: SlotAccessor::RichCompareNe, + accessor: SlotAccessor::TpRichcompare, + op: Some(SlotOp::Ne), doc: "Return self!=value.", }, SlotDef { name: "__lt__", - accessor: SlotAccessor::RichCompareLt, + accessor: SlotAccessor::TpRichcompare, + op: Some(SlotOp::Lt), doc: "Return selfvalue.", }, SlotDef { name: "__ge__", - accessor: SlotAccessor::RichCompareGe, + accessor: SlotAccessor::TpRichcompare, + op: Some(SlotOp::Ge), doc: "Return self>=value.", }, // Descriptor protocol SlotDef { name: "__get__", - accessor: SlotAccessor::DescrGet, + accessor: SlotAccessor::TpDescrGet, + op: None, doc: "Return an attribute of instance, which is of type owner.", }, SlotDef { name: "__set__", - accessor: SlotAccessor::DescrSet, + accessor: SlotAccessor::TpDescrSet, + op: None, doc: "Set an attribute of instance to value.", }, SlotDef { name: "__delete__", - accessor: SlotAccessor::DescrDel, + accessor: SlotAccessor::TpDescrSet, + op: Some(SlotOp::Delete), doc: "Delete an attribute of instance.", }, // Sequence protocol (sq_*) SlotDef { name: "__len__", - accessor: SlotAccessor::SeqLength, + accessor: SlotAccessor::SqLength, + op: None, doc: "Return len(self).", }, SlotDef { name: "__getitem__", - accessor: SlotAccessor::SeqItem, + accessor: SlotAccessor::SqItem, + op: None, doc: "Return self[key].", }, SlotDef { name: "__setitem__", - accessor: SlotAccessor::SeqAssItem, + accessor: SlotAccessor::SqAssItem, + op: None, doc: "Set self[key] to value.", }, SlotDef { name: "__delitem__", - accessor: SlotAccessor::SeqAssItem, + accessor: SlotAccessor::SqAssItem, + op: None, doc: "Delete self[key].", }, SlotDef { name: "__contains__", - accessor: SlotAccessor::SeqContains, + accessor: SlotAccessor::SqContains, + op: None, doc: "Return key in self.", }, - SlotDef { - name: "__add__", - accessor: SlotAccessor::SeqConcat, - doc: "Return self+value.", - }, - SlotDef { - name: "__mul__", - accessor: SlotAccessor::SeqRepeat, - doc: "Return self*value.", - }, - SlotDef { - name: "__iadd__", - accessor: SlotAccessor::SeqInplaceConcat, - doc: "Implement self+=value.", - }, - SlotDef { - name: "__imul__", - accessor: SlotAccessor::SeqInplaceRepeat, - doc: "Implement self*=value.", - }, // Mapping protocol (mp_*) SlotDef { name: "__len__", - accessor: SlotAccessor::MapLength, + accessor: SlotAccessor::MpLength, + op: None, doc: "Return len(self).", }, SlotDef { name: "__getitem__", - accessor: SlotAccessor::MapSubscript, + accessor: SlotAccessor::MpSubscript, + op: None, doc: "Return self[key].", }, SlotDef { name: "__setitem__", - accessor: SlotAccessor::MapAssSubscript, + accessor: SlotAccessor::MpAssSubscript, + op: None, doc: "Set self[key] to value.", }, SlotDef { name: "__delitem__", - accessor: SlotAccessor::MapAssSubscript, + accessor: SlotAccessor::MpAssSubscript, + op: None, doc: "Delete self[key].", }, - // Number protocol - Binary operations (nb_*) + // Number protocol - binary ops with left/right variants SlotDef { name: "__add__", - accessor: SlotAccessor::NumAdd, + accessor: SlotAccessor::NbAdd, + op: Some(SlotOp::Left), doc: "Return self+value.", }, SlotDef { name: "__radd__", - accessor: SlotAccessor::NumRightAdd, + accessor: SlotAccessor::NbAdd, + op: Some(SlotOp::Right), doc: "Return value+self.", }, SlotDef { name: "__iadd__", - accessor: SlotAccessor::NumInplaceAdd, + accessor: SlotAccessor::NbInplaceAdd, + op: None, doc: "Implement self+=value.", }, SlotDef { name: "__sub__", - accessor: SlotAccessor::NumSubtract, + accessor: SlotAccessor::NbSubtract, + op: Some(SlotOp::Left), doc: "Return self-value.", }, SlotDef { name: "__rsub__", - accessor: SlotAccessor::NumRightSubtract, + accessor: SlotAccessor::NbSubtract, + op: Some(SlotOp::Right), doc: "Return value-self.", }, SlotDef { name: "__isub__", - accessor: SlotAccessor::NumInplaceSubtract, + accessor: SlotAccessor::NbInplaceSubtract, + op: None, doc: "Implement self-=value.", }, SlotDef { name: "__mul__", - accessor: SlotAccessor::NumMultiply, + accessor: SlotAccessor::NbMultiply, + op: Some(SlotOp::Left), doc: "Return self*value.", }, SlotDef { name: "__rmul__", - accessor: SlotAccessor::NumRightMultiply, + accessor: SlotAccessor::NbMultiply, + op: Some(SlotOp::Right), doc: "Return value*self.", }, SlotDef { name: "__imul__", - accessor: SlotAccessor::NumInplaceMultiply, + accessor: SlotAccessor::NbInplaceMultiply, + op: None, doc: "Implement self*=value.", }, SlotDef { name: "__mod__", - accessor: SlotAccessor::NumRemainder, + accessor: SlotAccessor::NbRemainder, + op: Some(SlotOp::Left), doc: "Return self%value.", }, SlotDef { name: "__rmod__", - accessor: SlotAccessor::NumRightRemainder, + accessor: SlotAccessor::NbRemainder, + op: Some(SlotOp::Right), doc: "Return value%self.", }, SlotDef { name: "__imod__", - accessor: SlotAccessor::NumInplaceRemainder, + accessor: SlotAccessor::NbInplaceRemainder, + op: None, doc: "Implement self%=value.", }, SlotDef { name: "__divmod__", - accessor: SlotAccessor::NumDivmod, + accessor: SlotAccessor::NbDivmod, + op: Some(SlotOp::Left), doc: "Return divmod(self, value).", }, SlotDef { name: "__rdivmod__", - accessor: SlotAccessor::NumRightDivmod, + accessor: SlotAccessor::NbDivmod, + op: Some(SlotOp::Right), doc: "Return divmod(value, self).", }, SlotDef { name: "__pow__", - accessor: SlotAccessor::NumPower, + accessor: SlotAccessor::NbPower, + op: Some(SlotOp::Left), doc: "Return pow(self, value, mod).", }, SlotDef { name: "__rpow__", - accessor: SlotAccessor::NumRightPower, + accessor: SlotAccessor::NbPower, + op: Some(SlotOp::Right), doc: "Return pow(value, self, mod).", }, SlotDef { name: "__ipow__", - accessor: SlotAccessor::NumInplacePower, + accessor: SlotAccessor::NbInplacePower, + op: None, doc: "Implement self**=value.", }, - SlotDef { - name: "__floordiv__", - accessor: SlotAccessor::NumFloorDivide, - doc: "Return self//value.", - }, - SlotDef { - name: "__rfloordiv__", - accessor: SlotAccessor::NumRightFloorDivide, - doc: "Return value//self.", - }, - SlotDef { - name: "__ifloordiv__", - accessor: SlotAccessor::NumInplaceFloorDivide, - doc: "Implement self//=value.", - }, - SlotDef { - name: "__truediv__", - accessor: SlotAccessor::NumTrueDivide, - doc: "Return self/value.", - }, - SlotDef { - name: "__rtruediv__", - accessor: SlotAccessor::NumRightTrueDivide, - doc: "Return value/self.", - }, - SlotDef { - name: "__itruediv__", - accessor: SlotAccessor::NumInplaceTrueDivide, - doc: "Implement self/=value.", - }, - SlotDef { - name: "__matmul__", - accessor: SlotAccessor::NumMatrixMultiply, - doc: "Return self@value.", - }, - SlotDef { - name: "__rmatmul__", - accessor: SlotAccessor::NumRightMatrixMultiply, - doc: "Return value@self.", - }, - SlotDef { - name: "__imatmul__", - accessor: SlotAccessor::NumInplaceMatrixMultiply, - doc: "Implement self@=value.", - }, - // Bitwise operations SlotDef { name: "__lshift__", - accessor: SlotAccessor::NumLshift, + accessor: SlotAccessor::NbLshift, + op: Some(SlotOp::Left), doc: "Return self<>value.", }, SlotDef { name: "__rrshift__", - accessor: SlotAccessor::NumRightRshift, + accessor: SlotAccessor::NbRshift, + op: Some(SlotOp::Right), doc: "Return value>>self.", }, SlotDef { name: "__irshift__", - accessor: SlotAccessor::NumInplaceRshift, + accessor: SlotAccessor::NbInplaceRshift, + op: None, doc: "Implement self>>=value.", }, SlotDef { name: "__and__", - accessor: SlotAccessor::NumAnd, + accessor: SlotAccessor::NbAnd, + op: Some(SlotOp::Left), doc: "Return self&value.", }, SlotDef { name: "__rand__", - accessor: SlotAccessor::NumRightAnd, + accessor: SlotAccessor::NbAnd, + op: Some(SlotOp::Right), doc: "Return value&self.", }, SlotDef { name: "__iand__", - accessor: SlotAccessor::NumInplaceAnd, + accessor: SlotAccessor::NbInplaceAnd, + op: None, doc: "Implement self&=value.", }, SlotDef { name: "__xor__", - accessor: SlotAccessor::NumXor, + accessor: SlotAccessor::NbXor, + op: Some(SlotOp::Left), doc: "Return self^value.", }, SlotDef { name: "__rxor__", - accessor: SlotAccessor::NumRightXor, + accessor: SlotAccessor::NbXor, + op: Some(SlotOp::Right), doc: "Return value^self.", }, SlotDef { name: "__ixor__", - accessor: SlotAccessor::NumInplaceXor, + accessor: SlotAccessor::NbInplaceXor, + op: None, doc: "Implement self^=value.", }, SlotDef { name: "__or__", - accessor: SlotAccessor::NumOr, + accessor: SlotAccessor::NbOr, + op: Some(SlotOp::Left), doc: "Return self|value.", }, SlotDef { name: "__ror__", - accessor: SlotAccessor::NumRightOr, + accessor: SlotAccessor::NbOr, + op: Some(SlotOp::Right), doc: "Return value|self.", }, SlotDef { name: "__ior__", - accessor: SlotAccessor::NumInplaceOr, + accessor: SlotAccessor::NbInplaceOr, + op: None, doc: "Implement self|=value.", }, - // Number protocol - Unary operations + SlotDef { + name: "__floordiv__", + accessor: SlotAccessor::NbFloorDivide, + op: Some(SlotOp::Left), + doc: "Return self//value.", + }, + SlotDef { + name: "__rfloordiv__", + accessor: SlotAccessor::NbFloorDivide, + op: Some(SlotOp::Right), + doc: "Return value//self.", + }, + SlotDef { + name: "__ifloordiv__", + accessor: SlotAccessor::NbInplaceFloorDivide, + op: None, + doc: "Implement self//=value.", + }, + SlotDef { + name: "__truediv__", + accessor: SlotAccessor::NbTrueDivide, + op: Some(SlotOp::Left), + doc: "Return self/value.", + }, + SlotDef { + name: "__rtruediv__", + accessor: SlotAccessor::NbTrueDivide, + op: Some(SlotOp::Right), + doc: "Return value/self.", + }, + SlotDef { + name: "__itruediv__", + accessor: SlotAccessor::NbInplaceTrueDivide, + op: None, + doc: "Implement self/=value.", + }, + SlotDef { + name: "__matmul__", + accessor: SlotAccessor::NbMatrixMultiply, + op: Some(SlotOp::Left), + doc: "Return self@value.", + }, + SlotDef { + name: "__rmatmul__", + accessor: SlotAccessor::NbMatrixMultiply, + op: Some(SlotOp::Right), + doc: "Return value@self.", + }, + SlotDef { + name: "__imatmul__", + accessor: SlotAccessor::NbInplaceMatrixMultiply, + op: None, + doc: "Implement self@=value.", + }, + // Number unary operations SlotDef { name: "__neg__", - accessor: SlotAccessor::NumNegative, + accessor: SlotAccessor::NbNegative, + op: None, doc: "Return -self.", }, SlotDef { name: "__pos__", - accessor: SlotAccessor::NumPositive, + accessor: SlotAccessor::NbPositive, + op: None, doc: "Return +self.", }, SlotDef { name: "__abs__", - accessor: SlotAccessor::NumAbsolute, + accessor: SlotAccessor::NbAbsolute, + op: None, doc: "Return abs(self).", }, SlotDef { name: "__invert__", - accessor: SlotAccessor::NumInvert, + accessor: SlotAccessor::NbInvert, + op: None, doc: "Return ~self.", }, SlotDef { name: "__bool__", - accessor: SlotAccessor::NumBoolean, + accessor: SlotAccessor::NbBool, + op: None, doc: "Return self != 0.", }, SlotDef { name: "__int__", - accessor: SlotAccessor::NumInt, - doc: "int(self)", + accessor: SlotAccessor::NbInt, + op: None, + doc: "Return int(self).", }, SlotDef { name: "__float__", - accessor: SlotAccessor::NumFloat, - doc: "float(self)", + accessor: SlotAccessor::NbFloat, + op: None, + doc: "Return float(self).", }, SlotDef { name: "__index__", - accessor: SlotAccessor::NumIndex, + accessor: SlotAccessor::NbIndex, + op: None, doc: "Return self converted to an integer, if self is suitable for use as an index into a list.", }, + // Sequence inplace operations (also map to number slots for some types) + SlotDef { + name: "__add__", + accessor: SlotAccessor::SqConcat, + op: None, + doc: "Return self+value.", + }, + SlotDef { + name: "__mul__", + accessor: SlotAccessor::SqRepeat, + op: None, + doc: "Return self*value.", + }, + SlotDef { + name: "__iadd__", + accessor: SlotAccessor::SqInplaceConcat, + op: None, + doc: "Implement self+=value.", + }, + SlotDef { + name: "__imul__", + accessor: SlotAccessor::SqInplaceRepeat, + op: None, + doc: "Implement self*=value.", + }, ]; -/// Find all slot definitions with a given name -pub fn find_slot_defs_by_name(name: &str) -> impl Iterator { - SLOT_DEFS.iter().filter(move |def| def.name == name) -} - -/// Total number of slot definitions -pub const SLOT_DEFS_COUNT: usize = SLOT_DEFS.len(); - #[cfg(test)] mod tests { use super::*; - #[test] - fn test_slot_defs_count() { - // Should have a reasonable number of entries - assert!( - SLOT_DEFS.len() > 60, - "Expected at least 60 slot definitions" - ); - assert!(SLOT_DEFS.len() < 150, "Too many slot definitions"); - } - #[test] fn test_find_by_name() { // __len__ appears in both sequence and mapping @@ -1209,27 +1446,20 @@ mod tests { let init_defs: Vec<_> = find_slot_defs_by_name("__init__").collect(); assert_eq!(init_defs.len(), 1); - // __add__ appears in sequence and number + // __add__ appears in number (left/right) and sequence let add_defs: Vec<_> = find_slot_defs_by_name("__add__").collect(); - assert_eq!(add_defs.len(), 2); + assert_eq!(add_defs.len(), 2); // NbAdd(Left) and SqConcat } #[test] - fn test_repr_u8() { - // Verify that SlotAccessor fits in u8 - assert!(std::mem::size_of::() == 1); - } + fn test_slot_op() { + // Test comparison ops + assert_eq!(SlotOp::Lt.as_compare_op(), Some(PyComparisonOp::Lt)); + assert_eq!(SlotOp::Eq.as_compare_op(), Some(PyComparisonOp::Eq)); + assert_eq!(SlotOp::Left.as_compare_op(), None); - #[test] - fn test_rich_compare_op() { - assert_eq!( - SlotAccessor::RichCompareLt.rich_compare_op(), - Some(PyComparisonOp::Lt) - ); - assert_eq!( - SlotAccessor::RichCompareEq.rich_compare_op(), - Some(PyComparisonOp::Eq) - ); - assert_eq!(SlotAccessor::Hash.rich_compare_op(), None); + // Test right check + assert!(SlotOp::Right.is_right()); + assert!(!SlotOp::Left.is_right()); } } From 112aff686eba11bc22712ad5e7ebbd617e6de81e Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 27 Dec 2025 23:45:41 +0900 Subject: [PATCH 4/4] remove unsed slots --- crates/vm/src/builtins/bool.rs | 14 +-- crates/vm/src/builtins/complex.rs | 122 -------------------- crates/vm/src/builtins/float.rs | 186 ------------------------------ crates/vm/src/builtins/int.rs | 150 +----------------------- 4 files changed, 9 insertions(+), 463 deletions(-) diff --git a/crates/vm/src/builtins/bool.rs b/crates/vm/src/builtins/bool.rs index 8fee4af383..cfd1f136d1 100644 --- a/crates/vm/src/builtins/bool.rs +++ b/crates/vm/src/builtins/bool.rs @@ -126,10 +126,10 @@ impl PyBool { .and_then(|format_spec| format_spec.format_bool(new_bool)) .map_err(|err| err.into_pyexception(vm)) } +} - #[pymethod(name = "__ror__")] - #[pymethod] - fn __or__(lhs: PyObjectRef, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { +impl PyBool { + pub(crate) fn __or__(lhs: PyObjectRef, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { if lhs.fast_isinstance(vm.ctx.types.bool_type) && rhs.fast_isinstance(vm.ctx.types.bool_type) { @@ -143,9 +143,7 @@ impl PyBool { } } - #[pymethod(name = "__rand__")] - #[pymethod] - fn __and__(lhs: PyObjectRef, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { + pub(crate) fn __and__(lhs: PyObjectRef, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { if lhs.fast_isinstance(vm.ctx.types.bool_type) && rhs.fast_isinstance(vm.ctx.types.bool_type) { @@ -159,9 +157,7 @@ impl PyBool { } } - #[pymethod(name = "__rxor__")] - #[pymethod] - fn __xor__(lhs: PyObjectRef, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { + pub(crate) fn __xor__(lhs: PyObjectRef, rhs: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef { if lhs.fast_isinstance(vm.ctx.types.bool_type) && rhs.fast_isinstance(vm.ctx.types.bool_type) { diff --git a/crates/vm/src/builtins/complex.rs b/crates/vm/src/builtins/complex.rs index 83021a7b4f..ba74d5e036 100644 --- a/crates/vm/src/builtins/complex.rs +++ b/crates/vm/src/builtins/complex.rs @@ -264,133 +264,11 @@ impl PyComplex { self.value.im } - #[pymethod] - fn __abs__(&self, vm: &VirtualMachine) -> PyResult { - let Complex64 { im, re } = self.value; - let is_finite = im.is_finite() && re.is_finite(); - let abs_result = re.hypot(im); - if is_finite && abs_result.is_infinite() { - Err(vm.new_overflow_error("absolute value too large")) - } else { - Ok(abs_result) - } - } - - #[inline] - fn op( - &self, - other: PyObjectRef, - op: F, - vm: &VirtualMachine, - ) -> PyResult> - where - F: Fn(Complex64, Complex64) -> PyResult, - { - to_op_complex(&other, vm)?.map_or_else( - || Ok(NotImplemented), - |other| Ok(Implemented(op(self.value, other)?)), - ) - } - - #[pymethod(name = "__radd__")] - #[pymethod] - fn __add__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.op(other, |a, b| Ok(a + b), vm) - } - - #[pymethod] - fn __sub__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.op(other, |a, b| Ok(a - b), vm) - } - - #[pymethod] - fn __rsub__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.op(other, |a, b| Ok(b - a), vm) - } - #[pymethod] fn conjugate(&self) -> Complex64 { self.value.conj() } - #[pymethod(name = "__rmul__")] - #[pymethod] - fn __mul__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.op(other, |a, b| Ok(a * b), vm) - } - - #[pymethod] - fn __truediv__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.op(other, |a, b| inner_div(a, b, vm), vm) - } - - #[pymethod] - fn __rtruediv__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.op(other, |a, b| inner_div(b, a, vm), vm) - } - - #[pymethod] - const fn __pos__(&self) -> Complex64 { - self.value - } - - #[pymethod] - fn __neg__(&self) -> Complex64 { - -self.value - } - - #[pymethod] - fn __pow__( - &self, - other: PyObjectRef, - mod_val: OptionalOption, - vm: &VirtualMachine, - ) -> PyResult> { - if mod_val.flatten().is_some() { - Err(vm.new_value_error("complex modulo not allowed")) - } else { - self.op(other, |a, b| inner_pow(a, b, vm), vm) - } - } - - #[pymethod] - fn __rpow__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.op(other, |a, b| inner_pow(b, a, vm), vm) - } - - #[pymethod] - fn __bool__(&self) -> bool { - !Complex64::is_zero(&self.value) - } - #[pymethod] const fn __getnewargs__(&self) -> (f64, f64) { let Complex64 { re, im } = self.value; diff --git a/crates/vm/src/builtins/float.rs b/crates/vm/src/builtins/float.rs index 9ce0c8953f..f101a3aa8e 100644 --- a/crates/vm/src/builtins/float.rs +++ b/crates/vm/src/builtins/float.rs @@ -238,182 +238,6 @@ impl PyFloat { .to_owned()) } - #[pymethod] - const fn __abs__(&self) -> f64 { - self.value.abs() - } - - #[inline] - fn simple_op( - &self, - other: PyObjectRef, - op: F, - vm: &VirtualMachine, - ) -> PyResult> - where - F: Fn(f64, f64) -> PyResult, - { - to_op_float(&other, vm)?.map_or_else( - || Ok(NotImplemented), - |other| Ok(Implemented(op(self.value, other)?)), - ) - } - - #[inline] - fn complex_op(&self, other: PyObjectRef, op: F, vm: &VirtualMachine) -> PyResult - where - F: Fn(f64, f64) -> PyResult, - { - to_op_float(&other, vm)?.map_or_else( - || Ok(vm.ctx.not_implemented()), - |other| op(self.value, other), - ) - } - - #[inline] - fn tuple_op( - &self, - other: PyObjectRef, - op: F, - vm: &VirtualMachine, - ) -> PyResult> - where - F: Fn(f64, f64) -> PyResult<(f64, f64)>, - { - to_op_float(&other, vm)?.map_or_else( - || Ok(NotImplemented), - |other| Ok(Implemented(op(self.value, other)?)), - ) - } - - #[pymethod(name = "__radd__")] - #[pymethod] - fn __add__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult> { - self.simple_op(other, |a, b| Ok(a + b), vm) - } - - #[pymethod] - const fn __bool__(&self) -> bool { - self.value != 0.0 - } - - #[pymethod] - fn __divmod__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.tuple_op(other, |a, b| inner_divmod(a, b, vm), vm) - } - - #[pymethod] - fn __rdivmod__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.tuple_op(other, |a, b| inner_divmod(b, a, vm), vm) - } - - #[pymethod] - fn __floordiv__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.simple_op(other, |a, b| inner_floordiv(a, b, vm), vm) - } - - #[pymethod] - fn __rfloordiv__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.simple_op(other, |a, b| inner_floordiv(b, a, vm), vm) - } - - #[pymethod(name = "__mod__")] - fn mod_(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult> { - self.simple_op(other, |a, b| inner_mod(a, b, vm), vm) - } - - #[pymethod] - fn __rmod__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.simple_op(other, |a, b| inner_mod(b, a, vm), vm) - } - - #[pymethod] - const fn __pos__(&self) -> f64 { - self.value - } - - #[pymethod] - const fn __neg__(&self) -> f64 { - -self.value - } - - #[pymethod] - fn __pow__( - &self, - other: PyObjectRef, - mod_val: OptionalOption, - vm: &VirtualMachine, - ) -> PyResult { - if mod_val.flatten().is_some() { - Err(vm.new_type_error("floating point pow() does not accept a 3rd argument")) - } else { - self.complex_op(other, |a, b| float_pow(a, b, vm), vm) - } - } - - #[pymethod] - fn __rpow__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.complex_op(other, |a, b| float_pow(b, a, vm), vm) - } - - #[pymethod] - fn __sub__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult> { - self.simple_op(other, |a, b| Ok(a - b), vm) - } - - #[pymethod] - fn __rsub__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.simple_op(other, |a, b| Ok(b - a), vm) - } - - #[pymethod] - fn __truediv__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.simple_op(other, |a, b| inner_div(a, b, vm), vm) - } - - #[pymethod] - fn __rtruediv__( - &self, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult> { - self.simple_op(other, |a, b| inner_div(b, a, vm), vm) - } - - #[pymethod(name = "__rmul__")] - #[pymethod] - fn __mul__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult> { - self.simple_op(other, |a, b| Ok(a * b), vm) - } - #[pymethod] fn __trunc__(&self, vm: &VirtualMachine) -> PyResult { try_to_bigint(self.value, vm) @@ -459,16 +283,6 @@ impl PyFloat { Ok(value) } - #[pymethod] - fn __int__(&self, vm: &VirtualMachine) -> PyResult { - self.__trunc__(vm) - } - - #[pymethod] - const fn __float__(zelf: PyRef) -> PyRef { - zelf - } - #[pygetset] const fn real(zelf: PyRef) -> PyRef { zelf diff --git a/crates/vm/src/builtins/int.rs b/crates/vm/src/builtins/int.rs index 0a406abd78..37b41e085a 100644 --- a/crates/vm/src/builtins/int.rs +++ b/crates/vm/src/builtins/int.rs @@ -324,83 +324,15 @@ impl PyInt { with(PyRef, Comparable, Hashable, Constructor, AsNumber, Representable) )] impl PyInt { - #[pymethod(name = "__radd__")] - #[pymethod] - fn __add__(&self, other: PyObjectRef) -> PyArithmeticValue { - self.int_op(other, |a, b| a + b) - } - - #[pymethod] - fn __sub__(&self, other: PyObjectRef) -> PyArithmeticValue { - self.int_op(other, |a, b| a - b) - } - - #[pymethod] - fn __rsub__(&self, other: PyObjectRef) -> PyArithmeticValue { - self.int_op(other, |a, b| b - a) - } - - #[pymethod(name = "__rmul__")] - #[pymethod] - fn __mul__(&self, other: PyObjectRef) -> PyArithmeticValue { - self.int_op(other, |a, b| a * b) - } - - #[pymethod] - fn __truediv__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.general_op(other, |a, b| inner_truediv(a, b, vm), vm) - } - - #[pymethod] - fn __rtruediv__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.general_op(other, |a, b| inner_truediv(b, a, vm), vm) - } - - #[pymethod] - fn __floordiv__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.general_op(other, |a, b| inner_floordiv(a, b, vm), vm) - } - - #[pymethod] - fn __rfloordiv__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.general_op(other, |a, b| inner_floordiv(b, a, vm), vm) - } - - #[pymethod] - fn __lshift__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.general_op(other, |a, b| inner_lshift(a, b, vm), vm) - } - - #[pymethod] - fn __rlshift__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.general_op(other, |a, b| inner_lshift(b, a, vm), vm) - } - - #[pymethod] - fn __rshift__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.general_op(other, |a, b| inner_rshift(a, b, vm), vm) - } - - #[pymethod] - fn __rrshift__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.general_op(other, |a, b| inner_rshift(b, a, vm), vm) - } - - #[pymethod(name = "__rxor__")] - #[pymethod] - pub fn __xor__(&self, other: PyObjectRef) -> PyArithmeticValue { + pub(crate) fn __xor__(&self, other: PyObjectRef) -> PyArithmeticValue { self.int_op(other, |a, b| a ^ b) } - #[pymethod(name = "__ror__")] - #[pymethod] - pub fn __or__(&self, other: PyObjectRef) -> PyArithmeticValue { + pub(crate) fn __or__(&self, other: PyObjectRef) -> PyArithmeticValue { self.int_op(other, |a, b| a | b) } - #[pymethod(name = "__rand__")] - #[pymethod] - pub fn __and__(&self, other: PyObjectRef) -> PyArithmeticValue { + pub(crate) fn __and__(&self, other: PyObjectRef) -> PyArithmeticValue { self.int_op(other, |a, b| a & b) } @@ -446,54 +378,6 @@ impl PyInt { ) } - #[pymethod] - fn __pow__( - &self, - other: PyObjectRef, - r#mod: OptionalOption, - vm: &VirtualMachine, - ) -> PyResult { - match r#mod.flatten() { - Some(modulus) => self.modpow(other, modulus, vm), - None => self.general_op(other, |a, b| inner_pow(a, b, vm), vm), - } - } - - #[pymethod] - fn __rpow__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.general_op(other, |a, b| inner_pow(b, a, vm), vm) - } - - #[pymethod(name = "__mod__")] - fn mod_(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.general_op(other, |a, b| inner_mod(a, b, vm), vm) - } - - #[pymethod] - fn __rmod__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.general_op(other, |a, b| inner_mod(b, a, vm), vm) - } - - #[pymethod] - fn __divmod__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.general_op(other, |a, b| inner_divmod(a, b, vm), vm) - } - - #[pymethod] - fn __rdivmod__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - self.general_op(other, |a, b| inner_divmod(b, a, vm), vm) - } - - #[pymethod] - fn __neg__(&self) -> BigInt { - -(&self.value) - } - - #[pymethod] - fn __abs__(&self) -> BigInt { - self.value.abs() - } - #[pymethod] fn __round__( zelf: PyRef, @@ -536,16 +420,6 @@ impl PyInt { Ok(zelf) } - #[pymethod] - fn __pos__(&self) -> BigInt { - self.value.clone() - } - - #[pymethod] - fn __float__(&self, vm: &VirtualMachine) -> PyResult { - try_to_float(&self.value, vm) - } - #[pymethod] fn __trunc__(zelf: PyRef, vm: &VirtualMachine) -> PyRefExact { zelf.__int__(vm) @@ -561,16 +435,6 @@ impl PyInt { zelf.__int__(vm) } - #[pymethod] - fn __index__(zelf: PyRef, vm: &VirtualMachine) -> PyRefExact { - zelf.__int__(vm) - } - - #[pymethod] - fn __invert__(&self) -> BigInt { - !(&self.value) - } - #[pymethod] fn __format__(&self, spec: PyStrRef, vm: &VirtualMachine) -> PyResult { FormatSpec::parse(spec.as_str()) @@ -578,11 +442,6 @@ impl PyInt { .map_err(|err| err.into_pyexception(vm)) } - #[pymethod] - fn __bool__(&self) -> bool { - !self.value.is_zero() - } - #[pymethod] fn __sizeof__(&self) -> usize { std::mem::size_of::() + (((self.value.bits() + 7) & !7) / 8) as usize @@ -705,8 +564,7 @@ impl PyInt { #[pyclass] impl PyRef { - #[pymethod] - fn __int__(self, vm: &VirtualMachine) -> PyRefExact { + pub(crate) fn __int__(self, vm: &VirtualMachine) -> PyRefExact { self.into_exact_or(&vm.ctx, |zelf| unsafe { // TODO: this is actually safe. we need better interface PyRefExact::new_unchecked(vm.ctx.new_bigint(&zelf.value))