-- Type checking of union types

[case testUnion1]
from typing import Union
def f(x: Union[int, str]) -> None:
    if isinstance(x, int):
        y = 1
        y = x
    elif isinstance(x, str):
        z = 'a'
        z = x
[builtins fixtures/isinstance.pyi]

[case testUnion2]
from typing import Union
def f(x: Union[int, str]) -> None:
    if isinstance(x, int):
        y = 1
        y = x
    else:
        z = 'a'
        z = x
[builtins fixtures/isinstance.pyi]

[case testUnion3]
from typing import Union
def f(x: Union[int, str]) -> None:
    if isinstance(x, int):
        y = 1
        y = x
    else:
        z = 2
        z = x # E: Incompatible types in assignment (expression has type "str", variable has type "int")
[builtins fixtures/isinstance.pyi]
[out]

[case testUnionAnyIsInstance]
from typing import Any, Union

def func(v: Union[int, Any]) -> None:
    if isinstance(v, int):
        reveal_type(v) # E: Revealed type is 'builtins.int'
    else:
        reveal_type(v) # E: Revealed type is 'Any'
[builtins fixtures/isinstance.pyi]
[out]

[case testUnionAttributeAccess]
from typing import Union

class A: y = 1
class B: y = 2
class C: pass
class D: pass

u = None # type: Union[A, C, D]
v = None # type: Union[C, D]
w = None # type: Union[A, B]
x = None # type: Union[A, C]
y = None # type: int
z = None # type: str

y = w.y
v.y           # E: Item "C" of "Union[C, D]" has no attribute "y" \
              # E: Item "D" of "Union[C, D]" has no attribute "y"
u.y           # E: Item "C" of "Union[A, C, D]" has no attribute "y" \
              # E: Item "D" of "Union[A, C, D]" has no attribute "y"
z = w.y       # E: Incompatible types in assignment (expression has type "int", variable has type "str")
w.y = 'a'     # E: Incompatible types in assignment (expression has type "str", variable has type "int")
y = x.y       # E: Item "C" of "Union[A, C]" has no attribute "y"
zz = x.y      # E: Item "C" of "Union[A, C]" has no attribute "y"
z = zz        # E: Incompatible types in assignment (expression has type "Union[int, Any]", variable has type "str")

[builtins fixtures/isinstance.pyi]

[case testUnionMethodCalls]
from typing import Union

class A:
    def foo(self) -> int: pass
class B:
    def foo(self) -> int: pass
class C:
    def foo(self) -> str: pass

x = None # type: Union[A, B]
y = None # type: Union[A, C]
i = None # type: int

x.foo()
y.foo()
i = x.foo()
i = y.foo()   # E: Incompatible types in assignment (expression has type "Union[int, str]", variable has type "int")

[builtins fixtures/isinstance.pyi]

[case testUnionIndexing]
from typing import Union, List
x = None # type: Union[List[int], str]
x[2]
x[2] + 1 # E: Unsupported operand types for + ("str" and "int") \
         # N: Left operand is of type "Union[int, str]"
[builtins fixtures/isinstancelist.pyi]

[case testUnionAsOverloadArg]
from foo import *
x = 0
x = f(1)
x = f('')
s = ''
s = f(int)
s = f(1)    # E: Incompatible types in assignment (expression has type "int", variable has type "str")
x = f(int)  # E: Incompatible types in assignment (expression has type "str", variable has type "int")

[file foo.pyi]
from typing import Union, overload
@overload
def f(x: Union[int, str]) -> int: pass
@overload
def f(x: type) -> str: pass

[case testUnionWithNoneItem]
from typing import Union
def f() -> Union[int, None]: pass
x = 1
x = f()

[case testOptional]
from typing import Optional
def f(x: Optional[int]) -> None: pass
f(1)
f(None)
f('') # E: Argument 1 to "f" has incompatible type "str"; expected "Optional[int]"

[case testUnionSimplificationGenericFunction]
from typing import TypeVar, Union, List
T = TypeVar('T')
def f(x: List[T]) -> Union[T, int]: pass
def g(y: str) -> None: pass
a = f([1])
g(a) # E: Argument 1 to "g" has incompatible type "int"; expected "str"
[builtins fixtures/list.pyi]

[case testUnionSimplificationGenericClass]
from typing import TypeVar, Union, Generic
T = TypeVar('T')
U = TypeVar('U')
class C(Generic[T, U]):
    def f(self, x: str) -> Union[T, U]: pass
a = C() # type: C[int, int]
b = a.f('a')
a.f(b) # E: Argument 1 to "f" of "C" has incompatible type "int"; expected "str"

[case testUnionOrderEquivalence]
from typing import Union

def foo(): pass

