-- Return statement
-- ----------------


[case testReturnValue]
import typing
def f() -> 'A':
    return A()
def g() -> 'B':
    return A()
class A:
    pass
class B:
    pass
[out]
main:5: error: Incompatible return value type (got "A", expected "B")

[case testReturnSubtype]
import typing
def f() -> 'B':
    return A()
def g() -> 'A':
    return B()
class A:
    pass
class B(A):
    pass
[out]
main:3: error: Incompatible return value type (got "A", expected "B")

[case testReturnWithoutAValue]
import typing
def f() -> 'A':
    return
def g() -> None:
    return
class A:
    pass
[out]
main:3: error: Return value expected

[case testReturnNoneInFunctionReturningNone]
import typing
def f() -> None:
    return None
def g() -> None:
    return f()
[out]

[case testReturnInGenerator]
from typing import Generator
def f() -> Generator[int, None, str]:
    yield 1
    return "foo"
[out]

[case testEmptyReturnInGenerator]
from typing import Generator
def f() -> Generator[int, None, str]:
    yield 1
    return  # E: Return value expected
[out]

[case testNoReturnInGenerator]
from typing import Generator
def f() -> Generator[int, None, str]:  # E: Missing return statement
    yield 1
[out]

[case testEmptyReturnInNoneTypedGenerator]
from typing import Generator
def f() -> Generator[int, None, None]:
    yield 1
    return
[out]

[case testNonEmptyReturnInNoneTypedGenerator]
from typing import Generator
def f() -> Generator[int, None, None]:
    yield 1
    return 42  # E: No return value expected
[out]

[case testReturnInIterator]
from typing import Iterator
def f() -> Iterator[int]:
    yield 1
    return "foo"
[out]


-- If statement
-- ------------


[case testIfStatement]

a = None # type: A
a2 = None # type: A
a3 = None # type: A
b = None # type: bool
if a:
    a = b # E: Incompatible types in assignment (expression has type "bool", variable has type "A")
elif a2:
    a = b # E: Incompatible types in assignment (expression has type "bool", variable has type "A")
elif a3:
    a = b # E: Incompatible types in assignment (expression has type "bool", variable has type "A")
else:
    a = b # E: Incompatible types in assignment (expression has type "bool", variable has type "A")
if b:
    pass
elif b:
    pass
if b:
    pass

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


-- Loops
-- -----


[case testWhileStatement]

a = None # type: A
b = None # type: bool
while a:
    a = b    # Fail
else:
    a = b    # Fail
while b:
    b = b

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

[case testForStatement]

a = None # type: A
b = None # type: object
for a in [A()]:
    a = b    # Fail
else:
    a = b    # Fail

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

[case testBreakStatement]
import typing
while None:
    break
[builtins fixtures/bool.pyi]
[out]

[case testContinueStatement]
import typing
while None:
    continue
[builtins fixtures/bool.pyi]
[out]

[case testForStatementTypeComments]

from typing import List, Union
x = []  # type: List[int]

for y in x:  # type: str  # E: Incompatible types in assignment (expression has type "int", variable has type "str")
    pass

for z in x:  # type: int
    pass

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

for v in x:  # type: int, int  # E: Syntax error in type annotation # N: Suggestion: Use Tuple[T1, ..., Tn] instead of (T1, ..., Tn)
    pass
[builtins fixtures/list.pyi]

[case testForStatementMultipleTypeComments]

from typing import List, Tuple
x = []  # type: List[Tuple[int, int]]

for y in x:  # type: int, int  # E: Syntax error in type annotation # N: Suggestion: Use Tuple[T1, ..., Tn] instead of (T1, ..., Tn)
    pass

for z in x:  # type: Tuple[int, int]
    pass

for w,v in x:  # type: int, str  # E: Incompatible types in assignment (expression has type "int", variable has type "str")
    pass

for a, b in x:  # type: int, int, int  # E: Incompatible number of tuple items
    pass
[builtins fixtures/list.pyi]


-- Operator assignment
-- -------------------


[case testPlusAssign]

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

class A:
    def __add__(self, x: 'C') -> 'A': pass

class B:
    def __add__(self, x: A) -> 'C': pass

class C: pass
[out]
main:3: error: Unsupported operand types for + ("A" and "B")
main:4: error: Incompatible types in assignment (expression has type "C", variable has type "B")
main:5: error: Unsupported left operand type for + ("C")

[case testMinusAssign]

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

class A:
    def __sub__(self, x: 'C') -> 'A': pass

class B:
    def __sub__(self, x: A) -> 'C': pass

class C: pass
[out]
main:3: error: Unsupported operand types for - ("A" and "B")
main:4: error: Incompatible types in assignment (expression has type "C", variable has type "B")
main:5: error: Unsupported left operand type for - ("C")

[case testMulAssign]

a, c = None, None # type: (A, C)
a *= a   # Fail
c *= a   # Fail
a *= c

class A:
    def __mul__(self, x: 'C') -> 'A': pass

class C: pass
[out]
main:3: error: Unsupported operand types for * ("A" and "A")
main:4: error: Unsupported left operand type for * ("C")

[case testMatMulAssign]
a, c = None, None # type: (A, C)
a @= a   # E: Unsupported operand types for @ ("A" and "A")
c @= a   # E: Unsupported left operand type for @ ("C")
a @= c

class A:
    def __matmul__(self, x: 'C') -> 'A': pass

