Skip to content

reversible arithmetic operators don't respect subclassing if only one arm implemented #6024

@davidhewitt

Description

@davidhewitt

If a #[pyclass] defines only one of __add__ or __radd__, any base class implementation for the unimplemented operation is ignored.

The following patch added to test_arithmetics creates a failing test:

diff --git a/tests/test_arithmetics.rs b/tests/test_arithmetics.rs
index bf3f99c34..44f811194 100644
--- a/tests/test_arithmetics.rs
+++ b/tests/test_arithmetics.rs
@@ -363,7 +363,7 @@ fn rhs_arithmetic() {
     });
 }
 
-#[pyclass]
+#[pyclass(subclass)]
 struct LhsAndRhs {}
 
 impl std::fmt::Debug for LhsAndRhs {
@@ -496,6 +496,27 @@ fn lhs_fellback_to_rhs() {
     });
 }
 
+#[pyclass(extends = LhsAndRhs)]
+struct OverrideRhs {}
+
+#[pymethods]
+impl OverrideRhs {
+    fn __radd__(&self, other: &Bound<'_, PyAny>) -> String {
+        format!("{other:?} + OverrideRhs")
+    }
+}
+
+#[test]
+fn override_rhs() {
+    Python::attach(|py| {
+        let c = Py::new(py, LhsAndRhs {}).unwrap();
+        let sub = Py::new(py, (OverrideRhs {}, LhsAndRhs {})).unwrap();
+        py_run!(py, c sub, "assert 1 + sub == '1 + OverrideRhs'");
+        // `__add__` not overridden, should use `LhsAndRhs.__add__`
+        py_run!(py, c sub, "assert sub + 1 == 'LA + 1'");
+    });
+}
+
 #[pyclass]
 struct RichComparisons {}

In the pure-Python equivalent situation the subclassing is respected:

class Lhs:
    def __add__(self, other):
        return f'LHS + {other}'

class Rhs(Lhs):
    def __radd(self, other):
        return f'{other} + Rhs'

1 + Rhs()
#> '1 + Rhs'
Rhs() + 1
#> 'LHS + 1'

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions