-- Test cases for type checker related to super().


-- Supertype member reference
-- --------------------------


[case testAccessingSupertypeMethod]

class B:
  def f(self) -> 'B': pass
class A(B):
  def f(self) -> 'A':
    a, b = None, None # type: (A, B)
    a = super().f() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    a = super().g() # E: "g" undefined in superclass
    b = super().f()
    return a
[out]

[case testAccessingSuperTypeMethodWithArgs]
from typing import Any
class B:
  def f(self, y: 'A') -> None: pass
class A(B):
  def f(self, y: Any) -> None:
    a, b = None, None # type: (A, B)
    super().f(b) # E: Argument 1 to "f" of "B" has incompatible type "B"; expected "A"
    super().f(a)
    self.f(b)
    self.f(a)
[out]

[case testAccessingSuperInit]
import typing
class B:
    def __init__(self, x: A) -> None: pass
class A(B):
  def __init__(self) -> None:
    super().__init__(B(None)) # E: Argument 1 to "__init__" of "B" has incompatible type "B"; expected "A"
    super().__init__()       # E: Too few arguments for "__init__" of "B"
    super().__init__(A())
[out]

[case testAccessingSuperMemberWithDeepHierarchy]
import typing
class C:
  def f(self) -> None: pass
class B(C): pass
class A(B):
  def f(self) -> None:
    super().g() # E: "g" undefined in superclass
    super().f()
[out]

[case testAssignToBaseClassMethod]
import typing
class A:
    def f(self) -> None: pass
class B(A):
    def g(self) -> None:
        super().f = None
[out]
main:6: error: Invalid assignment target

[case testSuperWithMultipleInheritance]
import typing
class A:
  def f(self) -> None: pass
class B:
  def g(self, x: int) -> None: pass
class C(A, B):
    def f(self) -> None:
        super().f()
        super().g(1)
        super().f(1) # E: Too many arguments for "f" of "A"
        super().g() # E: Too few arguments for "g" of "B"
        super().not_there() # E: "not_there" undefined in superclass
[out]

[case testSuperWithNew]
class A:
    def __new__(cls, x: int) -> 'A':
        return object.__new__(cls)

class B(A):
    def __new__(cls, x: int, y: str = '') -> 'A':
        super().__new__(cls, 1)
        return super().__new__(cls, 1, '')  # E: Too many arguments for "__new__" of "A"
B('')  # E: Argument 1 to "B" has incompatible type "str"; expected "int"
B(1)
B(1, 'x')
[builtins fixtures/__new__.pyi]

reveal_type(C.a)  # E: Revealed type is 'Any'
[out]

[case testSuperWithUnknownBase]
from typing import Any
B = None  # type: Any
class C(B):
    def __init__(self, arg=0):
        super(C, self).__init__(arg, arg=arg)
[out]

[case testSuperSilentInDynamicFunction]
class A:
    pass

class B(A):
    def foo(self):
        super(B, self).foo() # Not an error
[out]

[case testSuperWithAny]
class B:
    def f(self) -> None: pass
class C(B):
    def h(self, x) -> None:
        reveal_type(super(x, x).f) # E: Revealed type is 'def ()'
        reveal_type(super(C, x).f) # E: Revealed type is 'def ()'

[case testSuperInUnannotatedMethod]
class C:
    def h(self):
        super(C, self).xyz

[case testSuperWithTypeObjects]
from typing import Type

class A:
    def f(self) -> object: pass

class B(A):
    def f(self) -> int: pass

    @classmethod
    def g(cls, x) -> None:
        reveal_type(super(cls, x).f) # E: Revealed type is 'def () -> builtins.object'

    def h(self, t: Type[B]) -> None:
        reveal_type(super(t, self).f) # E: Revealed type is 'def () -> builtins.object'
[builtins fixtures/classmethod.pyi]

[case testSuperWithTypeTypeAsSecondArgument]
class B:
    def f(self) -> None: pass