class C: pass

[case testDivAssign]

a, c = None, None # type: (A, C)
a /= a   # Fail
c /= a   # Fail
a /= c

class A:
    def __truediv__(self, x: 'C') -> 'A': pass

class C: pass
[out]
main:3: error: Unsupported operand types for / ("A" and "A")
main:4: error: Unsupported left operand type for / ("C")

[case testPowAssign]

a, c = None, None # type: (A, C)
a **= a   # Fail
c **= a   # Fail
a **= c

class A:
    def __pow__(self, x: 'C') -> 'A': pass

class C: pass
[out]
main:3: error: Unsupported operand types for ** ("A" and "A")
main:4: error: Unsupported left operand type for ** ("C")

[case testSubtypesInOperatorAssignment]

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

class A:
    def __add__(self, x: 'A') -> 'B': pass

class B(A): pass
[out]

[case testAdditionalOperatorsInOpAssign]

a, c = None, None # type: (A, C)
a &= a  # Fail
a >>= a # Fail
a //= a # Fail
a &= c
a >>= c
a //= c
class A:
    def __and__(self, x: 'C') -> 'A': pass
    def __rshift__(self, x: 'C') -> 'A': pass
    def __floordiv__(self, x: 'C') -> 'A': pass
class C: pass
[out]
main:3: error: Unsupported operand types for & ("A" and "A")
main:4: error: Unsupported operand types for >> ("A" and "A")
main:5: error: Unsupported operand types for // ("A" and "A")

[case testInplaceOperatorMethods]
import typing
class A:
    def __iadd__(self, x: int) -> 'A': pass
    def __imul__(self, x: str) -> 'A': pass
    def __imatmul__(self, x: str) -> 'A': pass
a = A()
a += 1
a *= ''
a @= ''
a += '' # E: Argument 1 to "__iadd__" of "A" has incompatible type "str"; expected "int"
a *= 1  # E: Argument 1 to "__imul__" of "A" has incompatible type "int"; expected "str"
a @= 1  # E: Argument 1 to "__imatmul__" of "A" has incompatible type "int"; expected "str"

[case testInplaceSetitem]
class A(object):
    def __init__(self) -> None:
        self.a = [1]

    def __iadd__(self, a):
        # type: (int) -> A
        self.a += [2]
        return self

a = A()
b = [a]
b[0] += 1
[builtins fixtures/list.pyi]
[out]


-- Assert statement
-- ----------------


[case testAssert]
import typing
assert None + None # Fail
assert None
[out]
main:2: error: Unsupported left operand type for + ("None")


-- Exception handling
-- ------------------


[case testRaiseStatement]

e = None # type: BaseException
f = None # type: MyError
a = None # type: A
raise a # Fail
raise e
raise f
class A: pass
class MyError(BaseException): pass
[builtins fixtures/exception.pyi]
[out]
main:5: error: Exception must be derived from BaseException

[case testRaiseClassobject]
import typing
class A: pass
class MyError(BaseException): pass
def f(): pass
raise BaseException
raise MyError
raise A # E: Exception must be derived from BaseException
raise object # E: Exception must be derived from BaseException
raise f # E: Exception must be derived from BaseException
[builtins fixtures/exception.pyi]

[case testRaiseExceptionType]
import typing
x = None # type: typing.Type[BaseException]
raise x
[builtins fixtures/exception.pyi]

[case testRaiseNonExceptionTypeFails]
import typing
x = int # type: typing.Type[int]
raise x # E: Exception must be derived from BaseException
[builtins fixtures/exception.pyi]

[case testRaiseFromStatement]
e = None # type: BaseException
f = None # type: MyError
a = None # type: A
raise e from a # E: Exception must be derived from BaseException
raise e from e
raise e from f
class A: pass
class MyError(BaseException): pass
[builtins fixtures/exception.pyi]

[case testRaiseFromClassobject]
import typing
class A: pass
class MyError(BaseException): pass
def f(): pass
raise BaseException from BaseException
raise BaseException from MyError
raise BaseException from A # E: Exception must be derived from BaseException
raise BaseException from object # E: Exception must be derived from BaseException
raise BaseException from f # E: Exception must be derived from BaseException
[builtins fixtures/exception.pyi]

[case testTryFinallyStatement]
import typing
try:
    b = object() # type: A # Fail
finally:
    c = object() # type: A # Fail
class A: pass
[out]
main:3: error: Incompatible types in assignment (expression has type "object", variable has type "A")
main:5: error: Incompatible types in assignment (expression has type "object", variable has type "A")

[case testSimpleTryExcept]

try:
  pass
except BaseException as e:
  a, o = None, None # type: (BaseException, object)
  e = a
  e = o # Fail
class A: pass
class B: pass
[builtins fixtures/exception.pyi]
[out]
main:7: error: Incompatible types in assignment (expression has type "object", variable has type "BaseException")

[case testTypeErrorInBlock]

while object:
  x = None # type: A
  x = object()
  x = B()
class A: pass
class B: pass
[out]
main:4: error: Incompatible types in assignment (expression has type "object", variable has type "A")
main:5: error: Incompatible types in assignment (expression has type "B", variable has type "A")

[case testTypeErrorInvolvingBaseException]

x, a = None, None # type: (BaseException, A)
a = BaseException()  # Fail
a = object()         # Fail
x = object()         # Fail
x = A()              # Fail
x = BaseException()
class A: pass
[builtins fixtures/exception.pyi]
[out]
main:3: error: Incompatible types in assignment (expression has type "BaseException", variable has type "A")
main:4: error: Incompatible types in assignment (expression has type "object", variable has type "A")
main:5: error: Incompatible types in assignment (expression has type "object", variable has type "BaseException")
main:6: error: Incompatible types in assignment (expression has type "A", variable has type "BaseException")

[case testSimpleTryExcept2]
import typing
try:
  pass
except BaseException as e:
  e = object() # Fail
  e = BaseException()
[builtins fixtures/exception.pyi]
[out]
main:5: error: Incompatible types in assignment (expression has type "object", variable has type "BaseException")

[case testBaseClassAsExceptionTypeInExcept]
import typing
try:
  pass
except Err as e:
  e = BaseException() # Fail
  e = Err()
class Err(BaseException): pass
[builtins fixtures/exception.pyi]
[out]
main:5: error: Incompatible types in assignment (expression has type "BaseException", variable has type "Err")

[case testMultipleExceptHandlers]
import typing
try:
    pass
except BaseException as e:
    pass
except Err as f:
    f = BaseException() # Fail
    f = Err()
class Err(BaseException): pass
[builtins fixtures/exception.pyi]
[out]
main:7: error: Incompatible types in assignment (expression has type "BaseException", variable has type "Err")

[case testTryExceptStatement]
import typing
try:
    a = B() # type: A       # Fail
except BaseException as e:
    e = A()             # Fail
    e = Err()
except Err as f:
    f = BaseException() # Fail
    f = Err()
class A: pass
class B: pass
class Err(BaseException): pass
[builtins fixtures/exception.pyi]
[out]
main:3: error: Incompatible types in assignment (expression has type "B", variable has type "A")
main:5: error: Incompatible types in assignment (expression has type "A", variable has type "BaseException")
main:8: error: Incompatible types in assignment (expression has type "BaseException", variable has type "Err")

[case testTryExceptWithinFunction]
import typing
def f() -> None:
  try: pass
  except BaseException as e:
    e = object() # Fail
    e = BaseException()
  except Err as f:
    f = BaseException() # Fail
    f = Err()
class Err(BaseException): pass
[builtins fixtures/exception.pyi]
[out]
main:5: error: Incompatible types in assignment (expression has type "object", variable has type "BaseException")
main:8: error: Incompatible types in assignment (expression has type "BaseException", variable has type "Err")

[case testTryExceptFlow]
def f() -> None:
  x = 1
  try:
    pass
  except:
    raise
  x + 'a' # E: Unsupported left operand type for + ("int")
[builtins fixtures/exception.pyi]
[out]

[case testTryWithElse]
import typing
try: pass
except BaseException: pass
else:
  object(None) # E: Too many arguments for "object"
[builtins fixtures/exception.pyi]

[case testRedefinedFunctionInTryWithElse]
def f() -> None: pass
try:
    pass
except BaseException:
    f2 = f
else:
    def f2() -> str: pass
try:
    pass
except BaseException:
    f3 = f
else:
    def f3() -> None: pass
[builtins fixtures/exception.pyi]
[out]
main:7: error: Incompatible redefinition (redefinition with type "Callable[[], str]", original type "Callable[[], None]")

[case testExceptWithoutType]
import typing
try:
    -None # E: Unsupported operand type for unary - ("None")
except:
    ~None # E: Unsupported operand type for ~ ("None")
[builtins fixtures/exception.pyi]

[case testRaiseWithoutArgument]
import typing
try:
    None
except:
    raise
[builtins fixtures/exception.pyi]

[case testExceptWithMultipleTypes]
import typing
class E1(BaseException): pass
class E2(E1): pass
try:
    pass
except (E1, E2): pass
except (E1, object): pass # E: Exception type must be derived from BaseException
except (object, E2): pass # E: Exception type must be derived from BaseException
except (E1, (E2,)): pass  # E: Exception type must be derived from BaseException

except (E1, E2): pass
except ((E1, E2)): pass
except (((E1, E2))): pass
[builtins fixtures/exception.pyi]

[case testExceptWithTypeType]
import typing
E = BaseException  # type: typing.Type[BaseException]

try:
    pass
except E:
    pass
[builtins fixtures/exception.pyi]

[case testExceptWithMultipleTypes2]
import typing
class E1(BaseException): pass
class E2(E1): pass
try:
    pass
except (E1, E2) as e1:
    x = e1 # type: E1
    y = e1 # type: E2 # E: Incompatible types in assignment (expression has type "E1", variable has type "E2")
except (E2, E1) as e2:
    a = e2 # type: E1
    b = e2 # type: E2 # E: Incompatible types in assignment (expression has type "E1", variable has type "E2")
except (E1, E2, int) as e3: # E: Exception type must be derived from BaseException
    pass
[builtins fixtures/exception.pyi]

[case testExceptWithMultipleTypes3]
import typing
class E1(BaseException): pass
class E1_1(E1): pass
class E1_2(E1): pass
try: pass
except (E1, E1_1, E1_2) as e1:
    x = e1 # type: E1
    y = e1 # type: E1_1 # E: Incompatible types in assignment (expression has type "E1", variable has type "E1_1")
    z = e1 # type: E1_2 # E: Incompatible types in assignment (expression has type "E1", variable has type "E1_2")
