Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
added patch for __radd__
  • Loading branch information
randolf-scholz committed May 6, 2025
commit 450b043500cd9a2f767ac86ee0cf6115b1ac20bf
21 changes: 14 additions & 7 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
from mypy.semanal_enum import ENUM_BASES
from mypy.state import state
from mypy.subtypes import (
covers_at_runtime,
find_member,
is_equivalent,
is_same_type,
Expand Down Expand Up @@ -4048,14 +4049,20 @@ def lookup_definer(typ: Instance, attr_name: str) -> str | None:

variants_raw = [(op_name, left_op, left_type, right_expr)]
elif (
is_subtype(right_type, left_type)
and isinstance(left_type, Instance)
and isinstance(right_type, Instance)
and not (
left_type.type.alt_promote is not None
and left_type.type.alt_promote.type is right_type.type
# Note: use covers_at_runtime instead of is_subtype.
# fixes https://github.com/python/mypy/issues/19006
covers_at_runtime(right_type, left_type)
and (
not (isinstance(left_type, Instance) and isinstance(right_type, Instance))
or (
(
left_type.type.alt_promote is None
or left_type.type.alt_promote.type is not right_type.type
)
and lookup_definer(left_type, op_name)
!= lookup_definer(right_type, rev_op_name)
)
)
and lookup_definer(left_type, op_name) != lookup_definer(right_type, rev_op_name)
):
# When we do "A() + B()" where B is a subclass of A, we'll actually try calling
# B's __radd__ method first, but ONLY if B explicitly defines or overrides the
Expand Down
23 changes: 23 additions & 0 deletions test-data/unit/check-expressions.test
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,29 @@ class B:
s: str
s = A() + B() # E: Unsupported operand types for + ("A" and "B")

[case testReverseBinaryOperator4]

from typing import assert_type, Never

class Size(tuple[int, ...]):
def __add__(self, other: tuple[int, ...], /) -> "Size": return Size()
def __radd__(self, other: tuple[int, ...], /) -> "Size": return Size()

size: Size = Size([3, 4])
tup0: tuple[()] = ()
tup1: tuple[int] = (1,)
tup2: tuple[int, int] = (1, 2)
tupN: tuple[int, ...] = (1, 2, 3)
tupX: tuple[Never, ...] = ()

assert_type(tup0 + size, Size)
assert_type(tup1 + size, Size)
assert_type(tup2 + size, Size)
assert_type(tupN + size, Size)
assert_type(tupX + size, Size)

[builtins fixtures/tuple.pyi]

[case testBinaryOperatorWithAnyRightOperand]
from typing import Any, cast
class A: pass
Expand Down