From 06621dd5619e20c99137b6c1e6333e281711c347 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Mon, 18 Jun 2018 20:44:49 +0100 Subject: [PATCH 1/3] Fix overload interaction with Any --- mypy/checkexpr.py | 4 ++-- test-data/unit/check-overloading.test | 17 ++++++++--------- test-data/unit/python2eval.test | 12 ++++++++++-- test-data/unit/pythoneval.test | 2 ++ 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 09232ba037d58..c0896ed852839 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1133,7 +1133,6 @@ def check_overload_call(self, erased_targets = self.overload_erased_call_targets(plausible_targets, arg_types, arg_kinds, arg_names, context) unioned_callable = self.union_overload_matches(erased_targets) - if unioned_callable is not None: unioned_errors = arg_messages.clean_copy() unioned_result = self.check_call(unioned_callable, args, arg_kinds, @@ -1304,7 +1303,8 @@ def infer_overload_return_type(self, return None elif any_causes_overload_ambiguity(matches, return_types, arg_types, arg_kinds, arg_names): # An argument of type or containing the type 'Any' caused ambiguity. - if all(is_subtype(ret_type, return_types[-1]) for ret_type in return_types[:-1]): + if all(is_subtype(ret_type, return_types[-1]) and is_subtype(return_types[-1], ret_type) + for ret_type in return_types[:-1]): # The last match is a supertype of all the previous ones, so it's safe # to return that inferred type. return return_types[-1], inferred_types[-1] diff --git a/test-data/unit/check-overloading.test b/test-data/unit/check-overloading.test index 0b1eedf16e64d..a1c4f49b648fb 100644 --- a/test-data/unit/check-overloading.test +++ b/test-data/unit/check-overloading.test @@ -1276,7 +1276,7 @@ def f(x: object) -> object: ... def f(x): pass a: Any -reveal_type(f(a)) # E: Revealed type is 'builtins.object' +reveal_type(f(a)) # E: Revealed type is 'Any' [case testOverloadWithOverlappingItemsAndAnyArgument2] from typing import overload, Any @@ -1288,7 +1288,7 @@ def f(x: float) -> float: ... def f(x): pass a: Any -reveal_type(f(a)) # E: Revealed type is 'builtins.float' +reveal_type(f(a)) # E: Revealed type is 'Any' [case testOverloadWithOverlappingItemsAndAnyArgument3] from typing import overload, Any @@ -1312,17 +1312,16 @@ def f(x: object, y: int, z: str) -> object: ... def f(x): pass a: Any -# Any causes ambiguity; we fall back to returning object since it's a -# supertype of int -reveal_type(f(a, 1, '')) # E: Revealed type is 'builtins.object' +# Any causes ambiguity +reveal_type(f(a, 1, '')) # E: Revealed type is 'Any' # Any causes no ambiguity reveal_type(f(1, a, a)) # E: Revealed type is 'builtins.int' reveal_type(f('', a, a)) # E: Revealed type is 'builtins.object' # Like above, but use keyword arguments. -reveal_type(f(y=1, z='', x=a)) # E: Revealed type is 'builtins.object' +reveal_type(f(y=1, z='', x=a)) # E: Revealed type is 'Any' reveal_type(f(y=a, z='', x=1)) # E: Revealed type is 'builtins.int' reveal_type(f(z='', x=1, y=a)) # E: Revealed type is 'builtins.int' -reveal_type(f(z='', x=a, y=1)) # E: Revealed type is 'builtins.object' +reveal_type(f(z='', x=a, y=1)) # E: Revealed type is 'Any' [case testOverloadWithOverlappingItemsAndAnyArgument5] from typing import overload, Any, Union @@ -1334,7 +1333,7 @@ def f(x: Union[int, float]) -> float: ... def f(x): pass a: Any -reveal_type(f(a)) # E: Revealed type is 'builtins.float' +reveal_type(f(a)) # E: Revealed type is 'Any' [case testOverloadWithOverlappingItemsAndAnyArgument6] from typing import overload, Any @@ -1372,7 +1371,7 @@ def g(x): pass a: Any reveal_type(f(1, *a)) # E: Revealed type is 'builtins.int' -reveal_type(g(1, *a)) # E: Revealed type is 'builtins.object' +reveal_type(g(1, *a)) # E: Revealed type is 'Any' [case testOverloadWithOverlappingItemsAndAnyArgument8] from typing import overload, Any diff --git a/test-data/unit/python2eval.test b/test-data/unit/python2eval.test index 6007cad7780c4..d92fab57e4be9 100644 --- a/test-data/unit/python2eval.test +++ b/test-data/unit/python2eval.test @@ -342,7 +342,7 @@ print b.x + 1 [out] 4 -[case testReModuleBytesPython2] +[case testReModuleBytes_python2] # Regression tests for various overloads in the re module -- bytes version import re if False: @@ -365,7 +365,7 @@ if False: re.subn(bpat, lambda m: b'', b'')[0] + b'' [out] -[case testReModuleStringPython2] +[case testReModuleString_python2] # Regression tests for various overloads in the re module -- string version import re ure = u'a+' @@ -393,3 +393,11 @@ def g(): # type: () -> int yield [out] _program.py:2: error: The return type of a generator function should be "Generator" or one of its supertypes + +[case testOsPathJoinWorksWithAny_python2] +import os +def f(): # no annotation + return 'tests' +path = 'test' +path = os.path.join(f(), 'test.py') +[out] diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index a7b8773f63c59..0bb9da3525fa7 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1109,9 +1109,11 @@ async def main() -> None: ((a_x, a_y),) = await asyncio.gather(get_location('start')) reveal_type(a_x) reveal_type(a_y) +reveal_type(asyncio.gather(*[asyncio.sleep(1), asyncio.sleep(1)])) [out] _testAsyncioGatherPreciseType.py:9: error: Revealed type is 'builtins.str' _testAsyncioGatherPreciseType.py:10: error: Revealed type is 'builtins.str' +_testAsyncioGatherPreciseType.py:11: error: Revealed type is 'asyncio.futures.Future[builtins.tuple[Any]]' [case testMultipleInheritanceWorksWithTupleTypeGeneric] from typing import SupportsAbs, NamedTuple From dbca4f1adfc0986e617022101d817c3dd38536f9 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Mon, 18 Jun 2018 20:49:01 +0100 Subject: [PATCH 2/3] Fix formattig --- mypy/checkexpr.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index c0896ed852839..5c52269636868 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1133,6 +1133,7 @@ def check_overload_call(self, erased_targets = self.overload_erased_call_targets(plausible_targets, arg_types, arg_kinds, arg_names, context) unioned_callable = self.union_overload_matches(erased_targets) + if unioned_callable is not None: unioned_errors = arg_messages.clean_copy() unioned_result = self.check_call(unioned_callable, args, arg_kinds, @@ -1303,7 +1304,8 @@ def infer_overload_return_type(self, return None elif any_causes_overload_ambiguity(matches, return_types, arg_types, arg_kinds, arg_names): # An argument of type or containing the type 'Any' caused ambiguity. - if all(is_subtype(ret_type, return_types[-1]) and is_subtype(return_types[-1], ret_type) + if all(is_subtype(ret_type, return_types[-1]) and + is_subtype(return_types[-1], ret_type) for ret_type in return_types[:-1]): # The last match is a supertype of all the previous ones, so it's safe # to return that inferred type. From 78208547502a58f4faed94a4a54f9ad80bd39a5d Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Mon, 18 Jun 2018 21:15:13 +0100 Subject: [PATCH 3/3] Update comment --- mypy/checkexpr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 5c52269636868..bd167b3f39200 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1307,7 +1307,7 @@ def infer_overload_return_type(self, if all(is_subtype(ret_type, return_types[-1]) and is_subtype(return_types[-1], ret_type) for ret_type in return_types[:-1]): - # The last match is a supertype of all the previous ones, so it's safe + # The last match is mutually compatible with all previous ones, so it's safe # to return that inferred type. return return_types[-1], inferred_types[-1] else: