-- Test cases for multiple inheritance.
--
-- Related: check-abstract.test


-- No name collisions
-- ------------------


[case testSimpleMultipleInheritanceAndMethods]
import typing
class A:
    def f(self, x: int) -> None: pass
class B:
    def g(self, x: str) -> None: pass
class C(A, B): pass
c = C()
c.f(1)
c.f('') # E: Argument 1 to "f" of "A" has incompatible type "str"; expected "int"
c.g('')
c.g(1)  # E: Argument 1 to "g" of "B" has incompatible type "int"; expected "str"

[case testSimpleMultipleInheritanceAndMethods2]
import typing
class A:
    def f(self, x: int) -> None: pass
class B:
    def g(self, x): pass
class C(A, B): pass
c = C()
c.f(1)
c.f('') # E: Argument 1 to "f" of "A" has incompatible type "str"; expected "int"
c.g('')
c.g(1)

[case testSimpleMultipleInheritanceAndInstanceVariables]
import typing
class A:
    def f(self) -> None:
        self.x = 1
class B:
    def g(self) -> None:
        self.y = ''
class C(A, B): pass
c = C()
c.x = 1
c.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
c.y = ''
c.y = 1  # E: Incompatible types in assignment (expression has type "int", variable has type "str")

[case testSimpleMultipleInheritanceAndInstanceVariableInClassBody]
import typing
class A:
    x = 1
class B:
    y = ''
class C(A, B): pass
c = C()
c.x = 1
c.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
c.y = ''
c.y = 1  # E: Incompatible types in assignment (expression has type "int", variable has type "str")

[case testSimpleMultipleInheritanceAndClassVariable]
import typing
class A:
    x = 1
class B:
    y = ''
class C(A, B): pass
C.x = 1
C.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
C.y = ''
C.y = 1  # E: Incompatible types in assignment (expression has type "int", variable has type "str")


-- Name collisions
-- ---------------


[case testMethodNameCollisionInMultipleInheritanceWithValidSigs]
import typing
class A:
    def f(self, x: int) -> None: pass
class B:
    def f(self, x: int) -> None: pass
class C(A, B): pass
c = C()
c.f(1)
c.f('') # E: Argument 1 to "f" of "A" has incompatible type "str"; expected "int"

[case testInstanceVarNameOverlapInMultipleInheritanceWithCompatibleTypes]
import typing
class A:
    def f(self) -> None:
        self.x = 1
class B:
    def g(self) -> None:
        self.x = 1
class C(A, B): pass
c = C()
c.x = 1
c.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")

[case testClassVarNameOverlapInMultipleInheritanceWithCompatibleTypes]
import typing
class A:
    x = 1
class B:
    x = 1
class C(A, B): pass
c = C()
c.x = 1
c.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
C.x = 1
C.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")

[case testMethodNameCollisionInMultipleInheritanceWithIncompatibleSigs]
import typing
class A:
    def f(self, x: int) -> None: pass
class B:
    def f(self, x: str) -> None: pass
class C(A, B): pass
[out]
main:6: error: Definition of "f" in base class "A" is incompatible with definition in base class "B"

[case testMethodNameCollisionInMultipleInheritanceWithIncompatibleSigs2]
import typing
class A:
    def f(self, x: int) -> None: pass
class B:
    def f(self, x, y): pass
class C(A, B): pass
class D(B, A): pass
[out]
main:6: error: Definition of "f" in base class "A" is incompatible with definition in base class "B"
main:7: error: Definition of "f" in base class "B" is incompatible with definition in base class "A"


[case testMethodOverridingWithBothDynamicallyAndStaticallyTypedMethods]
class A:
    def f(self) -> int: pass
class B:
    def f(self): pass
class C(B, A): pass
class D(A, B): pass
[out]

[case testInstanceVarNameOverlapInMultipleInheritanceWithInvalidTypes]
import typing
class A:
    def f(self) -> None:
        self.x = 1
class B:
    def g(self) -> None:
        self.x = ''
class C(A, B): pass
[out]
main:8: error: Definition of "x" in base class "A" is incompatible with definition in base class "B"

[case testClassVarNameOverlapInMultipleInheritanceWithInvalidTypes]
import typing
class A:
    x = 1
class B:
    x = ''
class C(A, B): pass
[out]
main:6: error: Definition of "x" in base class "A" is incompatible with definition in base class "B"

[case testMethodOverlapsWithClassVariableInMultipleInheritance]
from typing import Callable
class A:
    def f(self) -> None: pass
class B:
    f = ''
class C(A, B): pass
[out]
main:6: error: Definition of "f" in base class "A" is incompatible with definition in base class "B"

[case testMethodOverlapsWithInstanceVariableInMultipleInheritance]
from typing import Callable
class A:
    def f(self) -> None: pass
class B:
    def g(self) -> None:
        self.f = ''
class C(A, B): pass
[out]
main:7: error: Definition of "f" in base class "A" is incompatible with definition in base class "B"

[case testMultipleInheritanceAndInit]
import typing
class A:
    def __init__(self, x: int) -> None: pass
class B:
    def __init__(self) -> None: pass
class C(A, B): pass

[case testMultipleInheritanceAndDifferentButCompatibleSignatures]
class A:
    def clear(self): pass

class B:
    def clear(self, x=None): pass

class C(B, A): pass
class D(A, B): pass
[out]
main:8: error: Definition of "clear" in base class "A" is incompatible with definition in base class "B"


-- Special cases
-- -------------


[case testGenericInheritanceAndOverridingWithMultipleInheritance]
from typing import Generic, TypeVar
T = TypeVar('T')
class G(Generic[T]):
    def f(self, s: int) -> 'G[T]': pass
class A(G[int]):
    def f(self, s: int) -> 'A': pass
class B(A, int): pass

[case testCannotDetermineTypeInMultipleInheritance]
from typing import Callable, TypeVar
T = TypeVar('T')
class A(B, C):
    def f(self): pass
class B:
    @dec
    def f(self): pass
class C:
    @dec
    def f(self): pass
def dec(f: Callable[..., T]) -> Callable[..., T]:
    return f
[out]
main:3: error: Cannot determine type of 'f' in base class 'B'
main:3: error: Cannot determine type of 'f' in base class 'C'
