-- Test cases for the type checker related to varargs.


-- Varargs within body
-- -------------------


[case testVarArgsWithinFunction]
from typing import Tuple
def f( *b: 'B') -> None:
    ab = None # type: Tuple[B, ...]
    ac = None # type: Tuple[C, ...]
    b = ac # E: Incompatible types in assignment (expression has type "Tuple[C, ...]", variable has type "Tuple[B, ...]")
    ac = b # E: Incompatible types in assignment (expression has type "Tuple[B, ...]", variable has type "Tuple[C, ...]")
    b = ab
    ab = b

class B: pass
class C: pass
[builtins fixtures/tuple.pyi]
[out]


[case testVarArgsAreTuple]
from typing import Tuple, Sequence
def want_tuple(types: Tuple[type, ...]): pass
def want_sequence(types: Sequence[type]): pass
def test(*t: type) -> None:
    want_tuple(t)
    want_sequence(t)
[builtins fixtures/tuple.pyi]
[out]


-- Calling varargs function
-- ------------------------


[case testCallingVarArgsFunction]

a = None # type: A
b = None # type: B
c = None # type: C

f(c)       # E: Argument 1 to "f" has incompatible type "C"; expected "A"
f(a, b, c) # E: Argument 3 to "f" has incompatible type "C"; expected "A"
f(g())     # E: "g" does not return a value
f(a, g())  # E: "g" does not return a value
f()
f(a)
f(b)
f(a, b, a, b)

def f( *a: 'A') -> None: pass

def g() -> None: pass

class A: pass
class B(A): pass
class C: pass
[builtins fixtures/list.pyi]

[case testCallingVarArgsFunctionWithAlsoNormalArgs]

a = None # type: A
b = None # type: B
c = None # type: C

f(a)       # E: Argument 1 to "f" has incompatible type "A"; expected "C"
f(c, c)    # E: Argument 2 to "f" has incompatible type "C"; expected "A"
f(c, a, b, c)  # E: Argument 4 to "f" has incompatible type "C"; expected "A"
f(c)
f(c, a)
f(c, b, b, a, b)

def f(a: 'C', *b: 'A') -> None: pass

class A: pass
class B(A): pass
class C: pass
[builtins fixtures/list.pyi]

[case testCallingVarArgsFunctionWithDefaultArgs]

a = None # type: A
b = None # type: B
c = None # type: C

f(a)           # E: Argument 1 to "f" has incompatible type "A"; expected "Optional[C]"
f(c, c)        # E: Argument 2 to "f" has incompatible type "C"; expected "A"
f(c, a, b, c)  # E: Argument 4 to "f" has incompatible type "C"; expected "A"
f()
f(c)
f(c, a)
f(c, b, b, a, b)

def f(a: 'C' = None, *b: 'A') -> None:
    pass

class A: pass
class B(A): pass
class C: pass
[builtins fixtures/list.pyi]

[case testCallVarargsFunctionWithIterable]
from typing import Iterable
it1 = None  # type: Iterable[int]
it2 = None  # type: Iterable[str]
def f(*x: int) -> None: pass
f(*it1)
f(*it2) # E: Argument 1 to "f" has incompatible type "*Iterable[str]"; expected "int"
[builtins fixtures/for.pyi]

[case testCallVarargsFunctionWithIterableAndPositional]

from typing import Iterable
it1 = None  # type: Iterable[int]
def f(*x: int) -> None: pass
f(*it1, 1, 2)
f(*it1, 1, *it1, 2)
f(*it1, '') # E: Argument 2 to "f" has incompatible type "str"; expected "int"
[builtins fixtures/for.pyi]

[case testCallVarargsFunctionWithTupleAndPositional]

def f(*x: int) -> None: pass
it1 = (1, 2)
f(*it1, 1, 2)
f(*it1, 1, *it1, 2)
f(*it1, '') # E: Argument 2 to "f" has incompatible type "str"; expected "int"
[builtins fixtures/for.pyi]


-- Calling varargs function + type inference
-- -----------------------------------------


[case testTypeInferenceWithCalleeVarArgs]
from typing import TypeVar
T = TypeVar('T')
a = None # type: A
b = None # type: B
c = None # type: C
o = None # type: object

a = f(o) # E: Incompatible types in assignment (expression has type "object", variable has type "A")
b = f(b, a) # E: Incompatible types in assignment (expression has type "A", variable has type "B")
b = f(a, b) # E: Incompatible types in assignment (expression has type "A", variable has type "B")

