-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
List possible overload variants when none match #5296
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
List possible overload variants when none match #5296
Conversation
Resolves python#672 and supercedes python#5054. Currently, if a user calls an overloaded function and mypy is unable to find a match, mypy will display display a warning like 'No overload variant of "func" matches argument types" with no additional context. This pull request will list several matching variants in addition to that message. If possible, mypy will attempt to show only overloads that have a compatible number of arguments. The number of overloads shown is always capped at a maximum of 2. This pull request does *not* attempt to report a custom error when... 1. Union-math fails. Rationale: the pending PR will change how unions are handled dramatically enough to the point where any error handling here would be pointless. 2. Mypy is able to infer what signature the user most likely meant by looking at the erased types. Rationale: I attempted to implement this feature but was unable to make it consistently work without adding several ugly hacks around how mypy records errors so decided to defer implementing this feature.
Sorry, it looks like I will not be able to review today :-( Probably on Saturday evening. |
@ilevkivskyi -- no worries, take your time :) If you also want to prioritize landing the other overload PRs first, I'm fine with that. This PR feels like the kind of thing that'll cause a bunch of merge conflicts, so maybe it makes sense to just defer reviewing this so I can fix the conflicts all in one go instead of distributing them through the other PRs. |
Up to you though, of course. |
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.
Thanks! Looks good to me. There is one minor comment, feel free to merge when it is easier for you.
mypy/messages.py
Outdated
offset: int, max_items: int) -> None: | ||
for item in tp.items()[:max_items]: | ||
if len(targets) == 0: |
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.
if not targets:
would be more idiomatic.
@gvanrossum -- before I merge this in, did you want to take a quick look? I know you said that the error messages were too noisy in the previous incarnation of this PR. If you still feel that way, there are probably one or two things I could try doing to make the error message shorter. |
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.
OK, since you asked, I still have some quibbles with the output. I trust Ivan reviewed the algorithmic part of the code adequately.
mypy/messages.py
Outdated
shown = min(max_items, len(targets)) | ||
max_available = len(func.items()) | ||
if shown < max_available: | ||
self.note('<{} more overload(s) not shown>'.format(max_available - shown), |
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.
Apart form the uglines around plurals, it seems there are two possible reasons why not all overloads are shown:
- because they don't match the number of arguments (or the keywords or whatever)
- because the sheer number exceeds
max_items
I think it would be good to differentiate between these in the messages somehow.
mypy/messages.py
Outdated
for item in tp.items()[:max_items]: | ||
if not targets: | ||
targets = func.items() | ||
for item in targets[:max_items]: | ||
self.note('@overload', context, offset=2 * offset) |
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.
The extra line with @overload
just doubles the verbosity without adding any information. I think it's okay to leave it out.
This commit responds to the latest code review. It... 1. Handles plurals. 2. Removes the '@overload' text to help save space. 3. Modifies the 'some overloads not shown' message so it instead displays one of two variants: if we aren't showing all matching variants, we display: <X more matching overloads not shown, out of N total overloads> This happens if there are more then 2 matching overloads. If we do show all matching variants but hide non-matching overloads, we display: <X more non-matching overloads not shown> 4. Moves all of the new overload display functionality back to a new method named `pretty_overload_matches` and reverts `pretty_overload` back to the original logic. (The new logic was growing to be different enough from the previous logic that a split seemed like the cleanest approach.)
@gvanrossum and/or @ilevkivskyi -- how's this? The new format should handle plurals correctly and will display a message that looks like this if there are more then 2 overloads that have matching types/arity/whatever:
...or like this if we're suppressing only non-matching overloads:
...and of course, like this if we we were able to display all the variants:
(I guess since we cut the number of lines shown in half by removing |
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.
Thanks! Looks even better now.
mypy/messages.py
Outdated
if shown < max_available: | ||
left = max_available - shown | ||
msg = '<{} more overload{} not shown>'.format(left, plural_s(left)) | ||
self.note(msg, context, offset=2 * offset) |
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.
All changes in this function are unnecessary now, except plural_s
usage.
mypy/messages.py
Outdated
assert shown <= max_matching <= max_available | ||
if shown < max_matching <= max_available: | ||
left = max_matching - shown | ||
msg = '<{} more matching overload{} not shown, out of {} total overloads>'.format( |
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.
I would rather say this as {} more matching and {} non-matching overload{} not shown
. But this is still not perfect because the overloads aren't "matching" (as the error message above says). Anyway, I think it is not so important to delay merging this PR, so I will go ahead unless someone proposes better wording.
@Michael0x2a Will you have time to make minor final updates here before I cut the release branch tomorrow morning? (If not it is also OK.) |
@ilevkivskyi -- most likely. I'm planning on leaving work + finishing dinner in roughly 5 hours or so and can start making any necessary changes after that. I guess the timing might be a little tight, depending on whether you mean morning Dublin time vs Pacific time, but eh, whatever. |
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.
I'm personally happy at this point, though I'm not sure how Ivan feels. If you're going to iterate on this more, here's one more idea that will surely drive you nuts: why replace one line that has useful info with another line that says "<1 more not shown>"? It might make more sense to just display the extra overload, and only start suppressing overloads when the excess is 2 or more. (Then again maybe the overload is much longer than what fits on a line, so take this with a grain of salt. Also it's probably not worth the extra complexity in the code, and you are probably tired of me.)
@gvanrossum and @ilevkivskyi -- Mkay, I reverted the changes to I'll merge this in once the tests pass (unless there are any last-minute objections, I guess). |
Resolves #672 and supersedes #5054.
Currently, if a user calls an overloaded function and mypy is unable to find a match, mypy will display display a warning like 'No overload variant of "func" matches argument types" with no additional context.
This pull request will list several matching variants in addition to that message. If possible, mypy will attempt to show only overloads that have a compatible number of arguments. The number of overloads shown is always capped at a maximum of 2.
This pull request does not attempt to report a custom error when...
Union-math fails. Rationale: the pending PR will change how unions are handled dramatically enough to the point where any error handling here would be pointless.
Mypy is able to infer what signature the user most likely meant by looking at the erased types. Rationale: I attempted to implement this feature but was unable to make it consistently work without adding several ugly hacks around how mypy records errors so decided to defer implementing this feature.