except (E1_1, E1_2) as e2:
    a = e2 # type: E1
    b = e2 # type: E1_1 # E: Incompatible types in assignment (expression has type "Union[E1_1, E1_2]", variable has type "E1_1")
    c = e2 # type: E1_2 # E: Incompatible types in assignment (expression has type "Union[E1_1, E1_2]", variable has type "E1_2")
[builtins fixtures/exception.pyi]

[case testExceptWithMultipleTypes4]
from typing import Tuple, Type, Union

class E1(BaseException): pass
class E2(BaseException): pass
class E3(BaseException): pass

def variadic(exc: Tuple[Type[E1], ...]) -> None:
    try:
        pass
    except exc as e:
        reveal_type(e)  # E: Revealed type is '__main__.E1'

def union(exc: Union[Type[E1], Type[E2]]) -> None:
    try:
        pass
    except exc as e:
        reveal_type(e)  # E: Revealed type is 'Union[__main__.E1, __main__.E2]'

def tuple_in_union(exc: Union[Type[E1], Tuple[Type[E2], Type[E3]]]) -> None:
    try:
        pass
    except exc as e:
        reveal_type(e)  # E: Revealed type is 'Union[__main__.E1, __main__.E2, __main__.E3]'

def variadic_in_union(exc: Union[Type[E1], Tuple[Type[E2], ...]]) -> None:
    try:
        pass
    except exc as e:
        reveal_type(e)  # E: Revealed type is 'Union[__main__.E1, __main__.E2]'

def nested_union(exc: Union[Type[E1], Union[Type[E2], Type[E3]]]) -> None:
    try:
        pass
    except exc as e:
        reveal_type(e)  # E: Revealed type is 'Union[__main__.E1, __main__.E2, __main__.E3]'

def error_in_union(exc: Union[Type[E1], int]) -> None:
    try:
        pass
    except exc as e:  # E: Exception type must be derived from BaseException
        pass

def error_in_variadic(exc: Tuple[int, ...]) -> None:
    try:
        pass
    except exc as e:  # E: Exception type must be derived from BaseException
        pass

[builtins fixtures/tuple.pyi]

[case testExceptWithAnyTypes]
from typing import Any

E1 = None  # type: Any
class E2(BaseException): pass
class NotBaseDerived: pass

try:
    pass
except BaseException as e1:
    reveal_type(e1)  # E: Revealed type is 'builtins.BaseException'
except (E1, BaseException) as e2:
    reveal_type(e2)  # E: Revealed type is 'Union[Any, builtins.BaseException]'
except (E1, E2) as e3:
    reveal_type(e3)  # E: Revealed type is 'Union[Any, __main__.E2]'
except (E1, E2, BaseException) as e4:
    reveal_type(e4)  # E: Revealed type is 'Union[Any, builtins.BaseException]'

try: pass
except E1 as e1:
    reveal_type(e1)  # E: Revealed type is 'Any'
except E2 as e2:
    reveal_type(e2)  # E: Revealed type is '__main__.E2'
except NotBaseDerived as e3:  # E: Exception type must be derived from BaseException
    pass
except (NotBaseDerived, E1) as e4:  # E: Exception type must be derived from BaseException
    pass
except (NotBaseDerived, E2) as e5:  # E: Exception type must be derived from BaseException
    pass
except (NotBaseDerived, E1, E2) as e6:  # E: Exception type must be derived from BaseException
    pass
except (E1, E2, NotBaseDerived) as e6:  # E: Exception type must be derived from BaseException
    pass
[builtins fixtures/exception.pyi]

[case testReuseTryExceptionVariable]
import typing
class E1(BaseException): pass
class E2(BaseException): pass
try: pass
except E1 as e: pass
try: pass
except E1 as e: pass
try: pass
except E2 as e: pass
e + 1 # E: Trying to read deleted variable 'e'
e = E1() # E: Assignment to variable 'e' outside except: block
[builtins fixtures/exception.pyi]

[case testReuseDefinedTryExceptionVariable]
import typing
class E1(BaseException): pass
class E2(BaseException): pass
e = 1
e = 1
try: pass
except E1 as e: pass
e = 1 # E: Assignment to variable 'e' outside except: block
e = E1() # E: Assignment to variable 'e' outside except: block
[builtins fixtures/exception.pyi]

[case testExceptionVariableReuseInDeferredNode1]
def f(*a: BaseException) -> int:
    x
    try: pass
    except BaseException as err: pass
    try: pass
    except BaseException as err: f(err)
    return 0
x = f()
[builtins fixtures/exception.pyi]

[case testExceptionVariableReuseInDeferredNode2]
def f(*a: BaseException) -> int:
    try: pass
    except BaseException as err: pass
    x
    try: pass
    except BaseException as err: f(err)
    return 0
x = f()
[builtins fixtures/exception.pyi]

[case testExceptionVariableReuseInDeferredNode3]
def f(*a: BaseException) -> int:
    try: pass
    except BaseException as err: pass
    try: pass
    except BaseException as err: f(err)
    x
    return 0
x = f()
[builtins fixtures/exception.pyi]

[case testExceptionVariableReuseInDeferredNode4]
class EA(BaseException):
    a = None  # type: int
class EB(BaseException):
    b = None  # type: str