o = f()
a = f(a)
a = f(b)
a = f(a, b, a)
o = f(a, b, o)
c = f(c)

def f( *a: T) -> T:
    pass

class A: pass
class B(A): pass
class C: pass
[builtins fixtures/list.pyi]

[case testTypeInferenceWithCalleeVarArgsAndDefaultArgs]
from typing import TypeVar
T = TypeVar('T')
a = None # type: A
o = None # type: object

a = f(o) # E: Incompatible types in assignment (expression has type "object", variable has type "A")
a = f(a, o) # E: Incompatible types in assignment (expression has type "object", variable has type "A")
a = f(a, a, o) # E: Incompatible types in assignment (expression has type "object", variable has type "A")
a = f(a, a, a, o) # E: Incompatible types in assignment (expression has type "object", variable has type "A")

a = f(a)
a = f(a, a)
a = f(a, a, a)

def f(a: T, b: T = None, *c: T) -> T:
    pass

class A: pass
[builtins fixtures/list.pyi]


-- Calling normal function with varargs
-- ------------------------------------


[case testCallingWithListVarArgs]
from typing import List, Any, cast
aa = None # type: List[A]
ab = None # type: List[B]
a = None # type: A
b = None # type: B

f(*aa)    # Fail
f(a, *ab) # Ok
f(a, b)
(cast(Any, f))(*aa)     # IDEA: Move to check-dynamic?
(cast(Any, f))(a, *ab)  # IDEA: Move to check-dynamic?

def f(a: 'A', b: 'B') -> None:
    pass

class A: pass
class B: pass
[builtins fixtures/list.pyi]
[out]
main:7: error: Argument 1 to "f" has incompatible type "*List[A]"; expected "B"

[case testCallingWithTupleVarArgs]

a = None # type: A
b = None # type: B
c = None # type: C
cc = None # type: CC

f(*(a, b, b)) # E: Argument 1 to "f" has incompatible type "*Tuple[A, B, B]"; expected "C"
f(*(b, b, c)) # E: Argument 1 to "f" has incompatible type "*Tuple[B, B, C]"; expected "A"
f(a, *(b, b)) # E: Argument 2 to "f" has incompatible type "*Tuple[B, B]"; expected "C"
f(b, *(b, c)) # E: Argument 1 to "f" has incompatible type "B"; expected "A"
f(*(a, b))    # E: Too few arguments for "f"
f(*(a, b, c, c)) # E: Too many arguments for "f"
f(a, *(b, c, c)) # E: Too many arguments for "f"
f(*(a, b, c))
f(a, *(b, c))
f(a, b, *(c,))
f(a, *(b, cc))

def f(a: 'A', b: 'B', c: 'C') -> None: pass

class A: pass
class B: pass
class C: pass
class CC(C): pass
[builtins fixtures/tuple.pyi]

[case testInvalidVarArg]

a = None # type: A

f(*None)
f(*a)    # E: List or tuple expected as variable arguments
f(*(a,))

def f(a: 'A') -> None:
    pass

class A: pass
[builtins fixtures/tuple.pyi]


-- Calling varargs function with varargs
-- -------------------------------------


[case testCallingVarArgsFunctionWithListVarArgs]
from typing import List
aa, ab, a, b = None, None, None, None # type: (List[A], List[B], A, B)
f(*aa)           # Fail
f(a, *aa)        # Fail
f(b, *ab)        # Fail
f(a, a, *ab)     # Fail
f(a, b, *aa)     # Fail
f(b, b, *ab)     # Fail
g(*ab)           # Fail
f(a, *ab)
f(a, b, *ab)
f(a, b, b, *ab)
g(*aa)

def f(a: 'A', *b: 'B') -> None: pass
def g(a: 'A', *b: 'A') -> None: pass
class A: pass
class B: pass
[builtins fixtures/list.pyi]
[out]
main:3: error: Argument 1 to "f" has incompatible type "*List[A]"; expected "B"
main:4: error: Argument 2 to "f" has incompatible type "*List[A]"; expected "B"
main:5: error: Argument 1 to "f" has incompatible type "B"; expected "A"
main:6: error: Argument 2 to "f" has incompatible type "A"; expected "B"
main:7: error: Argument 3 to "f" has incompatible type "*List[A]"; expected "B"
main:8: error: Argument 1 to "f" has incompatible type "B"; expected "A"
main:9: error: Argument 1 to "g" has incompatible type "*List[B]"; expected "A"

