-
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] improve type shrinking coverage in red-knot property tests #15297
Conversation
|
I believe to have handled all the comments in the first review and have pushed up a new version |
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.
Thank you very much for working on this!
If it's not too much effort, it would be great to see some evidence that shrinking actually gets better. Is it possible to pin the random seed in quickcheck and then show a few before/after results?
Ty::Tuple(types) => Box::new(types.into_iter()), | ||
Ty::Intersection { pos, neg } => Box::new(pos.into_iter().chain(neg)), | ||
Ty::Union(types) => Box::new(types.shrink().filter_map(|elts| match elts.len() { | ||
0 => None, |
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.
It might not be completely unreasonable to try and return Ty::Never
here?
This also makes me think: I think we currently only try shrinking for the root of the Type
tree? Like if we have tuple[A | B, C]
, I think we would only try to remove either A | B
from the tuple, or try to remove C
from the tuple, i.e. we try to shrink to C
or to A | B
, but we would not try to shrink the A | B
union.
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.
Calling shrink on the vector of types actually does attempt to shrink the elements of the vector as well as trying to remove elements, so we get nice shrinking just leaning on the shrinking built into quickcheck (at least that was my read of the source)
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.
Regarding the empty union shrinking to Ty::Never
... feels fine by me! Especially now that I fully grok that Ty
is a smart constructor for Type
so I don't need to worried about types being in the "wrong location", so to speak
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.
Calling shrink on the vector of types actually does attempt to shrink the elements of the vector as well as trying to remove elements
👍
Regarding the empty union shrinking to
Ty::Never
... feels fine by me! Especially now that I fully grok thatTy
is a smart constructor forType
so I don't need to worried about types being in the "wrong location", so to speak
If we try to shrink at all "depths", I think we can skip this. The idea was to simplify nested Ty
unions like A | B | (C | D)
to A | B | Never
and then further down to A | B
, but there are many other possible shrinking-paths that would lead to that result (e.g. via the single-element union or via a element-removal shrink on the outer union).
@sharkdp do you know how to pin the quickcheck seed? I'm looking through the quickcheck source and readme and not seeing anything, but I am famously bad at finding things that are obvious. |
No, I just hoped there would be a way. But it does not seem to be the case: BurntSushi/quickcheck#278 In this case, I'm okay with your "now the errors seem more minimal" observation. |
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.
Thank you for this.
* main: Use uv consistently throughout the documentation (#15302) [red-knot] Eagerly normalize `type[]` types (#15272) [`pyupgrade`] Split `UP007` to two individual rules for `Union` and `Optional` (`UP007`, `UP045`) (#15313) [red-knot] Improve symbol-lookup tracing (#14907) [red-knot] improve type shrinking coverage in red-knot property tests (#15297) [`flake8-return`] Recognize functions returning `Never` as non-returning (`RET503`) (#15298) [`flake8-bugbear`] Implement `class-as-data-structure` (`B903`) (#9601) Avoid treating newline-separated sections as sub-sections (#15311) Remove call when removing final argument from `format` (#15309) Don't enforce `object-without-hash-method` in stubs (#15310) Don't special-case class instances in binary expression inference (#15161) Upgrade zizmor to the latest version in CI (#15300)
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 misunderstoodquickcheck
's core loopWhen shrinking
Intersection
s, in order to just rely onquickcheck
'sVec
shrinking without thinking about it too much, the shrinking strategy is: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 onmain
, but now the errors seem more minimal.