-- Test cases for the type checker related to subtyping and inheritance with
-- generics.


-- Subtyping + inheritance
-- -----------------------


[case testSubtypingAndInheritingNonGenericTypeFromGenericType]
from typing import TypeVar, Generic
T = TypeVar('T')
ac = None # type: A[C]
ad = None # type: A[D]
b = None # type: B

b = ad # E: Incompatible types in assignment (expression has type "A[D]", variable has type "B")
ad = b # E: Incompatible types in assignment (expression has type "B", variable has type "A[D]")
b = ac # E: Incompatible types in assignment (expression has type "A[C]", variable has type "B")

b = b
ac = b

class C: pass
class A(Generic[T]): pass
class B(A[C]): pass
class D: pass

[case testSubtypingAndInheritingGenericTypeFromNonGenericType]
from typing import TypeVar, Generic
T = TypeVar('T')
a = None # type: A
bc = None # type: B[C]
bd = None # type: B[D]

bc = bd # E: Incompatible types in assignment (expression has type "B[D]", variable has type "B[C]")
bd = bc # E: Incompatible types in assignment (expression has type "B[C]", variable has type "B[D]")
bc = a  # E: Incompatible types in assignment (expression has type "A", variable has type "B[C]")
bd = a  # E: Incompatible types in assignment (expression has type "A", variable has type "B[D]")

a = bc
a = bd

class A: pass
class B(A, Generic[T]): pass
class C: pass
class D: pass

[case testSubtypingAndInheritingGenericTypeFromGenericType]
from typing import TypeVar, Generic
T = TypeVar('T')
S = TypeVar('S')
ac = None # type: A[C]
ad = None # type: A[D]
bcc = None # type: B[C, C]
bdc = None # type: B[D, C]

ad = bcc # E: Incompatible types in assignment (expression has type "B[C, C]", variable has type "A[D]")
ad = bdc # E: Incompatible types in assignment (expression has type "B[D, C]", variable has type "A[D]")
bcc = ac # E: Incompatible types in assignment (expression has type "A[C]", variable has type "B[C, C]")
bdc = ac # E: Incompatible types in assignment (expression has type "A[C]", variable has type "B[D, C]")

bcc = bcc
bdc = bdc
ac = bcc
ac = bdc

class A(Generic[T]): pass
class B(A[S], Generic[T, S]): pass
class C: pass
class D: pass

[case testSubtypingAndInheritingGenericTypeFromGenericTypeAcrossHierarchy]
from typing import TypeVar, Generic
T = TypeVar('T')
S = TypeVar('S')
X = TypeVar('X')
Y = TypeVar('Y')
ae = None # type: A[A[E]]
af = None # type: A[A[F]]

cef = None # type: C[E, F]
cff = None # type: C[F, F]
cfe = None # type: C[F, E]

ae = cef # E: Incompatible types in assignment (expression has type "C[E, F]", variable has type "A[A[E]]")
af = cfe # E: Incompatible types in assignment (expression has type "C[F, E]", variable has type "A[A[F]]")

ae = cfe
af = cef
af = cff

class A(Generic[T]): pass
class B(A[S], Generic[T, S]): pass
class C(B[A[X], A[Y]], Generic[X, Y]): pass
class E: pass
class F: pass

[case testIncludingBaseClassTwice]
from typing import TypeVar, Generic
t = TypeVar('t')
class I(Generic[t]): pass
class A(I[C], I[object]): pass # E: Duplicate base class "I"
class C: pass


-- Accessing inherited generic members
-- -----------------------------------


[case testAccessingMethodInheritedFromGenericType]
from typing import TypeVar, Generic
T = TypeVar('T')
S = TypeVar('S')
b = None # type: B[C, D]
c, d = None, None # type: (C, D)

b.f(c) # E: Argument 1 to "f" of "A" has incompatible type "C"; expected "D"
b.f(d)

class A(Generic[T]):
    def f(self, a: T) -> None:
        pass
class B(A[S], Generic[T, S]): pass
class C: pass
class D: pass

[case testAccessingMethodInheritedFromGenericTypeInNonGenericType]
from typing import TypeVar, Generic
T = TypeVar('T')
b, c, d = None, None, None # type: (B, C, D)

b.f(c) # E: Argument 1 to "f" of "A" has incompatible type "C"; expected "D"
b.f(d)

class C: pass
class D: pass
class A(Generic[T]):
    def f(self, a: T) -> None:
        pass
class B(A[D]): pass

[case testAccessingMemberVarInheritedFromGenericType]
from typing import TypeVar, Generic
T = TypeVar('T')
S = TypeVar('S')
class A(Generic[T]):
    def __init__(self, a: T) -> None:
        self.a = a

