From 524fa163615d8c2a8e55b48dd03e3cf89876bae4 Mon Sep 17 00:00:00 2001 From: TH3CHARLie Date: Wed, 27 Nov 2019 10:56:41 +0800 Subject: [PATCH 1/4] fix --- mypy/checkexpr.py | 6 ++++++ test-data/unit/check-classes.test | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 46af4c853c51..27c248397c4b 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -2360,6 +2360,12 @@ def lookup_definer(typ: Instance, attr_name: str) -> Optional[str]: any_type = AnyType(TypeOfAny.from_another_any, source_any=right_type) return any_type, any_type + # If either the LHS or the RHS is Instance and fallbacks to Any, 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 1: # We start by getting the __op__ and __rop__ methods, if they exist. diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 03592da6e18a..e98a9b25ca0e 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -6566,3 +6566,31 @@ class A: reveal_type(A().y) # N: Revealed type is 'builtins.int' [builtins fixtures/property.pyi] + +[case testOpWithInheritedFromAny] +from typing import Any +C: Any +class D(C): + pass + +reveal_type(0.5 + C) # N: Revealed type is 'Any' + +reveal_type(0.5 + D()) # N: Revealed type is 'Any' +reveal_type(0.5 / D()) # N: Revealed type is 'Any' +reveal_type(0.5 * D()) # 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(D() / 0.5) # N: Revealed type is 'Any' +reveal_type(D() * 0.5) # N: Revealed type is 'Any' +reveal_type(D() - 0.5) # N: Revealed type is 'Any' + +reveal_type("aaa" * D()) # N: Revealed type is 'Any' +reveal_type("aaa" + D()) # N: Revealed type is 'Any' +reveal_type("aaa" - D()) # N: Revealed type is 'Any' +reveal_type("aaa" / D()) # N: Revealed type is 'Any' + +reveal_type(D() * "aaa") # N: Revealed type is 'Any' +reveal_type(D() + "aaa") # N: Revealed type is 'Any' +reveal_type(D() - "aaa") # N: Revealed type is 'Any' +reveal_type(D() / "aaa") # N: Revealed type is 'Any' From 78e6173223a17245ce820dcd5f096f6710bb3377 Mon Sep 17 00:00:00 2001 From: TH3CHARLie Date: Mon, 2 Dec 2019 16:40:31 +0800 Subject: [PATCH 2/4] restructure logic --- mypy/checkexpr.py | 14 ++++++++------ test-data/unit/check-classes.test | 27 ++++++++++----------------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 27c248397c4b..7c8f48df3862 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -2360,12 +2360,6 @@ def lookup_definer(typ: Instance, attr_name: str) -> Optional[str]: any_type = AnyType(TypeOfAny.from_another_any, source_any=right_type) return any_type, any_type - # If either the LHS or the RHS is Instance and fallbacks to Any, 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 1: # We start by getting the __op__ and __rop__ methods, if they exist. @@ -2456,6 +2450,14 @@ def lookup_definer(typ: Instance, attr_name: str) -> Optional[str]: results.append(result) 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 diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index e98a9b25ca0e..f2d36f6eef17 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -6573,24 +6573,17 @@ 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(0.5 / D()) # N: Revealed type is 'Any' -reveal_type(0.5 * D()) # 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(D() / 0.5) # N: Revealed type is 'Any' -reveal_type(D() * 0.5) # N: Revealed type is 'Any' -reveal_type(D() - 0.5) # N: Revealed type is 'Any' - -reveal_type("aaa" * D()) # N: Revealed type is 'Any' -reveal_type("aaa" + D()) # N: Revealed type is 'Any' -reveal_type("aaa" - D()) # N: Revealed type is 'Any' -reveal_type("aaa" / D()) # N: Revealed type is 'Any' - -reveal_type(D() * "aaa") # N: Revealed type is 'Any' -reveal_type(D() + "aaa") # N: Revealed type is 'Any' -reveal_type(D() - "aaa") # N: Revealed type is 'Any' -reveal_type(D() / "aaa") # 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' From 1a109c2e01c2e9f0ac300ab2a39a92b6e8729168 Mon Sep 17 00:00:00 2001 From: TH3CHARLie Date: Mon, 2 Dec 2019 16:54:29 +0800 Subject: [PATCH 3/4] remove trailing whitespace --- mypy/checkexpr.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 7c8f48df3862..68511945e777 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -2450,9 +2450,9 @@ def lookup_definer(typ: Instance, attr_name: str) -> Optional[str]: results.append(result) 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, + # 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)): From 744ed6fca9fa324d951e79474f4f32473357f123 Mon Sep 17 00:00:00 2001 From: Xuanda Yang Date: Fri, 13 Dec 2019 10:55:18 +0800 Subject: [PATCH 4/4] update newline --- test-data/unit/check-classes.test | 1 + 1 file changed, 1 insertion(+) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index e537ba569893..6681d30df76a 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -6575,6 +6575,7 @@ 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