Commit fe98838c authored by da-woods's avatar da-woods Committed by GitHub

Mark reverse operators with METHOD_COEXIST (GH-4753)

This means that reverse operators (e.g. `__radd__`) won't be
hidden by the automatic wrapper that `PyType_Ready()` produces if
the forward method exists. Although they won't work as
in Python, they will be possible to look up and call explicitly.
This should make it easier to write code that's compatible with
Cython 0.29.x and Cython 3 (where reverse operators will be full supported).

Closes https://github.com/cython/cython/issues/4750
parent 4060346c
...@@ -2233,8 +2233,8 @@ class CCodeWriter(object): ...@@ -2233,8 +2233,8 @@ class CCodeWriter(object):
method_flags = entry.signature.method_flags() method_flags = entry.signature.method_flags()
if not method_flags: if not method_flags:
return 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] method_flags += [TypeSlots.method_coexist]
func_ptr = wrapper_code_writer.put_pymethoddef_wrapper(entry) if wrapper_code_writer else entry.func_cname 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. # Add required casts, but try not to shadow real warnings.
......
...@@ -625,6 +625,20 @@ def get_slot_code_by_name(scope, slot_name): ...@@ -625,6 +625,20 @@ def get_slot_code_by_name(scope, slot_name):
slot = get_slot_by_name(slot_name) slot = get_slot_by_name(slot_name)
return slot.slot_code(scope) 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
#------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------
# #
......
...@@ -923,3 +923,27 @@ cdef class VerySpecialSubType(VerySpecial): ...@@ -923,3 +923,27 @@ cdef class VerySpecialSubType(VerySpecial):
def __get__(self, inst, own): def __get__(self, inst, own):
return VerySpecial.__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"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment