diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 8c05a0dff9a9..35c58478ce1e 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -2470,6 +2470,14 @@ def lookup_definer(typ: Instance, attr_name: str) -> Optional[str]: else: return result + # We finish invoking above operators and no early return happens. Therefore, + # we check if either the LHS or the RHS is Instance and fallbacks to Any, + # if so, we also return Any + if ((isinstance(left_type, Instance) and left_type.type.fallback_to_any) or + (isinstance(right_type, Instance) and right_type.type.fallback_to_any)): + any_type = AnyType(TypeOfAny.special_form) + return any_type, any_type + # STEP 4b: # Sometimes, the variants list is empty. In that case, we fall-back to attempting to # call the __op__ method (even though it's missing). diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 557e992ef1dd..6681d30df76a 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -6575,3 +6575,24 @@ class C: from typing import Callable class C: x: Callable[[C], int] = lambda x: x.y.g() # E: "C" has no attribute "y" + +[case testOpWithInheritedFromAny] +from typing import Any +C: Any +class D(C): + pass + +class D1(C): + def __add__(self, rhs: float) -> D1: + return self + +reveal_type(0.5 + C) # N: Revealed type is 'Any' + +reveal_type(0.5 + D()) # N: Revealed type is 'Any' +reveal_type(D() + 0.5) # N: Revealed type is 'Any' +reveal_type("str" + D()) # N: Revealed type is 'builtins.str' +reveal_type(D() + "str") # N: Revealed type is 'Any' + + +reveal_type(0.5 + D1()) # N: Revealed type is 'Any' +reveal_type(D1() + 0.5) # N: Revealed type is '__main__.D1'