-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
[red-knot] (Gradual) intersection types are not handled in assignability #14899
Comments
Moving this out of Backlog and into Ready, and also marking help-wanted in case a contributor is interested in it, because I think having the quickcheck tests stable and green on main is quite valuable. Just now I was making another change to type relations, ran the quickcheck tests, and hit this failure, which diverted me for a while until I realized it was failing also on main and found this issue. |
## Summary Teach red-knot that `type[...]` is always disjoint from `None` and from `LiteralString`. Fixes #14925. This should properly be generalized to "all instances of final types which are not subclasses of `type`", but until we support finality, hardcoding `None` (which is known to be final) allows us to fix the subtype transitivity property test. ## Test Plan Existing tests pass, added new unit tests for `is_disjoint_from` and `is_subtype_of`. `QUICKCHECK_TESTS=100000 cargo test -p red_knot_python_semantic -- --ignored types::property_tests::stable` fails only the "assignability is reflexive" test, which is known to fail on `main` (#14899). The same command, with `property_tests.rs` edited to prevent generating intersection tests (the cause of #14899), passes all quickcheck tests.
…<metaclass of T>)` (#14970) ## Summary A class is an instance of its metaclass, so `ClassLiteral("ABC")` is not disjoint from `Instance("ABCMeta")`. However, we erroneously consider the two types disjoint on the `main` branch. This PR fixes that. This bug was uncovered by adding some more core types to the property tests that provide coverage for classes that have custom metaclasses. The additions to the property tests are included in this PR. ## Test Plan New unit tests and property tests added. Tested with: - `cargo test -p red_knot_python_semantic` - `QUICKCHECK_TESTS=100000 cargo test -p red_knot_python_semantic -- --ignored types::property_tests::stable` The assignability property test fails on this branch, but that's a known issue that exists on `main`, due to #14899.
## Summary We understand `sys.version_info` branches now! As such, I _believe_ this branch is no longer required; all tests pass without it. I also ran `QUICKCHECK_TESTS=100000 cargo test -p red_knot_python_semantic -- --ignored types::property_tests::stable`, and no tests failed except for the known issue with `Type::is_assignable_to()` (#14899) ## Test Plan See above
Regarding this, is I think the arbitrary generator currently in the property tests will gladly generate non-normalized intersections in particular, which might be generating false positives in these tests. |
After poking at this a bit more, I now feel like the main problem with the existing |
Yeah, agreed that this would be a big usability improvement! |
The idle thought I had here is that it would be cool if quickcheck ran shrunk failures one last time after finding minimal repros, and had a "verbose log" mechanism that would let me put in "expensive" logs or For now I might try to just add something into the test harness and see how much slower it is. Computers still are fast after all. |
…#15297) ## Summary While looking at #14899, I looked at seeing if I could get shrinking on the examples. It turned out to be straightforward, with a couple of caveats. I'm calling `clone` a lot during shrinking. Since by the shrink step we're already looking at a test failure this feels fine? Unless I misunderstood `quickcheck`'s core loop When shrinking `Intersection`s, in order to just rely on `quickcheck`'s `Vec` shrinking without thinking about it too much, the shrinking strategy is: - try to shrink the negative side (keeping the positive side the same) - try to shrink the positive side (keeping the negative side the same) This means that you can't shrink from `(A & B & ~C & ~D)` directly to `(A & ~C)`! You would first need an intermediate failure at `(A & B & ~C)` or `(A & ~C & ~D)`. This feels good enough. Shrinking the negative side first also has the benefit of trying to strip down negative elements in these intersections. ## Test Plan `cargo test -p red_knot_python_semantic -- --ignored types::property_tests::stable` still fails as it current does on `main`, but now the errors seem more minimal.
This issue is actually a bit more general than the title/description make it sound like. We currently don't have any logic for handling intersection types in the def f(x) -> None:
if isinstance(x, int):
reveal_type(x) # Unknown & int
y: int = x # currently fails with invalid-assignment We could probably write a property test like |
is_assignable_to
is not reflexive
This bug now has some failing unit tests here: ruff/crates/red_knot_python_semantic/resources/mdtest/type_properties/is_assignable_to.md Lines 267 to 276 in beb8e2d
|
## Summary - Add a workflow to run property tests on a daily basis (based on `daily_fuzz.yaml`) - Mark `assignable_to_is_reflexive` as flaky (related to #14899) - Add new (failing) `intersection_assignable_to_both` test (also related to #14899) ## Test Plan Ran: ```bash export QUICKCHECK_TESTS=100000 while cargo test --release -p red_knot_python_semantic -- \ --ignored types::property_tests::stable; do :; done ``` Observed successful property_tests CI run
The
is_assignable_to
-is-reflexive property test, which makes sure that we can assign any type to itself, is currently failing with counter-examples likeAny & T
, whereT
is an arbitrary type (that doesn't let the intersection collapse).The reason for this is that we can't rely on equivalence for assignability of gradual types anymore ever since #14758. We do have some special casing for gradual types like
Any
andUnknown
, as well as for unions and tuples of these, but we do lack handling of intersections.This is not completely trivial. We can patch this with some superficial handling like
which also works for things like
T & ~Any
, because we always addAny
/Unknown
as positive contributions to intersections.But then quickcheck finds types like
~tuple[Any, T]
, for which the simple handling above breaks.The text was updated successfully, but these errors were encountered: