-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Fix type argument inference for overloaded functions with explicit self types (Fixes #14943). #14975
base: master
Are you sure you want to change the base?
Fix type argument inference for overloaded functions with explicit self types (Fixes #14943). #14975
Conversation
…lf types (Fixes python#14943). When finding no compatible callable right away, try to let method `ConstraintBuilderVisitor.find_matching_overload_item` return the first overloaded function with the suitable self type. Checked by test case `TestOverloadedMethodWithExplictSelfTypes`.
mypy/constraints.py
Outdated
# Try to return the first item with the correct self type (fixes issue 14943). | ||
for item in items: | ||
if isinstance(item.definition, FuncDef) and isinstance(item.definition.type, CallableType): | ||
if item.bound_args and item.definition.type.arg_types: |
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 definition
attribute is only supposed to be used for error messages, and it's not guaranteed to be set. It cannot be reliably used for type checking. It's not serialized, in particular, but there may well be other contexts where it's lost that I'm not aware of.
Also, the bound_args
attribute is unfortunately not documented (or the documentation seems incorrect). Again, I'm not sure if we can expect it to be always set.
Here's an alternative approach that might work. When we bind the self type to an overloaded method (in mypy.typeops.bind_self
), what about filtering the overload items at that point to those matching the self type (only when explicit self types are used)? This filtering would happen in an earlier stage, and I believe we have access to all the necessary information without using undocumented or inconsistently set attributes. The result of the filtering could be a non-overloaded callable type or an overloaded type with fewer items.
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 your feedback. Using two fragile attributes in five new lines - what a negative hit rate...
Your suggestion targets code sections I did not encounter yet. My first naive implementation of your suggestion solved the original issue but broke many other things. So far, I could not find any information to distinguish implicit and explicit self types within bind_self
. Is there some obvious way I am missing?
I would take a second, more thorough try within the next few days. Please do not hesitate to fix this yourself if you already have a good solution in mind and if you want that issue fixed before the 1.2 release.
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 tried to filter within bind_self
as suggested. All tests pass (on my computer). Let's see what Mypy primer says.
I am still not overly happy with my approach for the following reasons:
- I added the
ignore_type_vars
option tois_subtype
, which seems like a huge change for such a specific problem to me. - I found no way to distinguish explicit self types from implicit self types.
- The result is still always an overloaded type (changing this within
bind_self
would be simple but requires changing its signature and eventually many code sections that usebind_self
).
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.
3. The result is still always an overloaded type (changing this within
bind_self
would be simple but requires changing its signature and eventually many code sections that usebind_self
).
I played around with returning a single non-overloaded callable for a few minutes. Maybe it's not a good idea because it changes the signatures in error reports and notes. On the other hand, I did not encounter a case where an overloaded type with a single item caused a problem (but I did not actively search for such a problem).
This comment has been minimized.
This comment has been minimized.
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.
… from `testSelfTypeOverrideCompatibilityTypeVar`
Your tip seems helpful. I could remove the filtering logic you implemented in |
This comment has been minimized.
This comment has been minimized.
Yeah, I'm not sure about the ignore_type_vars See this other related PR I opened here: #15045 In this case I was able to replace type vars by their upper bound |
…n from python#15045 for comparison)
This comment has been minimized.
This comment has been minimized.
I added the test case you introduced in #15045 for testing (I can remove it later). It passes with the current For further testing, I also disabled the class C(Generic[T]):
@overload
def __init__(self: C[T], item: T, use_tuple: Literal[False]) -> None: ...
@overload
def __init__(self: C[Tuple[T, ...]], item: T, use_tuple: Literal[True]) -> None: ... Maybe assuming general TypeVar compatibility in the given context is not such a bad thing because |
I think that test case is buggy, there was some discussion at #14729 (comment) and python/typing#1340 (comment) |
Interesting. If we would disallow such self type definitions, the |
This comment has been minimized.
This comment has been minimized.
Diff from mypy_primer, showing the effect of this PR on open source code: pandas (https://github.com/pandas-dev/pandas)
+ pandas/core/series.py:3330: error: Signature of "sort_values" incompatible with supertype "NDFrame" [override]
+ pandas/core/series.py:3330: note: Superclass:
+ pandas/core/series.py:3330: note: @overload
+ pandas/core/series.py:3330: note: def sort_values(self, *, axis: Union[int, Literal['index', 'columns', 'rows']] = ..., ascending: Union[bool, Sequence[bool]] = ..., inplace: Literal[False] = ..., kind: str = ..., na_position: str = ..., ignore_index: bool = ..., key: Optional[Callable[[Series], Union[Series, Union[Union[ExtensionArray, ndarray[Any, Any]], Index, Series]]]] = ...) -> Series
+ pandas/core/series.py:3330: note: @overload
+ pandas/core/series.py:3330: note: def sort_values(self, *, axis: Union[int, Literal['index', 'columns', 'rows']] = ..., ascending: Union[bool, Sequence[bool]] = ..., inplace: Literal[True], kind: str = ..., na_position: str = ..., ignore_index: bool = ..., key: Optional[Callable[[Series], Union[Series, Union[Union[ExtensionArray, ndarray[Any, Any]], Index, Series]]]] = ...) -> None
+ pandas/core/series.py:3330: note: @overload
+ pandas/core/series.py:3330: note: def sort_values(self, *, axis: Union[int, Literal['index', 'columns', 'rows']] = ..., ascending: Union[bool, Sequence[bool]] = ..., inplace: bool = ..., kind: str = ..., na_position: str = ..., ignore_index: bool = ..., key: Optional[Callable[[Series], Union[Series, Union[Union[ExtensionArray, ndarray[Any, Any]], Index, Series]]]] = ...) -> Optional[Series]
+ pandas/core/series.py:3330: note: Subclass:
+ pandas/core/series.py:3330: note: @overload
+ pandas/core/series.py:3330: note: def sort_values(self, *, axis: Union[int, Literal['index', 'columns', 'rows']] = ..., ascending: Union[bool, int, Sequence[bool], Sequence[int]] = ..., inplace: Literal[False] = ..., kind: str = ..., na_position: str = ..., ignore_index: bool = ..., key: Optional[Callable[[Series], Union[Series, Union[Union[ExtensionArray, ndarray[Any, Any]], Index, Series]]]] = ...) -> Series
+ pandas/core/series.py:3330: note: @overload
+ pandas/core/series.py:3330: note: def sort_values(self, *, axis: Union[int, Literal['index', 'columns', 'rows']] = ..., ascending: Union[bool, int, Sequence[bool], Sequence[int]] = ..., inplace: Literal[True], kind: str = ..., na_position: str = ..., ignore_index: bool = ..., key: Optional[Callable[[Series], Union[Series, Union[Union[ExtensionArray, ndarray[Any, Any]], Index, Series]]]] = ...) -> None
pandas-stubs (https://github.com/pandas-dev/pandas-stubs)
- pandas-stubs/core/indexes/range.pyi:87: error: Unused "type: ignore" comment
cwltool (https://github.com/common-workflow-language/cwltool)
- cwltool/main.py:964: error: Unused "type: ignore[arg-type]" comment
mongo-python-driver (https://github.com/mongodb/mongo-python-driver)
- bson/son.py: note: At top level:
- bson/son.py:118: error: Unused "type: ignore" comment
|
The However, some other findings gave me the impression that the |
This requires an explicit `cast` of `shutil.copyfileobj` to work-around a typeshed/Mypy issue. Bumps [mypy](https://github.com/python/mypy) from 1.1.1 to 1.4.1. - [Commits](python/mypy@v1.1.1...v1.4.1) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-minor ... See: python/mypy#15031 See: https://github.com/python/mypy/pull/14902/files#diff-363460977156fcfda748f21565484fe1d5862edf2823e9784cbf34d1e52ff2f2 See: python/mypy#14975 Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Nicolas Trangez <ikke@nicolast.be>
This requires an explicit `cast` of `shutil.copyfileobj` to work-around a typeshed/Mypy issue. Bumps [mypy](https://github.com/python/mypy) from 1.1.1 to 1.4.1. - [Commits](python/mypy@v1.1.1...v1.4.1) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-minor ... See: python/mypy#15031 See: https://github.com/python/mypy/pull/14902/files#diff-363460977156fcfda748f21565484fe1d5862edf2823e9784cbf34d1e52ff2f2 See: python/mypy#14975 Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Nicolas Trangez <ikke@nicolast.be>
This requires an explicit `cast` of `shutil.copyfileobj` to work-around a typeshed/Mypy issue. Bumps [mypy](https://github.com/python/mypy) from 1.1.1 to 1.4.1. - [Commits](python/mypy@v1.1.1...v1.4.1) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-minor ... See: python/mypy#15031 See: https://github.com/python/mypy/pull/14902/files#diff-363460977156fcfda748f21565484fe1d5862edf2823e9784cbf34d1e52ff2f2 See: python/mypy#14975 Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Nicolas Trangez <ikke@nicolast.be>
Fix type argument inference for overloaded functions with explicit self types. Filter out the overload items based on the declared and actual types of self. The implementation is best effort and does the filtering only in simple cases, to reduce the risk of regressions (primarily performance, but I worry also about infinite recursion). I added a fast path for the typical case, since without it the filtering was quite expensive. Note that the overload item filtering already worked in many contexts. This only improves it in specific contexts -- at least when inferring generic protocol compatibility. This is a more localized (and thus lower-risk) fix compared to #14975 (thanks @tyralla!). #14975 might still be a good idea, but I'm not comfortable merging it now, and I want a quick fix to unblock the mypy 1.12 release. Fixes #15031. Fixes #17863. Co-authored by @tyralla.
I guess it becomes more and more unlikely this will ever be merged. So conflict solving and investigating if the |
Fix type argument inference for overloaded functions with explicit self types (Fixes #14943).
When finding no compatible callable right away, try to let method
ConstraintBuilderVisitor.find_matching_overload_item
return the first overloaded function with the suitable self type.Checked by test case
TestOverloadedMethodWithExplictSelfTypes
.