-- Inferring locals/globals with simple types
-- ------------------------------------------


[case testInferSimpleGvarType]
import typing
x = A()
y = B()
x = B() # Fail
x = A()
x = y   # Fail
x = x
class A: pass
class B: pass
[out]
main:4: error: Incompatible types in assignment (expression has type "B", variable has type "A")
main:6: error: Incompatible types in assignment (expression has type "B", variable has type "A")

[case testInferSimpleLvarType]
import typing
def f() -> None:
  x = A()
  y = B()
  x = B() # Fail
  x = A()
  x = y   # Fail
  x = x
class A: pass
class B: pass
[out]
main:5: error: Incompatible types in assignment (expression has type "B", variable has type "A")
main:7: error: Incompatible types in assignment (expression has type "B", variable has type "A")

[case testLvarInitializedToVoid]
import typing
def f() -> None:
    a = g()    # E: "g" does not return a value
    #b, c = g() # "g" does not return a value TODO

def g() -> None: pass
[out]

[case testInferringLvarTypeFromArgument]
import typing
def f(a: 'A') -> None:
    b = a
    b = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    b = a
    a = b

class A: pass
class B: pass
[out]

[case testInferringLvarTypeFromGvar]

g = None # type: B

def f() -> None:
    a = g
    a = A() # E: Incompatible types in assignment (expression has type "A", variable has type "B")
    a = B()

class A: pass
class B: pass
[out]

[case testInferringImplicitDynamicTypeForLvar]
import typing
def f() -> None:
    a = g()
    None(a) # E: "None" not callable
    a.x()

def g(): pass
[out]

[case testInferringExplicitDynamicTypeForLvar]
from typing import Any
g = None # type: Any

def f(a: Any) -> None:
    b = g
    None(b) # E: "None" not callable
    a.x()
[out]


-- Inferring types of local variables with complex types
-- -----------------------------------------------------


[case testInferringTupleTypeForLvar]

def f() -> None:
    a = A(), B()
    aa = None # type: A
    bb = None # type: B
    bb = a[0] # E: Incompatible types in assignment (expression has type "A", variable has type "B")
    aa = a[1] # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    aa = a[0]
    bb = a[1]

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

[case testInferringTupleTypeForLvarWithNones]
import typing
def f() -> None:
    a = A(), None
    b = None, A()

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

[case testInferringGenericTypeForLvar]
from typing import TypeVar, Generic
T = TypeVar('T')
class A(Generic[T]): pass
a_i = None # type: A[int]
a_s = None # type: A[str]

def f() -> None:
    a_int = A() # type: A[int]
    a = a_int
    a = a_s # E: Incompatible types in assignment (expression has type "A[str]", variable has type "A[int]")
    a = a_i
[builtins fixtures/tuple.pyi]
[out]

[case testInferringFunctionTypeForLvar]
import typing
def f() -> None:
    a = g
    a(B()) # E: Argument 1 has incompatible type "B"; expected "A"
    a(A())

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

class A: pass
class B: pass
[out]

[case testInferringFunctionTypeForLvarFromTypeObject]
import typing
def f() -> None:
    a = A
    a(A()) # E: Too many arguments
    a()
    t = a # type: type

class A: pass
[out]


-- Inferring variable types in multiple definition
-- -----------------------------------------------


[case testInferringLvarTypesInMultiDef]
import typing
def f() -> None:
    a, b = A(), B()
    a = b   # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    a = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    b = A() # E: Incompatible types in assignment (expression has type "A", variable has type "B")

    a = A()
    b = B()

class A: pass
class B: pass
[out]

[case testInferringLvarTypesInTupleAssignment]
from typing import Tuple
def f() -> None:
    t = None # type: Tuple[A, B]
    a, b = t
    a = b   # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    a = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    b = A() # E: Incompatible types in assignment (expression has type "A", variable has type "B")

    a = A()
    b = B()

class A: pass
class B: pass
[out]

[case testInferringLvarTypesInNestedTupleAssignment1]
from typing import Tuple
def f() -> None:
    t = None # type: Tuple[A, B]
    a1, (a, b) = A(), t
    a = b   # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    a = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    b = A() # E: Incompatible types in assignment (expression has type "A", variable has type "B")

    a = A()
    b = B()

class A: pass
class B: pass
[out]

[case testInferringLvarTypesInNestedTupleAssignment2]
import typing
def f() -> None:
    a, (b, c) = A(), (B(), C())
    a = b   # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    a = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    b = A() # E: Incompatible types in assignment (expression has type "A", variable has type "B")
    c = A() # E: Incompatible types in assignment (expression has type "A", variable has type "C")

    a = A()
    b = B()
    c = C()

class A: pass
class B: pass
class C: pass
[out]

[case testInferringLvarTypesInNestedListAssignment]
import typing
def f() -> None:
    a, (b, c) = A(), [B(), C()]
    a = b   # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    a = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    b = A() # E: Incompatible types in assignment (expression has type "A", variable has type "B")
    c = A() # E: Incompatible types in assignment (expression has type "A", variable has type "C")

    a = A()
    b = B()
    c = C()

class A: pass
class B: pass
class C: pass
[out]

[case testInferringLvarTypesInMultiDefWithNoneTypes]
import typing
def f() -> None:
    a, b = A(), None
    c, d = None, A()

class A: pass
[out]

[case testInferringLvarTypesInNestedTupleAssignmentWithNoneTypes]
import typing
def f() -> None:
    a1, (a2, b) = A(), (A(), None)

class A: pass
[out]

[case testInferringLvarTypesInMultiDefWithInvalidTuple]
from typing import Tuple
t = None # type: Tuple[object, object, object]

def f() -> None:
    a, b = t         # Fail
    c, d, e, f = t   # Fail
    g, h, i = t
[builtins fixtures/tuple.pyi]
[out]
main:5: error: Too many values to unpack (2 expected, 3 provided)
main:6: error: Need more than 3 values to unpack (4 expected)

[case testInvalidRvalueTypeInInferredMultipleLvarDefinition]
import typing
def f() -> None:
    a, b = f   # E: 'def ()' object is not iterable
    c, d = A() # E: '__main__.A' object is not iterable
class A: pass
[builtins fixtures/for.pyi]
[out]

[case testInvalidRvalueTypeInInferredNestedTupleAssignment]
import typing
def f() -> None:
    a1, (a2, b) = A(), f   # E: 'def ()' object is not iterable
    a3, (c, d) = A(), A() # E: '__main__.A' object is not iterable
class A: pass
[builtins fixtures/for.pyi]
[out]

[case testInferringMultipleLvarDefinitionWithListRvalue]
from typing import List

class C: pass
class D: pass

def f() -> None:
    list_c = [C()]
    list_d = [D()]
    a, b = list_c
    c, d, e = list_d
    a = D() # E: Incompatible types in assignment (expression has type "D", variable has type "C")
    b = D() # E: Incompatible types in assignment (expression has type "D", variable has type "C")
    c = C() # E: Incompatible types in assignment (expression has type "C", variable has type "D")
    b = c   # E: Incompatible types in assignment (expression has type "D", variable has type "C")

    a = C()
    b = C()
    c = D()
    d = D()
    e = D()

    a = b
    c = d
    d = e
[builtins fixtures/for.pyi]
[out]

[case testInferringNestedTupleAssignmentWithListRvalue]
from typing import List

class C: pass
class D: pass

def f() -> None:
    list_c = [C()]
    list_d = [D()]
    c1, (a, b) = C(), list_c
    c2, (c, d, e) = C(), list_d
    a = D() # E: Incompatible types in assignment (expression has type "D", variable has type "C")
    b = D() # E: Incompatible types in assignment (expression has type "D", variable has type "C")
    c = C() # E: Incompatible types in assignment (expression has type "C", variable has type "D")
    b = c   # E: Incompatible types in assignment (expression has type "D", variable has type "C")

    a = C()
    b = C()
    c = D()
    d = D()
    e = D()

    a = b
    c = d
    d = e