b = None # type: B[C, D]
c, d = None, None # type: (C, D)

b.a = c # E: Incompatible types in assignment (expression has type "C", variable has type "D")
b.a = d

class B(A[S], Generic[T, S]): pass
class C: pass
class D: pass


-- Overriding with generic types
-- -----------------------------


[case testOverridingMethodInSimpleTypeInheritingGenericType]
from typing import TypeVar, Generic
T = TypeVar('T')
class B(Generic[T]):
    def f(self, a: T) -> None: pass
    def g(self, a: T) -> None: pass
class C: pass
class D: pass
class A(B[C]):
    def f(self, a: D) -> None: pass \
        # E: Argument 1 of "f" incompatible with supertype "B"
    def g(self, a: C) -> None: pass
[out]

[case testOverridingMethodInGenericTypeInheritingSimpleType]
from typing import TypeVar, Generic
T = TypeVar('T')
class C: pass
class B:
    def f(self, a: C) -> None: pass
    def g(self, a: C) -> None: pass
class A(B, Generic[T]):
    def f(self, a: T) -> None: pass \
        # E: Argument 1 of "f" incompatible with supertype "B"
    def g(self, a: 'C') -> None: pass
[out]

[case testOverridingMethodInGenericTypeInheritingGenericType]
from typing import TypeVar, Generic
T = TypeVar('T')
S = TypeVar('S')
class B(Generic[T]):
    def f(self, a: T) -> None: pass
    def g(self, a: T) -> None: pass
class A(B[S], Generic[T, S]):
    def f(self, a: T) -> None: pass \
        # E: Argument 1 of "f" incompatible with supertype "B"
    def g(self, a: S) -> None: pass
[out]

[case testOverridingMethodInMultilevelHierarchyOfGenericTypes]
from typing import TypeVar, Generic
T = TypeVar('T')
S = TypeVar('S')
U = TypeVar('U')
V = TypeVar('V')

class D: pass
class C(Generic[T, U, V]):
    def f(self, a: V) -> None: pass
    def g(self, a: V) -> None: pass
class B(C[D, D, T], Generic[T]): pass
class A(B[S], Generic[T, S]):
    def f(self, a: T) -> None: pass \
        # E: Argument 1 of "f" incompatible with supertype "C"
    def g(self, a: S) -> None: pass
[out]

[case testOverrideGenericMethodInNonGenericClass]
from typing import TypeVar

T = TypeVar('T')
S = TypeVar('S')

class A:
    def f(self, x: T, y: S) -> None: pass
class B(A):
    def f(self, x: S, y: T) -> None: pass
class C(A):
    # Okay, because T = object allows any type for the arguments.
    def f(self, x: T, y: T) -> None: pass

[case testOverrideGenericMethodInNonGenericClassLists]
from typing import TypeVar, List

T = TypeVar('T')
S = TypeVar('S')

class A:
    def f(self, x: List[T], y: List[S]) -> None: pass
class B(A):
    def f(self, x: List[S], y: List[T]) -> None: pass
class C(A):
    def f(self, x: List[T], y: List[T]) -> None: pass # E: Signature of "f" incompatible with supertype "A"
[builtins fixtures/list.pyi]
[out]

[case testOverrideGenericMethodInNonGenericClassGeneralize]
from typing import TypeVar

T = TypeVar('T')
T1 = TypeVar('T1', bound=str)
S = TypeVar('S')

class A:
    def f(self, x: int, y: S) -> None: pass
class B(A):
    def f(self, x: T, y: S) -> None: pass
class C(A):
    def f(self, x: T, y: str) -> None: pass
class D(A):
    def f(self, x: T1, y: S) -> None: pass # TODO: This error could be more specific.
[out]
main:12: error: Argument 2 of "f" incompatible with supertype "A"
main:14: error: Signature of "f" incompatible with supertype "A"


-- Inheritance from generic types with implicit dynamic supertype
-- --------------------------------------------------------------


[case testInheritanceFromGenericWithImplicitDynamicAndSubtyping]
from typing import TypeVar, Generic
T = TypeVar('T')
a = None # type: A
bc = None # type: B[C]
bd = None # type: B[D]

a = bc # E: Incompatible types in assignment (expression has type "B[C]", variable has type "A")
bc = a
bd = a

class B(Generic[T]): pass
class A(B): pass
class C: pass
class D: pass
[out]

[case testInheritanceFromGenericWithImplicitDynamicAndExternalAccess]
from typing import TypeVar, Generic
T = TypeVar('T')

class B(Generic[T]):
    def f(self, a: 'B[T]') -> None: pass
    def __init__(self, x: 'B[T]') -> None:
        self.x = x
class A(B): pass
class C: pass

a = None # type: A
c = None # type: C
bc = None # type: B[C]

a.x = c # E: Incompatible types in assignment (expression has type "C", variable has type "B[Any]")
a.f(c)  # E: Argument 1 to "f" of "B" has incompatible type "C"; expected "B[Any]"
a.x = bc
a.f(bc)
[out]

[case testInheritanceFromGenericWithImplicitDynamic]
from typing import TypeVar, Generic
T = TypeVar('T')
a = None # type: A
c = None # type: C
bc = None # type: B[C]

class B(Generic[T]):
  def f(self, a: 'B[T]') -> None: pass
  def __init__(self, x: 'B[T]') -> None:
    self.x = x

class A(B):
  def g(self) -> None:
    self.x = c # E: Incompatible types in assignment (expression has type "C", variable has type "B[Any]")
    self.f(c)  # E: Argument 1 to "f" of "B" has incompatible type "C"; expected "B[Any]"
    self.x = bc
    self.f(bc)

class C: pass
[out]

[case testInheritanceFromGenericWithImplicitDynamicAndOverriding]
from typing import TypeVar, Generic, Tuple
T = TypeVar('T')
class B(Generic[T]):
    def f(self, a: T, b: 'Tuple[T, B[T]]') -> None:
        pass
class A(B):
    def f(self, a, b): pass
[builtins fixtures/tuple.pyi]
[out]


-- Inheritance from generic types and super expressions
-- ----------------------------------------------------


[case testSuperExpressionsWhenInheritingFromGenericType]
from typing import TypeVar, Generic
T = TypeVar('T')
S = TypeVar('S')
class B(Generic[T]):
    def f(self, a: T) -> None: pass
class A(B[S], Generic[T, S]):
    def g(self, t: T, s: S) -> None:
        super().f(t)   # E: Argument 1 to "f" of "B" has incompatible type "T"; expected "S"
        super().f(s)
[out]

[case testSuperExpressionsWhenInheritingFromGenericTypeAndDeepHierarchy]
from typing import TypeVar, Generic
T = TypeVar('T')
S = TypeVar('S')
U = TypeVar('U')
V = TypeVar('V')
class C(Generic[T, U, V]):
    def f(self, a: V) -> None: pass
class D: pass
class B(C[D, D, T], Generic[T]): pass
class A(B[S], Generic[T, S]):
    def g(self, t: T, s: S) -> None:
        super().f(t)   # E: Argument 1 to "f" of "C" has incompatible type "T"; expected "S"
        super().f(s)
[out]


-- Type of inherited constructor
-- -----------------------------


[case testInheritedConstructor]
from typing import TypeVar, Generic
T = TypeVar('T')
class A(Generic[T]):
    def __init__(self, x: T) -> None: pass
class B(A[T], Generic[T]): pass
class C(A[int]): pass
class D(A[A[T]], Generic[T]): pass
B(1)
C(1)
C('a')  # E: Argument 1 to "C" has incompatible type "str"; expected "int"
D(A(1))
D(1)  # E: Argument 1 to "D" has incompatible type "int"; expected "A[<nothing>]"


[case testInheritedConstructor2]
from typing import TypeVar, Generic
T = TypeVar('T')
U = TypeVar('U')
Z = TypeVar('Z')
class A(Generic[T, U]):
    def __init__(self, x: T, y: U, z: Z) -> None: pass
class B(A[int, T], Generic[T]): pass
class C(B[A[T, str]], Generic[T, U]): pass
# C[T, U] <: B[A[T, str]] <: A[int, A[T, str]]
C(1, A(1, 'a', 0), 'z')
C(1, A('1', 'a', 0), 'z')
C('1', A(1, 'a', 0), 'z')  # E: Argument 1 to "C" has incompatible type "str"; expected "int"
C(1, A(1, 1, 0), 'z')  # E: Argument 2 to "A" has incompatible type "int"; expected "str"


-- Subtyping with a generic abstract base class
-- --------------------------------------------


[case testSubtypingWithGenericTypeSubclassingGenericAbstractClass]
from typing import TypeVar, Generic
from abc import abstractmethod
T = TypeVar('T')
S = TypeVar('S')
acd = None # type: A[C, D]
adc = None # type: A[D, C]
ic = None # type: I[C]
id = None # type: I[D]