[case testCallingVarArgsFunctionWithTupleVarArgs]

a, b, c, cc = None, None, None, None # type: (A, B, C, CC)

f(*(b, b, b))   # E: Argument 1 to "f" has incompatible type "*Tuple[B, B, B]"; expected "A"
f(*(a, a, b))   # E: Argument 1 to "f" has incompatible type "*Tuple[A, A, B]"; expected "B"
f(*(a, b, a))   # E: Argument 1 to "f" has incompatible type "*Tuple[A, B, A]"; expected "B"
f(a, *(a, b))   # E: Argument 2 to "f" has incompatible type "*Tuple[A, B]"; expected "B"
f(b, *(b, b))   # E: Argument 1 to "f" has incompatible type "B"; expected "A"
f(b, b, *(b,))  # E: Argument 1 to "f" has incompatible type "B"; expected "A"
f(a, a, *(b,))  # E: Argument 2 to "f" has incompatible type "A"; expected "B"
f(a, b, *(a,))  # E: Argument 3 to "f" has incompatible type "*Tuple[A]"; expected "B"
f(*())          # E: Too few arguments for "f"
f(*(a, b, b))
f(a, *(b, b))
f(a, b, *(b,))

def f(a: 'A', *b: 'B') -> None:
    pass

class A: pass
class B: pass
class C: pass
class CC(C): pass
[builtins fixtures/list.pyi]


-- Varargs special cases
-- ---------------------


[case testDynamicVarArg]
from typing import Any
d, a = None, None # type: (Any, A)
f(a, a, *d) # Fail
f(a, *d)    # Fail
f(*d)       # Ok

g(*d)
g(a, *d)
g(a, a, *d)

def f(a: 'A') -> None: pass
def g(a: 'A', *b: 'A') -> None: pass
class A: pass
[builtins fixtures/list.pyi]
[out]
main:3: error: Too many arguments for "f"
main:4: error: Too many arguments for "f"

[case testListVarArgsAndSubtyping]
from typing import List
aa = None # type: List[A]
ab = None # type: List[B]

g(*aa) # E: Argument 1 to "g" has incompatible type "*List[A]"; expected "B"
f(*aa)
f(*ab)
g(*ab)

def f( *a: 'A') -> None:
    pass

def g( *a: 'B') -> None:
    pass

class A: pass
class B(A): pass
[builtins fixtures/list.pyi]

[case testCallerVarArgsAndDefaultArgs]

a, b = None, None # type: (A, B)
f(*())        # Fail
f(a, *[a])    # Fail
f(a, b, *[a]) # Fail
f(*(a, a, b)) # Fail
f(*(a,))
f(*(a, b))
f(*(a, b, b, b))
f(a, *[])
f(a, *[b])
f(a, *[b, b])

def f(a: 'A', b: 'B' = None, *c: 'B') -> None:
    pass

class A: pass
class B: pass
[builtins fixtures/list.pyi]
[out]
main:3: error: Too few arguments for "f"
main:4: error: Argument 2 to "f" has incompatible type "*List[A]"; expected "Optional[B]"
main:4: error: Argument 2 to "f" has incompatible type "*List[A]"; expected "B"
main:5: error: Argument 3 to "f" has incompatible type "*List[A]"; expected "B"
main:6: error: Argument 1 to "f" has incompatible type "*Tuple[A, A, B]"; expected "Optional[B]"

[case testVarArgsAfterKeywordArgInCall1-skip]
# see: mypy issue #2729
def f(x: int, y: str) -> None: pass
f(x=1, *[2])
[builtins fixtures/list.pyi]
[out]
main:2: error: "f" gets multiple values for keyword argument "x"
main:2: error: Argument 2 to "f" has incompatible type *List[int]; expected "str"

[case testVarArgsAfterKeywordArgInCall2-skip]
# see: mypy issue #2729
def f(x: int, y: str) -> None: pass
f(y='x', *[1])
[builtins fixtures/list.pyi]
[out]
main:2: error: "f" gets multiple values for keyword argument "y"
main:2: error: Argument 2 to "f" has incompatible type *List[int]; expected "str"

[case testVarArgsAfterKeywordArgInCall3]
def f(x: int, y: str) -> None: pass
f(y='x', *(1,))
[builtins fixtures/list.pyi]

[case testVarArgsAfterKeywordArgInCall4]
def f(x: int, *, y: str) -> None: pass
f(y='x', *[1])
[builtins fixtures/list.pyi]

