-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[red-knot] Check for invalid overload usages #17609
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
Conversation
CodSpeed Performance ReportMerging #17609 will not alter performanceComparing Summary
|
832935a to
0cdf087
Compare
251e321 to
44601fc
Compare
|
44601fc to
ea4e39e
Compare
f5ef315 to
1e31eea
Compare
|
This PR only adds a single check, I'm thinking of creating a "help wanted" issue that lists down the other checks as the core infrastructure is now in place. |
These all look like false positives where one of the overloads is additionally decorated with |
Yes, sorry I meant to add that to the PR description as I looked at them but somehow missed to do so. Thank you for looking at it. We don't support |
carljm
left a comment
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.
Looks great!
.../resources/mdtest/snapshots/overloads.md_-_Overloads_-_Invalid_-_At_least_two_overloads.snap
Outdated
Show resolved
Hide resolved
3fbeae4 to
8a219b5
Compare
|
I looked at the mypy-primer failure in #17681 which is on from typing import Any, Callable, TypeVar
_T = TypeVar("_T")
# https://github.com/python/typing/issues/769
def copy_type(f: _T) -> Callable[[Any], _T]:
return lambda x: x
@copy_type(open)
def backup_open():
passThe inference builder binds the |
carljm
left a comment
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.
Looks great!
* main: [red-knot] Preliminary `NamedTuple` support (#17738) [red-knot] Add tests for classes that have incompatible `__new__` and `__init__` methods (#17747) Update dependency vite to v6.2.7 (#17746) [red-knot] Update call binding to return all matching overloads (#17618) [`airflow`] apply Replacement::AutoImport to `AIR312` (#17570) [`ruff`] Add fix safety section (`RUF028`) (#17722) [syntax-errors] Detect single starred expression assignment `x = *y` (#17624) py-fuzzer: fix minimization logic when `--only-new-bugs` is passed (#17739) Fix example syntax for pydocstyle ignore_var_parameters option (#17740) [red-knot] Update salsa to prevent panic in custom panic-handler (#17742) [red-knot] Ban direct instantiation of generic protocols as well as non-generic ones (#17741) [red-knot] Lookup of `__new__` (#17733) [red-knot] Check decorator consistency on overloads (#17684) [`flake8-use-pathlib`] Avoid suggesting `Path.iterdir()` for `os.listdir` with file descriptor (`PTH208`) (#17715) [red-knot] Check overloads without an implementation (#17681) Expand Semantic Syntax Coverage (#17725) [red-knot] Check for invalid overload usages (#17609)
Summary
Part of #15383, this PR adds the core infrastructure to check for invalid overloads and adds a diagnostic to raise if there are < 2 overloads for a given definition.
Design notes
The requirements to check the overloads are:
FunctionTypewhich has theto_overloadedmethodFunctionTypeshould be for the function that is either the implementation or the last overload if the implementation doesn't existsFunctionTypethat are part of an overload chainThis required a couple of iteration to make sure all of the above requirements are fulfilled.
1. Use a set to deduplicate
The logic would first collect all the
FunctionTypethat are part of the overload chain except for the implementation or the last overload if the implementation doesn't exists. Then, when iterating over all the function declarations within the scope, we'd avoid checking these functions. But, this approach would fail to consider visibility constraints as certain overloads can be behind a version check. Those aren't part of the overload chain but those aren't a separate overload chain either.Implementation:
2. Define a
predecessorqueryThe
predecessorquery would return the previousFunctionTypefor the givenFunctionTypei.e., the current logic would be extracted to be a query instead. This could then be used to make sure that we're checking the entire overload chain once. The way this would've been implemented is to have ato_overloadedimplementation which would take the root of the overload chain instead of the leaf. But, this would require updates to the use-def map to somehow be able to return the following functions for a given definition.3. Create a successor link
This is what Pyrefly uses, we'd create a forward link between two functions that are involved in an overload chain. This means that for a given function, we can get the successor function. This could be used to find the leaf of the overload chain which can then be used with the
to_overloadedmethod to get the entire overload chain. But, this would also require updating the use-def map to be able to "see" the following function.Implementation
This leads us to the final implementation that this PR implements which is to consider the overloaded functions using:
to_overloadedand perform the checkThis has a limitation that in case a function redefines an overload, then that overload will not be checked. For example:
Test Plan
Update existing mdtest and add snapshot diagnostics.