def f(*arg: BaseException) -> int:
    x
    try: pass
    except EA as err:
        f(err)
        a = err.a
        reveal_type(a)
    try: pass
    except EB as err:
        f(err)
        b = err.b
        reveal_type(b)
    return 0
x = f()
[builtins fixtures/exception.pyi]
[out]
main:11: error: Revealed type is 'builtins.int'
main:16: error: Revealed type is 'builtins.str'

[case testExceptionVariableReuseInDeferredNode5]
class EA(BaseException):
    a = None  # type: int
class EB(BaseException):
    b = None  # type: str
def f(*arg: BaseException) -> int:
    try: pass
    except EA as err:
        f(err)
        a = err.a
        reveal_type(a)
    x
    try: pass
    except EB as err:
        f(err)
        b = err.b
        reveal_type(b)
    return 0
x = f()
[builtins fixtures/exception.pyi]
[out]
main:10: error: Revealed type is 'builtins.int'
main:16: error: Revealed type is 'builtins.str'

[case testExceptionVariableReuseInDeferredNode6]
class EA(BaseException):
    a = None  # type: int
class EB(BaseException):
    b = None  # type: str
def f(*arg: BaseException) -> int:
    try: pass
    except EA as err:
        f(err)
        a = err.a
        reveal_type(a)
    try: pass
    except EB as err:
        f(err)
        b = err.b
        reveal_type(b)
    x
    return 0
x = f()
[builtins fixtures/exception.pyi]
[out]
main:10: error: Revealed type is 'builtins.int'
main:15: error: Revealed type is 'builtins.str'

[case testArbitraryExpressionAsExceptionType]
import typing
a = BaseException
try: pass
except a as b:
    b = BaseException()
    b = object() # E: Incompatible types in assignment (expression has type "object", variable has type "BaseException")
[builtins fixtures/exception.pyi]

[case testInvalidExceptionCallable]
import typing
def exc() -> BaseException: pass
try: pass
except exc as e: pass             # E: Exception type must be derived from BaseException
except BaseException() as b: pass # E: Exception type must be derived from BaseException
[builtins fixtures/exception.pyi]

[case testTupleValueAsExceptionType]
import typing
def exc() -> BaseException: pass
class E1(BaseException): pass
class E1_1(E1): pass
class E1_2(E1): pass

exs1 = (E1, E1_1, E1_2)
try: pass
except exs1 as e1:
    x = e1 # type: E1
    y = e1 # type: E1_1 # E: Incompatible types in assignment (expression has type "E1", variable has type "E1_1")
    z = e1 # type: E1_2 # E: Incompatible types in assignment (expression has type "E1", variable has type "E1_2")

exs2 = (E1_1, E1_2)
try: pass
except exs2 as e2:
    a = e2 # type: E1
    b = e2 # type: E1_1 # E: Incompatible types in assignment (expression has type "Union[E1_1, E1_2]", variable has type "E1_1")
    c = e2 # type: E1_2 # E: Incompatible types in assignment (expression has type "Union[E1_1, E1_2]", variable has type "E1_2")

exs3 = (E1, (E1_1, (E1_2,)))
try: pass
except exs3 as e3: pass  # E: Exception type must be derived from BaseException
[builtins fixtures/exception.pyi]

[case testInvalidTupleValueAsExceptionType]
import typing
def exc() -> BaseException: pass
class E1(BaseException): pass
class E2(E1): pass

exs1 = (E1, E2, int)
try: pass
except exs1 as e: pass # E: Exception type must be derived from BaseException
[builtins fixtures/exception.pyi]

[case testOverloadedExceptionType]
from foo import *
[file foo.pyi]
from typing import overload
class E(BaseException):
    @overload
    def __init__(self) -> None: pass
    @overload
    def __init__(self, x) -> None: pass
try:
    pass
except E as e:
    e = E()
    e = BaseException() # E: Incompatible types in assignment (expression has type "BaseException", variable has type "E")
[builtins fixtures/exception.pyi]

[case testExceptionWithAnyBaseClass]
from typing import Any
E = None  # type: Any
class EE(E): pass
raise EE()
raise EE
[builtins fixtures/exception.pyi]

[case testExceptionIsType]
from typing import Type
class B(BaseException): pass
def f(e: Type[B]):
    try: pass
    except e: pass
def g(e: Type[BaseException]):
    try: pass
    except e as err:
        reveal_type(err)
def h(e: Type[int]):
    try: pass
    except e: pass
[builtins fixtures/exception.pyi]
[out]
main:9: error: Revealed type is 'builtins.BaseException'
main:12: error: Exception type must be derived from BaseException


-- Del statement
-- -------------


[case testDelStmtWithIndex]
a, b = None, None # type: (A, B)
del b[a]
del b[b] # E: Argument 1 to "__delitem__" of "B" has incompatible type "B"; expected "A"
del a[a] # E: "A" has no attribute "__delitem__"
del a[b] # E: "A" has no attribute "__delitem__"
class B:
  def __delitem__(self, index: 'A'): pass
class A: pass

[case testDelStmtWithAttribute]
class A:
    def f(self): pass
    x = 0
a = A()
del a.f
del a.x
del a.z # E: "A" has no attribute "z"

[case testDelStatementWithTuple]
class A:
    x = 0
a = A()
del a.x, a.y # E: "A" has no attribute "y"


[case testDelStatementWithAssignmentSimple]
a = 1
a + 1
del a
a + 1 # E: Trying to read deleted variable 'a'
[builtins fixtures/ops.pyi]