[builtins fixtures/for.pyi]
[out]

[case testInferringMultipleLvarDefinitionWithImplicitDynamicRvalue]
import typing
def f() -> None:
    a, b = g()
    a.x
    b.x
def g(): pass

[case testInferringMultipleLvarDefinitionWithExplicitDynamicRvalue]
from typing import Any
def f(d: Any) -> None:
    a, b = d
    a.x
    b.x

[case testInferringTypesFromIterable]
from typing import Iterable
class Nums(Iterable[int]):
    def __iter__(self): pass
    def __next__(self): pass
a, b = Nums()
a = b = 1
a = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
b = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
[builtins fixtures/for.pyi]


-- Type variable inference for generic functions
-- ---------------------------------------------


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

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

a = id(a)
b = id(b)
c = id(c)

def id(a: T) -> T: pass

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

[case testInferringGenericFunctionTypeForLvar]
from typing import TypeVar
T = TypeVar('T')
def f() -> None:
    a = id
    b = None # type: int
    c = None # type: str
    b = a(c) # E: Incompatible types in assignment (expression has type "str", variable has type "int")
    b = a(b)
    c = a(c)
def id(x: T) -> T:
    return x
[out]

[case testUnderspecifiedInferenceResult]
from typing import TypeVar
T = TypeVar('T')
class A: pass
a = None # type: A

def ff() -> None:
    x = f() # E: Need type annotation for 'x'
    reveal_type(x) # E: Revealed type is 'Any'

g(None) # Ok
f()     # Ok because not used to infer local variable type
g(a)

def f() -> T: pass
def g(a: T) -> None: pass
[out]

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

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

def f(a: T, b: T) -> T: pass

class A: pass
class B(A): pass

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

taa = f(a, b) # Fail
taa = f(b, a) # Fail
tba = f(a, b) # Fail

tab = f(a, b)
tba = f(b, a)

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

class A: pass
class B: pass
[builtins fixtures/tuple.pyi]
[out]
main:9: error: Argument 2 to "f" has incompatible type "B"; expected "A"
main:10: error: Argument 1 to "f" has incompatible type "B"; expected "A"
main:11: error: Argument 1 to "f" has incompatible type "A"; expected "B"
main:11: error: Argument 2 to "f" has incompatible type "B"; expected "A"

[case testConstraintSolvingWithSimpleGenerics]
from typing import TypeVar, Generic
T = TypeVar('T')
ao = None # type: A[object]
ab = None # type: A[B]
ac = None # type: A[C]

ab = f(ao) # E: Argument 1 to "f" has incompatible type "A[object]"; expected "A[B]"
ao = f(ab) # E: Argument 1 to "f" has incompatible type "A[B]"; expected "A[object]"
ab = f(ac) # E: Argument 1 to "f" has incompatible type "A[C]"; expected "A[B]"
ab = g(ao) # E: Argument 1 to "g" has incompatible type "A[object]"; expected "A[B]"
ao = g(ab) # E: Argument 1 to "g" has incompatible type "A[B]"; expected "A[object]"

ab = f(ab)
ac = f(ac)
ao = f(ao)

ab = g(ab)
ao = g(ao)

def f(a: 'A[T]') -> 'A[T]': pass

def g(a: T) -> T: pass

class A(Generic[T]): pass
class B: pass
class C: pass

[case testConstraintSolvingFailureWithSimpleGenerics]
from typing import TypeVar, Generic
T = TypeVar('T')
ao = None # type: A[object]
ab = None # type: A[B]

f(ao, ab) # E: Cannot infer type argument 1 of "f"
f(ab, ao) # E: Cannot infer type argument 1 of "f"
f(ao, ao)
f(ab, ab)

def f(a: 'A[T]', b: 'A[T]') -> None: pass

class A(Generic[T]): pass
class B: pass

[case testTypeInferenceWithCalleeDefaultArgs]
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 = g(a, o) # E: Incompatible types in assignment (expression has type "object", variable has type "A")

o = f()
o = f(o)
a = f(a)
a = g(a)

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

class A: pass


-- Generic function inference with multiple inheritance
-- ----------------------------------------------------


[case testGenericFunctionInferenceWithMultipleInheritance]
from typing import TypeVar

class I: pass
class J: pass

class A(I, J): pass
class B(I, J): pass
class C(I): pass
class D(J): pass

T = TypeVar('T')
def f(a: T, b: T) -> T: pass
def g(x: I) -> None: pass

a = f(A(), C())
g(a)
b = f(A(), B())
g(b)
c = f(A(), D())
g(c) # E: Argument 1 to "g" has incompatible type "J"; expected "I"
d = f(D(), A())
g(d) # E: Argument 1 to "g" has incompatible type "J"; expected "I"
e = f(D(), C())
g(e) # E: Argument 1 to "g" has incompatible type "object"; expected "I"

[case testGenericFunctionInferenceWithMultipleInheritance2]
from typing import TypeVar

class I: pass
class J: pass

class A(I): pass
class B(A, J): pass
class C(I, J): pass

T = TypeVar('T')
def f(a: T, b: T) -> T: pass
def g(x: I) -> None: pass
def h(x: J) -> None: pass

a = f(B(), C())
g(a)
h(a) # E: Argument 1 to "h" has incompatible type "I"; expected "J"
b = f(C(), B())
g(b)
h(b) # E: Argument 1 to "h" has incompatible type "I"; expected "J"
c = f(A(), B())
g(a)
h(b) # E: Argument 1 to "h" has incompatible type "I"; expected "J"

[case testGenericFunctionInferenceWithMultipleInheritance3]
from typing import TypeVar

class I: pass
class J: pass
class K(J): pass

class A(K): pass
class B(A, I): pass
class C(I, J): pass

T = TypeVar('T')
def f(a: T, b: T) -> T: pass
def g(x: K) -> None: pass

a = f(B(), C())
g(a) # E: Argument 1 to "g" has incompatible type "J"; expected "K"
b = f(A(), C())
g(b) # E: Argument 1 to "g" has incompatible type "J"; expected "K"
c = f(A(), B())
g(c)

[case testPrecedenceOfFirstBaseAsInferenceResult]
from typing import TypeVar
from abc import abstractmethod, ABCMeta
T = TypeVar('T')
a, i, j = None, None, None # type: (A, I, J)

a = f(B(), C())

class I(metaclass=ABCMeta): pass
class J(metaclass=ABCMeta): pass

def f(a: T, b: T) -> T: pass

class A: pass
class B(A, I, J): pass
class C(A, I, J): pass


-- Generic function inference with function arguments
-- --------------------------------------------------


[case testNonOverloadedMapInference]
from typing import TypeVar, Callable, List
t = TypeVar('t')
s = TypeVar('s')
class A: pass
b = bool()
def f(x: bool) -> A: pass
def mymap(f: Callable[[t], s], a: List[t]) -> List[s]: pass

l = mymap(f, [b])
l = [A()]
lb = [b]
l = lb # E: Incompatible types in assignment (expression has type "List[bool]", variable has type "List[A]")
[builtins fixtures/for.pyi]

[case testGenericFunctionWithTypeTypeAsCallable]
from typing import Callable, Type, TypeVar
T = TypeVar('T')
def f(x: Callable[..., T]) -> T: return x()
class A: pass
x = None  # type: Type[A]
y = f(x)
reveal_type(y)  # E: Revealed type is '__main__.A*'

-- Generic function inference with unions
-- --------------------------------------


[case testUnionInference]
from typing import TypeVar, Union, List
T = TypeVar('T')
U = TypeVar('U')
def f(x: Union[T, int], y: T) -> T: pass
f(1, 'a')() # E: "str" not callable
f('a', 1)() # E: "object" not callable
f('a', 'a')() # E: "str" not callable
f(1, 1)() # E: "int" not callable

def g(x: Union[T, List[T]]) -> List[T]: pass
def h(x: List[str]) -> None: pass
g('a')() # E: "List[str]" not callable

