-- Normal assignment and subtyping
-- -------------------------------


[case testTupleAssignmentWithTupleTypes]
from typing import Tuple
t1 = None # type: Tuple[A]
t2 = None # type: Tuple[B]
t3 = None # type: Tuple[A, A]
t4 = None # type: Tuple[A, B]
t5 = None # type: Tuple[B, A]

t1 = t2 # E: Incompatible types in assignment (expression has type "Tuple[B]", variable has type "Tuple[A]")
t1 = t3 # E: Incompatible types in assignment (expression has type "Tuple[A, A]", variable has type "Tuple[A]")
t3 = t1 # E: Incompatible types in assignment (expression has type "Tuple[A]", variable has type "Tuple[A, A]")
t3 = t4 # E: Incompatible types in assignment (expression has type "Tuple[A, B]", variable has type "Tuple[A, A]")
t3 = t5 # E: Incompatible types in assignment (expression has type "Tuple[B, A]", variable has type "Tuple[A, A]")

# Ok
t1 = t1
t2 = t2
t3 = t3
t4 = t4
t5 = t5

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

[case testTupleSubtyping]
from typing import Tuple
t1 = None # type: Tuple[A, A]
t2 = None # type: Tuple[A, B]
t3 = None # type: Tuple[B, A]

t2 = t1  # E: Incompatible types in assignment (expression has type "Tuple[A, A]", variable has type "Tuple[A, B]")
t2 = t3  # E: Incompatible types in assignment (expression has type "Tuple[B, A]", variable has type "Tuple[A, B]")
t3 = t1  # E: Incompatible types in assignment (expression has type "Tuple[A, A]", variable has type "Tuple[B, A]")
t3 = t2  # E: Incompatible types in assignment (expression has type "Tuple[A, B]", variable has type "Tuple[B, A]")

t1 = t2
t1 = t3

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

[case testTupleCompatibilityWithOtherTypes]
from typing import Tuple
a, o = None, None # type: (A, object)
t = None # type: Tuple[A, A]

a = t # E: Incompatible types in assignment (expression has type "Tuple[A, A]", variable has type "A")
t = o # E: Incompatible types in assignment (expression has type "object", variable has type "Tuple[A, A]")
t = a # E: Incompatible types in assignment (expression has type "A", variable has type "Tuple[A, A]")
# TODO: callable types + tuples

# Ok
o = t
t = None

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

[case testNestedTupleTypes]
from typing import Tuple
t1 = None # type: Tuple[A, Tuple[A, A]]
t2 = None # type: Tuple[B, Tuple[B, B]]

t2 = t1 # E: Incompatible types in assignment (expression has type "Tuple[A, Tuple[A, A]]", variable has type "Tuple[B, Tuple[B, B]]")
t1 = t2

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

[case testNestedTupleTypes2]
from typing import Tuple
t1 = None # type: Tuple[A, Tuple[A, A]]
t2 = None # type: Tuple[B, Tuple[B, B]]

t2 = t1 # E: Incompatible types in assignment (expression has type "Tuple[A, Tuple[A, A]]", variable has type "Tuple[B, Tuple[B, B]]")
t1 = t2

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

[case testSubtypingWithNamedTupleType]
from typing import Tuple
t1 = None # type: Tuple[A, A]
t2 = None # type: tuple

t1 = t2 # E: Incompatible types in assignment (expression has type "Tuple[Any, ...]", variable has type "Tuple[A, A]")
t2 = t1

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

[case testTupleInitializationWithNone]
from typing import Tuple
t = None # type: Tuple[A, A]
t = None
class A: pass
[builtins fixtures/tuple.pyi]


-- Tuple expressions
-- -----------------


[case testTupleExpressions]
from typing import Tuple
t1 = None # type: tuple
t2 = None # type: Tuple[A]
t3 = None # type: Tuple[A, B]

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

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

t1 = ()
t1 = (a,)
t2 = (a,)
t3 = (a, b)
t3 = (a, c)
t3 = (None, None)

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

[case testVoidValueInTuple]
import typing
(None, f()) # E: "f" does not return a value
(f(), None) # E: "f" does not return a value

def f() -> None: pass
[builtins fixtures/tuple.pyi]


-- Indexing
-- --------