[case testDelStatementWithAssignmentTuple]
a = 1
b = 1
del (a, b)
b + 1 # E: Trying to read deleted variable 'b'
[builtins fixtures/ops.pyi]

[case testDelStatementWithAssignmentClass]
class C:
    a = 1

c = C()
c.a = 1
c.a + 1
del c.a
c.a + 1
[builtins fixtures/ops.pyi]

[case testDelStatementWithConditions]
x = 5
del x
if x: ...  # E: Trying to read deleted variable 'x'

def f(x):
    return x

if 0: ...
elif f(x): ...  # E: Trying to read deleted variable 'x'

while x == 5: ...  # E: Trying to read deleted variable 'x'

-- Yield statement
-- ---------------


[case testSimpleYield]
from typing import Iterator
def f() -> Iterator[int]:
    yield 1
    yield '' # E: Incompatible types in "yield" (actual type "str", expected type "int")
[builtins fixtures/for.pyi]
[out]

[case testYieldInFunctionReturningGenerator]
from typing import Generator
def f() -> Generator[int, None, None]:
    yield 1
[builtins fixtures/for.pyi]
[out]

[case testYieldInFunctionReturningIterable]
from typing import Iterable
def f() -> Iterable[int]:
    yield 1
[builtins fixtures/for.pyi]
[out]

[case testYieldInFunctionReturningObject]
def f() -> object:
    yield 1
[builtins fixtures/for.pyi]
[out]

[case testYieldInFunctionReturningAny]
from typing import Any
def f() -> Any:
    yield object()
[out]

[case testYieldInFunctionReturningFunction]
from typing import Callable
def f() -> Callable[[], None]: # E: The return type of a generator function should be "Generator" or one of its supertypes
    yield object()
[out]

[case testYieldInDynamicallyTypedFunction]
import typing
def f():
    yield f

[case testWithInvalidInstanceReturnType]
import typing
def f() -> int: # E: The return type of a generator function should be "Generator" or one of its supertypes
    yield 1
[builtins fixtures/for.pyi]
[out]

[case testTypeInferenceContextAndYield]
from typing import List, Iterator
def f() -> 'Iterator[List[int]]':
    yield []
    yield [object()] # E: List item 0 has incompatible type "object"; expected "int"
[builtins fixtures/for.pyi]
[out]

[case testYieldAndReturnWithoutValue]
from typing import Iterator
def f() -> Iterator[int]:
    yield 1
    return
[builtins fixtures/for.pyi]

[case testYieldWithNoValue]
from typing import Iterator
def f() -> Iterator[None]:
    yield
[builtins fixtures/for.pyi]

[case testYieldWithNoValueWhenValueRequired]
from typing import Iterator
def f() -> Iterator[int]:
    yield  # E: Yield value expected
[builtins fixtures/for.pyi]
[out]

[case testYieldWithExplicitNone]
from typing import Iterator
def f() -> Iterator[None]:
    yield None
[builtins fixtures/for.pyi]
[out]


-- Yield from statement
-- --------------------
--
-- (It's not really a statement, but don't want to move the tests.)

[case testSimpleYieldFromWithIterator]
from typing import Iterator
def g() -> Iterator[str]:
    yield '42'
def h() -> Iterator[int]:
    yield 42
def f() -> Iterator[str]:
    yield from g()
    yield from h()  # E: Incompatible types in "yield from" (actual type "int", expected type "str")
[out]

[case testYieldFromAppliedToAny]
from typing import Any
def g() -> Any:
    yield object()
def f() -> Any:
    yield from g()
[out]

[case testYieldFromInFunctionReturningFunction]
from typing import Iterator, Callable
def g() -> Iterator[int]:
    yield 42
def f() -> Callable[[], None]:  # E: The return type of a generator function should be "Generator" or one of its supertypes
    yield from g()
[out]

[case testYieldFromNotIterableReturnType]
from typing import Iterator
def g() -> Iterator[int]:
    yield 42
def f() -> int:  # E: The return type of a generator function should be "Generator" or one of its supertypes
    yield from g()
[out]

[case testYieldFromNotAppliedIterator]
from typing import Iterator
def g() -> int:
    return 42
def f() -> Iterator[int]:
    yield from g()  # E: "yield from" can't be applied to "int"
[out]

[case testYieldFromCheckIncompatibleTypesTwoIterables]
from typing import List, Iterator
def g() -> Iterator[List[int]]:
    yield [2, 3, 4]
def f() -> Iterator[List[int]]:
    yield from g()
    yield from [1, 2, 3]  # E: Incompatible types in "yield from" (actual type "int", expected type "List[int]")
[builtins fixtures/for.pyi]
[out]

[case testYieldFromNotAppliedToNothing]
def h():
    yield from  # E: invalid syntax
[out]

[case testYieldFromAndYieldTogether]
from typing import Iterator
def f() -> Iterator[str]:
    yield "g1 ham"
    yield from g()
    yield "g1 eggs"
def g() -> Iterator[str]:
    yield "g2 spam"
    yield "g2 more spam"
[out]

[case testYieldFromAny]
from typing import Iterator
def f(a):
    b = yield from a
    return b
[out]

[case testYieldFromGenericCall]
from typing import Generator, TypeVar
T = TypeVar('T')
def f(a: T) -> Generator[int, str, T]: pass
def g() -> Generator[int, str, float]:
    r = yield from f('')
    reveal_type(r)  # E: Revealed type is 'builtins.str*'
    return 3.14

