@@ -909,18 +909,106 @@ where
909909
910910 let py_name = item_meta. method_name ( ) ?;
911911
912- // Disallow __new__ and __init__ as pymethod in impl blocks (not in traits)
912+ // Disallow slot methods - they should be defined via trait implementations
913+ // These are exposed as wrapper_descriptor via add_operators from SLOT_DEFS
913914 if !args. context . is_trait {
914- if py_name == "__new__" {
915- return Err ( syn:: Error :: new (
916- ident. span ( ) ,
917- "#[pymethod] cannot define '__new__'. Use #[pyclass(with(Constructor))] instead." ,
918- ) ) ;
919- }
920- if py_name == "__init__" {
915+ const FORBIDDEN_SLOT_METHODS : & [ ( & str , & str ) ] = & [
916+ // Constructor/Initializer traits
917+ ( "__new__" , "Constructor" ) ,
918+ ( "__init__" , "Initializer" ) ,
919+ // Representable trait
920+ // ("__repr__", "Representable"),
921+ // ("__str__", "???"), // allow __str__
922+ // Hashable trait
923+ ( "__hash__" , "Hashable" ) ,
924+ // Callable trait
925+ ( "__call__" , "Callable" ) ,
926+ // GetAttr/SetAttr traits
927+ // NOTE: __getattribute__, __setattr__, __delattr__ are intentionally NOT forbidden
928+ // because they need pymethod for subclass override mechanism to work properly.
929+ // GetDescriptor/SetDescriptor traits
930+ // ("__get__", "GetDescriptor"),
931+ // ("__set__", "SetDescriptor"),
932+ // ("__delete__", "SetDescriptor"),
933+ // AsNumber trait
934+ ( "__add__" , "AsNumber" ) ,
935+ ( "__radd__" , "AsNumber" ) ,
936+ ( "__iadd__" , "AsNumber" ) ,
937+ ( "__sub__" , "AsNumber" ) ,
938+ ( "__rsub__" , "AsNumber" ) ,
939+ ( "__isub__" , "AsNumber" ) ,
940+ ( "__mul__" , "AsNumber" ) ,
941+ ( "__rmul__" , "AsNumber" ) ,
942+ ( "__imul__" , "AsNumber" ) ,
943+ ( "__truediv__" , "AsNumber" ) ,
944+ ( "__rtruediv__" , "AsNumber" ) ,
945+ ( "__itruediv__" , "AsNumber" ) ,
946+ ( "__floordiv__" , "AsNumber" ) ,
947+ ( "__rfloordiv__" , "AsNumber" ) ,
948+ ( "__ifloordiv__" , "AsNumber" ) ,
949+ ( "__mod__" , "AsNumber" ) ,
950+ ( "__rmod__" , "AsNumber" ) ,
951+ ( "__imod__" , "AsNumber" ) ,
952+ ( "__pow__" , "AsNumber" ) ,
953+ ( "__rpow__" , "AsNumber" ) ,
954+ ( "__ipow__" , "AsNumber" ) ,
955+ ( "__divmod__" , "AsNumber" ) ,
956+ ( "__rdivmod__" , "AsNumber" ) ,
957+ ( "__matmul__" , "AsNumber" ) ,
958+ ( "__rmatmul__" , "AsNumber" ) ,
959+ ( "__imatmul__" , "AsNumber" ) ,
960+ ( "__lshift__" , "AsNumber" ) ,
961+ ( "__rlshift__" , "AsNumber" ) ,
962+ ( "__ilshift__" , "AsNumber" ) ,
963+ ( "__rshift__" , "AsNumber" ) ,
964+ ( "__rrshift__" , "AsNumber" ) ,
965+ ( "__irshift__" , "AsNumber" ) ,
966+ ( "__and__" , "AsNumber" ) ,
967+ ( "__rand__" , "AsNumber" ) ,
968+ ( "__iand__" , "AsNumber" ) ,
969+ ( "__or__" , "AsNumber" ) ,
970+ ( "__ror__" , "AsNumber" ) ,
971+ ( "__ior__" , "AsNumber" ) ,
972+ ( "__xor__" , "AsNumber" ) ,
973+ ( "__rxor__" , "AsNumber" ) ,
974+ ( "__ixor__" , "AsNumber" ) ,
975+ ( "__neg__" , "AsNumber" ) ,
976+ ( "__pos__" , "AsNumber" ) ,
977+ ( "__abs__" , "AsNumber" ) ,
978+ ( "__invert__" , "AsNumber" ) ,
979+ ( "__int__" , "AsNumber" ) ,
980+ ( "__float__" , "AsNumber" ) ,
981+ ( "__index__" , "AsNumber" ) ,
982+ ( "__bool__" , "AsNumber" ) ,
983+ // AsSequence trait
984+ // ("__len__", "AsSequence (or AsMapping)"),
985+ // ("__contains__", "AsSequence"),
986+ // AsMapping trait
987+ // ("__getitem__", "AsMapping (or AsSequence)"),
988+ // ("__setitem__", "AsMapping (or AsSequence)"),
989+ // ("__delitem__", "AsMapping (or AsSequence)"),
990+ // IterNext trait
991+ // ("__iter__", "IterNext"),
992+ // ("__next__", "IterNext"),
993+ // Comparable trait
994+ ( "__eq__" , "Comparable" ) ,
995+ ( "__ne__" , "Comparable" ) ,
996+ ( "__lt__" , "Comparable" ) ,
997+ ( "__le__" , "Comparable" ) ,
998+ ( "__gt__" , "Comparable" ) ,
999+ ( "__ge__" , "Comparable" ) ,
1000+ ] ;
1001+
1002+ if let Some ( ( _, trait_name) ) = FORBIDDEN_SLOT_METHODS
1003+ . iter ( )
1004+ . find ( |( method, _) | * method == py_name. as_str ( ) )
1005+ {
9211006 return Err ( syn:: Error :: new (
9221007 ident. span ( ) ,
923- "#[pymethod] cannot define '__init__'. Use #[pyclass(with(Initializer))] instead." ,
1008+ format ! (
1009+ "#[pymethod] cannot define '{py_name}'. Use `impl {trait_name} for ...` instead. \
1010+ Slot methods are exposed as wrapper_descriptor automatically.",
1011+ ) ,
9241012 ) ) ;
9251013 }
9261014 }
0 commit comments