[ty] Narrow later match cases after always-true guards - #28960
Conversation
Typing conformance resultsNo changes detected ✅Current numbersThe percentage of diagnostics emitted that were expected errors held steady at 98.24%. The percentage of expected errors that received a diagnostic held steady at 98.24%. The number of fully passing files held steady at 134/146. |
Memory usage reportMemory usage unchanged ✅ |
|
Merging this PR will improve performance by 8.63%
Performance Changes
Tip Curious why performance improved? Comment Comparing Footnotes
|
34f299c to
4de227b
Compare
There was a problem hiding this comment.
Thank you. This makes a lot of sense to me.
After reading the PR description I was expecting to see a test case like the following, but that seems too ambitious. Probably requires additional changes to narrowing?
class Color(Enum):
RED = 0
BLUE = 1
class Answer(Enum):
NO = 0
YES = 1
def _(color: Color, answer: Answer):
match color:
case Color.RED if answer is Answer.NO:
x = 0
case Color.RED if answer is Answer.YES: # always true guard
x = 1
case Color.RED:
x = 2 # unreachable
case _:
x = 3
reveal_type(x) # Literal[0, 1, 2, 3] on your branch, excluding 2 would be nice| class Color(Enum): | ||
| RED = 1 | ||
| BLUE = 2 |
There was a problem hiding this comment.
Deeply disappointed that you didn't pick up my
class Answer(Enum):
NO = 0
YES = 1pattern.
That would be very cool indeed, but yes, I think it's too ambitious for now |
19c5bb4 to
6f12c13
Compare
Summary
ty currently retains values matched by an earlier
matchcase whenever that case has a guard, even if the guard is statically true. This can make later pattern captures too broad and leave impossible cases appearing reachable.This PR changes our inference so that we treat a pattern whose guard is statically true like an unguarded pattern when narrowing later cases, including enum-pattern reachability. False and ambiguous guards remain conservative. Guard truthiness uses the existing condition analysis, including its conservative recovery for inference cycles.
On its own, this isn't a particularly important change, but codex was worried that analyzing reachability of
matchpatterns without this change would lead to false positives/negatives when it came to adding a check that would complain about non-exhaustivematchstatements. I'm therefore separating this into a standalone change that can be merged first.A naive implementation of this PR led to hangs (and eventual panics, if the script was left for a very long time) on three
py-fuzzerseeds. Some changes were therefore required toreachability.rsto tweak which queries we cache and which we don't. Happily, this PR appears to have the side effect of significantly speeding up one of our microbenchmarks following those tweaks.