-- With statement
-- --------------


[case testSimpleWith]
import typing
class A:
    def __enter__(self) -> None: pass
    def __exit__(self, x, y, z) -> None: pass
with A():
    object(A) # E: Too many arguments for "object"

[case testWithStmtAndInvalidExit]
import typing
class A:
    def __enter__(self) -> None: pass
    def __exit__(self, x, y) -> None: pass
with A(): # E: Too many arguments for "__exit__" of "A"
    pass

[case testWithStmtAndMissingExit]
import typing
class A:
    def __enter__(self) -> None: pass
with A(): # E: "A" has no attribute "__exit__"
    pass

[case testWithStmtAndInvalidEnter]
import typing
class A:
    def __enter__(self, x) -> None: pass
    def __exit__(self, x, y, z) -> None: pass
with A(): # E: Too few arguments for "__enter__" of "A"
    pass

[case testWithStmtAndMissingEnter]
import typing
class A:
    def __exit__(self, x, y, z) -> None: pass
with A(): # E: "A" has no attribute "__enter__"
    pass

[case testWithStmtAndMultipleExprs]
import typing
class A:
    def __enter__(self) -> None: pass
    def __exit__(self, x, y, z) -> None: pass
class B:
    def __enter__(self) -> None: pass
with A(), B(): # E: "B" has no attribute "__exit__"
    pass
with B(), A(): # E: "B" has no attribute "__exit__"
    pass

[case testWithStmtAndResult]
import typing
class B: pass
class A:
    def __enter__(self) -> B: pass
    def __exit__(self, x, y, z): pass
with A() as b:
    b = B()
    b = A() # E: Incompatible types in assignment (expression has type "A", variable has type "B")

[case testWithStmtAndMultipleResults]
from typing import TypeVar, Generic
t = TypeVar('t')
class B: pass
class C: pass
class A(Generic[t]):
    def __enter__(self) -> t: pass
    def __exit__(self, x, y, z): pass
a_b = A() # type: A[B]
a_c = A() # type: A[C]
with a_b as b, a_c as c:
    b = B()
    c = C()
    b = c # E: Incompatible types in assignment (expression has type "C", variable has type "B")
    c = b # E: Incompatible types in assignment (expression has type "B", variable has type "C")

[case testWithStmtAndComplexTarget]
from typing import Tuple
class A:
    def __enter__(self) -> Tuple[int, str]: pass
    def __exit__(self, x, y, z): pass
with A() as (a, b):
    a = 1
    b = ''
    a = b # E: Incompatible types in assignment (expression has type "str", variable has type "int")
[builtins fixtures/tuple.pyi]

[case testWithStmtTypeComment]

from typing import Union
class A:
    def __enter__(self) -> int: pass
    def __exit__(self, x, y, z): pass

with A():  # type: int  # E: Invalid type comment
    pass

with A() as a:  # type: int
    pass

with A() as b:  # type: str  # E: Incompatible types in assignment (expression has type "int", variable has type "str")
    pass

with A() as c:  # type: int, int  # E: Syntax error in type annotation # N: Suggestion: Use Tuple[T1, ..., Tn] instead of (T1, ..., Tn)
    pass

with A() as d:  # type: Union[int, str]
    reveal_type(d)  # E: Revealed type is 'Union[builtins.int, builtins.str]'

[case testWithStmtTupleTypeComment]

from typing import Tuple
class A:
    def __enter__(self) -> Tuple[int, int]: pass
    def __exit__(self, x, y, z): pass

with A():
    pass

with A() as a:  # type: Tuple[int, int]
    pass

with A() as b:  # type: Tuple[int, str]  # E: Incompatible types in assignment (expression has type "Tuple[int, int]", variable has type "Tuple[int, str]")
    pass

with A() as (c, d):  # type: int, int
    pass

with A() as (e, f):  # type: Tuple[int, int]
    pass

with A() as (g, h):  # type: int  # E: Tuple type expected for multiple variables
    pass

with A() as (i, j):  # type: int, int, str  # E: Incompatible number of tuple items
    pass

with A() as (k, l):  # type: int, str  # E: Incompatible types in assignment (expression has type "int", variable has type "str")
    pass
[builtins fixtures/tuple.pyi]

[case testWithStmtComplexTypeComment]

from typing import Tuple
class A:
    def __enter__(self) -> Tuple[int, int]: pass
    def __exit__(self, x, y, z): pass

class B:
    def __enter__(self) -> str: pass
    def __exit__(self, x, y, z): pass

with A() as a, A() as (b, c), B() as d:  # type: Tuple[int, int], (int, int), str
    pass

with A() as e, A() as (f, g), B() as h:  # type: Tuple[int, int], Tuple[int, int], str
    pass

with A() as i, A() as (j, k), B() as l:  # type: (int, int), (int, int), str  # E: Syntax error in type annotation # N: Suggestion: Use Tuple[T1, ..., Tn] instead of (T1, ..., Tn)
    pass

with A(), A(), B() as m, A() as n, B(), B() as o:  # type: int, Tuple[int, int]  # E: Incompatible number of types for `with` targets
    pass

with A(), B(), B() as p, A(), A():  # type: str
    pass
[builtins fixtures/tuple.pyi]

