Fix overload ambiguity returning Any when one overload returns Never#21592
Closed
LeSingh1 wants to merge 1 commit into
Closed
Fix overload ambiguity returning Any when one overload returns Never#21592LeSingh1 wants to merge 1 commit into
LeSingh1 wants to merge 1 commit into
Conversation
…contains Any When a function has overloads where one returns Never and another returns a concrete type, and the argument has type Any (causing overload ambiguity), mypy was falling back to Any instead of using the Never-returning overload. Never is a subtype of every type, so an overload returning Never is always the most specific possible result. When Any-argument ambiguity fires and exactly one matching overload returns Never, there is no real ambiguity to resolve: the Never overload is the right answer. This was particularly visible with iter() on generic classes that have both __iter__ (returning Never) and __getitem__: iter(x) was returning Any when x had an Any type argument, while x.__iter__() correctly returned Never. Fixes python#21027
Contributor
|
Diff from mypy_primer, showing the effect of this PR on open source code: optuna (https://github.com/optuna/optuna)
+ optuna/importance/_fanova/_tree.py:187: error: Need type annotation for "sizes" (hint: "sizes: list[<type>] = ...") [var-annotated]
+ optuna/importance/_fanova/_tree.py:199: error: Need type annotation for "size" [var-annotated]
+ optuna/importance/_fanova/_tree.py:306: error: Incompatible return value type (got "signedinteger[_32Bit | _64Bit]", expected "float") [return-value]
+ optuna/_hypervolume/wfg.py:12: error: Need type annotation for "edge_length_y" [var-annotated]
+ optuna/_hypervolume/wfg.py:35: error: Need type annotation for "x_delta" [var-annotated]
+ optuna/_hypervolume/wfg.py:58: error: Need type annotation for "inclusive_hvs" [var-annotated]
+ optuna/_hypervolume/hssp.py:115: error: Need type annotation for "diff_of_loss_vals_and_ref_point" [var-annotated]
+ optuna/samplers/_tpe/sampler.py:669: error: Need type annotation for "acq_func_vals" [var-annotated]
+ optuna/visualization/_optimization_history.py:281: error: Need type annotation for "lower" [var-annotated]
+ optuna/visualization/matplotlib/_optimization_history.py:135: error: Need type annotation for "lower" [var-annotated]
+ tests/gp_tests/test_batched_lbfgsb.py:36: error: Incompatible return value type (got "tuple[Any, float]", expected "tuple[ndarray[tuple[Any, ...], dtype[Any]], ndarray[tuple[Any, ...], dtype[Any]]]") [return-value]
spark (https://github.com/apache/spark)
+ python/pyspark/worker.py:2826: error: Need type annotation for "value_df" [var-annotated]
colour (https://github.com/colour-science/colour)
+ colour/geometry/intersection.py:214: error: Need type annotation for "x_4_x_3" [var-annotated]
+ colour/geometry/intersection.py:215: error: Need type annotation for "y_1_y_3" [var-annotated]
+ colour/geometry/intersection.py:216: error: Need type annotation for "y_4_y_3" [var-annotated]
+ colour/geometry/intersection.py:217: error: Need type annotation for "x_1_x_3" [var-annotated]
+ colour/geometry/intersection.py:218: error: Need type annotation for "x_2_x_1" [var-annotated]
+ colour/geometry/intersection.py:219: error: Need type annotation for "y_2_y_1" [var-annotated]
+ colour/geometry/intersection.py:221: error: Need type annotation for "numerator_a" [var-annotated]
+ colour/geometry/intersection.py:222: error: Need type annotation for "numerator_b" [var-annotated]
+ colour/geometry/intersection.py:223: error: Need type annotation for "denominator" [var-annotated]
+ colour/geometry/intersection.py:232: error: Need type annotation for "parallel" [var-annotated]
+ colour/difference/delta_e.py:1135: error: Need type annotation for "dLab" [var-annotated]
+ colour/characterisation/correction.py:1454: error: Need type annotation for "D" [var-annotated]
+ colour/quality/tm3018.py:206: error: Need type annotation for "a_deltas" [var-annotated]
+ colour/quality/tm3018.py:207: error: Need type annotation for "b_deltas" [var-annotated]
altair (https://github.com/vega/altair)
+ tests/vegalite/v6/test_api.py:748: error: Need type annotation for "input_condition" [var-annotated]
scipy (https://github.com/scipy/scipy)
+ scipy/stats/_multicomp.py:171: error: Need type annotation for "diff_means" [var-annotated]
pandas-stubs (https://github.com/pandas-dev/pandas-stubs)
+ tests/series/test_truediv.py:180: error: Expression is of type "Never", not "Any" [assert-type]
+ tests/series/test_sub.py:94: error: Expression is of type "Never", not "Any" [assert-type]
+ tests/series/test_sub.py:97: error: Statement is unreachable [unreachable]
+ tests/series/test_floordiv.py:148: error: Expression is of type "Never", not "Any" [assert-type]
+ tests/series/test_floordiv.py:153: error: Statement is unreachable [unreachable]
+ tests/series/test_floordiv.py:159: error: Unused "type: ignore" comment [unused-ignore]
+ tests/series/test_floordiv.py:165: error: Unused "type: ignore" comment [unused-ignore]
+ tests/series/test_floordiv.py:176: error: Unused "type: ignore" comment [unused-ignore]
+ tests/series/test_floordiv.py:177: error: Unused "type: ignore" comment [unused-ignore]
+ tests/indexes/test_sub.py:66: error: Expression is of type "Never", not "Any" [assert-type]
+ tests/indexes/test_sub.py:69: error: Statement is unreachable [unreachable]
+ tests/indexes/test_floordiv.py:115: error: Expression is of type "Never", not "Any" [assert-type]
pandas (https://github.com/pandas-dev/pandas)
+ pandas/core/indexes/base.py:4179: error: Need type annotation for "diff" [var-annotated]
xarray (https://github.com/pydata/xarray)
+ xarray/tests/test_cftime_offsets.py: note: In function "test_cftime_range":
+ xarray/tests/test_cftime_offsets.py:1272: error: Need type annotation for "deltas" [var-annotated]
+ xarray/tests/test_cftime_offsets.py:1273: error: Incompatible types in assignment (expression has type "ndarray[tuple[Any, ...], dtype[Any]]", variable has type "Never") [assignment]
+ xarray/tests/test_cftime_offsets.py:1273: error: Need type annotation for "delta" [var-annotated]
jax (https://github.com/google/jax)
+ jax/_src/pallas/mosaic/lowering.py:4291: error: Need type annotation for "sizes" [var-annotated]
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #21027.
When checking an overloaded call where the argument has type
Any, mypy collects all matching overloads and checks whether theAnycauses ambiguity. If it does and the return types differ, mypy falls back toAny. This is the right behavior in general, but it is wrong when one of the matching overloads returnsNever.Neveris a subtype of every type. An overload returningNeveris always the most specific result possible. If exactly one overload in the ambiguous set returnsNever, there is no actual ambiguity to resolve: theNeveroverload is the right answer regardless of which overload would have been selected at runtime.The bug was visible with
iter()on generic classes that have both__iter__(returningNever) and__getitem__. Theiter()builtin has two relevant overloads: one matchingSupportsIter(uses__iter__) and one matching_GetItemIterable(uses__getitem__). When the class had anAnytype argument, both overloads matched, ambiguity was detected, anditer(x)returnedAnyinstead ofNever.Calling
x.__iter__()directly returnedNevercorrectly; onlyiter(x)was broken.Before this fix:
After this fix:
The fix is in
infer_overload_return_typeinmypy/checkexpr.py. After detecting Any-caused ambiguity, before falling back toAny, it checks whether exactly one of the matching overloads returnsNever. If so, it returns that overload's result instead.