ic = acd # E: Incompatible types in assignment (expression has type "A[C, D]", variable has type "I[C]")
id = adc # E: Incompatible types in assignment (expression has type "A[D, C]", variable has type "I[D]")
adc = ic # E: Incompatible types in assignment (expression has type "I[C]", variable has type "A[D, C]")

ic = adc
id = acd

class I(Generic[T]):
    @abstractmethod
    def f(self): pass
class A(I[S], Generic[T, S]): pass
class C: pass
class D: pass

[case testSubtypingWithTypeImplementingGenericABCViaInheritance]
from typing import TypeVar, Generic
S = TypeVar('S')
a, b = None, None # type: (A, B)
ic, id, ie = None, None, None # type: (I[C], I[D], I[E])

class I(Generic[S]): pass
class B(I[C]): pass
class A(B): pass

ie = a # E: Incompatible types in assignment (expression has type "A", variable has type "I[E]")
a = ic # E: Incompatible types in assignment (expression has type "I[C]", variable has type "A")
a = id # E: Incompatible types in assignment (expression has type "I[D]", variable has type "A")
a = b  # E: Incompatible types in assignment (expression has type "B", variable has type "A")
id = a # E: Incompatible types in assignment (expression has type "A", variable has type "I[D]")

ic = a
b = a

class C: pass
class D: pass
class E: pass
[out]

[case testSubtypingWithTypeImplementingGenericABCViaInheritance2-skip]
from typing import TypeVar, Generic
T = TypeVar('T')
class I(Generic[T]): pass
class A(I[C]): pass
class B(A, I[D]): pass # Fail

class C: pass
class D: pass
[out]
main:5: error: Class "B" has base "I" duplicated inconsistently

[case testSubtypingAndABCExtension]
from typing import TypeVar, Generic
from abc import abstractmethod, ABCMeta
t = TypeVar('t')
a, i, j = None, None, None # type: (A[object], I[object], J[object])
(ii, jj) = (i, j)
ii = a
jj = a
jj = i
a = i # E: Incompatible types in assignment (expression has type "I[object]", variable has type "A[object]")
a = j # E: Incompatible types in assignment (expression has type "J[object]", variable has type "A[object]")

class J(Generic[t]): pass
class X(metaclass=ABCMeta): pass
class I(X, J[t], Generic[t]): pass
class A(I[t], Generic[t]): pass


-- Subclassing a generic ABC
-- -------------------------


[case testSubclassingGenericABC1]
from typing import TypeVar, Generic
from abc import abstractmethod
T = TypeVar('T')
class I(Generic[T]):
    @abstractmethod
    def f(self, a: T) -> None: pass
    @abstractmethod
    def g(self, a: T) -> None: pass
class A(I[C]):
    def f(self, a: 'D') -> None: pass \
        # E: Argument 1 of "f" incompatible with supertype "I"
    def g(self, a: 'C') -> None: pass
class C: pass
class D: pass
[out]


-- Extending a generic ABC with deep type hierarchy
-- ------------------------------------------------


[case testSubclassingGenericABCWithDeepHierarchy]
from typing import Any, TypeVar, Generic
from abc import abstractmethod
T = TypeVar('T')
a = None # type: A
ic, id = None, None # type: (I[C], I[D])

id = a # Fail
ic = a

class I(Generic[T]):
    @abstractmethod
    def f(self, a: T, b: T) -> None: pass
    @abstractmethod
    def g(self, a: T, b: 'D') -> None: pass
class B(I[C]):
    def f(self, a: 'C', b: 'C') -> None: pass
    def g(self, a: 'C', b: Any) -> None: pass
class A(B):
    def g(self, a: 'C', b: 'C') -> None: pass \
        # E: Argument 2 of "g" incompatible with supertype "I"
    def f(self, a: 'C', b: 'C') -> None: pass
class C: pass
class D: pass
[out]
main:7: error: Incompatible types in assignment (expression has type "A", variable has type "I[D]")

[case testSubclassingGenericABCWithDeepHierarchy2]
from typing import Any, TypeVar, Generic
from abc import abstractmethod
T = TypeVar('T')
class I(Generic[T]):
    @abstractmethod
    def f(self, a: T, b: T) -> None: pass
class B(I[C]):
    def f(self, a: 'C', b: Any) -> None: pass
class A(B):
    def f(self, a: 'C', b: 'D') -> None: pass \
        # E: Argument 2 of "f" incompatible with supertype "I"
class C: pass
class D: pass
[out]


-- Implicit Any types and subclassing generic ABC
-- ----------------------------------------------


[case testSubclassingGenericABCWithImplicitAny]
from typing import Any, TypeVar, Generic
from abc import abstractmethod
T = TypeVar('T')
a = None # type: Any
ic = None # type: I[C]
id = None # type: I[D]