[case testIndexingTuples]
from typing import Tuple
t1 = None # type: Tuple[A, B]
t2 = None # type: Tuple[A]
t3 = None # type: Tuple[A, B, C, D, E]
a, b = None, None # type: (A, B)
x = None # type: Tuple[A, B, C]
y = None # type: Tuple[A, C, E]
n = 0

a = t1[1] # E: Incompatible types in assignment (expression has type "B", variable has type "A")
b = t1[0] # E: Incompatible types in assignment (expression has type "A", variable has type "B")
t1[2]     # E: Tuple index out of range
t1[3]     # E: Tuple index out of range
t2[1]     # E: Tuple index out of range
reveal_type(t1[n])     # E: Revealed type is 'Union[__main__.A, __main__.B]'
reveal_type(t3[n:])    # E: Revealed type is 'Union[__main__.A, __main__.B, __main__.C, __main__.D, __main__.E]'
b = t1[(0)] # E: Incompatible types in assignment (expression has type "A", variable has type "B")

a = t1[0]
b = t1[1]
b = t1[-1]
a = t1[(0)]
x = t3[0:3] # type (A, B, C)
y = t3[0:5:2] # type (A, C, E)
x = t3[:-2] # type (A, B, C)

class A: pass
class B: pass
class C: pass
class D: pass
class E: pass
[builtins fixtures/tuple.pyi]

[case testIndexingTuplesWithNegativeIntegers]
from typing import Tuple
t1 = None  # type: Tuple[A, B]
t2 = None  # type: Tuple[A]
a, b = None, None  # type: A, B

a = t1[-1] # E: Incompatible types in assignment (expression has type "B", variable has type "A")
b = t1[-2] # E: Incompatible types in assignment (expression has type "A", variable has type "B")
t1[-3]     # E: Tuple index out of range
t1[-4]     # E: Tuple index out of range
b = t2[(-1)] # E: Incompatible types in assignment (expression has type "A", variable has type "B")

a = t1[-2]
b = t1[-1]
a = t2[(-1)]

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

[case testAssigningToTupleItems]
from typing import Tuple
t = None # type: Tuple[A, B]
n = 0

t[0] = A() # E: Unsupported target for indexed assignment
t[2] = A() # E: Unsupported target for indexed assignment
t[n] = A() # E: Unsupported target for indexed assignment

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


-- Multiple assignment
-- -------------------


[case testMultipleAssignmentWithTuples]
from typing import Tuple
t1 = None # type: Tuple[A, B]
t2 = None # type: Tuple[A, B, A]
a, b = None, None # type: (A, B)
(a1, b1) = None, None # type: Tuple[A, B]

reveal_type(a1)  # E: Revealed type is '__main__.A'
reveal_type(b1)  # E: Revealed type is '__main__.B'

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

a, b = t1
a, b, a1 = t2

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

[case testMultipleAssignmentWithSquareBracketTuples]
from typing import Tuple

def avoid_confusing_test_parser() -> None:
    t1 = None # type: Tuple[A, B]
    t2 = None # type: Tuple[A, B, A]
    [a, b] = None, None # type: (A, B)
    [a1, b1] = None, None # type: Tuple[A, B]

    reveal_type(a)  # E: Revealed type is '__main__.A'
    reveal_type(b)  # E: Revealed type is '__main__.B'
    reveal_type(a1)  # E: Revealed type is '__main__.A'
    reveal_type(b1)  # E: Revealed type is '__main__.B'

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

    [a, b] = t1
    [a, b, a1] = t2

    [a2, b2] = t1
    reveal_type(a2)  # E: Revealed type is '__main__.A'
    reveal_type(b2)  # E: Revealed type is '__main__.B'

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

[case testMultipleAssignmentWithSquareBracketTuplesPython2]
# flags: --python-version 2.7 --no-strict-optional
from typing import Tuple

def avoid_confusing_test_parser():
    # type: () -> None
    t1 = None # type: Tuple[A, B]
    t2 = None # type: Tuple[A, B, A]
    [a, b] = None, None # type: Tuple[A, B]
    [a1, b1] = None, None # type: Tuple[A, B]

    reveal_type(a1)  # E: Revealed type is '__main__.A'
    reveal_type(b1)  # E: Revealed type is '__main__.B'

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

    [a, b] = t1
    [a, b, a1] = t2

    [a2, b2] = t1
    reveal_type(a2)  # E: Revealed type is '__main__.A'
    reveal_type(b2)  # E: Revealed type is '__main__.B'

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

