Skip to content

Commit 89bb94a

Browse files
authored
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`.
1 parent e2178b8 commit 89bb94a

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

mypy/subtypes.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,8 @@ def find_node_type(node: Union[Var, FuncBase], itype: Instance, subtype: Type) -
730730
and node.is_initialized_in_class
731731
and not node.is_staticmethod)):
732732
assert isinstance(typ, FunctionLike)
733-
signature = bind_self(typ, subtype)
733+
signature = bind_self(typ, subtype,
734+
is_classmethod=isinstance(node, Var) and node.is_classmethod)
734735
if node.is_property:
735736
assert isinstance(signature, CallableType)
736737
typ = signature.ret_type

test-data/unit/check-selftype.test

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,37 @@ class Bad(metaclass=Meta):
802802
Good.do_x()
803803
Bad.do_x() # E: Invalid self argument "Type[Bad]" to attribute function "do_x" with type "Callable[[Type[T]], T]"
804804

805+
[case testSelfTypeProtocolClassmethodMatch]
806+
from typing import Type, TypeVar, Protocol
807+
808+
T = TypeVar('T')
809+
810+
class HasDoX(Protocol):
811+
@classmethod
812+
def do_x(cls: Type[T]) -> T:
813+
...
814+
815+
class Good:
816+
@classmethod
817+
def do_x(cls) -> 'Good':
818+
...
819+
820+
class Bad:
821+
@classmethod
822+
def do_x(cls) -> Good:
823+
...
824+
825+
good: HasDoX = Good()
826+
bad: HasDoX = Bad()
827+
[builtins fixtures/classmethod.pyi]
828+
[out]
829+
main:21: error: Incompatible types in assignment (expression has type "Bad", variable has type "HasDoX")
830+
main:21: note: Following member(s) of "Bad" have conflicts:
831+
main:21: note: Expected:
832+
main:21: note: def do_x(cls) -> Bad
833+
main:21: note: Got:
834+
main:21: note: def do_x(cls) -> Good
835+
805836
[case testSelfTypeNotSelfType]
806837
# Friendlier error messages for common mistakes. See #2950
807838
class A:

0 commit comments

Comments
 (0)