[case testVarArgsAfterKeywordArgInCall5]
def f(x: int, *, y: str) -> None: pass
f(y='x', *(1,))
[builtins fixtures/list.pyi]


-- Overloads + varargs
-- -------------------


[case testIntersectionTypesAndVarArgs]
from foo import *
[file foo.pyi]
from typing import overload
a, b = None, None # type: (A, B)

b = f()        # E: Incompatible types in assignment (expression has type "A", variable has type "B")
b = f(a)       # E: Incompatible types in assignment (expression has type "A", variable has type "B")
b = f(a, b)    # E: Incompatible types in assignment (expression has type "A", variable has type "B")
a = f(b)       # E: Incompatible types in assignment (expression has type "B", variable has type "A")
a = f(b, b)    # E: Incompatible types in assignment (expression has type "B", variable has type "A")
b = f(a, *[b]) # E: Incompatible types in assignment (expression has type "A", variable has type "B")
b = f(*())     # E: Incompatible types in assignment (expression has type "A", variable has type "B")
b = f(*(a,))   # E: Incompatible types in assignment (expression has type "A", variable has type "B")
b = f(*(a, b)) # E: Incompatible types in assignment (expression has type "A", variable has type "B")
a = f(*(b,))   # E: Incompatible types in assignment (expression has type "B", variable has type "A")
a = f(*(b, b)) # E: Incompatible types in assignment (expression has type "B", variable has type "A")
a = f(*[b])    # E: Incompatible types in assignment (expression has type "B", variable has type "A")

a = f()
a = f(a)
a = f(a, b)
b = f(b)
b = f(b, b)
a = f(a, *[b])
a = f(*())
a = f(*(a,))
a = f(*(a, b))
b = f(*(b,))
b = f(*(b, b))
b = f(*[b])

class A: pass
class B: pass

@overload
def f(a: A = None, *b: B) -> A: pass

@overload
def f(a: B, *b: B) -> B: pass
[builtins fixtures/list.pyi]


-- Caller varargs + type inference
-- -------------------------------


[case testCallerVarArgsListWithTypeInference]
from typing import List, TypeVar, Tuple
S = TypeVar('S')
T = TypeVar('T')
a, b, aa = None, None, None # type: (A, B, List[A])

a, b = f(*aa)    # Fail
b, b = f(*aa)    # Fail
a, a = f(b, *aa) # Fail
b, b = f(b, *aa) # Fail
b, b = f(b, b, *aa) # Fail
a, b = f(a, *a)  # Fail
a, b = f(*a)     # Fail

a, a = f(*aa)
b, a = f(b, *aa)
b, a = f(b, a, *aa)

def f(a: S, *b: T) -> Tuple[S, T]:
    pass

class A: pass
class B: pass
[builtins fixtures/list.pyi]
[out]
main:6: error: Argument 1 to "f" has incompatible type "*List[A]"; expected "B"
main:7: error: Argument 1 to "f" has incompatible type "*List[A]"; expected "B"
main:8: error: Argument 1 to "f" has incompatible type "B"; expected "A"
main:9: error: Argument 2 to "f" has incompatible type "*List[A]"; expected "B"
main:10: error: Argument 3 to "f" has incompatible type "*List[A]"; expected "B"
main:11: error: List or tuple expected as variable arguments
main:12: error: List or tuple expected as variable arguments

[case testCallerVarArgsTupleWithTypeInference]
from typing import TypeVar, Tuple
S = TypeVar('S')
T = TypeVar('T')
a, b = None, None # type: (A, B)

a, a = f(*(a, b))   # E: Argument 1 to "f" has incompatible type "*Tuple[A, B]"; expected "A"
b, b = f(a, *(b,))  # E: Argument 1 to "f" has incompatible type "A"; expected "B"
a, a = f(*(a, b))   # E: Argument 1 to "f" has incompatible type "*Tuple[A, B]"; expected "A"
b, b = f(a, *(b,))  # E: Argument 1 to "f" has incompatible type "A"; expected "B"
a, b = f(*(a, b, b)) # E: Too many arguments for "f"

a, b = f(*(a, b))
a, b = f(a, *(b,))

def f(a: S, b: T) -> Tuple[S, T]: pass

class A: pass
class B: pass
[builtins fixtures/list.pyi]

[case testCallerVarargsAndComplexTypeInference]
from typing import List, TypeVar, Generic, Tuple
T = TypeVar('T')
S = TypeVar('S')
a, b = None, None # type: (A, B)
ao = None # type: List[object]
aa = None # type: List[A]
ab = None # type: List[B]