[case testMultipleAssignmentWithInvalidNumberOfValues]
from typing import Tuple
t1 = None # type: Tuple[A, A, A]
a = None # type: A

a, a = t1       # E: Too many values to unpack (2 expected, 3 provided)
a, a, a, a = t1 # E: Need more than 3 values to unpack (4 expected)

a, a, a = t1

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

[case testMultipleAssignmentWithTupleExpressionRvalue]

a, b = None, None # type: (A, B)

a, b = a, a # Fail
a, b = b, a # Fail

a, b = a, b
a, a = a, a

class A: pass
class B: pass
[builtins fixtures/tuple.pyi]
[out]
main:4: error: Incompatible types in assignment (expression has type "A", variable has type "B")
main:5: error: Incompatible types in assignment (expression has type "B", variable has type "A")
main:5: error: Incompatible types in assignment (expression has type "A", variable has type "B")

[case testSubtypingInMultipleAssignment]

a, b = None, None # type: (A, B)

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

a, b = b, b
b, a = b, b

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

[case testInitializationWithMultipleValues]

a, b = None, None # type: (A, B)

a1, b1 = a, a # type: (A, B)  # E: Incompatible types in assignment (expression has type "A", variable has type "B")
a2, b2 = b, b # type: (A, B)  # E: Incompatible types in assignment (expression has type "B", variable has type "A")
a3, b3 = a # type: (A, B)     # E: '__main__.A' object is not iterable
a4, b4 = None # type: (A, B)  # E: 'None' object is not iterable
a5, b5 = a, b, a # type: (A, B)  # E: Too many values to unpack (2 expected, 3 provided)

ax, bx = a, b # type: (A, B)

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

[case testMultipleAssignmentWithNonTupleRvalue]

a, b = None, None # type: (A, B)
def f(): pass

a, b = None # E: 'None' object is not iterable
a, b = a   # E: '__main__.A' object is not iterable
a, b = f   # E: 'def () -> Any' object is not iterable

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

[case testMultipleAssignmentWithIndexedLvalues]

a, b = None, None # type: (A, B)
aa, bb = None, None # type: (AA, BB)

a[a], b[b] = a, bb   # E: Incompatible types in assignment (expression has type "A", target has type "AA")
a[a], b[b] = aa, b   # E: Incompatible types in assignment (expression has type "B", target has type "BB")
a[aa], b[b] = aa, bb # E: Invalid index type "AA" for "A"; expected type "A"
a[a], b[bb] = aa, bb # E: Invalid index type "BB" for "B"; expected type "B"
a[a], b[b] = aa, bb

class A:
    def __setitem__(self, x: 'A', y: 'AA') -> None: pass
class B:
    def __setitem__(self, x: 'B', y: 'BB') -> None: pass

class AA: pass
class BB: pass
[builtins fixtures/tuple.pyi]

[case testMultipleDeclarationWithParentheses]

(a, b) = (None, None) # type: int, str
a = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
b = 1  # E: Incompatible types in assignment (expression has type "int", variable has type "str")
a = 1
b = ''

[case testMultipleAssignmentWithExtraParentheses]

a, b = None, None # type: (A, B)

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

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

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

[case testMultipleAssignmentUsingSingleTupleType]
from typing import Tuple
a, b = None, None  # type: Tuple[int, str]
a = 1
b = ''
a = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
b = 1  # E: Incompatible types in assignment (expression has type "int", variable has type "str")

[case testMultipleAssignmentWithMixedVariables]
a = b, c = 1, 1
x, y = p, q = 1, 1
u, v, w = r, s = 1, 1 # E: Need more than 2 values to unpack (3 expected)
d, e = f, g, h = 1, 1 # E: Need more than 2 values to unpack (3 expected)


-- Assignment to starred expressions
-- ---------------------------------


[case testAssignmentToStarMissingAnnotation]
from typing import List
t = 1, 2
a, b, *c = 1, 2  # E: Need type annotation for 'c'
aa, bb, *cc = t  # E: Need type annotation for 'cc'
[builtins fixtures/list.pyi]

