diff options
-rw-r--r-- | Cython/Compiler/Code.py | 4 | ||||
-rw-r--r-- | Cython/Compiler/TypeSlots.py | 14 | ||||
-rw-r--r-- | tests/run/special_methods_T561.pyx | 24 |
3 files changed, 40 insertions, 2 deletions
diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index f43c4b2b8..45c5a325c 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -2233,8 +2233,8 @@ class CCodeWriter(object): method_flags = entry.signature.method_flags() if not method_flags: return - if entry.is_special: - from . import TypeSlots + from . import TypeSlots + if entry.is_special or TypeSlots.is_reverse_number_slot(entry.name): method_flags += [TypeSlots.method_coexist] func_ptr = wrapper_code_writer.put_pymethoddef_wrapper(entry) if wrapper_code_writer else entry.func_cname # Add required casts, but try not to shadow real warnings. diff --git a/Cython/Compiler/TypeSlots.py b/Cython/Compiler/TypeSlots.py index 0b4ff6704..c6867447d 100644 --- a/Cython/Compiler/TypeSlots.py +++ b/Cython/Compiler/TypeSlots.py @@ -625,6 +625,20 @@ def get_slot_code_by_name(scope, slot_name): slot = get_slot_by_name(slot_name) return slot.slot_code(scope) +def is_reverse_number_slot(name): + """ + Tries to identify __radd__ and friends (so the METH_COEXIST flag can be applied). + + There's no great consequence if it inadvertently identifies a few other methods + so just use a simple rule rather than an exact list. + """ + if name.startswith("__r") and name.endswith("__"): + forward_name = name.replace("r", "", 1) + for meth in PyNumberMethods: + if getattr(meth, "method_name", None) == forward_name: + return True + return False + #------------------------------------------------------------------------------------------ # diff --git a/tests/run/special_methods_T561.pyx b/tests/run/special_methods_T561.pyx index 350d452f4..e5d1ec5bc 100644 --- a/tests/run/special_methods_T561.pyx +++ b/tests/run/special_methods_T561.pyx @@ -923,3 +923,27 @@ cdef class VerySpecialSubType(VerySpecial): def __get__(self, inst, own): return VerySpecial.__get__(self, inst, own) + + +cdef class ReverseMethodsExist: + """ + reverse methods (such as __radd__) don't work in Cython <3. However, if they + are defined then it should be possible to look them up explicitly instead of + looking up autogenerated wrapper (which points to the forward method) + + >>> o = ReverseMethodsExist() + >>> o + o + 'add' + >>> o.__add__(o) + 'add' + >>> o.__radd__(o) + 'radd' + >>> o.__rsub__(o) + 'rsub' + """ + def __add__(self, other): + return "add" + def __radd__(self, other): + return "radd" + def __rsub__(self, other): + return "rsub" |