Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pyright + __or__ in generic type annotations gives unknown type #1143

Open
jakkdl opened this issue May 10, 2024 · 1 comment
Open

pyright + __or__ in generic type annotations gives unknown type #1143

jakkdl opened this issue May 10, 2024 · 1 comment
Labels
enhancement New feature or request machinery Internal plumbing for visitor, transformer, matcher APIs

Comments

@jakkdl
Copy link
Contributor

jakkdl commented May 10, 2024

pyright gets confused by your custom __or__ methods on matcher classes, giving "Expected type expression but received UnionType". It does work with mypy, though I suspect that might simply be because mypy doesn't try to parse it for type hints.
It's possible to work around it by using Union in types, but that's on its way out & inconvenient.

repro

from __future__ import annotations

from libcst.matchers import Name
from typing_extensions import reveal_type

# Name.__or__ is broken
l1: list[Name|int] = [Name("foo"), 5]
reveal_type(l1)
# int.__or__ works, but if you want to union multiple matcher types it's not going to help
l2: list[int|Name] = [Name("foo"), 5]
reveal_type(l2)
$ pyright foo.py
./foo.py
  ./foo.py:8:1 - error: Type of "l1" is partially unknown
    Type of "l1" is "list[Unknown]" (reportUnknownVariableType)
  ./foo.py:8:10 - error: Expected type expression but received "UnionType" (reportGeneralTypeIssues)
  ./foo.py:9:13 - information: Type of "l1" is "list[Unknown]"
  ./foo.py:11:13 - information: Type of "l2" is "list[int | Name]"
2 errors, 0 warnings, 2 informations 
$ mypy foo.py
foo.py:7: note: Revealed type is "builtins.list[Union[libcst.matchers.Name, builtins.int]]"
foo.py:9: note: Revealed type is "builtins.list[Union[builtins.int, libcst.matchers.Name]]"
Success: no issues found in 1 source file

versions

libcst 1.3.1
pyright 1.1.362
mypy 1.9.0

@zsol
Copy link
Member

zsol commented May 13, 2024

I think Pyright's behavior is correct here; essentially we're running into the incompatible changes section in PEP 604.

Other than changing the matcher syntax to use something other than | to delineate alternatives, the only other way I can see us resolving this is if we make types.UnionType work with matchers the same way as TypeOf does - then we could remove this override

def __or__(self, node: Type["BaseMatcherNode"]) -> "TypeOf[Type[BaseMatcherNode]]":
return TypeOf(self, node)

which I believe is causing the problem.

We also override __or__ to produce OneOf matchers, but these are generally instance method overrides, so I don't think they would produce type errors like above

@zsol zsol added enhancement New feature or request machinery Internal plumbing for visitor, transformer, matcher APIs labels May 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request machinery Internal plumbing for visitor, transformer, matcher APIs
Projects
None yet
Development

No branches or pull requests

2 participants