[case testAssignmentToStarAnnotation]
from typing import List
li, lo = None, None # type: List[int], List[object]
a, b, *c = 1, 2  # type: int, int, List[int]
c = lo  # E: Incompatible types in assignment (expression has type "List[object]", variable has type "List[int]")
c = li
[builtins fixtures/list.pyi]

[case testAssignmentToStarCount1]
from typing import List
ca = None # type: List[int]
c = [1]
a, b, *c = 1,  # E: Need more than 1 value to unpack (2 expected)
a, b, *c = 1, 2
a, b, *c = 1, 2, 3
a, b, *c = 1, 2, 3, 4
[builtins fixtures/list.pyi]

[case testAssignmentToStarCount2]
from typing import List
ca = None # type: List[int]
t1 = 1,
t2 = 1, 2
t3 = 1, 2, 3
t4 = 1, 2, 3, 4
c = [1]
a, b, *c = t1  # E: Need more than 1 value to unpack (2 expected)
a, b, *c = t2
a, b, *c = t3
a, b, *c = t4
[builtins fixtures/list.pyi]

[case testAssignmentToStarFromAny]
from typing import Any, cast
a, c = cast(Any, 1), C()
p, *q = a
c = a
c = q

class C: pass

[case testAssignmentToComplexStar]
from typing import List
li = None # type: List[int]
a, *(li) = 1,
a, *(b, c) = 1, 2  # E: Need more than 1 value to unpack (2 expected)
a, *(b, c) = 1, 2, 3
a, *(b, c) = 1, 2, 3, 4  # E: Too many values to unpack (2 expected, 3 provided)
[builtins fixtures/list.pyi]

[case testAssignmentToStarFromTupleType]
from typing import List, Tuple
li = None # type: List[int]
la = None # type: List[A]
ta = None # type: Tuple[A, A, A]
a, *la = ta
a, *li = ta  # E
a, *na = ta
na = la
na = a  # E

class A: pass
[builtins fixtures/list.pyi]
[out]
main:6: error: List item 0 has incompatible type "A"; expected "int"
main:6: error: List item 1 has incompatible type "A"; expected "int"
main:9: error: Incompatible types in assignment (expression has type "A", variable has type "List[A]")

[case testAssignmentToStarFromTupleInference]
from typing import List
li = None # type: List[int]
la = None # type: List[A]
a, *l = A(), A()
l = li  # E: Incompatible types in assignment (expression has type "List[int]", variable has type "List[A]")
l = la

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

[case testAssignmentToStarFromListInference]
from typing import List
li = None # type: List[int]
la = None # type: List[A]
a, *l = [A(), A()]
l = li  # E: Incompatible types in assignment (expression has type "List[int]", variable has type "List[A]")
l = la

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

[case testAssignmentToStarFromTupleTypeInference]
from typing import List, Tuple
li = None # type: List[int]
la = None # type: List[A]
ta = None # type: Tuple[A, A, A]
a, *l = ta
l = li  # E: Incompatible types in assignment (expression has type "List[int]", variable has type "List[A]")
l = la

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

[case testAssignmentToStarFromListTypeInference]
from typing import List
li = None # type: List[int]
la = None # type: List[A]
a, *l = la
l = li  # E: Incompatible types in assignment (expression has type "List[int]", variable has type "List[A]")
l = la

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

[case testAssignmentToStarFromIterable]
from typing import List, Tuple, Iterable

class CustomIterable(Iterable[int]): pass

a: List[int]
b: Tuple[int, ...]
c: Tuple[int, int, int]
d: Iterable[int]
e: CustomIterable

a1, *a2 = a
b1, *b2 = b
c1, *c2 = c
d1, *d2 = d
e1, *e2 = e

reveal_type(a2)  # E: Revealed type is 'builtins.list[builtins.int*]'
reveal_type(b2)  # E: Revealed type is 'builtins.list[builtins.int*]'
reveal_type(c2)  # E: Revealed type is 'builtins.list[builtins.int*]'
reveal_type(d2)  # E: Revealed type is 'builtins.list[builtins.int]'
reveal_type(e2)  # E: Revealed type is 'builtins.list[builtins.int]'
[builtins fixtures/tuple.pyi]

-- Nested tuple assignment
-- ----------------------------


[case testNestedTupleAssignment1]

