[ty] Refactor if narrowing#18392
Conversation
|
Looks like there are still some failing tests here? Let me know if any of these are things you'd like a second pair of eyes on how to address; otherwise I'll mark this as draft, go ahead and put it back up for review when CI is green. |
Looks like we're green now, but mypy primer seems unhappy (sorry if that means I shouldn't have opened it, but I'm not sure how to proceed with primer failures) |
|
Thank you for working on this!
The mypy_primer run was failing due to a network error. I re-ran it now and it fails with This might be related to astral-sh/ty#365 (comment). I am planning to fix that bug as soon as #18041 is merged (which makes significant changes to the semantic index builder, and has a much higher impact). I suggest that we wait with this PR until these two things have been resolved. |
| def _[T](x: A | B): | ||
| if type(x) is A[str]: | ||
| reveal_type(x) # revealed: (A[int] & A[Unknown]) | (B & A[Unknown]) | ||
| # TODO: previous was revealed: (A[int] & A[Unknown]) | (B & A[Unknown]) |
There was a problem hiding this comment.
I think the conclusion that this is unreachable code is actually correct -- type(x) will never return a GenericAlias at runtime, so type(x) is A[str] can never be true, only type(x) is A can be.
This test probably warrants some expansion, but it doesn't need to happen in this PR. We have an issue open for improving how we handle narrowing against generic types.
| # TODO: false positive due to unreachable, causing @overload to be typed at | ||
| # Never |
There was a problem hiding this comment.
We intend to generally silence diagnostics in unreachable code, which should take care of this
| let v_constraint = self.record_visibility_constraint(predicate); | ||
| self.visit_body(clause_body); | ||
| self.record_visibility_constraint_id(v_constraint); |
There was a problem hiding this comment.
As we discussed, it definitely looks weird that we have to record the visibility constraint both before and after. I'm going to take a closer look to try to understand why that is.
|
Not able to reproduce the mypy-primer error running this locally. Will push a rebase and see if it repros in CI. |
d282919 to
4af0119
Compare
CodSpeed Performance ReportMerging #18392 will degrade performances by 4.14%Comparing Summary
Benchmarks breakdown
|
|
Hmm, well, it definitely repros here. That's odd. This is what I'm running locally: |
|
Ah, figured it out. The failing file is # Windows imports
if sys.platform == "win32":
from ._run import (
current_iocp,
monitor_completion_key,
readinto_overlapped,
register_with_iocp,
wait_overlapped,
write_overlapped,
)
# Kqueue imports
elif sys.platform != "linux" and sys.platform != "win32":
from ._run import current_kqueue, monitor_kevent, wait_keventAnd the failure repros locally if I run with Since the repro is an |
|
@sharkdp is now working on a larger refactor of reachability and visibility constraints, we should revisit this after that's done and see what is still needed/relevant here. Thanks for the work on this PR, it helped demonstrate the need for this refactor. |
## Summary * Completely removes the concept of visibility constraints. Reachability constraints are now used to model the static visibility of bindings and declarations. Reachability constraints are *much* easier to reason about / work with, since they are applied at the beginning of a branch, and not applied retroactively. Removing the duplication between visibility and reachability constraints also leads to major code simplifications [^1]. For an overview of how the new constraint system works, see the updated doc comment in `reachability_constraints.rs`. * Fixes a [control-flow modeling bug (panic)](astral-sh/ty#365) involving `break` statements in loops * Fixes a [bug where](astral-sh/ty#624) where `elif` branches would have wrong reachability constraints * Fixes a [bug where](astral-sh/ty#648) code after infinite loops would not be considered unreachble * Fixes a panic on the `pywin32` ecosystem project, which we should be able to move to `good.txt` once this has been merged. * Removes some false positives in unreachable code because we infer `Never` more often, due to the fact that reachability constraints now apply retroactively to *all* active bindings, not just to bindings inside a branch. * As one example, this removes the `division-by-zero` diagnostic from astral-sh/ty#443 because we now infer `Never` for the divisor. * Supersedes and includes similar test changes as #18392 closes astral-sh/ty#365 closes astral-sh/ty#624 closes astral-sh/ty#642 closes astral-sh/ty#648 ## Benchmarks Benchmarks on black, pandas, and sympy showed that this is neither a performance improvement, nor a regression. ## Test Plan Regression tests for: - [x] astral-sh/ty#365 - [x] astral-sh/ty#624 - [x] astral-sh/ty#642 - [x] astral-sh/ty#648 [^1]: I'm afraid this is something that @carljm advocated for since the beginning, and I'm not sure anymore why we have never seriously tried this before. So I suggest we do *not* attempt to do a historical deep dive to find out exactly why this ever became so complicated, and just enjoy the fact that we eventually arrived here. --------- Co-authored-by: Carl Meyer <[email protected]>
|
I'm going to close this, now that #18621 has been merged. @ericmarkmartin thank you for your work here. |
Summary
Refactor the semantic index builder’s If statement analysis. This change also lets us detect more unreachable code paths.
Test Plan