summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cython/Compiler/Code.py4
-rw-r--r--Cython/Compiler/TypeSlots.py14
-rw-r--r--tests/run/special_methods_T561.pyx24
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"