S = str
T = int

if foo():
    def f(x: Union[int, str]) -> None: pass
elif foo():
    def f(x: Union[str, int]) -> None: pass
elif foo():
    def f(x: Union[int, str, int, int, str]) -> None: pass
elif foo():
    def f(x: Union[int, str, float]) -> None: pass  # E: All conditional function variants must have identical signatures
elif foo():
    def f(x: Union[S, T]) -> None: pass
elif foo():
    def f(x: Union[str]) -> None: pass  # E: All conditional function variants must have identical signatures
else:
    def f(x: Union[Union[int, T], Union[S, T], str]) -> None: pass

# Checks bidirectionality of testing. The first definition of g is consistent with
# the second, but not vice-versa.
if foo():
    def g(x: Union[int, str, bytes]) -> None: pass
else:
    def g(x: Union[int, str]) -> None: pass  # E: All conditional function variants must have identical signatures

[case testUnionSimplificationSpecialCases]
from typing import Any, TypeVar, Union

class C(Any): pass

T = TypeVar('T')
S = TypeVar('S')
def u(x: T, y: S) -> Union[S, T]: pass

a = None # type: Any

reveal_type(u(C(), None))  # E: Revealed type is '__main__.C*'
reveal_type(u(None, C()))  # E: Revealed type is '__main__.C*'

reveal_type(u(C(), a))  # E: Revealed type is 'Union[Any, __main__.C*]'
reveal_type(u(a, C()))  # E: Revealed type is 'Union[__main__.C*, Any]'

reveal_type(u(C(), C()))  # E: Revealed type is '__main__.C*'
reveal_type(u(a, a))  # E: Revealed type is 'Any'

[case testUnionSimplificationSpecialCase2]
from typing import Any, TypeVar, Union

class C(Any): pass

T = TypeVar('T')
S = TypeVar('S')
def u(x: T, y: S) -> Union[S, T]: pass

def f(x: T) -> None:
    reveal_type(u(C(), x)) # E: Revealed type is 'Union[T`-1, __main__.C*]'
    reveal_type(u(x, C())) # E: Revealed type is 'Union[__main__.C*, T`-1]'

[case testUnionSimplificationSpecialCase3]
from typing import Any, TypeVar, Generic, Union

class C(Any): pass

V = TypeVar('V')
T = TypeVar('T')

class M(Generic[V]):
    def get(self, default: T) -> Union[V, T]: ...

def f(x: M[C]) -> None:
    y = x.get(None)
    reveal_type(y) # E: Revealed type is '__main__.C'

[case testUnionSimplificationSpecialCases]
from typing import Any, TypeVar, Union

class C(Any): pass

T = TypeVar('T')
S = TypeVar('S')
def u(x: T, y: S) -> Union[S, T]: pass

a = None # type: Any

# Base-class-Any and None, simplify
reveal_type(u(C(), None))  # E: Revealed type is '__main__.C*'
reveal_type(u(None, C()))  # E: Revealed type is '__main__.C*'

# Normal instance type and None, simplify
reveal_type(u(1, None))  # E: Revealed type is 'builtins.int*'
reveal_type(u(None, 1))  # E: Revealed type is 'builtins.int*'

# Normal instance type and base-class-Any, no simplification
reveal_type(u(C(), 1))  # E: Revealed type is 'Union[builtins.int*, __main__.C*]'
reveal_type(u(1, C()))  # E: Revealed type is 'Union[__main__.C*, builtins.int*]'

# Normal instance type and Any, no simplification
reveal_type(u(1, a))  # E: Revealed type is 'Union[Any, builtins.int*]'
reveal_type(u(a, 1))  # E: Revealed type is 'Union[builtins.int*, Any]'

# Any and base-class-Any, no simplificaiton
reveal_type(u(C(), a))  # E: Revealed type is 'Union[Any, __main__.C*]'
reveal_type(u(a, C()))  # E: Revealed type is 'Union[__main__.C*, Any]'

# Two normal instance types, simplify
reveal_type(u(1, object()))  # E: Revealed type is 'builtins.object*'
reveal_type(u(object(), 1))  # E: Revealed type is 'builtins.object*'

# Two normal instance types, no simplification
reveal_type(u(1, ''))  # E: Revealed type is 'Union[builtins.str*, builtins.int*]'
reveal_type(u('', 1))  # E: Revealed type is 'Union[builtins.int*, builtins.str*]'

[case testUnionSimplificationWithDuplicateItems]
from typing import Any, TypeVar, Union

class C(Any): pass

T = TypeVar('T')
S = TypeVar('S')
R = TypeVar('R')
def u(x: T, y: S, z: R) -> Union[R, S, T]: pass

a = None # type: Any

