-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Fix negative narrowing of tuples in match statement #17817
Fix negative narrowing of tuples in match statement #17817
Conversation
DetailsFor the sake of explanation, consider the setup from the linked issue: x: tuple[Literal[1], int]
match x:
case (1, 5):
... The root cause of this issue comes from this snippet: Lines 307 to 314 in 9ffb9dd
This loop iterates of the current types of the tuple positions ( The problem appears to be that the arguments being passed to In the setup above, this causes mypy to deduce that the pattern The fix is to swap the arguments, so that it correctly considers the case of narrowing old-type to new-type. This fixes the linked issue. However, only applying the fix above leads to a test regression; specifically, this test case will fail: mypy/test-data/unit/check-python310.test Lines 1436 to 1442 in ecfab6a
To my understanding, this test is included erroneously, since this sort of narrowing is not technically implemented (yet). Currently, mypy only applies negative narrowing if all subpatterns unconditionally match: Lines 320 to 322 in 9ffb9dd
Matching This can be behavior can be preserved by relaxing the negative-narrowing criteria from all subpatterns match unconditionally to at most one subpattern may match conditionally, and the rest match unconditionally. We can then safely negatively-narrow the single position that conditionally matches. This behavior is demonstrated in the before/after example above with the Open IssuesNegative narrowing of variadic tuples also has a similar issue: from typing import Literal, Unpack
m: tuple[int | str, Unpack[tuple[str, ...]]]
match m:
case (int(), *_):
reveal_type(m) # N: Revealed type is "tuple[builtins.int, Unpack[builtins.tuple[builtins.str, ...]]]"
case _:
reveal_type(m) # E: Statement is unreachable However, the fix is more complicated, so I'm leaving it for a separate PR. |
CC @freundTech as original author in #10191. |
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thank you again for another helpful writeup!
Fixes #17328
Before
Lines marked with
!!!
denote incorrect behavior. (Playground link)After