ic = a
id = a

class I(Generic[T]):
    @abstractmethod
    def f(self, a: T) -> None: pass
class A(I):
    def f(self, a): pass

class C: pass
class D: pass

[case testSubclassingGenericABCWithImplicitAnyAndDeepHierarchy]
from typing import Any, TypeVar, Generic
from abc import abstractmethod
T = TypeVar('T')
a = None # type: Any
ic = None # type: I[C]
id = None # type: I[D]

ic = a
id = a

class I(Generic[T]):
    @abstractmethod
    def f(self, a: T, b: T) -> None: pass
class B(I):
    def f(self, a, b): pass
class A(B):
    def f(self, a: 'C', b: 'D') -> None: pass
class C: pass
class D: pass

[case testImplementingGenericABCWithImplicitAnyAndDeepHierarchy2]
from typing import Any, TypeVar, Generic
from abc import abstractmethod
T = TypeVar('T')
a = None # type: Any
jc = None # type: J[C]
jd = None # type: J[D]

jc = a
jd = a

class J(Generic[T]):
    @abstractmethod
    def f(self, a: T, b: T) -> None: pass
class I(J):
    @abstractmethod
    def f(self, a, b): pass
class A(I):
    def f(self, a: 'C', b: 'D') -> None: pass

class C: pass
class D: pass


-- Accessing generic ABC members
-- -----------------------------


[case testAccessingGenericABCMembers]
from typing import TypeVar, Generic
from abc import abstractmethod
T = TypeVar('T')
class I(Generic[T]):
    @abstractmethod
    def f(self, a: T) -> None: pass
class A: pass
class B: pass

a, b = None, None # type: (A, B)
ia = None # type: I[A]

ia.f(b)  # E: Argument 1 to "f" of "I" has incompatible type "B"; expected "A"
ia.f(a)

[case testAccessingInheritedGenericABCMembers]
from typing import TypeVar, Generic
from abc import abstractmethod
T = TypeVar('T')
class J(Generic[T]):
    @abstractmethod
    def f(self, a: T) -> None: pass
class I(J[T], Generic[T]): pass
class A: pass
class B: pass
a, b = None, None # type: (A, B)
ia = None # type: I[A]

ia.f(b)  # E: Argument 1 to "f" of "J" has incompatible type "B"; expected "A"
ia.f(a)


-- Misc
-- ----


[case testMultipleAssignmentAndGenericSubtyping]
from typing import Iterable
n, s = None, None # type: int, str
class Nums(Iterable[int]):
    def __iter__(self): pass
    def __next__(self): pass
n, n = Nums()
s, s = Nums() # E: Incompatible types in assignment (expression has type "int", variable has type "str")
[builtins fixtures/for.pyi]
[out]


-- Variance
-- --------


[case testCovariant]
from typing import TypeVar, Generic
T = TypeVar('T', covariant=True)

class G(Generic[T]): pass
class A: pass
class B(A): pass
class C(B): pass

a = None  # type: G[A]
b = None  # type: G[B]
c = None  # type: G[C]

b = a  # E: Incompatible types in assignment (expression has type "G[A]", variable has type "G[B]")
b = c
[builtins fixtures/bool.pyi]
[out]

[case testContravariant]
from typing import TypeVar, Generic
T = TypeVar('T', contravariant=True)

class G(Generic[T]): pass
class A: pass
class B(A): pass
class C(B): pass

a = None  # type: G[A]
b = None  # type: G[B]
c = None  # type: G[C]

b = a
b = c  # E: Incompatible types in assignment (expression has type "G[C]", variable has type "G[B]")
[builtins fixtures/bool.pyi]
[out]

[case testInvariant]
from typing import TypeVar, Generic
T = TypeVar('T')  # invariant (default)

class G(Generic[T]): pass
class A: pass
class B(A): pass
class C(B): pass

a = None  # type: G[A]
b = None  # type: G[B]
c = None  # type: G[C]

b = a  # E: Incompatible types in assignment (expression has type "G[A]", variable has type "G[B]")
b = c  # E: Incompatible types in assignment (expression has type "G[C]", variable has type "G[B]")
[builtins fixtures/bool.pyi]
[out]


[case testTypeVarSubtypeUnion]
from typing import Union, TypeVar, Generic

class U: pass
class W: pass

T = TypeVar('T', bound=Union[U, W])

class Y(Generic[T]):
    def __init__(self) -> None:
        pass
    def f(self) -> T:
        return U()  # E: Incompatible return value type (got "U", expected "T")

[out]