reveal_type(u(1, 1, 1))  # E: Revealed type is 'builtins.int*'
reveal_type(u(C(), C(), None))  # E: Revealed type is '__main__.C*'
reveal_type(u(a, a, 1))  # E: Revealed type is 'Union[builtins.int*, Any]'
reveal_type(u(a, C(), a))  # E: Revealed type is 'Union[Any, __main__.C*]'
reveal_type(u('', 1, 1))  # E: Revealed type is 'Union[builtins.int*, builtins.str*]'

[case testUnionAndBinaryOperation]
from typing import Union
class A: pass
def f(x: Union[int, str, A]):
    x + object() # E: Unsupported operand types for + ("int" and "object") \
                 # E: Unsupported operand types for + ("str" and "object") \
                 # E: Unsupported left operand type for + ("A") \
                 # N: Left operand is of type "Union[int, str, A]"

[case testNarrowingDownNamedTupleUnion]
from typing import NamedTuple, Union

A = NamedTuple('A', [('y', int)])
B = NamedTuple('B', [('x', int)])
C = NamedTuple('C', [('x', int)])

def foo(a: Union[A, B, C]):
    if isinstance(a, (B, C)):
        reveal_type(a) # E: Revealed type is 'Union[Tuple[builtins.int, fallback=__main__.B], Tuple[builtins.int, fallback=__main__.C]]'
        a.x
        a.y # E: Item "B" of "Union[B, C]" has no attribute "y" \
            # E: Item "C" of "Union[B, C]" has no attribute "y"
        b = a # type: Union[B, C]
[builtins fixtures/isinstance.pyi]

[case testSimplifyingUnionAndTypePromotions]
from typing import TypeVar, Union
T = TypeVar('T')
S = TypeVar('S')
def u(x: T, y: S) -> Union[S, T]: pass

reveal_type(u(1, 2.3))  # E: Revealed type is 'builtins.float*'
reveal_type(u(2.3, 1))  # E: Revealed type is 'builtins.float*'
reveal_type(u(False, 2.2)) # E: Revealed type is 'builtins.float*'
reveal_type(u(2.2, False)) # E: Revealed type is 'builtins.float*'
[builtins fixtures/primitives.pyi]

[case testSimplifyingUnionWithTypeTypes1]
from typing import TypeVar, Union, Type, Any

T = TypeVar('T')
S = TypeVar('S')
def u(x: T, y: S) -> Union[S, T]: pass

t_o = None  # type: Type[object]
t_s = None  # type: Type[str]
t_a = None  # type: Type[Any]

# Two identical items
reveal_type(u(t_o, t_o)) # E: Revealed type is 'Type[builtins.object]'
reveal_type(u(t_s, t_s)) # E: Revealed type is 'Type[builtins.str]'
reveal_type(u(t_a, t_a)) # E: Revealed type is 'Type[Any]'
reveal_type(u(type, type)) # E: Revealed type is 'def (x: builtins.object) -> builtins.type'

# One type, other non-type
reveal_type(u(t_s, 1)) # E: Revealed type is 'Union[builtins.int*, Type[builtins.str]]'
reveal_type(u(1, t_s)) # E: Revealed type is 'Union[Type[builtins.str], builtins.int*]'
reveal_type(u(type, 1)) # E: Revealed type is 'Union[builtins.int*, def (x: builtins.object) -> builtins.type]'
reveal_type(u(1, type)) # E: Revealed type is 'Union[def (x: builtins.object) -> builtins.type, builtins.int*]'
reveal_type(u(t_a, 1)) # E: Revealed type is 'Union[builtins.int*, Type[Any]]'
reveal_type(u(1, t_a)) # E: Revealed type is 'Union[Type[Any], builtins.int*]'
reveal_type(u(t_o, 1)) # E: Revealed type is 'Union[builtins.int*, Type[builtins.object]]'
reveal_type(u(1, t_o)) # E: Revealed type is 'Union[Type[builtins.object], builtins.int*]'

[case testSimplifyingUnionWithTypeTypes2]
from typing import TypeVar, Union, Type, Any

T = TypeVar('T')
S = TypeVar('S')
def u(x: T, y: S) -> Union[S, T]: pass

t_o = None  # type: Type[object]
t_s = None  # type: Type[str]
t_a = None  # type: Type[Any]
t = None    # type: type

# Union with object
reveal_type(u(t_o, object())) # E: Revealed type is 'builtins.object*'
reveal_type(u(object(), t_o)) # E: Revealed type is 'builtins.object*'
reveal_type(u(t_s, object())) # E: Revealed type is 'builtins.object*'
reveal_type(u(object(), t_s)) # E: Revealed type is 'builtins.object*'
reveal_type(u(t_a, object())) # E: Revealed type is 'builtins.object*'
reveal_type(u(object(), t_a)) # E: Revealed type is 'builtins.object*'

