diff --git a/mypy/typeops.py b/mypy/typeops.py index 57fdfeadad9a..007a54e17b95 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -107,6 +107,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 de15055927ae..f560ac81e645 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1575,6 +1575,19 @@ reveal_type(x) # Revealed type is "collections.OrderedDict[builtins.str, builti [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 + [case testEnumValueWithPlaceholderNodeType] # https://github.com/python/mypy/issues/11971 from enum import Enum