# The next line is a case where there are multiple ways to satisfy a constraint
# involving a Union. Either T = List[str] or T = str would turn out to be valid,
# but mypy doesn't know how to branch on these two options (and potentially have
# to backtrack later) and defaults to T = <nothing>. The result is an
# awkward error message. Either a better error message, or simply accepting the
# call, would be preferable here.
g(['a']) # E: Argument 1 to "g" has incompatible type "List[str]"; expected "List[<nothing>]"

h(g(['a']))

def i(x: Union[List[T], List[U]], y: List[T], z: List[U]) -> None: pass
a = [1]
b = ['b']
i(a, a, b)
i(b, a, b)
i(a, b, b) # E: Argument 1 to "i" has incompatible type "List[int]"; expected "List[str]"
[builtins fixtures/list.pyi]

[case testCallableListJoinInference]
from typing import Any, Callable

def fun() -> None:
    callbacks = [
        callback1,
        callback2,
    ]

    for c in callbacks:
        call(c, 1234) # this must not fail

def callback1(i: int) -> int:
    return i
def callback2(i: int) -> str:
    return 'hello'
def call(c: Callable[[int], Any], i: int) -> None:
    c(i)
[builtins fixtures/list.pyi]
[out]

[case testCallableMeetAndJoin]
# flags: --python-version 3.6
from typing import Callable, Any, TypeVar

class A: ...
class B(A): ...

def f(c: Callable[[B], int]) -> None: ...

c: Callable[[A], int]
d: Callable[[B], int]

lst = [c, d]
reveal_type(lst) # E: Revealed type is 'builtins.list[def (__main__.B) -> builtins.int]'

T = TypeVar('T')
def meet_test(x: Callable[[T], int], y: Callable[[T], int]) -> T: ...

CA = Callable[[A], A]
CB = Callable[[B], B]

ca: Callable[[CA], int]
cb: Callable[[CB], int]
reveal_type(meet_test(ca, cb)) # E: Revealed type is 'def (__main__.A) -> __main__.B'
[builtins fixtures/list.pyi]
[out]

[case testUnionInferenceWithTypeVarValues]
from typing import TypeVar, Union
AnyStr = TypeVar('AnyStr', bytes, str)
def f(x: Union[AnyStr, int], *a: AnyStr) -> None: pass
f('foo')
f('foo', 'bar')
f('foo', b'bar') # E: Value of type variable "AnyStr" of "f" cannot be "object"
f(1)
f(1, 'foo')
f(1, 'foo', b'bar') # E: Value of type variable "AnyStr" of "f" cannot be "object"
[builtins fixtures/primitives.pyi]


[case testUnionTwoPassInference-skip]
from typing import TypeVar, Union, List
T = TypeVar('T')
U = TypeVar('U')
def j(x: Union[List[T], List[U]], y: List[T]) -> List[U]: pass

a = [1]
b = ['b']
# We could infer: Since List[str] <: List[T], we must have T = str.
# Then since List[int] <: Union[List[str], List[U]], and List[int] is
# not a subtype of List[str], we must have U = int.
# This is not currently implemented.
j(a, b)
[builtins fixtures/list.pyi]


[case testUnionContext]
from typing import TypeVar, Union, List
T = TypeVar('T')
def f() -> List[T]: pass
d1 = f() # type: Union[List[int], str]
d2 = f() # type: Union[int, str] # E: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "Union[int, str]")
def g(x: T) -> List[T]: pass
d3 = g(1) # type: Union[List[int], List[str]]
[builtins fixtures/list.pyi]


[case testGenericFunctionSubtypingWithUnions]
from typing import TypeVar, Union, List
T = TypeVar('T')
S = TypeVar('S')
def k1(x: int, y: List[T]) -> List[Union[T, int]]: pass
def k2(x: S, y: List[T]) -> List[Union[T, int]]: pass
a = k2
a = k2
a = k1 # E: Incompatible types in assignment (expression has type "Callable[[int, List[T]], List[Union[T, int]]]", variable has type "Callable[[S, List[T]], List[Union[T, int]]]")
b = k1
b = k1
b = k2
[builtins fixtures/list.pyi]

[case testAmbiguousUnionContextAndMultipleInheritance]
from typing import TypeVar, Union, Generic

_T = TypeVar('_T')

class T(Generic[_T]): pass
class U(Generic[_T]): pass
class V(T[_T], U[_T]): pass

def wait_for(fut: Union[T[_T], U[_T]]) -> _T: ...

reveal_type(wait_for(V[str]()))  # E: Revealed type is 'builtins.str*'

[case testAmbiguousUnionContextAndMultipleInheritance2]
from typing import TypeVar, Union, Generic

_T = TypeVar('_T')
_S = TypeVar('_S')

class T(Generic[_T, _S]): pass
class U(Generic[_T, _S]): pass
class V(T[_T, _S], U[_T, _S]): pass

def wait_for(fut: Union[T[_T, _S], U[_T, _S]]) -> T[_T, _S]: ...

reveal_type(wait_for(V[int, str]()))  \
    # E: Revealed type is '__main__.T[builtins.int*, builtins.str*]'


-- Literal expressions
-- -------------------


[case testDictLiteral]
from typing import Dict
class A: pass
class B: pass
def d_ab() -> Dict[A, B]: return {}
def d_aa() -> Dict[A, A]: return {}
a, b = None, None # type: (A, B)
d = {a:b}
d = d_ab()
d = d_aa() # E: Incompatible types in assignment (expression has type "Dict[A, A]", variable has type "Dict[A, B]")
[builtins fixtures/dict.pyi]

[case testSetLiteral]
from typing import Any, Set
a, x = None, None # type: (int, Any)
def s_i() -> Set[int]: return set()
def s_s() -> Set[str]: return set()
s = {a}
s = {x}
s = s_i()
s = s_s() # E: Incompatible types in assignment (expression has type "Set[str]", variable has type "Set[int]")
[builtins fixtures/set.pyi]

[case testSetWithStarExpr]
s = {1, 2, *(3, 4)}
t = {1, 2, *s}
reveal_type(s)  # E: Revealed type is 'builtins.set[builtins.int*]'
reveal_type(t)  # E: Revealed type is 'builtins.set[builtins.int*]'
[builtins fixtures/set.pyi]

[case testListLiteralWithFunctionsErasesNames]
def f1(x: int) -> int: ...
def g1(y: int) -> int: ...
def h1(x: int) -> int: ...

list_1 = [f1, g1]
list_2 = [f1, h1]
reveal_type(list_1)  # E: Revealed type is 'builtins.list[def (builtins.int) -> builtins.int]'
reveal_type(list_2)  # E: Revealed type is 'builtins.list[def (x: builtins.int) -> builtins.int]'

def f2(x: int, z: str) -> int: ...
def g2(y: int, z: str) -> int: ...
def h2(x: int, z: str) -> int: ...

list_3 = [f2, g2]
list_4 = [f2, h2]
reveal_type(list_3)  # E: Revealed type is 'builtins.list[def (builtins.int, z: builtins.str) -> builtins.int]'
reveal_type(list_4)  # E: Revealed type is 'builtins.list[def (x: builtins.int, z: builtins.str) -> builtins.int]'
[builtins fixtures/list.pyi]

[case testListLiteralWithSimilarFunctionsErasesName]
from typing import Union

class A: ...
class B(A): ...
class C: ...
class D: ...

def f(x: Union[A, C], y: B) -> A: ...
def g(z: Union[B, D], y: A) -> B: ...
def h(x: Union[B, D], y: A) -> B: ...

list_1 = [f, g]
list_2 = [f, h]
reveal_type(list_1)  # E: Revealed type is 'builtins.list[def (__main__.B, y: __main__.B) -> __main__.A]'
reveal_type(list_2)  # E: Revealed type is 'builtins.list[def (x: __main__.B, y: __main__.B) -> __main__.A]'
[builtins fixtures/list.pyi]

[case testListLiteralWithNameOnlyArgsDoesNotEraseNames]
def f(*, x: int) -> int: ...
def g(*, y: int) -> int: ...
def h(*, x: int) -> int: ...