# Union between type objects
reveal_type(u(t_o, t_a)) # E: Revealed type is 'Union[Type[Any], Type[builtins.object]]'
reveal_type(u(t_a, t_o)) # E: Revealed type is 'Union[Type[builtins.object], Type[Any]]'
reveal_type(u(t_s, t_o)) # E: Revealed type is 'Type[builtins.object]'
reveal_type(u(t_o, t_s)) # E: Revealed type is 'Type[builtins.object]'
reveal_type(u(t_o, type)) # E: Revealed type is 'Type[builtins.object]'
reveal_type(u(type, t_o)) # E: Revealed type is 'Type[builtins.object]'
reveal_type(u(t_a, t)) # E: Revealed type is 'builtins.type*'
reveal_type(u(t, t_a)) # E: Revealed type is 'builtins.type*'
# The following should arguably not be simplified, but it's unclear how to fix then
# without causing regressions elsewhere.
reveal_type(u(t_o, t)) # E: Revealed type is 'builtins.type*'
reveal_type(u(t, t_o)) # E: Revealed type is 'builtins.type*'

[case testNotSimplifyingUnionWithMetaclass]
from typing import TypeVar, Union, Type, Any

class M(type): pass
class M2(M): pass
class A(metaclass=M): pass

T = TypeVar('T')
S = TypeVar('S')
def u(x: T, y: S) -> Union[S, T]: pass

a: Any
t_a: Type[A]

reveal_type(u(M(*a), t_a)) # E: Revealed type is 'Union[Type[__main__.A], __main__.M*]'
reveal_type(u(t_a, M(*a))) # E: Revealed type is 'Union[__main__.M*, Type[__main__.A]]'

reveal_type(u(M2(*a), t_a)) # E: Revealed type is 'Union[Type[__main__.A], __main__.M2*]'
reveal_type(u(t_a, M2(*a))) # E: Revealed type is 'Union[__main__.M2*, Type[__main__.A]]'

[case testSimplifyUnionWithCallable]
from typing import TypeVar, Union, Any, Callable

T = TypeVar('T')
S = TypeVar('S')
def u(x: T, y: S) -> Union[S, T]: pass

class C: pass
class D(C): pass

D_C: Callable[[D], C]
A_C: Callable[[Any], C]
D_A: Callable[[D], Any]
C_C: Callable[[C], C]
D_D: Callable[[D], D]
i_C: Callable[[int], C]

# TODO: Test argument names and kinds once we have flexible callable types.

reveal_type(u(D_C, D_C)) # E: Revealed type is 'def (__main__.D) -> __main__.C'

reveal_type(u(A_C, D_C)) # E: Revealed type is 'Union[def (__main__.D) -> __main__.C, def (Any) -> __main__.C]'
reveal_type(u(D_C, A_C)) # E: Revealed type is 'Union[def (Any) -> __main__.C, def (__main__.D) -> __main__.C]'

reveal_type(u(D_A, D_C)) # E: Revealed type is 'Union[def (__main__.D) -> __main__.C, def (__main__.D) -> Any]'
reveal_type(u(D_C, D_A)) # E: Revealed type is 'Union[def (__main__.D) -> Any, def (__main__.D) -> __main__.C]'

reveal_type(u(D_C, C_C)) # E: Revealed type is 'def (__main__.D) -> __main__.C'
reveal_type(u(C_C, D_C)) # E: Revealed type is 'def (__main__.D) -> __main__.C'

reveal_type(u(D_C, D_D)) # E: Revealed type is 'def (__main__.D) -> __main__.C'
reveal_type(u(D_D, D_C)) # E: Revealed type is 'def (__main__.D) -> __main__.C'

reveal_type(u(D_C, i_C)) # E: Revealed type is 'Union[def (builtins.int) -> __main__.C, def (__main__.D) -> __main__.C]'

[case testUnionOperatorMethodSpecialCase]
from typing import Union
class C:
    def __le__(self, x: 'C') -> int: ...
class D:
    def __le__(self, other) -> int: ...
class E:
    def __ge__(self, other: Union[C, D]) -> int: ...

[case testUnionSimplificationWithBoolIntAndFloat]
from typing import List, Union
l = reveal_type([]) # type: List[Union[bool, int, float]] \
    # E: Revealed type is 'builtins.list[builtins.float]'
reveal_type(l) \
    # E: Revealed type is 'builtins.list[Union[builtins.bool, builtins.int, builtins.float]]'
[builtins fixtures/list.pyi]

