diff --git a/mypy/checker.py b/mypy/checker.py index fc9733117a0a..0639340d30bb 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -7190,7 +7190,7 @@ def check_subtype( if ( isinstance(supertype, Instance) and supertype.type.is_protocol - and isinstance(subtype, (CallableType, Instance, TupleType, TypedDictType)) + and isinstance(subtype, (CallableType, Instance, TupleType, TypedDictType, TypeType)) ): self.msg.report_protocol_problems(subtype, supertype, context, parent_error=error) if isinstance(supertype, CallableType) and isinstance(subtype, Instance): diff --git a/mypy/messages.py b/mypy/messages.py index 46ade80df61d..01414f1c7f2b 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -3090,9 +3090,14 @@ def get_bad_protocol_flags( assert right.type.is_protocol all_flags: list[tuple[str, set[int], set[int]]] = [] for member in right.type.protocol_members: - if find_member(member, left, left): - item = (member, get_member_flags(member, left), get_member_flags(member, right)) - all_flags.append(item) + if find_member(member, left, left, class_obj=class_obj): + all_flags.append( + ( + member, + get_member_flags(member, left, class_obj=class_obj), + get_member_flags(member, right), + ) + ) bad_flags = [] for name, subflags, superflags in all_flags: if ( diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 15c8014c0f3f..acb41609fdc5 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -1319,8 +1319,8 @@ def find_member( is_lvalue=is_lvalue, is_super=False, is_operator=is_operator, - original_type=itype, - self_type=subtype, + original_type=TypeType.make_normalized(itype) if class_obj else itype, + self_type=TypeType.make_normalized(subtype) if class_obj else subtype, context=Context(), # all errors are filtered, but this is a required argument chk=type_checker, suppress_errors=True, diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test index 4d7f46e5de2b..f330aa4ecc02 100644 --- a/test-data/unit/check-protocols.test +++ b/test-data/unit/check-protocols.test @@ -4552,6 +4552,32 @@ t = Test(Mock()) reveal_type(t) # N: Revealed type is "__main__.Test[Any]" [builtins fixtures/dict.pyi] +[case testProtocolClassObjectDescriptor] +from typing import Any, Protocol, overload + +class Desc: + @overload + def __get__(self, instance: None, owner: Any) -> Desc: ... + @overload + def __get__(self, instance: object, owner: Any) -> int: ... + def __get__(self, instance, owner): + pass + +class HasDesc(Protocol): + attr: Desc + +class HasInt(Protocol): + attr: int + +class C: + attr = Desc() + +x: HasInt = C() +y: HasDesc = C +z: HasInt = C # E: Incompatible types in assignment (expression has type "type[C]", variable has type "HasInt") \ + # N: Following member(s) of "C" have conflicts: \ + # N: attr: expected "int", got "Desc" + [case testProtocolErrorReportingNoDuplicates] from typing import Callable, Protocol, TypeVar