list_1 = [f, g]  # E: List item 0 has incompatible type "Callable[[NamedArg(int, 'x')], int]"; expected "Callable[[NamedArg(int, 'y')], int]"
list_2 = [f, h]
[builtins fixtures/list.pyi]


-- For statements
-- --------------


[case testInferenceOfFor1]
a, b = None, None # type: (A, B)

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

for y in []: # E: Need type annotation for 'y'
    a = y # E: Cannot determine type of 'y'
    reveal_type(y)  # E: Revealed type is 'Any' \
                    # E: Cannot determine type of 'y'

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

[case testInferenceOfFor2]

a, b, c = None, None, None # type: (A, B, C)
for x, (y, z) in [(A(), (B(), C()))]:
    b = x # Fail
    c = y # Fail
    a = z # Fail
    a = x
    b = y
    c = z
for xx, yy, zz in [(A(), B())]: # Fail
    pass
for xx, (yy, zz) in [(A(), B())]: # Fail
    pass
for xxx, yyy in [(None, None)]:
    pass

class A: pass
class B: pass
class C: pass
[builtins fixtures/for.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 "C")
main:6: error: Incompatible types in assignment (expression has type "C", variable has type "A")
main:10: error: Need more than 2 values to unpack (3 expected)
main:12: error: '__main__.B' object is not iterable

[case testInferenceOfFor3]

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

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

for e, f in [[]]:  # E: Need type annotation for 'e' \
                   # E: Need type annotation for 'f'
    reveal_type(e)  # E: Revealed type is 'Any' \
                    # E: Cannot determine type of 'e'
    reveal_type(f)  # E: Revealed type is 'Any' \
                    # E: Cannot determine type of 'f'

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

[case testForStatementInferenceWithVoid]
import typing
for x in f(): # E: "f" does not return a value
    pass
def f() -> None: pass
[builtins fixtures/for.pyi]

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

[case testReusingInferredForIndex2]
import typing
def f() -> None:
    for a in [A()]: pass
    a = A()
    a = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
    for a in []: pass
    a = A()
    a = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
class A: pass
class B: pass
[builtins fixtures/for.pyi]
[out]


-- Regression tests
-- ----------------


[case testMultipleAssignmentWithPartialDefinition]

a = None # type: A
x, a = a, a
x = a
a = x
x = object() # E: Incompatible types in assignment (expression has type "object", variable has type "A")
a = object() # E: Incompatible types in assignment (expression has type "object", variable has type "A")
class A: pass

[case testMultipleAssignmentWithPartialDefinition2]

a = None # type: A
a, x = [a, a]
x = a
a = x
x = object() # E: Incompatible types in assignment (expression has type "object", variable has type "A")
a = object() # E: Incompatible types in assignment (expression has type "object", variable has type "A")
class A: pass
[builtins fixtures/for.pyi]

[case testMultipleAssignmentWithPartialDefinition3]
from typing import Any, cast
a = None # type: A
x, a = cast(Any, a)
x = a
a = x
x = object()
a = object() # E: Incompatible types in assignment (expression has type "object", variable has type "A")
class A: pass

[case testInferGlobalDefinedInBlock]
import typing
if A:
    a = A()
    a = A()
    a = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
class A: pass
class B: pass

[case testAssigningAnyStrToNone]
from typing import Tuple, TypeVar
AnyStr = TypeVar('AnyStr', str, bytes)

def f(x: AnyStr) -> Tuple[AnyStr]: pass
x = None
(x,) = f('')
reveal_type(x)  # E: Revealed type is 'builtins.str'


-- Inferring attribute types
-- -------------------------


[case testInferAttributeType]
import typing
class A:
    a = B()
class B: pass

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

[case testInferAttributeTypeAndAssignInInit]
import typing
class A:
    a = B()
    def __init__(self) -> None:
        self.a = A() # E: Incompatible types in assignment (expression has type "A", variable has type "B")
        self.a = B()
class B: pass
[out]

[case testInferAttributeInInit]
import typing
class B: pass
class A:
    def __init__(self) -> None:
        self.a = A()
        self.b = B()
a = A()
a.a = A()
a.b = B()
a.a = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
a.b = A() # E: Incompatible types in assignment (expression has type "A", variable has type "B")

[case testInferAttributeInInitUsingChainedAssignment]
import typing
class B: pass
class A:
    def __init__(self) -> None:
        self.a = self.b = A()
a = A()
a.a = A()
a.b = A()
a.a = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A")
a.b = B() # E: Incompatible types in assignment (expression has type "B", variable has type "A")


-- Lambdas
-- -------


[case testInferLambdaType]
from typing import List, Callable
li = [1]
l = lambda: li
f1 = l # type: Callable[[], List[int]]
f2 = l # type: Callable[[], List[str]] # E: Incompatible types in assignment (expression has type "Callable[[], List[int]]", variable has type "Callable[[], List[str]]")
[builtins fixtures/list.pyi]

[case testInferLambdaType2]
from typing import List, Callable
l = lambda: [B()]
f1 = l # type: Callable[[], List[B]]
f2 = l # type: Callable[[], List[A]] # E: Incompatible types in assignment (expression has type "Callable[[], List[B]]", variable has type "Callable[[], List[A]]")

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

[case testUninferableLambda]
from typing import TypeVar, Callable
X = TypeVar('X')
def f(x: Callable[[X], X]) -> X: pass
y = f(lambda x: x) # E: Cannot infer type argument 1 of "f"

[case testUninferableLambdaWithTypeError]
from typing import TypeVar, Callable
X = TypeVar('X')
def f(x: Callable[[X], X], y: str) -> X: pass
y = f(lambda x: x, 1) # Fail
[out]
main:4: error: Cannot infer type argument 1 of "f"
main:4: error: Argument 2 to "f" has incompatible type "int"; expected "str"

[case testInferLambdaNone]
from typing import Callable
def f(x: Callable[[], None]) -> None: pass
def g(x: Callable[[], int]) -> None: pass
a = lambda: None
f(a)
g(a)
b = lambda: None  # type: Callable[[], None]
f(b)
g(b)

[case testLambdaDefaultContext]
# flags: --strict-optional
from typing import Callable
def f(a: Callable[..., None] = lambda *a, **k: None):
    pass

def g(a: Callable[..., None] = lambda *a, **k: 1):  # E: Incompatible default for argument "a" (default has type "Callable[[VarArg(Any), KwArg(Any)], int]", argument has type "Callable[..., None]")
    pass
[builtins fixtures/dict.pyi]

[case testLambdaVarargContext]
# Should not crash
from typing import Callable
def f(a: Callable[[int, int, int], int] = lambda *a, **k: 1):
    pass
[builtins fixtures/dict.pyi]

[case testLambdaDeferredSpecialCase]
from typing import Callable

class A:
    def f(self) -> None:
        h(lambda: self.x)

    def g(self) -> None:
        self.x = 1

def h(x: Callable[[], int]) -> None:
    pass


-- Boolean operators
-- -----------------


[case testOrOperationWithGenericOperands]
from typing import List
a = None # type: List[A]
o = None # type: List[object]
a2 = a or []
a = a2
a2 = o # E: Incompatible types in assignment (expression has type "List[object]", variable has type "List[A]")
class A: pass
[builtins fixtures/list.pyi]


-- Accessing variable before its type has been inferred
-- ----------------------------------------------------


[case testAccessGlobalVarBeforeItsTypeIsAvailable]
import typing
x.y  # E: Cannot determine type of 'x'
x = object()
x.y  # E: "object" has no attribute "y"

[case testAccessDataAttributeBeforeItsTypeIsAvailable]

a = None # type: A
a.x.y  # E: Cannot determine type of 'x'
class A:
   def __init__(self) -> None:
       self.x = object()
a.x.y  # E: "object" has no attribute "y"


-- Ducktype declarations
-- ---------------------


