From 769eb8762c7e641b34386904f4dcb047743963fe Mon Sep 17 00:00:00 2001 From: Ilia Novoselov Date: Fri, 19 Nov 2021 05:21:30 +0500 Subject: [PATCH] Correctly handle cls in protocol classmethod (#11119) Closes #11115. Correctly handle cls in generic classmethods of protocol. This should correctly handle cls in classmethods. Current behavior of not passing is_classmethod seems like an omission in implementation, so this should only correct buggy behavior and shouldn't break something else. Adds a test case `testSelfTypeProtocolClassmethodMatch`. --- mypy/subtypes.py | 3 ++- test-data/unit/check-selftype.test | 31 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index f9d27b7a1656..a3a678a941e7 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -730,7 +730,8 @@ def find_node_type(node: Union[Var, FuncBase], itype: Instance, subtype: Type) - and node.is_initialized_in_class and not node.is_staticmethod)): assert isinstance(typ, FunctionLike) - signature = bind_self(typ, subtype) + signature = bind_self(typ, subtype, + is_classmethod=isinstance(node, Var) and node.is_classmethod) if node.is_property: assert isinstance(signature, CallableType) typ = signature.ret_type diff --git a/test-data/unit/check-selftype.test b/test-data/unit/check-selftype.test index a1fa234e6d0d..afd75111743d 100644 --- a/test-data/unit/check-selftype.test +++ b/test-data/unit/check-selftype.test @@ -802,6 +802,37 @@ class Bad(metaclass=Meta): Good.do_x() Bad.do_x() # E: Invalid self argument "Type[Bad]" to attribute function "do_x" with type "Callable[[Type[T]], T]" +[case testSelfTypeProtocolClassmethodMatch] +from typing import Type, TypeVar, Protocol + +T = TypeVar('T') + +class HasDoX(Protocol): + @classmethod + def do_x(cls: Type[T]) -> T: + ... + +class Good: + @classmethod + def do_x(cls) -> 'Good': + ... + +class Bad: + @classmethod + def do_x(cls) -> Good: + ... + +good: HasDoX = Good() +bad: HasDoX = Bad() +[builtins fixtures/classmethod.pyi] +[out] +main:21: error: Incompatible types in assignment (expression has type "Bad", variable has type "HasDoX") +main:21: note: Following member(s) of "Bad" have conflicts: +main:21: note: Expected: +main:21: note: def do_x(cls) -> Bad +main:21: note: Got: +main:21: note: def do_x(cls) -> Good + [case testSelfTypeNotSelfType] # Friendlier error messages for common mistakes. See #2950 class A: