From 89ccd9a7621f04005e81732f650d75ff65e34f59 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Tue, 27 Mar 2018 20:35:37 -0700 Subject: [PATCH 1/2] Removes incorrect override check on overloaded methods This commit fixes https://github.com/python/mypy/issues/4565 Currently, when we override a method and annotate the implementation, mypy appears to check the legality of the override twice: once for the overloads, and once for the implementation. This second check is unnecessary and causes a spurious error. --- mypy/checker.py | 4 ++- test-data/unit/check-overloading.test | 42 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/mypy/checker.py b/mypy/checker.py index 9d18fff8200c..208919ee59db 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -610,7 +610,9 @@ def _visit_func_def(self, defn: FuncDef) -> None: """Type check a function definition.""" self.check_func_item(defn, name=defn.name()) if defn.info: - if not defn.is_dynamic(): + if not defn.is_dynamic() and not defn.is_overload: + # If the definition is the implementation for an overload, the legality + # of the override has already been typechecked. self.check_method_override(defn) self.check_inplace_operator_method(defn) if defn.original_def: diff --git a/test-data/unit/check-overloading.test b/test-data/unit/check-overloading.test index 3b0abadbf408..070bf0c239a1 100644 --- a/test-data/unit/check-overloading.test +++ b/test-data/unit/check-overloading.test @@ -1399,3 +1399,45 @@ def g(x: Tuple[A, B]) -> D: ... def g(x: Any) -> Any:... [builtins fixtures/tuple.pyi] + +[case testOverloadWithMethodOverrideAndImplementation] +from typing import overload, Union, Any + +class Parent: + @overload + def f(self, arg: int) -> int: ... + @overload + def f(self, arg: str) -> str: ... + def f(self, arg: Any) -> Any: ... + +class Child1(Parent): + @overload + def f(self, arg: int) -> int: ... + @overload + def f(self, arg: str) -> str: ... + def f(self, arg: Union[int, str]) -> Union[int, str]: ... + +class Child2(Parent): + @overload + def f(self, arg: int) -> int: ... + @overload + def f(self, arg: str) -> str: ... + def f(self, arg: Union[int, str]) -> int: ... # E: Overloaded function implementation cannot produce return type of signature 2 + +class Child3(Parent): + @overload + def f(self, arg: int) -> int: ... + @overload + def f(self, arg: str) -> str: ... + def f(self, arg: Any) -> Any: ... + +class Child4(Parent): + @overload + def f(self, arg: int) -> int: ... + @overload + def f(self, arg: str) -> str: ... + def f(self, arg: Union[int, str]) -> Union[int, str]: + return True # E: Incompatible return value type (got "bool", expected "Union[int, str]") + +[builtins fixtures/tuple.pyi] + From b92547a6ff6179bbfc1f1a1af3d39d35d83620e2 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Wed, 28 Mar 2018 07:52:05 -0700 Subject: [PATCH 2/2] Adds a test where subtypes are incompatible --- test-data/unit/check-overloading.test | 49 +++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test-data/unit/check-overloading.test b/test-data/unit/check-overloading.test index 070bf0c239a1..88eabcaf4a61 100644 --- a/test-data/unit/check-overloading.test +++ b/test-data/unit/check-overloading.test @@ -1441,3 +1441,52 @@ class Child4(Parent): [builtins fixtures/tuple.pyi] +[case testOverloadWithIncompatibleMethodOverrideAndImplementation] +from typing import overload, Union, Any + +class StrSub: pass + +class ParentWithTypedImpl: + @overload + def f(self, arg: int) -> int: ... + @overload + def f(self, arg: str) -> str: ... + def f(self, arg: Union[int, str]) -> Union[int, str]: ... + +class Child1(ParentWithTypedImpl): + @overload # E: Signature of "f" incompatible with supertype "ParentWithTypedImpl" + def f(self, arg: int) -> int: ... + @overload + def f(self, arg: StrSub) -> str: ... + def f(self, arg: Union[int, StrSub]) -> Union[int, str]: ... + +class Child2(ParentWithTypedImpl): + @overload # E: Signature of "f" incompatible with supertype "ParentWithTypedImpl" + def f(self, arg: int) -> int: ... + @overload + def f(self, arg: StrSub) -> str: ... + def f(self, arg: Any) -> Any: ... + +class ParentWithDynamicImpl: + @overload + def f(self, arg: int) -> int: ... + @overload + def f(self, arg: str) -> str: ... + def f(self, arg: Any) -> Any: ... + +class Child3(ParentWithDynamicImpl): + @overload # E: Signature of "f" incompatible with supertype "ParentWithDynamicImpl" + def f(self, arg: int) -> int: ... + @overload + def f(self, arg: StrSub) -> str: ... + def f(self, arg: Union[int, StrSub]) -> Union[int, str]: ... + +class Child4(ParentWithDynamicImpl): + @overload # E: Signature of "f" incompatible with supertype "ParentWithDynamicImpl" + def f(self, arg: int) -> int: ... + @overload + def f(self, arg: StrSub) -> str: ... + def f(self, arg: Any) -> Any: ... + +[builtins fixtures/tuple.pyi] +