Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
31 changes: 5 additions & 26 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,23 +596,9 @@ def check_reverse_op_method(self, defn: FuncItem, typ: CallableType,
method: str) -> None:
"""Check a reverse operator method such as __radd__."""

# If the argument of a reverse operator method such as __radd__
# does not define the corresponding non-reverse method such as __add__
# the return type of __radd__ may not reliably represent the value of
# the corresponding operation even in a fully statically typed program.
#
# This example illustrates the issue:
#
# class A: pass
# class B:
# def __radd__(self, x: A) -> int: # Note that A does not define
# return 1 # __add__!
# class C(A):
# def __add__(self, x: Any) -> str: return 'x'
# def f(a: A) -> None:
# a + B() # Result would be 'x', even though static type seems to
# # be int!
# f(C())
# This used to check for some very obscure scenario. It now
# just decides whether it's worth calling
# check_overlapping_op_methods().

if method in ('__eq__', '__ne__'):
# These are defined for all objects => can't cause trouble.
Expand All @@ -634,22 +620,15 @@ def check_reverse_op_method(self, defn: FuncItem, typ: CallableType,
# Check for the issue described above.
arg_type = typ.arg_types[1]
other_method = nodes.normal_from_reverse_op[method]
fail = False
if isinstance(arg_type, Instance):
if not arg_type.type.has_readable_member(other_method):
fail = True
return
elif isinstance(arg_type, AnyType):
self.msg.reverse_operator_method_with_any_arg_must_return_any(
method, defn)
return
elif isinstance(arg_type, UnionType):
if not arg_type.has_readable_member(other_method):
fail = True
return
else:
fail = True
if fail:
self.msg.invalid_reverse_operator_signature(
method, other_method, defn)
return

typ2 = self.expr_checker.analyze_external_member_access(
Expand Down
12 changes: 0 additions & 12 deletions mypy/test/data/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -1004,8 +1004,6 @@ class C:
class D:
def __radd__(self, x: A) -> object: pass
[out]
main: note: In member "__radd__" of class "B":
main:4: error: "Any" return type expected since argument to __radd__ does not support __add__

[case testReverseOperatorMethoddArgumentType2]
from typing import Any, Tuple, Callable
Expand All @@ -1016,12 +1014,6 @@ class B:
class C:
def __radd__(self, x: Any) -> int: pass
[out]
main: note: In member "__radd__" of class "A":
main:3: error: "Any" return type expected since argument to __radd__ does not support __add__
main: note: In member "__radd__" of class "B":
main:5: error: "Any" return type expected since argument to __radd__ does not support __add__
main: note: In member "__radd__" of class "C":
main:7: error: "Any" return type expected since argument to __radd__ has type "Any"

[case testOverloadedReverseOperatorMethodArgumentType]
from typing import overload, Any
Expand All @@ -1031,8 +1023,6 @@ class A:
@overload
def __radd__(self, x: 'A') -> Any: pass
[out]
main: note: In member "__radd__" of class "A":
main:4: error: "Any" return type expected since argument to __radd__ does not support __add__

[case testReverseOperatorMethodArgumentTypeAndOverloadedMethod]
from typing import overload
Expand All @@ -1055,8 +1045,6 @@ class B:
@abstractmethod
def __gt__(self, x: 'B') -> int: pass
[out]
main: note: In member "__lt__" of class "A":
main:5: error: "Any" return type expected since argument to __lt__ does not support __gt__

[case testOperatorMethodsAndOverloadingSpecialCase]
from typing import overload
Expand Down