[case testUnionSimplificationWithBoolIntAndFloat2]
from typing import List, Union
l = reveal_type([]) # type: List[Union[bool, int, float, str]] \
    # E: Revealed type is 'builtins.list[Union[builtins.float, builtins.str]]'
reveal_type(l) \
    # E: Revealed type is 'builtins.list[Union[builtins.bool, builtins.int, builtins.float, builtins.str]]'
[builtins fixtures/list.pyi]

[case testNestedUnionsProcessedCorrectly]
from typing import Union

class A: pass
class B: pass
class C: pass

def foo(bar: Union[Union[A, B], C]) -> None:
    if isinstance(bar, A):
        reveal_type(bar)  # E: Revealed type is '__main__.A'
    else:
        reveal_type(bar)  # E: Revealed type is 'Union[__main__.B, __main__.C]'
[builtins fixtures/isinstance.pyi]
[out]

[case testAssignAnyToUnion]
from typing import Union, Any
x: Union[int, str]
a: Any
if bool():
    x = a
    # TODO: Maybe we should infer Any as the type instead.
    reveal_type(x)  # E: Revealed type is 'Union[builtins.int, builtins.str]'
reveal_type(x)  # E: Revealed type is 'Union[builtins.int, builtins.str]'
[builtins fixtures/bool.pyi]

[case testAssignAnyToUnionWithAny]
from typing import Union, Any
x: Union[int, Any]
a: Any
if bool():
    x = a
    reveal_type(x)  # E: Revealed type is 'Any'
reveal_type(x)  # E: Revealed type is 'Union[builtins.int, Any]'
[builtins fixtures/bool.pyi]

[case testUnionMultiassignSingle]
from typing import Union, Tuple, Any

a: Union[Tuple[int], Tuple[float]]
(a1,) = a
reveal_type(a1)  # E: Revealed type is 'builtins.float'

b: Union[Tuple[int], Tuple[str]]
(b1,) = b
reveal_type(b1)  # E: Revealed type is 'Union[builtins.int, builtins.str]'

[case testUnionMultiassignDouble]
from typing import Union, Tuple

c: Union[Tuple[int, int], Tuple[int, float]]
(c1, c2) = c
reveal_type(c1)  # E: Revealed type is 'builtins.int'
reveal_type(c2)  # E: Revealed type is 'builtins.float'

[case testUnionMultiassignGeneric]
from typing import Union, Tuple, TypeVar
T = TypeVar('T')
S = TypeVar('S')

def pack_two(x: T, y: S) -> Union[Tuple[T, T], Tuple[S, S]]:
    pass

(x, y) = pack_two(1, 'a')
reveal_type(x)  # E: Revealed type is 'Union[builtins.int*, builtins.str*]'
reveal_type(y)  # E: Revealed type is 'Union[builtins.int*, builtins.str*]'

[case testUnionMultiassignAny]
from typing import Union, Tuple, Any

d: Union[Any, Tuple[float, float]]
(d1, d2) = d
reveal_type(d1)  # E: Revealed type is 'Union[Any, builtins.float]'
reveal_type(d2)  # E: Revealed type is 'Union[Any, builtins.float]'

e: Union[Any, Tuple[float, float], int]
(e1, e2) = e  # E: 'builtins.int' object is not iterable

[case testUnionMultiassignNotJoin]
from typing import Union, List

class A: pass
class B(A): pass
class C(A): pass
a: Union[List[B], List[C]]
x, y = a
reveal_type(x)  # E: Revealed type is 'Union[__main__.B*, __main__.C*]'
[builtins fixtures/list.pyi]

[case testUnionMultiassignRebind]
from typing import Union, List

class A: pass
class B(A): pass
class C(A): pass
obj: object
a: Union[List[B], List[C]]
obj, new = a
reveal_type(obj)  # E: Revealed type is 'Union[__main__.B*, __main__.C*]'
reveal_type(new)  # E: Revealed type is 'Union[__main__.B*, __main__.C*]'

obj = 1
reveal_type(obj)  # E: Revealed type is 'builtins.int'
[builtins fixtures/list.pyi]

[case testUnionMultiassignAlreadyDeclared]
from typing import Union, Tuple

a: Union[Tuple[int, int], Tuple[int, float]]
a1: object
a2: int
(a1, a2) = a  # E: Incompatible types in assignment (expression has type "float", variable has type "int")

b: Union[Tuple[float, int], Tuple[int, int]]
b1: object
b2: int
(b1, b2) = b
reveal_type(b1) # E: Revealed type is 'builtins.float'
reveal_type(b2) # E: Revealed type is 'builtins.int'

c: Union[Tuple[int, int], Tuple[int, int]]
c1: object
c2: int
(c1, c2) = c
reveal_type(c1)  # E: Revealed type is 'builtins.int'
reveal_type(c2)  # E: Revealed type is 'builtins.int'

