[case testCallableDef]
def f() -> None: pass

if callable(f):
    f()
else:
    f += 5

[builtins fixtures/callable.pyi]

[case testCallableLambda]
f = lambda: None

if callable(f):
    f()
else:
    f += 5

[builtins fixtures/callable.pyi]

[case testCallableNotCallable]
x = 5

if callable(x):
    x()
else:
    x += 5

[builtins fixtures/callable.pyi]

[case testUnion]
from typing import Callable, Union

x = 5  # type: Union[int, Callable[[], str]]

if callable(x):
    y = x() + 'test'
else:
    z = x + 6

[builtins fixtures/callable.pyi]

[case testUnionMultipleReturnTypes]
from typing import Callable, Union

x = 5  # type: Union[int, Callable[[], str], Callable[[], int]]

if callable(x):
    y = x() + 2 # E: Unsupported operand types for + ("str" and "int") \
                # N: Left operand is of type "Union[str, int]"
else:
    z = x + 6

[builtins fixtures/callable.pyi]

[case testUnionMultipleNonCallableTypes]
from typing import Callable, Union

x = 5  # type: Union[int, str, Callable[[], str]]

if callable(x):
    y = x() + 'test'
else:
    z = x + 6  # E: Unsupported operand types for + ("str" and "int") \
               # N: Left operand is of type "Union[int, str]"

[builtins fixtures/callable.pyi]

[case testCallableThenIsinstance]
from typing import Callable, Union

x = 5  # type: Union[int, str, Callable[[], str], Callable[[], int]]

if callable(x):
    y = x()
    if isinstance(y, int):
        b1 = y + 2
    else:
        b2 = y + 'test'
else:
    if isinstance(x, int):
        b3 = x + 3
    else:
        b4 = x + 'test2'

[builtins fixtures/callable.pyi]

[case testIsinstanceThenCallable]
from typing import Callable, Union

x = 5  # type: Union[int, str, Callable[[], str], Callable[[], int]]

if isinstance(x, int):
    b1 = x + 1
else:
    if callable(x):
        y = x()
        if isinstance(y, int):
            b2 = y + 1
        else:
            b3 = y + 'test'
    else:
        b4 = x + 'test2'

[builtins fixtures/callable.pyi]

[case testCallableWithDifferentArgTypes]
from typing import Callable, Union

x = 5  # type: Union[int, Callable[[], None], Callable[[int], None]]

if callable(x):
    x()  # E: Too few arguments

[builtins fixtures/callable.pyi]

[case testClassInitializer]
from typing import Callable, Union

class A:
    x = 5

a = A  # type: Union[A, Callable[[], A]]

if callable(a):
    a = a()

a.x + 6

[builtins fixtures/callable.pyi]

[case testCallableVariables]
from typing import Union

class A:
    x = 5

class B:
    x = int

x = A()  # type: Union[A, B]

if callable(x.x):
    y = x.x()
else:
    y = x.x + 5

[builtins fixtures/callable.pyi]

[case testCallableAnd]
from typing import Union, Callable

x = 5  # type: Union[int, Callable[[], str]]

if callable(x) and x() == 'test':
    x()
else:
    x + 5  # E: Unsupported left operand type for + ("Callable[[], str]") \
           # N: Left operand is of type "Union[int, Callable[[], str]]"

[builtins fixtures/callable.pyi]

[case testCallableOr]
from typing import Union, Callable

x = 5  # type: Union[int, Callable[[], str]]

if callable(x) or x() == 'test':  # E: "int" not callable
    x()  # E: "int" not callable
else:
    x + 5
[builtins fixtures/callable.pyi]

[case testCallableOrOtherType]
from typing import Union, Callable

x = 5  # type: Union[int, Callable[[], str]]

if callable(x) or x == 2:
    pass
else:
    pass
[builtins fixtures/callable.pyi]

[case testAnyCallable]
from typing import Any

x = 5  # type: Any

if callable(x):
    reveal_type(x)  # E: Revealed type is 'Any'
else:
    reveal_type(x)  # E: Revealed type is 'Any'
[builtins fixtures/callable.pyi]

[case testCallableCallableClasses]
from typing import Union


class A:
    pass


class B:
    def __call__(self) -> None:
        pass


a = A()  # type: A
b = B()  # type: B
c = A()  # type: Union[A, B]

if callable(a):
    5 + 'test'  # E: Unsupported operand types for + ("int" and "str")

if not callable(b):
    5 + 'test'

if callable(c):
    reveal_type(c)  # E: Revealed type is '__main__.B'
else:
    reveal_type(c)  # E: Revealed type is '__main__.A'

[builtins fixtures/callable.pyi]

[case testCallableNestedUnions]
from typing import Callable, Union

T = Union[Union[int, Callable[[], int]], Union[str, Callable[[], str]]]