[case testListWithDucktypeCompatibility]
from typing import List, _promote
class A: pass
@_promote(A)
class B: pass
a = None  # type: List[A]
x1 = [A(), B()]
x2 = [B(), A()]
x3 = [B(), B()]
a = x1
a = x2
a = x3 # E: Incompatible types in assignment (expression has type "List[B]", variable has type "List[A]")
[builtins fixtures/list.pyi]

[case testListWithDucktypeCompatibilityAndTransitivity]
from typing import List, _promote
class A: pass
@_promote(A)
class B: pass
@_promote(B)
class C: pass
a = None  # type: List[A]
x1 = [A(), C()]
x2 = [C(), A()]
x3 = [B(), C()]
a = x1
a = x2
a = x3 # E: Incompatible types in assignment (expression has type "List[B]", variable has type "List[A]")
[builtins fixtures/list.pyi]


-- Inferring type of variable when initialized to an empty collection
-- ------------------------------------------------------------------


[case testInferListInitializedToEmpty]
a = []
a.append(1)
a.append('')  # E: Argument 1 to "append" of "list" has incompatible type "str"; expected "int"
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyUsingUpdate]
a = []
a.extend([''])
a.append(0)  # E: Argument 1 to "append" of "list" has incompatible type "int"; expected "str"
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyAndNotAnnotated]
a = []  # E: Need type annotation for 'a'
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyAndReadBeforeAppend]
a = []  # E: Need type annotation for 'a'
if a: pass
a.xyz
a.append('')
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyAndIncompleteTypeInAppend]
a = [] # E: Need type annotation for 'a'
a.append([])
a()
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyAndMultipleAssignment]
a, b = [], []
a.append(1)
b.append('')
a() # E: "List[int]" not callable
b() # E: "List[str]" not callable
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyInFunction]
def f() -> None:
   a = []
   a.append(1)
   a.append('')  # E: Argument 1 to "append" of "list" has incompatible type "str"; expected "int"
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyAndNotAnnotatedInFunction]
def f() -> None:
    a = []  # E: Need type annotation for 'a'

def g() -> None: pass

a = []
a.append(1)
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyAndReadBeforeAppendInFunction]
def f() -> None:
    a = []  # E: Need type annotation for 'a'
    if a: pass
    a.xyz
    a.append('')
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyInClassBody]
class A:
   a = []
   a.append(1)
   a.append('')  # E: Argument 1 to "append" of "list" has incompatible type "str"; expected "int"
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyAndNotAnnotatedInClassBody]
class A:
    a = []  # E: Need type annotation for 'a'

class B:
    a = []
    a.append(1)
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyInMethod]
class A:
    def f(self) -> None:
        a = []
        a.append(1)
        a.append('')  # E: Argument 1 to "append" of "list" has incompatible type "str"; expected "int"
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyAndNotAnnotatedInMethod]
class A:
    def f(self) -> None:
        a = []  # E: Need type annotation for 'a'
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyInMethodViaAttribute]
class A:
    def f(self) -> None:
        # Attributes aren't supported right now.
        self.a = [] # E: Need type annotation for 'a'
        self.a.append(1)
        self.a.append('')
[builtins fixtures/list.pyi]
[out]

[case testInferListInitializedToEmptyInClassBodyAndOverriden]
from typing import List

class A:
    def __init__(self) -> None:
        self.x = [] # E: Need type annotation for 'x'

class B(A):
    @property
    def x(self) -> List[int]:
        return [123]
[builtins fixtures/list.pyi]
[out]

[case testInferSetInitializedToEmpty]
a = set()
a.add(1)
a.add('')  # E: Argument 1 to "add" of "set" has incompatible type "str"; expected "int"
[builtins fixtures/set.pyi]
[out]

[case testInferSetInitializedToEmptyUsingDiscard]
a = set()
a.discard('')
a.add(0)  # E: Argument 1 to "add" of "set" has incompatible type "int"; expected "str"
[builtins fixtures/set.pyi]
[out]

[case testInferSetInitializedToEmptyUsingUpdate]
a = set()
a.update({0})
a.add('')  # E: Argument 1 to "add" of "set" has incompatible type "str"; expected "int"
[builtins fixtures/set.pyi]
[out]

[case testInferDictInitializedToEmpty]
a = {}
a[1] = ''
a() # E: "Dict[int, str]" not callable
[builtins fixtures/dict.pyi]
[out]

[case testInferDictInitializedToEmptyUsingUpdate]
a = {}
a.update({'': 42})
a() # E: "Dict[str, int]" not callable
[builtins fixtures/dict.pyi]
[out]

[case testInferDictInitializedToEmptyUsingUpdateError]
a = {}  # E: Need type annotation for 'a'
a.update([1, 2])
a()
[builtins fixtures/dict.pyi]
[out]

[case testInferDictInitializedToEmptyAndIncompleteTypeInUpdate]
a = {} # E: Need type annotation for 'a'
a[1] = {}
b = {} # E: Need type annotation for 'b'
b[{}] = 1
[builtins fixtures/dict.pyi]
[out]

[case testInferDictInitializedToEmptyAndUpdatedFromMethod]
map = {}
def add() -> None:
    map[1] = 2
[builtins fixtures/dict.pyi]

[case testInferDictInitializedToEmptyAndUpdatedFromMethodUnannotated]
map = {}
def add():
    map[1] = 2
[builtins fixtures/dict.pyi]

[case testSpecialCaseEmptyListInitialization]
def f(blocks: Any): # E: Name 'Any' is not defined
    to_process = [] # E: Need type annotation for 'to_process'
    to_process = list(blocks)
[builtins fixtures/list.pyi]
[out]

[case testSpecialCaseEmptyListInitialization2]
def f(blocks: object):
    to_process = [] # E: Need type annotation for 'to_process'
    to_process = list(blocks) # E: No overload variant of "list" matches argument type "object" \
                              # N: Possible overload variant: \
                              # N:     def [T] __init__(self, x: Iterable[T]) -> List[T] \
                              # N:     <1 more non-matching overload not shown>
[builtins fixtures/list.pyi]
[out]


-- Inferring types of variables first initialized to None (partial types)
-- ----------------------------------------------------------------------


[case testLocalVariablePartiallyInitializedToNone]
def f() -> None:
    if object():
        x = None
    else:
        x = 1
    x() # E: "int" not callable
[out]

[case testLocalVariablePartiallyTwiceInitializedToNone]
def f() -> None:
    if object():
        x = None
    elif object():
        x = None
    else:
        x = 1
    x() # E: "int" not callable
[out]

[case testLvarInitializedToNoneWithoutType]
import typing
def f() -> None:
    a = None
    a.x() # E: "None" has no attribute "x"
[out]

[case testGvarPartiallyInitializedToNone]
x = None
if object():
    x = 1
x() # E: "int" not callable

[case testPartiallyInitializedToNoneAndThenToPartialList]
x = None
if object():
    # Promote from partial None to partial list.
    x = []
    x.append(1)
x.append('') # E: Argument 1 to "append" of "list" has incompatible type "str"; expected "int"
[builtins fixtures/list.pyi]

[case testPartiallyInitializedToNoneAndThenReadPartialList]
x = None
if object():
    # Promote from partial None to partial list.
    x = []  # E: Need type annotation for 'x'
    x
[builtins fixtures/list.pyi]

[case testPartiallyInitializedToNoneAndPartialListAndLeftPartial]
def f() -> None:
    x = None
    if object():
        # Promote from partial None to partial list.
        x = []  # E: Need type annotation for 'x'
[builtins fixtures/list.pyi]
[out]

[case testPartiallyInitializedToNoneAndThenToIncompleteType-skip]
# TODO(ddfisher): fix partial type bug and re-enable
from typing import TypeVar,  Dict
T = TypeVar('T')
def f(*x: T) -> Dict[int, T]: pass
x = None  # E: Need type annotation for 'x'
if object():
    x = f()
[builtins fixtures/dict.pyi]

[case testPartiallyInitializedVariableDoesNotEscapeScope1]
def f() -> None:
    x = None
    reveal_type(x)  # E: Revealed type is 'None'
