Skip to content

Commit aea1971

Browse files
committed
Compute type of inherited constructor correctly
Fixes #1246.
1 parent 2db9dc3 commit aea1971

File tree

3 files changed

+68
-30
lines changed

3 files changed

+68
-30
lines changed

mypy/checker.py

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from mypy.sametypes import is_same_type
3535
from mypy.messages import MessageBuilder
3636
import mypy.checkexpr
37+
from mypy.checkmember import map_type_from_supertype
3738
from mypy import defaults
3839
from mypy import messages
3940
from mypy.subtypes import (
@@ -2326,36 +2327,6 @@ def method_type(self, func: FuncBase) -> FunctionLike:
23262327
return method_type_with_fallback(func, self.named_type('builtins.function'))
23272328

23282329

2329-
def map_type_from_supertype(typ: Type, sub_info: TypeInfo,
2330-
super_info: TypeInfo) -> Type:
2331-
"""Map type variables in a type defined in a supertype context to be valid
2332-
in the subtype context. Assume that the result is unique; if more than
2333-
one type is possible, return one of the alternatives.
2334-
2335-
For example, assume
2336-
2337-
. class D(Generic[S]) ...
2338-
. class C(D[E[T]], Generic[T]) ...
2339-
2340-
Now S in the context of D would be mapped to E[T] in the context of C.
2341-
"""
2342-
# Create the type of self in subtype, of form t[a1, ...].
2343-
inst_type = self_type(sub_info)
2344-
if isinstance(inst_type, TupleType):
2345-
inst_type = inst_type.fallback
2346-
# Map the type of self to supertype. This gets us a description of the
2347-
# supertype type variables in terms of subtype variables, i.e. t[t1, ...]
2348-
# so that any type variables in tN are to be interpreted in subtype
2349-
# context.
2350-
inst_type = map_instance_to_supertype(inst_type, super_info)
2351-
# Finally expand the type variables in type with those in the previously
2352-
# constructed type. Note that both type and inst_type may have type
2353-
# variables, but in type they are interpreterd in supertype context while
2354-
# in inst_type they are interpreted in subtype context. This works even if
2355-
# the names of type variables in supertype and subtype overlap.
2356-
return expand_type_by_instance(typ, inst_type)
2357-
2358-
23592330
def find_isinstance_check(node: Node,
23602331
type_map: Dict[Node, Type],
23612332
weak: bool=False) \

mypy/checkmember.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,8 @@ def type_object_type(info: TypeInfo, builtin_type: Callable[[str], Instance]) ->
359359
def type_object_type_from_function(init_or_new: FuncBase, info: TypeInfo,
360360
fallback: Instance) -> FunctionLike:
361361
signature = method_type_with_fallback(init_or_new, fallback)
362+
signature = cast(FunctionLike,
363+
map_type_from_supertype(signature, info, init_or_new.info))
362364
if isinstance(signature, CallableType):
363365
return class_callable(signature, info, fallback)
364366
else:
@@ -416,3 +418,33 @@ def translate_variables(self,
416418
else:
417419
items.append(v)
418420
return items
421+
422+
423+
def map_type_from_supertype(typ: Type, sub_info: TypeInfo,
424+
super_info: TypeInfo) -> Type:
425+
"""Map type variables in a type defined in a supertype context to be valid
426+
in the subtype context. Assume that the result is unique; if more than
427+
one type is possible, return one of the alternatives.
428+
429+
For example, assume
430+
431+
. class D(Generic[S]) ...
432+
. class C(D[E[T]], Generic[T]) ...
433+
434+
Now S in the context of D would be mapped to E[T] in the context of C.
435+
"""
436+
# Create the type of self in subtype, of form t[a1, ...].
437+
inst_type = self_type(sub_info)
438+
if isinstance(inst_type, TupleType):
439+
inst_type = inst_type.fallback
440+
# Map the type of self to supertype. This gets us a description of the
441+
# supertype type variables in terms of subtype variables, i.e. t[t1, ...]
442+
# so that any type variables in tN are to be interpreted in subtype
443+
# context.
444+
inst_type = map_instance_to_supertype(inst_type, super_info)
445+
# Finally expand the type variables in type with those in the previously
446+
# constructed type. Note that both type and inst_type may have type
447+
# variables, but in type they are interpreterd in supertype context while
448+
# in inst_type they are interpreted in subtype context. This works even if
449+
# the names of type variables in supertype and subtype overlap.
450+
return expand_type_by_instance(typ, inst_type)

mypy/test/data/check-generic-subtyping.test

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,41 @@ class A(B[S], Generic[T, S]):
352352
main: note: In member "g" of class "A":
353353

354354

355+
-- Type of inherited constructor
356+
-- -----------------------------
357+
358+
359+
[case testInheritedConstructor]
360+
from typing import TypeVar, Generic
361+
T = TypeVar('T')
362+
class A(Generic[T]):
363+
def __init__(self, x: T) -> None: pass
364+
class B(A[T], Generic[T]): pass
365+
class C(A[int]): pass
366+
class D(A[A[T]], Generic[T]): pass
367+
B(1)
368+
C(1)
369+
C('a') # E: Argument 1 to "C" has incompatible type "str"; expected "int"
370+
D(A(1))
371+
D(1) # E: Argument 1 to "D" has incompatible type "int"; expected A[None]
372+
373+
374+
[case testInheritedConstructor2]
375+
from typing import TypeVar, Generic
376+
T = TypeVar('T')
377+
U = TypeVar('U')
378+
Z = TypeVar('Z')
379+
class A(Generic[T, U]):
380+
def __init__(self, x: T, y: U, z: Z) -> None: pass
381+
class B(A[int, T], Generic[T]): pass
382+
class C(B[A[T, str]], Generic[T, U]): pass
383+
# C[T, U] <: B[A[T, str]] <: A[int, A[T, str]]
384+
C(1, A(1, 'a', 0), 'z')
385+
C(1, A('1', 'a', 0), 'z')
386+
C('1', A(1, 'a', 0), 'z') # E: Argument 1 to "C" has incompatible type "str"; expected "int"
387+
C(1, A(1, 1, 0), 'z') # E: Argument 2 to "A" has incompatible type "int"; expected "str"
388+
389+
355390
-- Subtyping with a generic abstract base class
356391
-- --------------------------------------------
357392

0 commit comments

Comments
 (0)