def f(t: T) -> None:
    if callable(t):
        reveal_type(t())  # E: Revealed type is 'Union[builtins.int, builtins.str]'
    else:
        reveal_type(t)  # E: Revealed type is 'Union[builtins.int, builtins.str]'

[builtins fixtures/callable.pyi]

[case testCallableTypeVarEmpty]
from typing import TypeVar

T = TypeVar('T')

def f(t: T) -> T:
    if callable(t):
        return 5  # E: Incompatible return value type (got "int", expected "T")
    else:
        return t

[builtins fixtures/callable.pyi]

[case testCallableTypeVarUnion]
from typing import Callable, TypeVar, Union

T = TypeVar('T', int, Callable[[], int], Union[str, Callable[[], str]])

def f(t: T) -> None:
    if callable(t):
        reveal_type(t())  # E: Revealed type is 'Any'  \
            # E: Revealed type is 'builtins.int'  \
            # E: Revealed type is 'builtins.str'
    else:
        reveal_type(t)  # E: Revealed type is 'builtins.int*'  # E: Revealed type is 'builtins.str'

[builtins fixtures/callable.pyi]

[case testCallableTypeVarBound]
from typing import TypeVar


class A:
    def __call__(self) -> str:
        return 'hi'


T = TypeVar('T', bound=A)

def f(t: T) -> str:
    if callable(t):
        return t()
    else:
        return 5

[builtins fixtures/callable.pyi]

[case testCallableTypeType]
from typing import Type


class A:
    pass


T = Type[A]

def f(t: T) -> A:
    if callable(t):
        return t()
    else:
        return 5

[builtins fixtures/callable.pyi]

[case testCallableTypeUnion]
from abc import ABCMeta, abstractmethod
from typing import Type, Union


class A(metaclass=ABCMeta):
    @abstractmethod
    def f(self) -> None:
        pass


class B:
    pass


x = B  # type: Union[Type[A], Type[B]]
if callable(x):
    # Abstract classes raise an error when called, but are indeed `callable`
    pass
else:
    'test' + 5

[builtins fixtures/callable.pyi]

[case testCallableUnionOfTypes]
from abc import ABCMeta, abstractmethod
from typing import Type, Union


class A(metaclass=ABCMeta):
    @abstractmethod
    def f(self) -> None:
        pass


class B:
    pass


x = B  # type: Type[Union[A, B]]
if callable(x):
    # Abstract classes raise an error when called, but are indeed `callable`
    pass
else:
    'test' + 5

[builtins fixtures/callable.pyi]

[case testCallableObject]

def f(o: object) -> None:
    if callable(o):
        o(1,2,3)
        1 + 'boom'  # E: Unsupported operand types for + ("int" and "str")
        o('hi') + 12
        reveal_type(o)  # E: Revealed type is '__main__.<callable subtype of object>'

[builtins fixtures/callable.pyi]

[case testCallableObject2]

class Foo(object):
    def bar(self) -> None:
        pass

def g(o: Foo) -> None:
    o.bar()
    if callable(o):
        o.foo()  # E: "Foo" has no attribute "foo"
        o.bar()
        o(1,2,3)
    else:
        o.bar()

[builtins fixtures/callable.pyi]

[case testCallableObjectAny]

from typing import Any

class Foo(Any):
    def bar(self) -> None:
        pass

def g(o: Foo) -> None:
    o.bar()
    o.baz()
    if callable(o):
        o('test')
        o.lurr(1,2,3)

[builtins fixtures/callable.pyi]

[case testCallableObjectGeneric]

from typing import TypeVar, Generic

T = TypeVar('T')
class Test(Generic[T]):
    def __self__(self, x: T) -> None:
        self.x = x

def g(o: Test[T], x: T) -> T:
    if callable(o):
        o.foo()  # E: "Test[T]" has no attribute "foo"
        o(1,2,3)
        o.x = x
        o.x = 1  # E: Incompatible types in assignment (expression has type "int", variable has type "T")
        1 + o.x  # E: Unsupported operand types for + ("int" and "T")
        return o.x

    return x

[builtins fixtures/callable.pyi]

[case testCallablePromote]

def take_float(f: float) -> None:
    pass

def g(o: int) -> None:
    if callable(o):
        take_float(o)
        o(1,2,3)

[builtins fixtures/callable.pyi]

[case testCallableTuple]

from typing import NamedTuple

Thing = NamedTuple('Thing', [('s', str), ('n', int)])

def g(o: Thing) -> None:
    if callable(o):
        o.s + o.n  # E: Unsupported operand types for + ("str" and "int")
        i, s = o
        i + s  # E: Unsupported operand types for + ("str" and "int")
        o(1,2,3)

[builtins fixtures/callable.pyi]