x = 1
[out]

[case testPartiallyInitializedVariableDoesNotEscapeScope2]
x = None
def f() -> None:
    x = None
    x = 1
x()  # E: "None" not callable

[case testAttributePartiallyInitializedToNone]
class A:
    def f(self) -> None:
        self.x = None
        self.x = 1
        self.x() # E: "int" not callable
[out]

[case testAttributePartiallyInitializedToNoneWithMissingAnnotation]
class A:
    def f(self) -> None:
        self.x = None

    def g(self) -> None:
        self.x = 1
        self.x()
[out]
main:6: error: Incompatible types in assignment (expression has type "int", variable has type "None")
main:7: error: "None" not callable

[case testGlobalInitializedToNoneSetFromFunction]
a = None
def f():
    global a
    a = 42
[out]

[case testGlobalInitializedToNoneSetFromMethod]
a = None
class C:
    def m(self):
        global a
        a = 42
[out]

-- More partial type errors
-- ------------------------

[case testPartialTypeErrorSpecialCase1]
# This used to crash.
class A:
    x = None
    def f(self) -> None:
        for a in self.x:
            pass
[builtins fixtures/for.pyi]
[out]
main:5: error: "None" has no attribute "__iter__" (not iterable)

[case testPartialTypeErrorSpecialCase2]
# This used to crash.
class A:
    x = []
    def f(self) -> None:
        for a in self.x:
            pass
[builtins fixtures/for.pyi]
[out]
main:3: error: Need type annotation for 'x'

[case testPartialTypeErrorSpecialCase3]
class A:
    x = None
    def f(self) -> None:
        for a in A.x:
            pass
[builtins fixtures/for.pyi]
[out]
main:4: error: "None" has no attribute "__iter__" (not iterable)


-- Multipass
-- ---------


[case testMultipassAndAccessVariableBeforeDefinition]
def f() -> None:
    y = x
    y() # E: "int" not callable
x = 1
[out]

[case testMultipassAndAccessInstanceVariableBeforeDefinition]
class A:
    def f(self) -> None:
        y = self.x
        y() # E: "int" not callable

    def g(self) -> None:
        self.x = 1
[out]

[case testMultipassAndTopLevelVariable]
y = x # E: Cannot determine type of 'x'
y()
x = 1+0
[out]

[case testMultipassAndDecoratedMethod]
from typing import Callable, TypeVar

T = TypeVar('T')

class A:
    def f(self) -> None:
        self.g() # E: Too few arguments for "g" of "A"
        self.g(1)
    @dec
    def g(self, x: str) -> None: pass

def dec(f: Callable[[A, str], T]) -> Callable[[A, int], T]: pass
[out]

[case testMultipassAndDefineAttributeBasedOnNotReadyAttribute]
class A:
    def f(self) -> None:
        self.y = self.x

    def g(self) -> None:
        self.x = 1

    def h(self) -> None:
        self.y() # E: "int" not callable
[out]

[case testMultipassAndDefineAttributeBasedOnNotReadyAttribute2]
class A:
    def f(self) -> None:
        self.y = self.x
        self.z = self.y
        self.z() # E
        self.y() # E

    def g(self) -> None:
        self.x = 1

    def h(self) -> None:
        self.y() # E
[out]
main:5: error: "int" not callable
main:6: error: "int" not callable
main:12: error: "int" not callable

[case testMultipassAndPartialTypes]
def f() -> None:
    x = []
    y
    x.append(1)
    x.append('') # E: Argument 1 to "append" of "list" has incompatible type "str"; expected "int"
    x.append(y) # E: Argument 1 to "append" of "list" has incompatible type "str"; expected "int"
y = ''
[builtins fixtures/list.pyi]
[out]

[case testMultipassAndPartialTypes2]
s = ''
n = 0
def f() -> None:
    global s, n
    x = []
    x.append(y)
    s = x[0]
    n = x[0] # E: Incompatible types in assignment (expression has type "str", variable has type "int")
    x.append(1) # E: Argument 1 to "append" of "list" has incompatible type "int"; expected "str"
y = ''
[builtins fixtures/list.pyi]
[out]

[case testMultipassAndPartialTypes3]
from typing import Dict
def g(d: Dict[str, int]) -> None: pass
def f() -> None:
    x = {}
    x[1] = y
    g(x) # E: Argument 1 to "g" has incompatible type "Dict[int, str]"; expected "Dict[str, int]"
    x[1] = 1 # E: Incompatible types in assignment (expression has type "int", target has type "str")
    x[1] = ''
y = ''
[builtins fixtures/dict.pyi]
[out]

[case testMultipassAndPartialTypes4]
from typing import Dict
def g(d: Dict[str, int]) -> None: pass
def f() -> None:
    x = {}
    y
    x[1] = 1
    g(x) # E: Argument 1 to "g" has incompatible type "Dict[int, int]"; expected "Dict[str, int]"
y = ''
[builtins fixtures/dict.pyi]
[out]

[case testMultipassAndCircularDependency]
class A:
    def f(self) -> None:
        self.x = self.y # E: Cannot determine type of 'y'

    def g(self) -> None:
        self.y = self.x
[out]

[case testMultipassAndPartialTypesSpecialCase1]
def f() -> None:
    y = o
    x = []
    x.append(y)
    x() # E: "List[int]" not callable
o = 1
[builtins fixtures/list.pyi]
[out]

[case testMultipassAndPartialTypesSpecialCase2]
def f() -> None:
    y = o
    x = {}
    x[''] = y
    x() # E: "Dict[str, int]" not callable
o = 1
[builtins fixtures/dict.pyi]
[out]

[case testMultipassAndPartialTypesSpecialCase3]
def f() -> None:
    x = {} # E: Need type annotation for 'x'
    y = o
    z = {} # E: Need type annotation for 'z'
o = 1
[builtins fixtures/dict.pyi]
[out]

[case testMultipassAndPartialTypesSpecialCase4]
def f() -> None:
    y = o
    x = None
    x = y
    x() # E: "int" not callable
o = 1
[out]

[case testMultipassAndPartialTypesSpecialCase5]
def f() -> None:
    x = None
    y = o
    x = y
    x() # E: "int" not callable
o = 1
[out]

[case testMultipassAndClassAttribute]
class S:
    def foo(self) -> int:
        return R.X

class R:
    X = 2

[case testMultipassAndMultipleFiles]
import m
def f() -> None:
    x()
x = 0
[file m.py]
def g() -> None:
    y()
y = 0
[out]
tmp/m.py:2: error: "int" not callable
main:3: error: "int" not callable

[case testForwardReferenceToDecoratedClassMethod]
from typing import TypeVar, Callable

T = TypeVar('T')
def dec() -> Callable[[T], T]: pass

A.g  # E: Cannot determine type of 'g'

class A:
    @classmethod
    def f(cls) -> None:
        reveal_type(cls.g)  # E: Revealed type is 'def (x: builtins.str)'

    @classmethod
    @dec()
    def g(cls, x: str) -> None:
        pass

    @classmethod
    def h(cls) -> None:
        reveal_type(cls.g)  # E: Revealed type is 'def (x: builtins.str)'

reveal_type(A.g)  # E: Revealed type is 'def (x: builtins.str)'
[builtins fixtures/classmethod.pyi]


-- Tests for special cases of unification
-- --------------------------------------


[case testUnificationRedundantUnion]
from typing import Union
a = None  # type: Union[int, str]
b = None  # type: Union[str, tuple]
def f(): pass
def g(x: Union[int, str]): pass
c = a if f() else b
g(c) # E: Argument 1 to "g" has incompatible type "Union[int, str, tuple]"; expected "Union[int, str]"

[case testUnificationMultipleInheritance]
class A: pass
class B:
    def foo(self): pass
class C(A, B): pass
def f(): pass
a1 = B() if f() else C()
a1.foo()
a2 = C() if f() else B()
a2.foo()