d: Union[Tuple[int, int], Tuple[int, float]]
d1: object
(d1, d2) = d
reveal_type(d1)  # E: Revealed type is 'builtins.int'
reveal_type(d2)  # E: Revealed type is 'builtins.float'

[case testUnionMultiassignIndexed]
from typing import Union, Tuple, List

class B:
    x: object

x: List[int]
b: B

a: Union[Tuple[int, int], Tuple[int, object]]
(x[0], b.x) = a
reveal_type(x[0])  # E: Revealed type is 'builtins.int*'
reveal_type(b.x)  # E: Revealed type is 'builtins.object'
[builtins fixtures/list.pyi]

[case testUnionMultiassignIndexedWithError]
from typing import Union, Tuple, List

class A: pass
class B:
    x: int

x: List[A]
b: B

a: Union[Tuple[int, int], Tuple[int, object]]
(x[0], b.x) = a  # E: Incompatible types in assignment (expression has type "int", target has type "A") \
                 # E: Incompatible types in assignment (expression has type "object", variable has type "int")
reveal_type(x[0])  # E: Revealed type is '__main__.A*'
reveal_type(b.x)  # E: Revealed type is 'builtins.int'
[builtins fixtures/list.pyi]

[case testUnionMultiassignPacked]
from typing import Union, Tuple, List

a: Union[Tuple[int, int, int], Tuple[int, int, str]]
a1: int
a2: object
(a1, *xs, a2) = a

reveal_type(a1)  # E: Revealed type is 'builtins.int'
reveal_type(xs)  # E: Revealed type is 'builtins.list[builtins.int*]'
reveal_type(a2)  # E: Revealed type is 'Union[builtins.int, builtins.str]'
[builtins fixtures/list.pyi]

[case testUnpackingUnionOfListsInFunction]
from typing import Union, List

def f(x: bool) -> Union[List[int], List[str]]:
    if x:
        return [1, 1]
    else:
        return ['a', 'a']

def g(x: bool) -> None:
    a, b = f(x)
    reveal_type(a) # E: Revealed type is 'Union[builtins.int*, builtins.str*]'
    reveal_type(b) # E: Revealed type is 'Union[builtins.int*, builtins.str*]'
[builtins fixtures/list.pyi]

[case testUnionOfVariableLengthTupleUnpacking]
from typing import Tuple, Union
VarTuple = Union[Tuple[int, int], Tuple[int, int, int]]

def make_tuple() -> VarTuple:
    pass
x = make_tuple()

a, b = x # E: Too many values to unpack (2 expected, 3 provided)
a, b, c = x # E: Need more than 2 values to unpack (3 expected)
c, *d = x
reveal_type(c) # E: Revealed type is 'builtins.int'
reveal_type(d) # E: Revealed type is 'builtins.list[builtins.int*]'
[builtins fixtures/tuple.pyi]

[case testUnionOfNonIterableUnpacking]
from typing import Union
bad: Union[int, str]

x, y = bad # E: 'builtins.int' object is not iterable \
           # E: 'builtins.str' object is not iterable
reveal_type(x) # E: Revealed type is 'Any'
reveal_type(y) # E: Revealed type is 'Any'
[out]

[case testUnionAlwaysTooMany]
from typing import Union, Tuple
bad: Union[Tuple[int, int, int], Tuple[str, str, str]]

x, y = bad # E: Too many values to unpack (2 expected, 3 provided)
reveal_type(x) # E: Revealed type is 'Any'
reveal_type(y) # E: Revealed type is 'Any'
[builtins fixtures/tuple.pyi]
[out]

[case testUnionAlwaysTooFew]
from typing import Union, Tuple
bad: Union[Tuple[int, int, int], Tuple[str, str, str]]

x, y, z, w = bad # E: Need more than 3 values to unpack (4 expected)
reveal_type(x) # E: Revealed type is 'Any'
reveal_type(y) # E: Revealed type is 'Any'
reveal_type(z) # E: Revealed type is 'Any'
reveal_type(w) # E: Revealed type is 'Any'
[builtins fixtures/tuple.pyi]
[out]

[case testUnionUnpackingChainedTuple]
from typing import Union, Tuple
good: Union[Tuple[int, int], Tuple[str, str]]

x, y = t = good
reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.str]'
reveal_type(y) # E: Revealed type is 'Union[builtins.int, builtins.str]'
reveal_type(t) # E: Revealed type is 'Union[Tuple[builtins.int, builtins.int], Tuple[builtins.str, builtins.str]]'
[builtins fixtures/tuple.pyi]
[out]