-- Chained assignment
-- ------------------


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

[case testChainedAssignment2]
import typing
def f() -> None:
    x = 1
    y = 'x'
    x = y = 'x' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
    x = y = 1   # E: Incompatible types in assignment (expression has type "int", variable has type "str")
[builtins fixtures/primitives.pyi]
[out]

[case testChainedAssignmentWithType]

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


-- Star assignment
-- ---------------


[case testAssignListToStarExpr]
from typing import List
bs, cs = None, None # type: List[A], List[B]
*bs, b = bs
*bs, c = cs  # E: Incompatible types in assignment (expression has type "List[B]", variable has type "List[A]")
*ns, c = cs
nc = cs

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


-- Type aliases
-- ------------


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

[case testTypeAliasDefinedInAModule]
import typing
import m
def f(x: m.foo) -> None: pass
f(1)
f('x') # E: Argument 1 to "f" has incompatible type "str"; expected "int"
[file m.py]
import typing
foo = int

[case testTypeAliasDefinedInAModule2]
import typing
from m import foo
def f(x: foo) -> None: pass
f(1)
f('x') # E: Argument 1 to "f" has incompatible type "str"; expected "int"
[file m.py]
import typing
foo = int


-- nonlocal and global
-- -------------------


[case testTypeOfGlobalUsed]
import typing
g = A()
def f() -> None:
    global g
    g = B()

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

[case testTypeOfNonlocalUsed]
import typing
def f() -> None:
    a = A()
    def g() -> None:
        nonlocal a
        a = B()

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

[case testTypeOfOuterMostNonlocalUsed]
import typing
def f() -> None:
    a = A()
    def g() -> None:
        a = B()
        def h() -> None:
            nonlocal a
            a = A()
            a = B()

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

[case testAugmentedAssignmentIntFloat]
weight0 = 65.5
reveal_type(weight0)  # E: Revealed type is 'builtins.float'
weight0 = 65
reveal_type(weight0)  # E: Revealed type is 'builtins.int'
weight0 *= 'a'  # E: Incompatible types in assignment (expression has type "str", variable has type "float")
weight0 *= 0.5
reveal_type(weight0)  # E: Revealed type is 'builtins.float'
weight0 *= object()  # E: Unsupported operand types for * ("float" and "object")
reveal_type(weight0) # E: Revealed type is 'builtins.float'

[builtins fixtures/float.pyi]

[case testAugmentedAssignmentIntFloatMember]
class A:
    def __init__(self) -> None:
        self.weight0 = 65.5
        reveal_type(self.weight0)  # E: Revealed type is 'builtins.float'
        self.weight0 = 65
        reveal_type(self.weight0)  # E: Revealed type is 'builtins.int'
        self.weight0 *= 'a'  # E: Incompatible types in assignment (expression has type "str", variable has type "float")
        self.weight0 *= 0.5
        reveal_type(self.weight0)  # E: Revealed type is 'builtins.float'
        self.weight0 *= object()  # E: Unsupported operand types for * ("float" and "object")
        reveal_type(self.weight0) # E: Revealed type is 'builtins.float'

[builtins fixtures/float.pyi]

[case testAugmentedAssignmentIntFloatDict]
from typing import Dict
d = {'weight0': 65.5}
reveal_type(d['weight0'])  # E: Revealed type is 'builtins.float*'
d['weight0'] = 65
reveal_type(d['weight0'])  # E: Revealed type is 'builtins.float*'
d['weight0'] *= 'a'  # E: Unsupported operand types for * ("float" and "str")
d['weight0'] *= 0.5
reveal_type(d['weight0'])  # E: Revealed type is 'builtins.float*'
d['weight0'] *= object()  # E: Unsupported operand types for * ("float" and "object")
reveal_type(d['weight0']) # E: Revealed type is 'builtins.float*'

[builtins fixtures/floatdict.pyi]

[case testForwardRefsInForStatementImplicit]
from typing import List, NamedTuple
lst: List[N]

for i in lst:
    reveal_type(i.x)  # E: Revealed type is 'builtins.int'
    a: str = i[0] # E: Incompatible types in assignment (expression has type "int", variable has type "str")

N = NamedTuple('N', [('x', int)])
[builtins fixtures/list.pyi]
[out]

[case testForwardRefsInForStatement]
from typing import List, NamedTuple
lst: List[M]

for i in lst: # type: N
    reveal_type(i.x)  # E: Revealed type is 'builtins.int'
    a: str = i[0] # E: Incompatible types in assignment (expression has type "int", variable has type "str")

N = NamedTuple('N', [('x', int)])
class M(N): pass
[builtins fixtures/list.pyi]
[out]

[case testForwardRefsInWithStatementImplicit]
from typing import ContextManager, Any
from mypy_extensions import TypedDict
cm: ContextManager[N]

with cm as g:
    a: int = g['x']

N = TypedDict('N', {'x': int})
[builtins fixtures/dict.pyi]
[typing fixtures/typing-full.pyi]
[out]

[case testForwardRefsInWithStatement]
from typing import ContextManager, Any
from mypy_extensions import TypedDict
cm: ContextManager[Any]

with cm as g:  # type: N
    a: str = g['x']  # E: Incompatible types in assignment (expression has type "int", variable has type "str")

N = TypedDict('N', {'x': int})
[builtins fixtures/dict.pyi]
[typing fixtures/typing-full.pyi]
[out]