a1, b1, c1 = None, None, None # type: (A, B, C)
a2, b2, c2 = None, None, None # type: (A, B, C)

a1, (b1, c1) = a2, (b2, c2)
a1, (a1, (b1, c1)) = a2, (a2, (b2, c2))
a1, (a1, (a1, b1)) = a1, (a1, (a1, c1))  # Fail

class A: pass
class B: pass
class C: pass
[out]
main:7: error: Incompatible types in assignment (expression has type "C", variable has type "B")

[case testNestedTupleAssignment2]

a1, b1, c1 = None, None, None # type: (A, B, C)
a2, b2, c2 = None, None, None # type: (A, B, C)
t = a1, b1

a2, b2 = t
(a2, b2), c2 = t, c1
(a2, c2), c2 = t, c1  # Fail
t, c2 = (a2, b2), c2
t, c2 = (a2, a2), c2  # Fail
t = a1, a1, a1  # Fail
t = a1  # Fail
a2, a2, a2 = t  # Fail
a2, = t  # Fail
a2 = t  # Fail

class A: pass
class B: pass
class C: pass
[out]
main:8: error: Incompatible types in assignment (expression has type "B", variable has type "C")
main:10: error: Incompatible types in assignment (expression has type "Tuple[A, A]", variable has type "Tuple[A, B]")
main:11: error: Incompatible types in assignment (expression has type "Tuple[A, A, A]", variable has type "Tuple[A, B]")
main:12: error: Incompatible types in assignment (expression has type "A", variable has type "Tuple[A, B]")
main:13: error: Need more than 2 values to unpack (3 expected)
main:14: error: Too many values to unpack (1 expected, 2 provided)
main:15: error: Incompatible types in assignment (expression has type "Tuple[A, B]", variable has type "A")


-- Error messages
-- --------------


[case testTupleErrorMessages]

a = None # type: A

(a, a) + a  # E: Unsupported left operand type for + ("Tuple[A, A]")
a + (a, a)  # E: Unsupported operand types for + ("A" and "Tuple[A, A]")
f((a, a))   # E: Argument 1 to "f" has incompatible type "Tuple[A, A]"; expected "A"
(a, a).foo  # E: "Tuple[A, A]" has no attribute "foo"

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

class A:
    def __add__(self, x: 'A') -> 'A': pass
[builtins fixtures/tuple.pyi]

[case testLargeTuplesInErrorMessages]

a = None # type: LongTypeName
a + (a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a) # Fail

class LongTypeName:
    def __add__(self, x: 'LongTypeName') -> 'LongTypeName': pass
[builtins fixtures/tuple.pyi]
[out]
main:3: error: Unsupported operand types for + ("LongTypeName" and <tuple: 50 items>)


-- Tuple methods
-- -------------


[case testTupleMethods]
from typing import Tuple
t = None # type: Tuple[int, str]
i = 0
s = ''
b = bool()

s = t.__len__()  # E: Incompatible types in assignment (expression has type "int", variable has type "str")
i = t.__str__()  # E: Incompatible types in assignment (expression has type "str", variable has type "int")
i = s in t       # E: Incompatible types in assignment (expression has type "bool", variable has type "int")
t.foo            # E: "Tuple[int, str]" has no attribute "foo"

i = t.__len__()
s = t.__str__()
b = s in t

[file builtins.py]
from typing import TypeVar, Generic
_T = TypeVar('_T')
class object:
    def __init__(self) -> None: pass
class tuple(Generic[_T]):
    def __len__(self) -> int: pass
    def __str__(self) -> str: pass
    def __contains__(self, o: object) -> bool: pass
class int: pass
class str: pass
class bool: pass
class type: pass
class function: pass


-- For loop over tuple
-- -------------------


[case testForLoopOverTuple]
import typing
t = 1, 2
for x in t:
    x = 1
    x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
[builtins fixtures/for.pyi]

[case testForLoopOverEmptyTuple]
import typing
t = ()
for x in t: pass  # E: Need type annotation for 'x'
[builtins fixtures/for.pyi]

[case testForLoopOverNoneValuedTuple]
import typing
for x in None, None: pass
[builtins fixtures/for.pyi]

[case testForLoopOverTupleAndSubtyping]
import typing
class A: pass
class B(A): pass
for x in B(), A():
    x = A()
    x = B()
    x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "A")
