You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Python version (and distribution if applicable, e.g. Anaconda): Python 3.12.3
python.analysis.indexing: true
python.analysis.typeCheckingMode: standard
Code Snippet
importtypingtypeMaybe[T] =T|NonetypeSparsePair[T, S] =tuple[Maybe[T], Maybe[S]]
defmaybe_add(sparse_pair: SparsePair[int, int]) ->int:
matchsparse_pair:
caseNone, None:
return0casea, None:
# Pylance: "assert_type" mismatch: expected "int" but received "int | None"typing.assert_type(a, int)
returnacaseNone, b:
# No problem in this case!typing.assert_type(b, int)
returnbcasea, b:
# Also okay here, too!typing.assert_type(a, int)
typing.assert_type(b, int)
returna+bcase_:
typing.assert_never(sparse_pair)
Expected behavior
I expect the typing.assert_type(a, int) statement to not raise any sort of error with Pylance/Pyright.
Actual behavior
Pylance/Pyright thinks that a has type int | None in the case a, None: ... block.
And for what it's worth, you can switch the order of the case a, None: ... and case None, b: ... and observe that the issue is only ever with the first case statement after the case None, None: ....
I realize that I could just use case int(a), None: ... or case None, int(b): ... but I'd like this to work when I otherwise cannot use a concrete type to use in the case statement to match against, like if the sparse pair was generic still (so, each element has type T | None for some generic T.
Additionally, I experimented with how Mypy handles this and Mypy does not seem to correctly narrow the types when matching against tuples like this at all, so this behavior is beyond what Mypy guarantees—which I appreciate!
This is by design. Pyright (the type checker upon which pylance is built) performs type narrowing for tuples only in the case where one tuple element can be narrowed. It doesn't perform generalized tuple expansion for all combinations of possible tuples. Such behavior would lead to a combinatoric explosion. For example, the type tuple[int | None, int | None] would need to be expanded to tuple[int, int] | tuple[int, None] | tuple[None, int] | tuple[None | None]. This isn't too bad for a two-element tuple, but it grows exponentially with the size of the tuple.
Environment data
Code Snippet
Expected behavior
I expect the
typing.assert_type(a, int)
statement to not raise any sort of error with Pylance/Pyright.Actual behavior
Pylance/Pyright thinks that
a
has typeint | None
in thecase a, None: ...
block.And for what it's worth, you can switch the order of the
case a, None: ...
andcase None, b: ...
and observe that the issue is only ever with the first case statement after thecase None, None: ...
.I realize that I could just use
case int(a), None: ...
orcase None, int(b): ...
but I'd like this to work when I otherwise cannot use a concrete type to use in the case statement to match against, like if the sparse pair was generic still (so, each element has typeT | None
for some genericT
.Additionally, I experimented with how Mypy handles this and Mypy does not seem to correctly narrow the types when matching against tuples like this at all, so this behavior is beyond what Mypy guarantees—which I appreciate!
Related Mypy issue: python/mypy#12364
Thank you!
The text was updated successfully, but these errors were encountered: