[ty] chore: ContextManagerError message update#20199
[ty] chore: ContextManagerError message update#20199Y3K wants to merge 3 commits intoastral-sh:mainfrom
ContextManagerError message update#20199Conversation
Diagnostic diff on typing conformance testsNo changes detected when running ty on typing conformance tests ✅ |
|
06686e9 to
0fdf81e
Compare
ContextManagerError message update
0fdf81e to
9733d41
Compare
carljm
left a comment
There was a problem hiding this comment.
Thanks for the pull request! This is definitely an improvement.
My idea when I filed the issue was that we would bubble up the information about which types had the dunder unbound or possibly-unbound as part of the CallDunderError, but looking at it now I see this would probably require special-casing Type::Union in try_call_dunder (because member_lookup_with_policy squashes union information into a single PlaceAndQualifiers). I still think this might make sense, but I also think it's OK to just re-create the information once we know there's a problem.
| ``` | ||
|
|
||
| ## Union context managers with specific member issues | ||
|
|
There was a problem hiding this comment.
We can snapshot diagnostics for these tests, which is an easier way to see the full resulting diagnostic, instead of putting full error messages directly in the mdtest. This is usually preferred for tests focused on diagnostic rendering, and is especially useful when the diagnostic is not all crammed into a single sentence, as I suggest below.
| <!-- snapshot-diagnostics --> | |
Then you use cargo insta test -p ty_python_semantic to generate new snapshots to review with cargo insta review and then commit.
There was a problem hiding this comment.
Sorry for the rookie question.
Can I get a really brief example of how snapshots work?
e.g. should be snapshotted in main or post changes? What if the message changes do I need to update snaps? Are all the snaps run when I do cargo nextest run?
|
|
||
| context_expr = Bound() if flag else EnterUnbound() | ||
|
|
||
| # error: [invalid-context-manager] "Object of type `Bound | EnterUnbound` cannot be used with `async with` because the method `__aenter__` of `EnterUnbound` is possibly unbound" |
There was a problem hiding this comment.
E.g. if we snapshot diagnostics, then we can just do this here:
| # error: [invalid-context-manager] "Object of type `Bound | EnterUnbound` cannot be used with `async with` because the method `__aenter__` of `EnterUnbound` is possibly unbound" | |
| # error: [invalid-context-manager] |
|
Thank you for your review @carljm! I'm quite rookie with Rust and I'll read each suggestion carefully and work on a new approach, will ping you once it's ready. Thanks! |
|
@Y3K happy to offer clarification on any comments. I think for purposes of this PR you can ignore the comment about "bubbling up the information through |
|
Thank you again, @carljm ! I don't want to waste a lot of your time, but I do accept any extra help you want and can provide. Will address all your feedback within this PR 🙌🏼 |
aee5519 to
67846c0
Compare
|
I'm closing this due to inactivity. Please feel free to comment in case it should be re-opened. I'll add a comment to the linked ticket that this is useful as a resource if someone picks that task up again. |
…m context manager dunder methods invoked on a union. (#24662) <!-- Thank you for contributing to Ruff/ty! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? (Please prefix with `[ty]` for ty pull requests.) - Does this pull request include references to any relevant issues? - Does this PR follow our AI policy (https://github.com/astral-sh/.github/blob/main/AI_POLICY.md)? --> ## Summary As part of astral-sh/ty#940, this helps us emit more specific diagnostics for possibly unbound context manager dunders (e.g., `__enter__`, `__exit__`) invoked on a union type. Where previously the following snippet would produce just the top-level diagnostic commented below: ```py class Context: def __enter__(self): ... def __exit__(self, *args): ... class NotContext: pass def _(x: Context | NotContext): # error: [invalid-context-manager] "Object of type `Context | NotContext` cannot be used with `with` because the methods `__enter__` and `__exit__` are possibly unbound" with x: pass ``` We will now produce two further "info" sub-diagnostics: ``` info: `NotContext` does not implement `__enter__` info: `NotContext` does not implement `__exit__` ``` ## Approach - This implements the approach suggested by `@carljm` [here](#20199 (review)) from a previous attempt to address astral-sh/ty#940; it extends `CallDunderError::PossiblyUnbound` with a new `unbound_on` field that stores a list of the union members on which a particular dunder is unbound. We create the new, richer error with a new `UnionType.try_call_dunder_with_policy` method that looks up the dunder on each member of the union, and then aggregates the results. This is supersedes the previous `UnionType.map_with_boundness_and_qualifiers` approach, and allows us to preserve the per-member binding information that we use to produce the more detailed diagnostic. - There are two alternatives to this approach that I considered but rejected: - Rebuild the specific union member diagnositic information at each callsite, and only when relevant. This was the approach originally taken by #20199, but I think it will lead to some unnecessary code duplication across callsites (of which there are at least three more). - Refactor such that `UnionType.map_with_boundness_and_qualifiers` such that it no longer loses member-specific binding information when producing its result. This would have required an extension to `PlaceAndQualifiers`, which would have a large blast radius and also introduce overhead in several cases where member-specific information for unions is not necessary. - There are more implicit dunder calls that can benefit from the new shape of `CallDunderError::PossiblyUnbound`, but I have intentionally deferred those to [a follow-up](#24676) in order to first collect feedback on a more targeted changeset. - The first three commits in this PR (926bcec, 65dc3fb, 988e81d) are "prefactors" that do not change any observable behaviour. The fourth (2422844) actually implements the improvement, and deserves the most scrutiny. ## Test Plan Please see updated mdtests and associated snapshots.
Summary
Fixes astral-sh/ty#940
Test Plan