class C(B):
    def __new__(cls) -> 'C':
        super(C, cls).f
        return C()

[case testSuperWithGenericSelf]
from typing import TypeVar

T = TypeVar('T', bound='C')

class B:
    def f(self) -> float: pass

class C(B):
    def f(self) -> int: pass

    def g(self: T) -> T:
        reveal_type(super(C, self).f) # E: Revealed type is 'def () -> builtins.float'
        return self

[case testSuperWithTypeVarValues1]
from typing import TypeVar

T = TypeVar('T', 'C', 'D')
S = TypeVar('S', 'B', 'C')

class B:
    def f(self) -> None: pass

class C(B):
    def f(self) -> None: pass

    def g(self, x: T, y: S) -> None:
        super(C, x).f
        super(C, y).f # E: Argument 2 for "super" not an instance of argument 1

class D(C): pass

[case testSuperWithTypeVarValues2]
from typing import TypeVar, Generic

T = TypeVar('T', 'C', 'D')
S = TypeVar('S', 'B', 'C')

class B:
    def f(self) -> None: pass

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

    def g(self, x: T, y: S) -> None:
        super(C, x).f
        super(C, y).f # E: Argument 2 for "super" not an instance of argument 1

class D(C): pass


-- Invalid uses of super()
-- -----------------------


[case testSuperOutsideMethodNoCrash]
class C:
    a = super().whatever  # E: super() outside of a method is not supported

[case testSuperWithSingleArgument]
class B:
    def f(self) -> None: pass
class C(B):
    def __init__(self) -> None:
        super(C).f() # E: "super" with a single argument not supported

[case testSuperWithThreeArguments]
class B:
    def f(self) -> None: pass
class C(B):
    def h(self) -> None:
        super(C, self, 1).f() # E: Too many arguments for "super"

[case testSuperWithNonPositionalArguments]
class B:
    def f(self) -> None: pass
class C(B):
    def h(self) -> None:
        super(C, x=self).f() # E: "super" only accepts positional arguments
        super(**{}).f() # E: "super" only accepts positional arguments

[case testSuperWithVarArgs]
class B:
    def f(self) -> None: pass
class C(B):
    def h(self) -> None:
        super(*(C, self)).f() # E: Varargs not supported with "super"

[case testInvalidSuperArg]
class B:
    def f(self) -> None: pass
class C(B):
    def h(self) -> None:
        super(x, y).f # E: Name 'x' is not defined # E: Name 'y' is not defined

[case testTypeErrorInSuperArg]
class B:
    def f(self) -> None: pass
class C(B):
    def h(self) -> None:
        super(1(), self).f # E: "int" not callable
        super(C, ''()).f  # E: "str" not callable

[case testFlippedSuperArgs]
class B:
    def f(self) -> None: pass
class C(B):
    def h(self) -> None:
        super(self, C).f # E: Argument 1 for "super" must be a type object; got a non-type instance

[case testInvalidFirstSuperArg]
class B:
    def f(self) -> None: pass
class C(B):
    def h(self) -> None:
        super(None, C).f # E: Argument 1 for "super" must be a type object; got "None"

[case testInvalidSecondArgumentToSuper]
class B:
    def f(self) -> None: pass
class C(B):
    def h(self) -> None:
        super(C, 1).f # E: Argument 2 for "super" not an instance of argument 1
        super(C, None).f # E: Unsupported argument 2 for "super"

[case testSuperInMethodWithNoArguments]
class A:
    def f(self) -> None: pass

class B(A):
    def g() -> None: # E: Method must have at least one argument
        super().f() # E: super() requires one or more positional arguments in enclosing function
    def h(self) -> None:
        def a() -> None:
            super().f() # E: super() requires one or more positional arguments in enclosing function

[case testSuperWithUnsupportedTypeObject]
from typing import Type

class A:
    def f(self) -> int: pass

class B(A):
    def h(self, t: Type[None]) -> None:
        super(t, self).f # E: Unsupported argument 1 for "super"