a, aa = G().f(*[a])  # Fail
aa, a = G().f(*[a])  # Fail
ab, aa = G().f(*[a]) # Fail

ao, ao = G().f(*[a]) # E: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "List[object]")
aa, aa = G().f(*[a]) # E: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "List[A]")

class G(Generic[T]):
    def f(self, *a: S) -> Tuple[List[S], List[T]]:
        pass

class A: pass
class B: pass
[builtins fixtures/list.pyi]
[out]
main:9: error: Incompatible types in assignment (expression has type "List[A]", variable has type "A")
main:9: error: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "List[A]")
main:10: error: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "A")
main:11: error: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "List[A]")
main:11: error: Argument 1 to "f" of "G" has incompatible type "*List[A]"; expected "B"


-- Comment signatures
-- ------------------


[case testVarArgsAndCommentSignature]
import typing
def f(*x): # type: (*int) -> None
    pass
f(1)
f(1, 2)
f('') # E: Argument 1 to "f" has incompatible type "str"; expected "int"
f(1, '') # E: Argument 2 to "f" has incompatible type "str"; expected "int"
[builtins fixtures/list.pyi]


-- Subtyping
-- ---------


[case testVarArgsFunctionSubtyping]
from typing import Callable
x = None # type: Callable[[int], None]
def f(*x: int) -> None: pass
def g(*x: str) -> None: pass
x = f
x = g # E: Incompatible types in assignment (expression has type "Callable[[VarArg(str)], None]", variable has type "Callable[[int], None]")
[builtins fixtures/list.pyi]
[out]


-- Decorated method where self is implied by *args
-- -----------------------------------------------

[case testVarArgsCallableSelf]
from typing import Callable
def cm(func) -> Callable[..., None]: pass
class C:
    @cm
    def foo(self) -> None: pass
C().foo()
C().foo(1)  # The decorator's return type says this should be okay

[case testInvariantDictArgNote]
from typing import Dict, Sequence
def f(x: Dict[str, Sequence[int]]) -> None: pass
def g(x: Dict[str, float]) -> None: pass
def h(x: Dict[str, int]) -> None: pass
a = {'a': [1, 2]}
b = {'b': ['c', 'd']}
c = {'c': 1.0}
d = {'d': 1}
f(a) # E: Argument 1 to "f" has incompatible type "Dict[str, List[int]]"; expected "Dict[str, Sequence[int]]" \
     # N: "Dict" is invariant -- see http://mypy.readthedocs.io/en/latest/common_issues.html#variance \
     # N: Consider using "Mapping" instead, which is covariant in the value type
f(b) # E: Argument 1 to "f" has incompatible type "Dict[str, List[str]]"; expected "Dict[str, Sequence[int]]"
g(c)
g(d) # E: Argument 1 to "g" has incompatible type "Dict[str, int]"; expected "Dict[str, float]" \
     # N: "Dict" is invariant -- see http://mypy.readthedocs.io/en/latest/common_issues.html#variance \
     # N: Consider using "Mapping" instead, which is covariant in the value type
h(c) # E: Argument 1 to "h" has incompatible type "Dict[str, float]"; expected "Dict[str, int]"
h(d)
[builtins fixtures/dict.pyi]
[typing fixtures/typing-full.pyi]

[case testInvariantListArgNote]
from typing import List, Union
def f(numbers: List[Union[int, float]]) -> None: pass
a = [1, 2]
f(a) # E: Argument 1 to "f" has incompatible type "List[int]"; expected "List[Union[int, float]]" \
     # N: "List" is invariant -- see http://mypy.readthedocs.io/en/latest/common_issues.html#variance \
     # N: Consider using "Sequence" instead, which is covariant
x = [1]
y = ['a']
x = y # E: Incompatible types in assignment (expression has type "List[str]", variable has type "List[int]")
[builtins fixtures/list.pyi]

[case testInvariantTypeConfusingNames]
from typing import TypeVar
class Listener: pass
class DictReader: pass
def f(x: Listener) -> None: pass
def g(y: DictReader) -> None: pass
a = [1, 2]
b = {'b': 1}
f(a) # E: Argument 1 to "f" has incompatible type "List[int]"; expected "Listener"
g(b) # E: Argument 1 to "g" has incompatible type "Dict[str, int]"; expected "DictReader"
[builtins fixtures/dict.pyi]