[case testUnificationMultipleInheritanceAmbiguous]
# Show that join_instances_via_supertype() breaks ties using the first base class.
class A1: pass
class B1:
    def foo1(self): pass
class C1(A1, B1): pass

class A2: pass
class B2:
    def foo2(self): pass
class C2(A2, B2): pass

class D1(C1, C2): pass
class D2(C2, C1): pass

def f(): pass

a1 = D1() if f() else D2()
a1.foo1()
a2 = D2() if f() else D1()
a2.foo2()

[case testUnificationEmptyListLeft]
def f(): pass
a = [] if f() else [0]
a() # E: "List[int]" not callable
[builtins fixtures/list.pyi]

[case testUnificationEmptyListRight]
def f(): pass
a = [0] if f() else []
a() # E: "List[int]" not callable
[builtins fixtures/list.pyi]

[case testUnificationEmptyListLeftInContext]
from typing import List
def f(): pass
a = [] if f() else [0] # type: List[int]
a() # E: "List[int]" not callable
[builtins fixtures/list.pyi]

[case testUnificationEmptyListRightInContext]
# TODO Find an example that really needs the context
from typing import List
def f(): pass
a = [0] if f() else [] # type: List[int]
a() # E: "List[int]" not callable
[builtins fixtures/list.pyi]

[case testUnificationEmptySetLeft]
def f(): pass
a = set() if f() else {0}
a() # E: "Set[int]" not callable
[builtins fixtures/set.pyi]

[case testUnificationEmptyDictLeft]
def f(): pass
a = {} if f() else {0: 0}
a() # E: "Dict[int, int]" not callable
[builtins fixtures/dict.pyi]

[case testUnificationEmptyDictRight]
def f(): pass
a = {0: 0} if f() else {}
a() # E: "Dict[int, int]" not callable
[builtins fixtures/dict.pyi]

[case testUnificationDictWithEmptyListLeft]
def f(): pass
a = {0: []} if f() else {0: [0]}
a() # E: "Dict[int, List[int]]" not callable
[builtins fixtures/dict.pyi]

[case testUnificationDictWithEmptyListRight]
def f(): pass
a = {0: [0]} if f() else {0: []}
a() # E: "Dict[int, List[int]]" not callable
[builtins fixtures/dict.pyi]

[case testMisguidedSetItem]
from typing import Generic, Sequence, TypeVar
T = TypeVar('T')
class C(Sequence[T], Generic[T]): pass
C[0] = 0
[out]
main:4: error: Type expected within [...]
main:4: error: Unsupported target for indexed assignment

[case testNoCrashOnPartialMember]
class C:
    x = None
    def __init__(self) -> None:
        self.x = []  # E: Need type annotation for 'x'
[builtins fixtures/list.pyi]
[out]

[case testNoCrashOnPartialVariable]
from typing import Tuple, TypeVar
T = TypeVar('T', bound=str)

def f(x: T) -> Tuple[T]:
    ...
x = None
(x,) = f('')
reveal_type(x) # E: Revealed type is 'builtins.str'
[out]

[case testNoCrashOnPartialVariable2]
from typing import Tuple, TypeVar
T = TypeVar('T', bound=str)

def f() -> Tuple[T]:
    ...
x = None
(x,) = f()
[out]

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

def f(x: T) -> Tuple[T, T]:
    ...
x = None
(x, x) = f('')
reveal_type(x) # E: Revealed type is 'builtins.str'
[out]

[case testInferenceNestedTuplesFromGenericIterable]
from typing import Tuple, TypeVar

T = TypeVar('T')

def make_tuple(elem: T) -> Tuple[T]:
    return (elem,)

def main() -> None:
    ((a, b),) = make_tuple((1, 2))
    reveal_type(a) # E: Revealed type is 'builtins.int'
    reveal_type(b) # E: Revealed type is 'builtins.int'
[builtins fixtures/tuple.pyi]
[out]

[case testDontMarkUnreachableAfterInferenceUninhabited]
from typing import TypeVar
T = TypeVar('T')
def f() -> T: pass

class C:
    x = f() # E: Need type annotation for 'x'
    def m(self) -> str:
        return 42 # E: Incompatible return value type (got "int", expected "str")

if bool():
    f()
    1() # E: "int" not callable
[builtins fixtures/list.pyi]
[out]

[case testDontMarkUnreachableAfterInferenceUninhabited2]
# flags: --strict-optional
from typing import TypeVar, Optional
T = TypeVar('T')
def f(x: Optional[T] = None) -> T: pass

class C:
    x = f() # E: Need type annotation for 'x'
    def m(self) -> str:
        return 42 # E: Incompatible return value type (got "int", expected "str")

if bool():
    f()
    1() # E: "int" not callable
[builtins fixtures/list.pyi]
[out]

[case testDontMarkUnreachableAfterInferenceUninhabited3]
from typing import TypeVar, List
T = TypeVar('T')
def f(x: List[T]) -> T: pass

class C:
    x = f([]) # E: Need type annotation for 'x'
    def m(self) -> str:
        return 42 # E: Incompatible return value type (got "int", expected "str")

if bool():
    f([])
    1() # E: "int" not callable
[builtins fixtures/list.pyi]
[out]


-- --local-partial-types
-- ---------------------


[case testLocalPartialTypesWithGlobalInitializedToNone]
# flags: --local-partial-types
x = None # E: Need type annotation for 'x'

def f() -> None:
    global x
    x = 1

# TODO: "Any" could be a better type here to avoid multiple error messages
reveal_type(x) # E: Revealed type is 'None'

[case testLocalPartialTypesWithGlobalInitializedToNone2]
# flags: --local-partial-types
x = None # E: Need type annotation for 'x'

def f():
    global x
    x = 1

# TODO: "Any" could be a better type here to avoid multiple error messages
reveal_type(x) # E: Revealed type is 'None'

[case testLocalPartialTypesWithGlobalInitializedToNone3]
# flags: --local-partial-types --no-strict-optional
x = None

def f() -> None:
    global x
    x = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "str")

x = ''
reveal_type(x) # E: Revealed type is 'builtins.str'

[case testLocalPartialTypesWithGlobalInitializedToNoneStrictOptional]
# flags: --local-partial-types --strict-optional
x = None

def f() -> None:
    global x
    x = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "Optional[str]")

x = ''
def g() -> None:
    reveal_type(x) # E: Revealed type is 'Union[builtins.str, None]'

[case testLocalPartialTypesWithGlobalInitializedToNone4]
# flags: --local-partial-types --no-strict-optional
a = None

def f() -> None:
    reveal_type(a)  # E: Revealed type is 'builtins.str'

# TODO: This should probably be 'builtins.str', since there could be a
#     call that causes a non-None value to be assigned
reveal_type(a)  # E: Revealed type is 'None'
a = ''
reveal_type(a)  # E: Revealed type is 'builtins.str'
[builtins fixtures/list.pyi]

[case testLocalPartialTypesWithClassAttributeInitializedToNone]
# flags: --local-partial-types
class A:
    x = None # E: Need type annotation for 'x'

    def f(self) -> None:
        self.x = 1

[case testLocalPartialTypesWithClassAttributeInitializedToEmptyDict]
# flags: --local-partial-types
class A:
    x = {}  # E: Need type annotation for 'x'

    def f(self) -> None:
        self.x[0] = ''

reveal_type(A().x)  # E: Revealed type is 'Any'
reveal_type(A.x)  # E: Revealed type is 'Any'
[builtins fixtures/dict.pyi]

[case testLocalPartialTypesWithGlobalInitializedToEmptyList]
# flags: --local-partial-types
a = []

def f() -> None:
    a[0]
    reveal_type(a)  # E: Revealed type is 'builtins.list[builtins.int]'

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

[case testLocalPartialTypesWithGlobalInitializedToEmptyList2]
# flags: --local-partial-types
a = [] # E: Need type annotation for 'a'

def f() -> None:
    a.append(1)
    reveal_type(a)  # E: Revealed type is 'Any'