[case testUnionUnpackingChainedTuple2]
from typing import Union, Tuple
good: Union[Tuple[int, int], Tuple[str, str]]

t = x, y = good
reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.str]'
reveal_type(y) # E: Revealed type is 'Union[builtins.int, builtins.str]'
reveal_type(t) # E: Revealed type is 'Union[Tuple[builtins.int, builtins.int], Tuple[builtins.str, builtins.str]]'
[builtins fixtures/tuple.pyi]
[out]

[case testUnionUnpackingChainedTuple3]
from typing import Union, Tuple
good: Union[Tuple[int, int], Tuple[str, str]]

x, y = a, b = good
reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.str]'
reveal_type(y) # E: Revealed type is 'Union[builtins.int, builtins.str]'
reveal_type(a) # E: Revealed type is 'Union[builtins.int, builtins.str]'
reveal_type(b) # E: Revealed type is 'Union[builtins.int, builtins.str]'
[builtins fixtures/tuple.pyi]
[out]

[case testUnionUnpackingChainedList]
from typing import Union, List
good: Union[List[int], List[str]]

lst = x, y = good
reveal_type(x) # E: Revealed type is 'Union[builtins.int*, builtins.str*]'
reveal_type(y) # E: Revealed type is 'Union[builtins.int*, builtins.str*]'
reveal_type(lst) # E: Revealed type is 'Union[builtins.list[builtins.int], builtins.list[builtins.str]]'
[builtins fixtures/list.pyi]
[out]

[case testUnionUnpackingChainedList2]
from typing import Union, List
good: Union[List[int], List[str]]

x, *y, z = lst = good
reveal_type(x) # E: Revealed type is 'Union[builtins.int*, builtins.str*]'
reveal_type(y) # E: Revealed type is 'Union[builtins.list[builtins.int*], builtins.list[builtins.str*]]'
reveal_type(z) # E: Revealed type is 'Union[builtins.int*, builtins.str*]'
reveal_type(lst) # E: Revealed type is 'Union[builtins.list[builtins.int], builtins.list[builtins.str]]'
[builtins fixtures/list.pyi]
[out]

[case testUnionUnpackingInForTuple]
from typing import Union, Tuple, NamedTuple
class NTInt(NamedTuple):
    x: int
    y: int
class NTStr(NamedTuple):
    x: str
    y: str

nt: Union[NTInt, NTStr]
for nx in nt:
    reveal_type(nx) # E: Revealed type is 'Union[builtins.int*, builtins.str*]'

t: Union[Tuple[int, int], Tuple[str, str]]
for x in t:
    # TODO(Ivan): This will be OK when tuple fallback patches are added (like above)
    reveal_type(x) # E: Revealed type is 'Any'
[builtins fixtures/for.pyi]
[out]

[case testUnionUnpackingInForList]
from typing import Union, List, Tuple

t: Union[List[Tuple[int, int]], List[Tuple[str, str]]]
for x, y in t:
    reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.str]'
    reveal_type(y) # E: Revealed type is 'Union[builtins.int, builtins.str]'

t2: List[Union[Tuple[int, int], Tuple[str, str]]]
for x2, y2 in t2:
    reveal_type(x2) # E: Revealed type is 'Union[builtins.int, builtins.str]'
    reveal_type(y2) # E: Revealed type is 'Union[builtins.int, builtins.str]'
[builtins fixtures/for.pyi]
[out]

[case testUnionUnpackingDoubleBinder]
from typing import Union, Tuple

x: object
y: object
class A: pass
class B: pass

t1: Union[Tuple[A, A], Tuple[B, B]]
t2: Union[Tuple[int, int], Tuple[str, str]]

x, y = t1
reveal_type(x) # E: Revealed type is 'Union[__main__.A, __main__.B]'
reveal_type(y) # E: Revealed type is 'Union[__main__.A, __main__.B]'

x, y = t2
reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.str]'
reveal_type(y) # E: Revealed type is 'Union[builtins.int, builtins.str]'

x, y = object(), object()
reveal_type(x) # E: Revealed type is 'builtins.object'
reveal_type(y) # E: Revealed type is 'builtins.object'
[builtins fixtures/tuple.pyi]
[out]

[case testUnionUnpackingFromNestedTuples]
from typing import Union, Tuple

t: Union[Tuple[int, Tuple[int, int]], Tuple[str, Tuple[str, str]]]
x, (y, z) = t
reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.str]'
reveal_type(y) # E: Revealed type is 'Union[builtins.int, builtins.str]'
reveal_type(z) # E: Revealed type is 'Union[builtins.int, builtins.str]'
[builtins fixtures/tuple.pyi]
[out]

[case testNestedUnionUnpackingFromNestedTuples]
from typing import Union, Tuple

