diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 52d03282494f..a01cafc1c8cd 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -739,7 +739,7 @@ def non_method_protocol_members(tp: TypeInfo) -> List[str]: for member in tp.protocol_members: typ = get_proper_type(find_member(member, instance, instance)) - if not isinstance(typ, CallableType): + if not isinstance(typ, (CallableType, Overloaded)): result.append(member) return result @@ -1376,8 +1376,14 @@ def visit_literal_type(self, left: LiteralType) -> bool: return self._is_proper_subtype(left.fallback, self.right) def visit_overloaded(self, left: Overloaded) -> bool: - # TODO: What's the right thing to do here? - return False + if isinstance(self.right, Overloaded): + for right_item in self.right.items: + if not any(self._is_proper_subtype(left_item, right_item) + for left_item in left.items): + return False + return True + else: + return False def visit_union_type(self, left: UnionType) -> bool: return all([self._is_proper_subtype(item, self.orig_right) for item in left.items]) diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index b9c3376ad83a..5ba2237ca843 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -2331,7 +2331,7 @@ y: PBad = None # E: Incompatible types in assignment (expression has type "None [out] [case testOnlyMethodProtocolUsableWithIsSubclass] -from typing import Protocol, runtime_checkable, Union, Type +from typing import Protocol, runtime_checkable, Union, Type, overload @runtime_checkable class P(Protocol): def meth(self) -> int: @@ -2344,6 +2344,41 @@ class C: x: str def meth(self) -> int: pass + +class E: pass + +cls: Type[Union[C, E]] +issubclass(cls, PBad) # E: Only protocols that don't have non-method members can be used with issubclass() \ + # N: Protocol "PBad" has non-method member(s): x +if issubclass(cls, P): + reveal_type(cls) # N: Revealed type is "Type[__main__.C]" +else: + reveal_type(cls) # N: Revealed type is "Type[__main__.E]" +[builtins fixtures/isinstance.pyi] +[typing fixtures/typing-full.pyi] +[out] + +[case testProtocolWithOverloadUsableWithIsSubclass] +from typing import Protocol, runtime_checkable, Union, Type, overload +@runtime_checkable +class P(Protocol): + @overload + def meth(self, x: str) -> int: ... + @overload + def meth(self, x: int) -> str: ... +@runtime_checkable +class PBad(Protocol): + x: str + +class C: + x: str + @overload + def meth(self, x: str) -> int: ... + @overload + def meth(self, x: int) -> str: ... + def meth(self, x: Union[str, int]) -> Union[int, str]: + pass + class E: pass cls: Type[Union[C, E]]