[builtins fixtures/for.pyi]

[case testTupleIterable]
y = 'a'
x = sum((1,2))
y = x # E: Incompatible types in assignment (expression has type "int", variable has type "str")
[builtins fixtures/tuple.pyi]


-- Tuple as a base type
-- --------------------


[case testTupleBaseClass]
import m
[file m.pyi]
from typing import Tuple
class A(Tuple[int, str]):
    def f(self, x: int) -> None:
        a, b = 1, ''
        a, b = self
        b, a = self  # Error
        self.f('')   # Error
[builtins fixtures/tuple.pyi]
[out]
tmp/m.pyi:6: error: Incompatible types in assignment (expression has type "int", variable has type "str")
tmp/m.pyi:6: error: Incompatible types in assignment (expression has type "str", variable has type "int")
tmp/m.pyi:7: error: Argument 1 to "f" of "A" has incompatible type "str"; expected "int"

[case testValidTupleBaseClass2]
from typing import Tuple
class A(Tuple[int, str]): pass

x, y = A()
reveal_type(x) # E: Revealed type is 'builtins.int'
reveal_type(y) # E: Revealed type is 'builtins.str'

x1 = A()[0] # type: int
x2 = A()[1] # type: int # E: Incompatible types in assignment (expression has type "str", variable has type "int")
A()[2] # E: Tuple index out of range

class B(Tuple[int, ...]): pass

z1 = B()[0] # type: int
z2 = B()[1] # type: str # E: Incompatible types in assignment (expression has type "int", variable has type "str")
B()[100]
[builtins fixtures/tuple.pyi]
[out]

[case testValidTupleBaseClass]
from typing import Tuple
class A(tuple): pass
[out]

[case testTupleBaseClass2]
import m
[file m.pyi]
from typing import Tuple
a = None # type: A
class A(Tuple[int, str]): pass
x, y = a
x() # E: "int" not callable
y() # E: "str" not callable
[builtins fixtures/tuple.pyi]
[out]

[case testGenericClassWithTupleBaseClass]
from typing import TypeVar, Generic, Tuple
T = TypeVar('T')
class Test(Generic[T], Tuple[T]): pass
x = Test() # type: Test[int]
[builtins fixtures/tuple.pyi]
[out]
main:4: error: Generic tuple types not supported


-- Variable-length tuples (Tuple[t, ...] with literal '...')
-- ---------------------------------------------------------


[case testIndexingVariableLengthTuple]
from typing import Tuple
x = () # type: Tuple[str, ...]
n = 5
x[n]() # E: "str" not callable
x[3]() # E: "str" not callable
[builtins fixtures/tuple.pyi]

[case testSubtypingVariableLengthTuple]
from typing import Tuple
class A: pass
class B(A): pass
def fa(t: Tuple[A, ...]) -> None: pass
def fb(t: Tuple[B, ...]) -> None: pass
ta = () # type: Tuple[A, ...]
tb = () # type: Tuple[B, ...]
fa(ta)
fa(tb)
fb(tb)
fb(ta) # E: Argument 1 to "fb" has incompatible type "Tuple[A, ...]"; expected "Tuple[B, ...]"
[builtins fixtures/tuple.pyi]

[case testSubtypingFixedAndVariableLengthTuples]
from typing import Tuple
class A: pass
class B(A): pass
def fa(t: Tuple[A, ...]) -> None: pass
def fb(t: Tuple[B, ...]) -> None: pass
aa = (A(), A())
ab = (A(), B())
bb = (B(), B())
fa(aa)
fa(ab)
fa(bb)
fb(bb)
fb(ab) # E: Argument 1 to "fb" has incompatible type "Tuple[A, B]"; expected "Tuple[B, ...]"
fb(aa) # E: Argument 1 to "fb" has incompatible type "Tuple[A, A]"; expected "Tuple[B, ...]"
[builtins fixtures/tuple.pyi]

[case testSubtypingTupleIsContainer]
from typing import Container
a = None  # type: Container[str]
a = ()
[typing fixtures/typing-full.pyi]

[case testSubtypingTupleIsSized]
from typing import Sized
a = None  # type: Sized
a = ()

[case testTupleWithStarExpr1]

a = (1, 2)
b = (*a, '')
reveal_type(b)  # E: Revealed type is 'Tuple[builtins.int, builtins.int, builtins.str]'

