Description
I think there are a few problems with isinstance
inference.
- This code type checks with
mypy --strcit --python-version 3.6
, but it should not:
from typing import *
def f(x: Union[int, str], typ: type) -> None:
if isinstance(x, (typ, int)):
print(x + 1)
The semantic analyzer concludes that within the body of if isinstance()
, the type of x
must be int
. It's not, however. For example, in this case f('a', str)
, the if
branch will be followed even though x
is not an int
(and this will cause runtime TypeError
without any mypy warnings).
The reason this happens is that type
annotation is represented as an Instance
rather than as a FunctionLike
inside checker.py:get_isinstance_type()
. As a result, it's skipped entirely in the loop, and only int
is added to types
, so sem analyzer thinks x
must absolutely be int
.
One solution is to make type
represented with an instance of CallableType
(why isn't it btw?!). Another solution is to simply add a bit of logic to the loop to properly handle this case.
- This code:
def f(x: Union[int, str, List, Tuple]) -> None:
if isinstance(x, (str, (list, tuple))):
print(x[1])
results in error: Argument 2 to "isinstance" has incompatible type "Tuple[str, Tuple[List[_T], Tuple[_T_co, ...]]]"; expected "Union[type, Tuple[type, ...]]"
.
This is because there's this weird thing in python that allows to put nested tuples as the second argument to isinstance
, and mypy
(along with most other people) doesn't know about it. I don't know if it's worth fixing, but it's super easy (just flatten the second argument if it's a tuple).
If my understanding is correct, I'll make a PR.