facebook / pyre-check

Performant type-checking for python.
https://pyre-check.org/
MIT License
6.8k stars 434 forks source link

Errors with recursive type aliases: "JSON is declared to have type `TypeAlias` but is used as type `UnionType`" #813

Open cjolowicz opened 8 months ago

cjolowicz commented 8 months ago

Pyre Bug

Bug description

This recursive type alias for JSON data does not work in pyre:

from typing import TypeAlias

JSON: TypeAlias = None | bool | int | float | str | list["JSON"] | dict[str, "JSON"]

Output:

ƛ Found 5 type errors!
jsontype.py:3:0 Incompatible variable type [9]: JSON is declared to have type `TypeAlias` but is used as type `UnionType`.
jsontype.py:3:18 Missing argument [20]: Call `bool.__ror__` expects argument in position 1.
jsontype.py:3:18 Missing argument [20]: Call `int.__ror__` expects argument in position 1.
jsontype.py:3:57 Incompatible parameter type [6]: In call `typing.GenericMeta.__getitem__`, for 1st positional argument, expected `Type[Variable[_T]]` but got `str`.
jsontype.py:3:72 Incompatible parameter type [6]: In call `typing.GenericMeta.__getitem__`, for 1st positional argument, expected `Tuple[Type[Variable[_KT]], Type[Variable[_VT]]]` but got `Tuple[Type[str], str]`.

Reproduction steps

https://pyre-check.org/play?input=%23%20pyre-strict%0Afrom%20typing%20import%20TypeAlias%0A%0AJSON%3A%20TypeAlias%20%3D%20None%20%7C%20bool%20%7C%20int%20%7C%20float%20%7C%20str%20%7C%20list%5B%22JSON%22%5D%20%7C%20dict%5Bstr%2C%20%22JSON%22%5D

Alternatively:

$ pipx install pyre-check  # 0.9.19
$ cat jsontype.py  # source as above
$ pyre --source-directory . check  # errors as above

Expected behavior

No errors

Logs

Please run your reproduction steps followed by pyre rage > pyre_rage.log, and upload the file here:

pyre_rage.log

Additional context

This is the recommended definition from https://github.com/python/typing/issues/182#issuecomment-1320974824

The code type-checks in mypy and pytype.

Omitting the quotes makes the code pass in pyre, but results in NameError at runtime:

NameError: name 'JSON' is not defined

This NameError cannot be avoided with future annotations, because it doesn't occur in an annotation.

PEP 695 type aliases don't appear to be supported yet:

type JSON = None | bool | int | float | str | list[JSON] | dict[str, JSON]
# jsontype.py:1:6 Parsing failure [404]: invalid syntax

Omitting the TypeAlias annotation avoids the first of the errors, but not the remaining four (missing argument, incompatible parameter type).

vthemelis commented 2 months ago

Not being able to type recursive types seems like a big regression? I thought this used to be possible in pyre. I stumbled upon this today at work and I'm surprised not more people are asking for this.

Also, is PEP 695 going to be implemented in pyre?