[case testTupleWithStarExpr2]
a = [1]
b = (0, *a)
reveal_type(b)  # E: Revealed type is 'builtins.tuple[builtins.int*]'
[builtins fixtures/tuple.pyi]

[case testTupleWithStarExpr3]
a = ['']
b = (0, *a)
reveal_type(b)  # E: Revealed type is 'builtins.tuple[builtins.object*]'
c = (*a, '')
reveal_type(c)  # E: Revealed type is 'builtins.tuple[builtins.str*]'
[builtins fixtures/tuple.pyi]

[case testTupleWithStarExpr4]
a = (1, 1, 'x', 'x')
b = (1, 'x')
a = (0, *b, '')
[builtins fixtures/tuple.pyi]

[case testTupleMeetTupleAny]
from typing import Union, Tuple
class A: pass
class B: pass

def f(x: Union[B, Tuple[A, A]]) -> None:
    if isinstance(x, tuple):
        reveal_type(x) # E: Revealed type is 'Tuple[__main__.A, __main__.A]'
    else:
        reveal_type(x) # E: Revealed type is '__main__.B'

def g(x: Union[str, Tuple[str, str]]) -> None:
    if isinstance(x, tuple):
        reveal_type(x) # E: Revealed type is 'Tuple[builtins.str, builtins.str]'
    else:
        reveal_type(x) # E: Revealed type is 'builtins.str'

[builtins fixtures/tuple.pyi]
[out]

[case testTupleMeetTupleAnyComplex]
from typing import Tuple, Union

Pair = Tuple[int, int]
Variant = Union[int, Pair]
def tuplify(v: Variant) -> None:
    reveal_type(v) # E: Revealed type is 'Union[builtins.int, Tuple[builtins.int, builtins.int]]'
    if not isinstance(v, tuple):
        reveal_type(v) # E: Revealed type is 'builtins.int'
        v = (v, v)
        reveal_type(v) # E: Revealed type is 'Tuple[builtins.int, builtins.int]'
    reveal_type(v) # E: Revealed type is 'Tuple[builtins.int, builtins.int]'
    reveal_type(v[0]) # E: Revealed type is 'builtins.int'

Pair2 = Tuple[int, str]
Variant2 = Union[int, Pair2]
def tuplify2(v: Variant2) -> None:
    if isinstance(v, tuple):
        reveal_type(v) # E: Revealed type is 'Tuple[builtins.int, builtins.str]'
    else:
        reveal_type(v) # E: Revealed type is 'builtins.int'
[builtins fixtures/tuple.pyi]
[out]

[case testTupleMeetTupleAnyAfter]
from typing import Tuple, Union

def good(blah: Union[Tuple[int, int], int]) -> None:
    reveal_type(blah) # E: Revealed type is 'Union[Tuple[builtins.int, builtins.int], builtins.int]'
    if isinstance(blah, tuple):
        reveal_type(blah) # E: Revealed type is 'Tuple[builtins.int, builtins.int]'
    reveal_type(blah) # E: Revealed type is 'Union[Tuple[builtins.int, builtins.int], builtins.int]'
[builtins fixtures/tuple.pyi]
[out]

[case testTupleMeetTupleVariable]
from typing import Tuple, TypeVar, Generic, Union
T = TypeVar('T')

class A: pass
class B1(A): pass
class B2(A): pass
class C: pass

x = None # type: Tuple[A, ...]
y = None # type: Tuple[Union[B1, C], Union[B2, C]]

def g(x: T) -> Tuple[T, T]:
    return (x, x)

z = 1
x, y = g(z) # E: Argument 1 to "g" has incompatible type "int"; expected "Tuple[B1, B2]"
[builtins fixtures/tuple.pyi]
[out]

[case testTupleWithUndersizedContext]
a = ([1], 'x')
a = ([], 'x', 1)  # E: Incompatible types in assignment (expression has type "Tuple[List[int], str, int]", variable has type "Tuple[List[int], str]")
[builtins fixtures/tuple.pyi]

[case testTupleWithOversizedContext]
a = (1, [1], 'x')
a = (1, [])  # E: Incompatible types in assignment (expression has type "Tuple[int, List[int]]", variable has type "Tuple[int, List[int], str]")
[builtins fixtures/tuple.pyi]

