Skip to content

Commit bbc18ac

Browse files
committed
slotdef
1 parent d241269 commit bbc18ac

File tree

12 files changed

+1913
-671
lines changed

12 files changed

+1913
-671
lines changed

.cspell.dict/cpython.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
argtypes
22
asdl
33
asname
4+
attro
45
augassign
56
badcert
67
badsyntax

Lib/test/test_descr.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1399,7 +1399,6 @@ class Q2:
13991399
__qualname__ = object()
14001400
__slots__ = ["__qualname__"]
14011401

1402-
@unittest.expectedFailure # TODO: RUSTPYTHON
14031402
def test_slots_descriptor(self):
14041403
# Issue2115: slot descriptors did not correctly check
14051404
# the type of the given object

Lib/test/test_inspect/test_inspect.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,8 +2126,6 @@ class DataDescriptorSub(DataDescriptorWithNoGet,
21262126
self.assertFalse(inspect.ismethoddescriptor(MethodDescriptorSub))
21272127
self.assertFalse(inspect.ismethoddescriptor(DataDescriptorSub))
21282128

2129-
# TODO: RUSTPYTHON
2130-
@unittest.expectedFailure
21312129
def test_builtin_descriptors(self):
21322130
builtin_slot_wrapper = int.__add__ # This one is mentioned in docs.
21332131
class Owner:
@@ -2217,8 +2215,6 @@ class DataDescriptor2:
22172215
self.assertTrue(inspect.isdatadescriptor(DataDescriptor2()),
22182216
'class with __set__ = None is a data descriptor')
22192217

2220-
# TODO: RUSTPYTHON
2221-
@unittest.expectedFailure
22222218
def test_slot(self):
22232219
class Slotted:
22242220
__slots__ = 'foo',

Lib/test/test_sqlite3/test_factory.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,6 @@ def test_sqlite_row_hash_cmp(self):
241241

242242
self.assertEqual(hash(row_1), hash(row_2))
243243

244-
# TODO: RUSTPYTHON
245-
@unittest.expectedFailure
246244
def test_sqlite_row_as_sequence(self):
247245
""" Checks if the row object can act like a sequence """
248246
self.con.row_factory = sqlite.Row

Lib/test/test_unittest/testmock/testhelpers.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -884,8 +884,6 @@ def f(a, self): pass
884884
a.f.assert_called_with(self=10)
885885

886886

887-
# TODO: RUSTPYTHON
888-
@unittest.expectedFailure
889887
def test_autospec_data_descriptor(self):
890888
class Descriptor(object):
891889
def __init__(self, value):

crates/vm/src/builtins/descriptor.rs

Lines changed: 105 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ use crate::{
66
common::hash::PyHash,
77
convert::{ToPyObject, ToPyResult},
88
function::{FuncArgs, PyMethodDef, PyMethodFlags, PySetterValue},
9+
protocol::{PyNumberBinaryFunc, PyNumberTernaryFunc, PyNumberUnaryFunc},
910
types::{
1011
Callable, Comparable, DelFunc, DescrGetFunc, DescrSetFunc, GenericMethod, GetDescriptor,
11-
GetattroFunc, HashFunc, Hashable, InitFunc, IterFunc, IterNextFunc, PyComparisonOp,
12-
Representable, RichCompareFunc, SetattroFunc, StringifyFunc,
12+
GetattroFunc, HashFunc, Hashable, InitFunc, IterFunc, IterNextFunc, MapAssSubscriptFunc,
13+
MapLenFunc, MapSubscriptFunc, PyComparisonOp, Representable, RichCompareFunc,
14+
SeqAssItemFunc, SeqConcatFunc, SeqContainsFunc, SeqItemFunc, SeqLenFunc, SeqRepeatFunc,
15+
SetattroFunc, StringifyFunc,
1316
},
1417
};
1518
use rustpython_common::lock::PyRwLock;
@@ -394,7 +397,6 @@ pub fn init(ctx: &Context) {
394397

395398
// PyWrapper - wrapper_descriptor
396399

397-
/// Type-erased slot function - mirrors CPython's void* d_wrapped
398400
/// Each variant knows how to call the wrapped function with proper types
399401
#[derive(Clone, Copy)]
400402
pub enum SlotFunc {
@@ -420,6 +422,25 @@ pub enum SlotFunc {
420422
DescrGet(DescrGetFunc),
421423
DescrSet(DescrSetFunc), // __set__
422424
DescrDel(DescrSetFunc), // __delete__ (same func type, different PySetterValue)
425+
426+
// Sequence sub-slots (sq_*)
427+
SeqLength(SeqLenFunc),
428+
SeqConcat(SeqConcatFunc),
429+
SeqRepeat(SeqRepeatFunc),
430+
SeqItem(SeqItemFunc),
431+
SeqAssItem(SeqAssItemFunc),
432+
SeqContains(SeqContainsFunc),
433+
434+
// Mapping sub-slots (mp_*)
435+
MapLength(MapLenFunc),
436+
MapSubscript(MapSubscriptFunc),
437+
MapAssSubscript(MapAssSubscriptFunc),
438+
439+
// Number sub-slots (nb_*) - grouped by signature
440+
NumBoolean(PyNumberUnaryFunc<bool>), // __bool__
441+
NumUnary(PyNumberUnaryFunc), // __int__, __float__, __index__
442+
NumBinary(PyNumberBinaryFunc), // __add__, __sub__, __mul__, etc.
443+
NumTernary(PyNumberTernaryFunc), // __pow__
423444
}
424445

425446
impl std::fmt::Debug for SlotFunc {
@@ -440,6 +461,22 @@ impl std::fmt::Debug for SlotFunc {
440461
SlotFunc::DescrGet(_) => write!(f, "SlotFunc::DescrGet(...)"),
441462
SlotFunc::DescrSet(_) => write!(f, "SlotFunc::DescrSet(...)"),
442463
SlotFunc::DescrDel(_) => write!(f, "SlotFunc::DescrDel(...)"),
464+
// Sequence sub-slots
465+
SlotFunc::SeqLength(_) => write!(f, "SlotFunc::SeqLength(...)"),
466+
SlotFunc::SeqConcat(_) => write!(f, "SlotFunc::SeqConcat(...)"),
467+
SlotFunc::SeqRepeat(_) => write!(f, "SlotFunc::SeqRepeat(...)"),
468+
SlotFunc::SeqItem(_) => write!(f, "SlotFunc::SeqItem(...)"),
469+
SlotFunc::SeqAssItem(_) => write!(f, "SlotFunc::SeqAssItem(...)"),
470+
SlotFunc::SeqContains(_) => write!(f, "SlotFunc::SeqContains(...)"),
471+
// Mapping sub-slots
472+
SlotFunc::MapLength(_) => write!(f, "SlotFunc::MapLength(...)"),
473+
SlotFunc::MapSubscript(_) => write!(f, "SlotFunc::MapSubscript(...)"),
474+
SlotFunc::MapAssSubscript(_) => write!(f, "SlotFunc::MapAssSubscript(...)"),
475+
// Number sub-slots
476+
SlotFunc::NumBoolean(_) => write!(f, "SlotFunc::NumBoolean(...)"),
477+
SlotFunc::NumUnary(_) => write!(f, "SlotFunc::NumUnary(...)"),
478+
SlotFunc::NumBinary(_) => write!(f, "SlotFunc::NumBinary(...)"),
479+
SlotFunc::NumTernary(_) => write!(f, "SlotFunc::NumTernary(...)"),
443480
}
444481
}
445482
}
@@ -541,6 +578,71 @@ impl SlotFunc {
541578
func(&obj, instance, PySetterValue::Delete, vm)?;
542579
Ok(vm.ctx.none())
543580
}
581+
// Sequence sub-slots
582+
SlotFunc::SeqLength(func) => {
583+
args.bind::<()>(vm)?;
584+
let len = func(obj.sequence_unchecked(), vm)?;
585+
Ok(vm.ctx.new_int(len).into())
586+
}
587+
SlotFunc::SeqConcat(func) => {
588+
let (other,): (PyObjectRef,) = args.bind(vm)?;
589+
func(obj.sequence_unchecked(), &other, vm)
590+
}
591+
SlotFunc::SeqRepeat(func) => {
592+
let (n,): (isize,) = args.bind(vm)?;
593+
func(obj.sequence_unchecked(), n, vm)
594+
}
595+
SlotFunc::SeqItem(func) => {
596+
let (index,): (isize,) = args.bind(vm)?;
597+
func(obj.sequence_unchecked(), index, vm)
598+
}
599+
SlotFunc::SeqAssItem(func) => {
600+
let (index, value): (isize, crate::function::OptionalArg<PyObjectRef>) =
601+
args.bind(vm)?;
602+
func(obj.sequence_unchecked(), index, value.into_option(), vm)?;
603+
Ok(vm.ctx.none())
604+
}
605+
SlotFunc::SeqContains(func) => {
606+
let (item,): (PyObjectRef,) = args.bind(vm)?;
607+
let result = func(obj.sequence_unchecked(), &item, vm)?;
608+
Ok(vm.ctx.new_bool(result).into())
609+
}
610+
// Mapping sub-slots
611+
SlotFunc::MapLength(func) => {
612+
args.bind::<()>(vm)?;
613+
let len = func(obj.mapping_unchecked(), vm)?;
614+
Ok(vm.ctx.new_int(len).into())
615+
}
616+
SlotFunc::MapSubscript(func) => {
617+
let (key,): (PyObjectRef,) = args.bind(vm)?;
618+
func(obj.mapping_unchecked(), &key, vm)
619+
}
620+
SlotFunc::MapAssSubscript(func) => {
621+
let (key, value): (PyObjectRef, crate::function::OptionalArg<PyObjectRef>) =
622+
args.bind(vm)?;
623+
func(obj.mapping_unchecked(), &key, value.into_option(), vm)?;
624+
Ok(vm.ctx.none())
625+
}
626+
// Number sub-slots
627+
SlotFunc::NumBoolean(func) => {
628+
args.bind::<()>(vm)?;
629+
let result = func(obj.number(), vm)?;
630+
Ok(vm.ctx.new_bool(result).into())
631+
}
632+
SlotFunc::NumUnary(func) => {
633+
args.bind::<()>(vm)?;
634+
func(obj.number(), vm)
635+
}
636+
SlotFunc::NumBinary(func) => {
637+
let (other,): (PyObjectRef,) = args.bind(vm)?;
638+
func(&obj, &other, vm)
639+
}
640+
SlotFunc::NumTernary(func) => {
641+
let (y, z): (PyObjectRef, crate::function::OptionalArg<PyObjectRef>) =
642+
args.bind(vm)?;
643+
let z = z.unwrap_or_else(|| vm.ctx.none());
644+
func(&obj, &y, &z, vm)
645+
}
544646
}
545647
}
546648
}