reveal_type(a) # E: Revealed type is 'Any'
[builtins fixtures/list.pyi]

[case testLocalPartialTypesWithGlobalInitializedToEmptyList3]
# flags: --local-partial-types
a = [] # E: Need type annotation for 'a'

def f():
    a.append(1)

reveal_type(a) # E: Revealed type is 'Any'
[builtins fixtures/list.pyi]

[case testLocalPartialTypesWithGlobalInitializedToEmptyDict]
# flags: --local-partial-types
a = {}

def f() -> None:
    a[0]
    reveal_type(a)  # E: Revealed type is 'builtins.dict[builtins.int, builtins.str]'

a[0] = ''
reveal_type(a) # E: Revealed type is 'builtins.dict[builtins.int, builtins.str]'
[builtins fixtures/dict.pyi]

[case testLocalPartialTypesWithGlobalInitializedToEmptyDict2]
# flags: --local-partial-types
a = {} # E: Need type annotation for 'a'

def f() -> None:
    a[0] = ''
    reveal_type(a)  # E: Revealed type is 'Any'

reveal_type(a) # E: Revealed type is 'Any'
[builtins fixtures/dict.pyi]

[case testLocalPartialTypesWithGlobalInitializedToEmptyDict3]
# flags: --local-partial-types
a = {} # E: Need type annotation for 'a'

def f():
    a[0] = ''

reveal_type(a) # E: Revealed type is 'Any'
[builtins fixtures/dict.pyi]

[case testLocalPartialTypesWithNestedFunction]
# flags: --local-partial-types
def f() -> None:
    a = {}
    def g() -> None:
        a[0] = ''
    reveal_type(a) # E: Revealed type is 'builtins.dict[builtins.int, builtins.str]'
[builtins fixtures/dict.pyi]

[case testLocalPartialTypesWithNestedFunction2]
# flags: --local-partial-types
def f() -> None:
    a = []
    def g() -> None:
        a.append(1)
    reveal_type(a) # E: Revealed type is 'builtins.list[builtins.int]'
[builtins fixtures/list.pyi]

[case testLocalPartialTypesWithNestedFunction3]
# flags: --local-partial-types --no-strict-optional
def f() -> None:
    a = None
    def g() -> None:
        nonlocal a
        a = ''
    reveal_type(a) # E: Revealed type is 'builtins.str'
[builtins fixtures/dict.pyi]

[case testLocalPartialTypesWithInheritance]
# flags: --local-partial-types
from typing import Optional

class A:
    x: Optional[str]

class B(A):
    x = None

reveal_type(B.x) # E: Revealed type is 'None'

[case testLocalPartialTypesWithInheritance2]
# flags: --local-partial-types --strict-optional
class A:
    x: str

class B(A):
    x = None  # E: Incompatible types in assignment (expression has type "None", base class "A" defined the type as "str")

[case testLocalPartialTypesWithAnyBaseClass]
# flags: --local-partial-types --strict-optional
from typing import Any

A: Any

class B(A):
    x = None

class C(B):
    y = None

[case testLocalPartialTypesInMultipleMroItems]
# flags: --local-partial-types --strict-optional
from typing import Optional

class A:
    x: Optional[str]

class B(A):
    x = None

class C(B):
    x = None

# TODO: Inferring None below is unsafe (https://github.com/python/mypy/issues/3208)
reveal_type(B.x)  # E: Revealed type is 'None'
reveal_type(C.x)  # E: Revealed type is 'None'

[case testLocalPartialTypesWithInheritance2-skip]
# flags: --local-partial-types
# This is failing because of https://github.com/python/mypy/issues/4552
from typing import Optional

class X: pass
class Y(X): pass

class A:
    x: Optional[X]

class B(A):
    x = None
    x = Y()

reveal_type(B.x) # E: revealed type is 'Union[__main__.Y, None]'

[case testLocalPartialTypesBinderSpecialCase]
# flags: --local-partial-types
from typing import List

def f(x): pass

class A:
    x = None  # E: Need type annotation for 'x'

    def f(self, p: List[str]) -> None:
        self.x = f(p)
        f(z for z in p)
[builtins fixtures/list.pyi]

[case testLocalPartialTypesAccessPartialNoneAttribute]
# flags: --local-partial-types
class C:
    a = None  # E: Need type annotation for 'a'

    def f(self, x) -> None:
        # TODO: It would be better for the type to be Any here
        C.a.y  # E: "None" has no attribute "y"

[case testLocalPartialTypesAccessPartialNoneAttribute]
# flags: --local-partial-types
class C:
    a = None  # E: Need type annotation for 'a'

    def f(self, x) -> None:
        # TODO: It would be better for the type to be Any here
        self.a.y  # E: "None" has no attribute "y"

-- Special case for assignment to '_'
-- ----------------------------------

[case testUnusedTargetLocal]
def foo() -> None:
    _ = 0
    _ = ''

[case testUnusedTargetNotGlobal]
_ = 0
_ = ''  # E: Incompatible types in assignment (expression has type "str", variable has type "int")

[case testUnusedTargetNotClass]
class C:
    _ = 0
    _ = ''  # E: Incompatible types in assignment (expression has type "str", variable has type "int")

[case testUnusedTargetTupleUnpacking]
def foo() -> None:
    _, _ = (0, '')
    _ = 0
    _ = ''
def bar() -> None:
    t = (0, '')
    _, _ = t
    _ = 0
    _ = ''

[case testUnusedTargetMultipleTargets]
def foo() -> None:
    _ = x = 0
    _ = y = ''
    _ = 0
    _ = ''
def bar() -> None:
    x = _ = 0
    y = _ = ''
    _ = 0
    _ = ''
    x + 0
    y + ''
    x + ''  # E: Unsupported operand types for + ("int" and "str")
    y + 0  # E: Unsupported operand types for + ("str" and "int")

[case testUnusedTargetNotImport]
import d, c, b, a
[file _.py]
def f(): pass
[file m.py]
def f(): pass
_ = f
_ = 0  # E: Incompatible types in assignment (expression has type "int", variable has type "Callable[[], Any]")
[file a.py]
def foo() -> None:
    import _
    _.f()
    _ = 0  # E: Incompatible types in assignment (expression has type "int", variable has type Module)
[file b.py]
def foo() -> None:
    import m as _
    _.f()
    _ = 0  # E: Incompatible types in assignment (expression has type "int", variable has type Module)
[file c.py]
def foo() -> None:
    from m import _
    _()
    _ = 0  # E: Incompatible types in assignment (expression has type "int", variable has type "Callable[[], Any]")
[file d.py]
def foo() -> None:
    from m import f as _
    _()
    _ = 0  # E: Incompatible types in assignment (expression has type "int", variable has type "Callable[[], Any]")
[builtins fixtures/module.pyi]

[case testUnusedTargetNotClass]
def foo() -> None:
    class _:
        pass
    _().method()  # E: "_" has no attribute "method"

[case testUnusedTargetNotDef]
def foo() -> None:
    def _() -> int:
        pass
    _() + ''  # E: Unsupported operand types for + ("int" and "str")

[case testUnusedTargetForLoop]
def f() -> None:
    a = [(0, '', 0)]
    for _, _, x in a:
        x = 0
        x = ''  # E: Incompatible types in assignment (expression has type "str", variable has type "int")
    _ = 0
    _ = ''
[builtins fixtures/list.pyi]

[case testUnusedTargetWithClause]
class C:
    def __enter__(self) -> int: pass
    def __exit__(self, *args): pass
def f() -> None:
    with C() as _: pass
    _ = 0
    _ = ''

[case testUnusedTargetNotExceptClause]
# Things don't work for except clauses.
# This is due to the implementation, but it's just as well.
def f() -> None:
    try: pass
    except BaseException as _:
        _ = 0  # E: Incompatible types in assignment (expression has type "int", variable has type "BaseException")
        _ = ''  # E: Incompatible types in assignment (expression has type "str", variable has type "BaseException")
[builtins fixtures/exception.pyi]
