google / pytype

A static type analyzer for Python code

Home Page:https://google.github.io/pytype

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.