crates/vm/src/builtins/type.rs

Lines changed: 5 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::{
2626
protocol::{PyIterReturn, PyNumberMethods},
2727
types::{
2828
AsNumber, Callable, Constructor, GetAttr, Initializer, PyTypeFlags, PyTypeSlots,
29-
Representable, SetAttr, TypeDataRef, TypeDataRefMut, TypeDataSlot,
29+
Representable, SLOT_DEFS, SetAttr, TypeDataRef, TypeDataRefMut, TypeDataSlot,
3030
},
3131
};
3232
use indexmap::{IndexMap, map::Entry};
@@ -464,173 +464,11 @@ impl PyType {
464464

465465
/// Inherit slots from base type. inherit_slots
466466
pub(crate) fn inherit_slots(&self, base: &Self) {
467-
macro_rules! copyslot {
468-
($slot:ident) => {
469-
if self.slots.$slot.load().is_none() {
470-
if let Some(base_val) = base.slots.$slot.load() {
471-
self.slots.$slot.store(Some(base_val));
472-
}
473-
}
474-
};
475-
}
476-
477-
// Copy init slot only if base actually defines it (not just inherited)
478-
// This is needed for multiple inheritance where a later base might
479-
// have a more specific init slot
480-
macro_rules! copyslot_defined {
481-
($slot:ident) => {
482-
if self.slots.$slot.load().is_none() {
483-
if let Some(base_val) = base.slots.$slot.load() {
484-
// SLOTDEFINED: base->SLOT && (basebase == NULL || base->SLOT != basebase->SLOT)
485-
let basebase = base.base.as_ref();
486-
let slot_defined = match basebase {
487-
None => true,
488-
Some(bb) => bb.slots.$slot.load().map(|v| v as usize)
489-
!= Some(base_val as usize),
490-
};
491-
if slot_defined {
492-
self.slots.$slot.store(Some(base_val));
493-
}
494-
}
495-
}
496-
};
497-
}
498-
499-
// Core slots
500-
copyslot!(hash);
501-
copyslot!(call);
502-
copyslot!(str);
503-
copyslot!(repr);
504-
copyslot!(getattro);
505-
copyslot!(setattro);
506-
copyslot!(richcompare);
507-
copyslot!(iter);
508-
copyslot!(iternext);
509-
copyslot!(descr_get);
510-
copyslot!(descr_set);
511-
// init uses SLOTDEFINED check for multiple inheritance support
512-
copyslot_defined!(init);
513-
copyslot!(del);
514-
// new is handled by set_new()
515-
// as_buffer is inherited at type creation time (not AtomicCell)
516-
517-
// Sub-slots (number, sequence, mapping)
518-
self.inherit_number_slots(base);
519-
self.inherit_sequence_slots(base);
520-
self.inherit_mapping_slots(base);
521-
}
522-
523-
/// Inherit number sub-slots from base type
524-
fn inherit_number_slots(&self, base: &Self) {
525-
macro_rules! copy_num_slot {
526-
($slot:ident) => {
527-
if self.slots.as_number.$slot.load().is_none() {
528-
if let Some(base_val) = base.slots.as_number.$slot.load() {
529-
self.slots.as_number.$slot.store(Some(base_val));
530-
}
531-
}
532-
};
533-
}
534-
535-
// Binary operations
536-
copy_num_slot!(add);
537-
copy_num_slot!(right_add);
538-
copy_num_slot!(inplace_add);
539-
copy_num_slot!(subtract);
540-
copy_num_slot!(right_subtract);
541-
copy_num_slot!(inplace_subtract);
542-
copy_num_slot!(multiply);
543-
copy_num_slot!(right_multiply);
544-
copy_num_slot!(inplace_multiply);
545-
copy_num_slot!(remainder);
546-
copy_num_slot!(right_remainder);
547-
copy_num_slot!(inplace_remainder);
548-
copy_num_slot!(divmod);
549-
copy_num_slot!(right_divmod);
550-
copy_num_slot!(power);
551-
copy_num_slot!(right_power);
552-
copy_num_slot!(inplace_power);
553-
554-
// Bitwise operations
555-
copy_num_slot!(lshift);
556-
copy_num_slot!(right_lshift);
557-
copy_num_slot!(inplace_lshift);
558-
copy_num_slot!(rshift);
559-
copy_num_slot!(right_rshift);
560-
copy_num_slot!(inplace_rshift);
561-
copy_num_slot!(and);
562-
copy_num_slot!(right_and);
563-
copy_num_slot!(inplace_and);
564-
copy_num_slot!(xor);
565-
copy_num_slot!(right_xor);
566-
copy_num_slot!(inplace_xor);
567-
copy_num_slot!(or);
568-
copy_num_slot!(right_or);
569-
copy_num_slot!(inplace_or);
570-
571-
// Division operations
572-
copy_num_slot!(floor_divide);
573-
copy_num_slot!(right_floor_divide);
574-
copy_num_slot!(inplace_floor_divide);
575-
copy_num_slot!(true_divide);
576-
copy_num_slot!(right_true_divide);
577-
copy_num_slot!(inplace_true_divide);
578-
579-
// Matrix multiplication
580-
copy_num_slot!(matrix_multiply);
581-
copy_num_slot!(right_matrix_multiply);
582-
copy_num_slot!(inplace_matrix_multiply);
583-
584-
// Unary operations
585-
copy_num_slot!(negative);
586-
copy_num_slot!(positive);
587-
copy_num_slot!(absolute);
588-
copy_num_slot!(boolean);
589-
copy_num_slot!(invert);
590-
591-
// Conversion
592-
copy_num_slot!(int);
593-
copy_num_slot!(float);
594-
copy_num_slot!(index);
595-
}
596-
597-
/// Inherit sequence sub-slots from base type
598-
fn inherit_sequence_slots(&self, base: &Self) {
599-
macro_rules! copy_seq_slot {
600-
($slot:ident) => {
601-
if self.slots.as_sequence.$slot.load().is_none() {
602-
if let Some(base_val) = base.slots.as_sequence.$slot.load() {
603-
self.slots.as_sequence.$slot.store(Some(base_val));
604-
}
605-
}
606-
};
467+
// Use SLOT_DEFS to iterate all slots
468+
// Note: as_buffer is handled in inherit_static_slots (not AtomicCell)
469+
for def in SLOT_DEFS {
470+
def.accessor.copyslot_if_none(self, base);
607471
}
608-
609-
copy_seq_slot!(length);
610-
copy_seq_slot!(concat);
611-
copy_seq_slot!(repeat);
612-
copy_seq_slot!(item);
613-
copy_seq_slot!(ass_item);
614-
copy_seq_slot!(contains);
615-
copy_seq_slot!(inplace_concat);
616-
copy_seq_slot!(inplace_repeat);
617-
}
618-
619-
/// Inherit mapping sub-slots from base type
620-
fn inherit_mapping_slots(&self, base: &Self) {
621-
macro_rules! copy_map_slot {
622-
($slot:ident) => {
623-
if self.slots.as_mapping.$slot.load().is_none() {
624-
if let Some(base_val) = base.slots.as_mapping.$slot.load() {
625-
self.slots.as_mapping.$slot.store(Some(base_val));
626-
}
627-
}
628-
};
629-
}
630-
631-
copy_map_slot!(length);
632-
copy_map_slot!(subscript);
633-
copy_map_slot!(ass_subscript);
634472
}
635473

636474
// This is used for class initialization where the vm is not yet available.

0 commit comments

Comments
 (0)