[case testTupleWithoutContext]
a = (1, [])  # E: Need type annotation for 'a'
[builtins fixtures/tuple.pyi]

[case testTupleWithUnionContext]
from typing import List, Union, Tuple
def f() -> Union[int, Tuple[List[str]]]:
    return ([],)
[builtins fixtures/tuple.pyi]

[case testTupleWithVariableSizedTupleContext]
from typing import List, Tuple
def f() -> Tuple[List[str], ...]:
    return ([],)
[builtins fixtures/tuple.pyi]

[case testTupleWithoutArgs]
from typing import Tuple
def f(a: Tuple) -> None: pass
f(())
f((1,))
f(('', ''))
f(0)  # E: Argument 1 to "f" has incompatible type "int"; expected "Tuple[Any, ...]"
[builtins fixtures/tuple.pyi]

[case testTupleSingleton]

from typing import Tuple
def f(a: Tuple[()]) -> None: pass
f(())
f((1,))  # E: Argument 1 to "f" has incompatible type "Tuple[int]"; expected "Tuple[]"
f(('', ''))  # E: Argument 1 to "f" has incompatible type "Tuple[str, str]"; expected "Tuple[]"
f(0)  # E: Argument 1 to "f" has incompatible type "int"; expected "Tuple[]"
[builtins fixtures/tuple.pyi]

[case testNonliteralTupleIndex]
t = (0, "")
x = 0
y = ""
reveal_type(t[x])  # E: Revealed type is 'Union[builtins.int, builtins.str]'
t[y]  # E: Invalid tuple index type (actual type "str", expected type "Union[int, slice]")
[builtins fixtures/tuple.pyi]

[case testNonliteralTupleSlice]
t = (0, "")
x = 0
y = ""
reveal_type(t[x:])  # E: Revealed type is 'Union[builtins.int, builtins.str]'
t[y:]  # E: Slice index must be an integer or None
[builtins fixtures/tuple.pyi]

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

class Base(Generic[T]): pass
def f(x: Base[T]) -> T: pass

class DT(Tuple[str, str], Base[int]):
    pass

reveal_type(f(DT())) # E: Revealed type is 'builtins.int*'

[builtins fixtures/tuple.pyi]
[out]

[case testTypeTupleClassmethod]
from typing import Tuple, Type

class C(Tuple[int, str]):
    @classmethod
    def f(cls) -> None: pass

t: Type[C]
t.g()  # E: "Type[C]" has no attribute "g"
t.f()
[builtins fixtures/classmethod.pyi]

[case testTypeTupleCall]
from typing import Tuple

def foo(o: CallableTuple) -> int:
    reveal_type(o)  # E: Revealed type is 'Tuple[builtins.str, builtins.int, fallback=__main__.CallableTuple]'
    return o(1, 2)

class CallableTuple(Tuple[str, int]):
    def __call__(self, n: int, m: int) -> int:
        return n

[builtins fixtures/tuple.pyi]

[case testTupleCompatibleWithSequence]
from typing import Sequence
s: Sequence[str]
s = tuple()
reveal_type(s) # E: Revealed type is 'builtins.tuple[builtins.str]'

[builtins fixtures/tuple.pyi]

[case testTupleInstanceCompatibleWithIterable]
from typing import Iterable, Tuple
x: Iterable[int] = ()
y: Tuple[int, ...] = (1, 2, 3)
x = y
reveal_type(x) # E: Revealed type is 'builtins.tuple[builtins.int]'

[builtins fixtures/tuple.pyi]

[case testTupleTypeCompatibleWithIterable]
from typing import Iterable, Tuple
x: Iterable[int] = ()
y: Tuple[int, int] = (1, 2)
x = y
reveal_type(x) # E: Revealed type is 'Tuple[builtins.int, builtins.int]'

[case testTupleOverlapDifferentTuples]
from typing import Optional, Tuple
class A: pass
class B: pass

possibles: Tuple[int, Tuple[A]]
x: Optional[Tuple[B]]

if x in possibles:
    reveal_type(x) # E: Revealed type is 'Union[Tuple[__main__.B], None]'
else:
    reveal_type(x) # E: Revealed type is 'Union[Tuple[__main__.B], None]'

[builtins fixtures/tuple.pyi]
