@@ -538,6 +538,12 @@ int PyType_Ready(PyTypeObject* cls) {
538538 type_ready_set_new (cls , dict , base );
539539
540540 /* fill dict */
541+
542+ /*
543+ * NOTE: ADD_SLOT_CONV won't overwrite existing attributes, so the order is crucial and must
544+ * reflect CPython's 'slotdefs' array.
545+ */
546+
541547 // add special methods defined directly on the type structs
542548 ADD_SLOT_CONV ("__dealloc__" , cls -> tp_dealloc , -1 , JWRAPPER_DIRECT );
543549 // https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_getattr
@@ -583,20 +589,7 @@ int PyType_Ready(PyTypeObject* cls) {
583589 ADD_SLOT_CONV ("__del__" , cls -> tp_del , -1 , JWRAPPER_DIRECT );
584590 ADD_SLOT_CONV ("__finalize__" , cls -> tp_finalize , -1 , JWRAPPER_DIRECT );
585591
586- PySequenceMethods * sequences = PyTypeObject_tp_as_sequence (cls );
587- if (sequences ) {
588- // sequence functions first, so that the number functions take precendence
589- ADD_SLOT_CONV ("__len__" , sequences -> sq_length , -1 , JWRAPPER_LENFUNC );
590- ADD_SLOT_CONV ("__add__" , sequences -> sq_concat , -2 , JWRAPPER_BINARYFUNC );
591- ADD_SLOT_CONV ("__mul__" , sequences -> sq_repeat , -2 , JWRAPPER_SSIZE_ARG );
592- ADD_SLOT_CONV ("__getitem__" , sequences -> sq_item , -2 , JWRAPPER_GETITEM );
593- ADD_SLOT_CONV ("__setitem__" , sequences -> sq_ass_item , -3 , JWRAPPER_SETITEM );
594- ADD_SLOT_CONV ("__delitem__" , sequences -> sq_ass_item , -3 , JWRAPPER_DELITEM );
595- ADD_SLOT_CONV ("__contains__" , sequences -> sq_contains , -2 , JWRAPPER_OBJOBJPROC );
596- ADD_SLOT_CONV ("__iadd__" , sequences -> sq_inplace_concat , -2 , JWRAPPER_BINARYFUNC );
597- ADD_SLOT_CONV ("__imul__" , sequences -> sq_inplace_repeat , -2 , JWRAPPER_SSIZE_ARG );
598- }
599-
592+ // 'tp_as_number' takes precedence over 'tp_as_mapping' and 'tp_as_sequence' !
600593 PyNumberMethods * numbers = PyTypeObject_tp_as_number (cls );
601594 if (numbers ) {
602595 ADD_SLOT_CONV ("__add__" , numbers -> nb_add , -2 , JWRAPPER_BINARYFUNC_L );
@@ -650,6 +643,7 @@ int PyType_Ready(PyTypeObject* cls) {
650643 ADD_SLOT_CONV ("__imatmul__" , numbers -> nb_inplace_matrix_multiply , -2 , JWRAPPER_BINARYFUNC_L );
651644 }
652645
646+ // 'tp_as_mapping' takes precedence over 'tp_as_sequence' !
653647 PyMappingMethods * mappings = PyTypeObject_tp_as_mapping (cls );
654648 if (mappings ) {
655649 ADD_SLOT_CONV ("__len__" , mappings -> mp_length , -1 , JWRAPPER_LENFUNC );
@@ -658,6 +652,20 @@ int PyType_Ready(PyTypeObject* cls) {
658652 ADD_SLOT_CONV ("__delitem__" , mappings -> mp_ass_subscript , -3 , JWRAPPER_MP_DELITEM );
659653 }
660654
655+ PySequenceMethods * sequences = PyTypeObject_tp_as_sequence (cls );
656+ if (sequences ) {
657+ // sequence functions first, so that the number functions take precendence
658+ ADD_SLOT_CONV ("__len__" , sequences -> sq_length , -1 , JWRAPPER_LENFUNC );
659+ ADD_SLOT_CONV ("__add__" , sequences -> sq_concat , -2 , JWRAPPER_BINARYFUNC );
660+ ADD_SLOT_CONV ("__mul__" , sequences -> sq_repeat , -2 , JWRAPPER_SSIZE_ARG );
661+ ADD_SLOT_CONV ("__getitem__" , sequences -> sq_item , -2 , JWRAPPER_GETITEM );
662+ ADD_SLOT_CONV ("__setitem__" , sequences -> sq_ass_item , -3 , JWRAPPER_SETITEM );
663+ ADD_SLOT_CONV ("__delitem__" , sequences -> sq_ass_item , -3 , JWRAPPER_DELITEM );
664+ ADD_SLOT_CONV ("__contains__" , sequences -> sq_contains , -2 , JWRAPPER_OBJOBJPROC );
665+ ADD_SLOT_CONV ("__iadd__" , sequences -> sq_inplace_concat , -2 , JWRAPPER_BINARYFUNC );
666+ ADD_SLOT_CONV ("__imul__" , sequences -> sq_inplace_repeat , -2 , JWRAPPER_SSIZE_ARG );
667+ }
668+
661669 PyAsyncMethods * async = PyTypeObject_tp_as_async (cls );
662670 if (async ) {
663671 ADD_SLOT_CONV ("__await__" , async -> am_await , -1 , JWRAPPER_DIRECT );
0 commit comments