From 582e24b6364923a05f991b1d87de8c362d284b20 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Mon, 20 Dec 2021 20:40:39 +0300 Subject: [PATCH] Recognize `Hashable` as a real protocol, refs #11799 --- mypy/typeops.py | 4 ++++ test-data/unit/pythoneval.test | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/mypy/typeops.py b/mypy/typeops.py index 9ba170b4b822..241f19ec7adb 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -125,6 +125,10 @@ def class_callable(init_type: CallableType, info: TypeInfo, type_type: Instance, explicit_type = init_ret_type if is_new else orig_self_type if ( isinstance(explicit_type, (Instance, TupleType)) + # We have to skip protocols, because it can can be a subtype of a return type + # by accident. Like `Hashable` is a subtype of `object`. See #11799 + and isinstance(default_ret_type, Instance) + and not default_ret_type.type.is_protocol # Only use the declared return type from __new__ or declared self in __init__ # if it is actually returning a subtype of what we would return otherwise. and is_subtype(explicit_type, default_ret_type, ignore_type_params=True) diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 90588a86d8bf..7cd83b4a58d3 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1573,3 +1573,17 @@ x: OrderedDict[str, str] = OrderedDict({}) reveal_type(x) # Revealed type is "collections.OrderedDict[builtins.str, builtins.int]" [out] _testTypingExtensionsOrderedDictAlias.py:3: note: Revealed type is "collections.OrderedDict[builtins.str, builtins.str]" + + +[case testSpecialTypingProtocols] +# flags: --warn-unreachable +from typing import Awaitable, Hashable, Union, Tuple, List + +obj: Union[Tuple[int], List[int]] +if isinstance(obj, Hashable): + reveal_type(obj) +if isinstance(obj, Awaitable): + reveal_type(obj) +[out] +_testSpecialTypingProtocols.py:6: note: Revealed type is "Tuple[builtins.int]" +_testSpecialTypingProtocols.py:8: error: Statement is unreachable