Type narrowing narrows type too much for TypeVar
Yatt0Ikigai opened this issue · comments
Description
Pytype narrows typeVar too much for nested functions using it
Example Code
from typing import TypeVar
T = TypeVar("T", float, complex)
Y = TypeVar("Y", str, complex, float)
def example(a: T, b: T) -> T:
def helper(c: Y, d: Y) -> str:
return str(c * 7) + str(d)
return complex(helper(b,a))
print(example(1.1, complex(1,2)))
Output:
pytype:
Computing dependencies
Analyzing 3 sources with 0 local dependencies
ninja: Entering directory `.pytype'
[1/1] check pytype-exp-1.main
Leaving directory '.pytype'
Success: no errors found
python:
Traceback (most recent call last):
File "/Users/piotrberestka/Desktop/Studia/exp-1/main.py", line 34, in
print(example(1.1, complex(1,2)))
^^^^^^^^^^^^^^^^^^^^^
File "/Users/piotrberestka/Desktop/Studia/exp-1/main.py", line 32, in example
return complex(helper(b,a))
^^^^^^^^^^^^^^^^^^
ValueError: complex() arg is a malformed string
i don't understand the issue - T
in the signature of the outer function ensures that a
and b
are the same type, bounded to {complex, float}
. then the function body calls helper(b, a)
, which satisfies the signature of helper
, since c
and d
will indeed be the same type, bounded to {complex, float, str}
which is a superset of {complex, float}
.
the top-level function call succeeds because 1.1
is compatible with complex
via promotion, so T
would get bound to complex
when example
is called, as would Y
when helper
gets called.
as for the runtime error, complex()
does indeed support a string argument. the runtime error is a value error, because the string passed to it does not get parsed properly.
Yeah, the runtime error appears to be due to complex
being passed an argument with an allowed type but a bad value, which isn't something we can generally detect.