class A: pass
class B: pass

t: Union[Tuple[int, Union[Tuple[int, int], Tuple[A, A]]], Tuple[str, Union[Tuple[str, str], Tuple[B, B]]]]
x, (y, z) = t
reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.str]'
reveal_type(y) # E: Revealed type is 'Union[builtins.int, __main__.A, builtins.str, __main__.B]'
reveal_type(z) # E: Revealed type is 'Union[builtins.int, __main__.A, builtins.str, __main__.B]'
[builtins fixtures/tuple.pyi]
[out]

[case testNestedUnionUnpackingFromNestedTuplesBinder]
from typing import Union, Tuple

class A: pass
class B: pass

x: object
y: object
z: object

t: Union[Tuple[int, Union[Tuple[int, int], Tuple[A, A]]], Tuple[str, Union[Tuple[str, str], Tuple[B, B]]]]
x, (y, z) = t
reveal_type(x) # E: Revealed type is 'Union[builtins.int, builtins.str]'
reveal_type(y) # E: Revealed type is 'Union[builtins.int, __main__.A, builtins.str, __main__.B]'
reveal_type(z) # E: Revealed type is 'Union[builtins.int, __main__.A, builtins.str, __main__.B]'
[builtins fixtures/tuple.pyi]
[out]

[case testUnpackUnionNoCrashOnPartialNone]
# flags: --strict-optional
from typing import Dict, Tuple, List, Any

a: Any
d: Dict[str, Tuple[List[Tuple[str, str]], str]]
x, _ = d.get(a, (None, None))

for y in x: pass # E: Item "None" of "Optional[List[Tuple[str, str]]]" has no attribute "__iter__" (not iterable)
if x:
    for s, t in x:
        reveal_type(s) # E: Revealed type is 'builtins.str'
[builtins fixtures/dict.pyi]
[out]

[case testUnpackUnionNoCrashOnPartialNone2]
# flags: --strict-optional
from typing import Dict, Tuple, List, Any

a: Any
x = None
d: Dict[str, Tuple[List[Tuple[str, str]], str]]
x, _ = d.get(a, (None, None))

for y in x: pass # E: Item "None" of "Optional[List[Tuple[str, str]]]" has no attribute "__iter__" (not iterable)
if x:
    for s, t in x:
        reveal_type(s) # E: Revealed type is 'builtins.str'
[builtins fixtures/dict.pyi]
[out]

[case testUnpackUnionNoCrashOnPartialNoneBinder]
# flags: --strict-optional
from typing import Dict, Tuple, List, Any

x: object
a: Any
d: Dict[str, Tuple[List[Tuple[str, str]], str]]
x, _ = d.get(a, (None, None))
reveal_type(x) # E: Revealed type is 'Union[builtins.list[Tuple[builtins.str, builtins.str]], None]'

if x:
    for y in x: pass
[builtins fixtures/dict.pyi]
[out]

[case testUnpackUnionNoCrashOnPartialNoneList]
# flags: --strict-optional
from typing import Dict, Tuple, List, Any

a: Any
d: Dict[str, Tuple[List[Tuple[str, str]], str]]
x, _ = d.get(a, ([], []))
reveal_type(x) # E: Revealed type is 'Union[builtins.list[Tuple[builtins.str, builtins.str]], builtins.list[<nothing>]]'

for y in x: pass
[builtins fixtures/dict.pyi]
[out]

[case testLongUnionFormatting]
from typing import Any, Generic, TypeVar, Union

T = TypeVar('T')

class ExtremelyLongTypeNameWhichIsGenericSoWeCanUseItMultipleTimes(Generic[T]):
    pass

x: Union[ExtremelyLongTypeNameWhichIsGenericSoWeCanUseItMultipleTimes[int],
         ExtremelyLongTypeNameWhichIsGenericSoWeCanUseItMultipleTimes[object],
         ExtremelyLongTypeNameWhichIsGenericSoWeCanUseItMultipleTimes[float],
         ExtremelyLongTypeNameWhichIsGenericSoWeCanUseItMultipleTimes[str],
         ExtremelyLongTypeNameWhichIsGenericSoWeCanUseItMultipleTimes[Any],
         ExtremelyLongTypeNameWhichIsGenericSoWeCanUseItMultipleTimes[bytes]]

def takes_int(arg: int) -> None: pass

takes_int(x)  # E: Argument 1 to "takes_int" has incompatible type <union: 6 items>; expected "int"

[case testRecursiveForwardReferenceInUnion]
from typing import List, Union
MYTYPE = List[Union[str, "MYTYPE"]]
[builtins fixtures/list.pyi]
[out]
main:2: error: Recursive types not fully supported yet, nested types replaced with "Any"
