Skip to content

Commit 7e610b7

Browse files
committed
Map class type parameters to superclass when checking class method use
Fixes python#1337.
1 parent dedba6e commit 7e610b7

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

mypy/checkmember.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ def analyze_class_attribute_access(itype: Instance,
300300

301301
t = node.type
302302
if t:
303+
if isinstance(node.node, Decorator):
304+
info = node.node.var.info
305+
elif isinstance(node.node, (Var, FuncBase)):
306+
info = node.node.info
307+
t = map_type_from_supertype(t, itype.type, info)
303308
if isinstance(t, PartialType):
304309
return handle_partial_attribute_type(t, is_lvalue, msg, node.node)
305310
is_classmethod = is_decorated and cast(Decorator, node.node).func.is_class

test-data/unit/check-generics.test

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,71 @@ main:9: error: Incompatible types in assignment (expression has type A[C, B], va
188188
main:10: error: Incompatible types in assignment (expression has type A[B, B], variable has type A[B, C])
189189

190190

191+
[case testClassMethodOfGenericClass]
192+
from typing import TypeVar, Generic
193+
T = TypeVar('T')
194+
U = TypeVar('U')
195+
class X(Generic[T,U]):
196+
def __init__(self, t: T, u: U) -> None:
197+
pass
198+
199+
class A(Generic[T]):
200+
@classmethod
201+
def f(cls, x: T) -> T:
202+
pass
203+
@classmethod
204+
def g(cls) -> T:
205+
pass
206+
class B(A[X[int, T]], Generic[T]):
207+
pass
208+
class C(B[str]):
209+
pass
210+
211+
A.f(3)() # E: "int" not callable
212+
B.f(3) # E: Argument 1 to "f" of "A" has incompatible type "int"; expected X[int, None]
213+
B.f(X(3, 4))() # E: X[int, int] not callable
214+
C.f(X(3, 4)) # E: Argument 2 to "X" has incompatible type "int"; expected "str"
215+
C.f(X(3, 'a'))() # E: X[int, str] not callable
216+
217+
ga = A.g() # E: Need type annotation for variable
218+
gb = B.g() # E: Need type annotation for variable
219+
gc = C.g()
220+
gc() # E: X[int, str] not callable
221+
[builtins fixtures/classmethod.py]
222+
223+
[case testStaticMethodOfGenericClass]
224+
from typing import TypeVar, Generic
225+
T = TypeVar('T')
226+
U = TypeVar('U')
227+
class X(Generic[T,U]):
228+
def __init__(self, t: T, u: U) -> None:
229+
pass
230+
231+
class A(Generic[T]):
232+
@staticmethod
233+
def f(x: T) -> T:
234+
pass
235+
@staticmethod
236+
def g() -> T:
237+
pass
238+
class B(A[X[int, T]], Generic[T]):
239+
pass
240+
class C(B[str]):
241+
pass
242+
243+
A.f(3)() # E: "int" not callable
244+
B.f(3) # E: Argument 1 to "f" of "A" has incompatible type "int"; expected X[int, None]
245+
B.f(X(3, 4))() # E: X[int, int] not callable
246+
C.f(X(3, 4)) # E: Argument 2 to "X" has incompatible type "int"; expected "str"
247+
C.f(X(3, 'a'))() # E: X[int, str] not callable
248+
249+
ga = A.g() # E: Need type annotation for variable
250+
gb = B.g() # E: Need type annotation for variable
251+
gc = C.g()
252+
gc() # E: X[int, str] not callable
253+
[builtins fixtures/staticmethod.py]
254+
255+
191256
-- Simple generic type bodies
192257
-- --------------------------
193258

0 commit comments

Comments
 (0)