-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Re-work overload overlap logic #17392
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
for more information, see https://pre-commit.ci
This comment has been minimized.
This comment has been minimized.
for more information, see https://pre-commit.ci
This comment has been minimized.
This comment has been minimized.
for more information, see https://pre-commit.ci
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Various tests are failing, can you have a look? |
There is only one test failing |
Our checks for overlapping overload items have been pretty ad-hoc and they've generated false positives, so thanks for cleaning this up! This looks good. I think the false negatives are acceptable, and false positives here generally cause more issues than (rare) false negatives. The only potential issue (based on a quick review) is missing test coverage. Do we have tests for these things:
Technically these could refer to different objects that are defined outside the function (e.g. attributes), and thus the caller could add values of type |
Seems like it's complaining about these overloads for To unblock this PR you could add the type ignore directly in mypy's vendored copy of typeshed; then we can also add the ignore in typeshed. |
This comment has been minimized.
This comment has been minimized.
Oh yes, right. I added an explicit comment about this, to make it clear. |
for more information, see https://pre-commit.ci
This comment has been minimized.
This comment has been minimized.
I fixed another minor ( @JukkaL I added dedicated (explicit) tests for edge cases as you suggested. If there are no more suggestions, I am going to merge this soon. |
Diff from mypy_primer, showing the effect of this PR on open source code: comtypes (https://github.com/enthought/comtypes)
- comtypes/hints.pyi:221: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
- comtypes/hints.pyi:229: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
jinja (https://github.com/pallets/jinja)
+ src/jinja2/environment.py:711: error: Unused "type: ignore" comment [unused-ignore]
steam.py (https://github.com/Gobot1234/steam.py)
- steam/ext/commands/commands.py:695: error: Overloaded function signatures 2 and 3 overlap with incompatible return types [overload-overlap]
- steam/ext/commands/commands.py:741: error: Overloaded function signatures 2 and 3 overlap with incompatible return types [overload-overlap]
- steam/ext/commands/commands.py:795: error: Overloaded function signatures 2 and 3 overlap with incompatible return types [overload-overlap]
- steam/ext/commands/commands.py:844: error: Overloaded function signatures 2 and 3 overlap with incompatible return types [overload-overlap]
- steam/ext/commands/commands.py:906: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
antidote (https://github.com/Finistere/antidote)
- src/antidote/core/_catalog.py:265: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
- src/antidote/core/__init__.py:144: error: Overloaded function signatures 5 and 6 overlap with incompatible return types [overload-overlap]
+ src/antidote/core/__init__.py:192: error: Overloaded function signatures 1 and 3 overlap with incompatible return types [overload-overlap]
+ src/antidote/core/__init__.py:197: note: Flipping the order of overloads will fix this error
+ src/antidote/core/__init__.py:398: note: Flipping the order of overloads will fix this error
+ src/antidote/lib/interface_ext/_interface.py:78: note: Flipping the order of overloads will fix this error
+ src/antidote/lib/interface_ext/_interface.py:118: note: Flipping the order of overloads will fix this error
+ src/antidote/lib/interface_ext/__init__.py:357: note: Flipping the order of overloads will fix this error
+ src/antidote/lib/interface_ext/__init__.py:396: note: Flipping the order of overloads will fix this error
+ src/antidote/lib/interface_ext/__init__.py:1207: note: Flipping the order of overloads will fix this error
- src/antidote/lib/interface_ext/__init__.py:1293: error: Overloaded function signatures 2 and 3 overlap with incompatible return types [overload-overlap]
- src/antidote/lib/interface_ext/__init__.py:1293: error: Overloaded function signatures 2 and 4 overlap with incompatible return types [overload-overlap]
- src/antidote/lib/interface_ext/__init__.py:1325: error: Overloaded function signatures 2 and 3 overlap with incompatible return types [overload-overlap]
- src/antidote/lib/interface_ext/__init__.py:1325: error: Overloaded function signatures 2 and 4 overlap with incompatible return types [overload-overlap]
itsdangerous (https://github.com/pallets/itsdangerous)
+ src/itsdangerous/timed.py:57: error: Unused "type: ignore" comment [unused-ignore]
mypy (https://github.com/python/mypy)
+ mypy/types.py:3098: error: Unused "type: ignore" comment [unused-ignore]
aioredis (https://github.com/aio-libs/aioredis)
- aioredis/utils.py:45: error: Unused "type: ignore" comment, use narrower [overload-overlap] instead of [misc] code [unused-ignore]
+ aioredis/utils.py:45: error: Unused "type: ignore" comment [unused-ignore]
asynq (https://github.com/quora/asynq)
+ asynq/decorators.pyi:107: error: Unused "type: ignore" comment [unused-ignore]
pandas-stubs (https://github.com/pandas-dev/pandas-stubs)
+ pandas-stubs/core/series.pyi:234: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:251: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:261: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:271: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:287: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:772: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:908: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:1240: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:1509: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:1543: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:1556: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:1560: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:1575: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:1579: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:1584: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:1588: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:1608: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/series.pyi:1992: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/frame.pyi:193: error: Overloaded function signatures 3 and 4 overlap with incompatible return types [overload-overlap]
+ pandas-stubs/core/frame.pyi:309: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/frame.pyi:325: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/frame.pyi:333: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/frame.pyi:341: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/frame.pyi:349: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/frame.pyi:1220: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/frame.pyi:1231: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/algorithms.pyi:27: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/algorithms.pyi:31: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/reshape/tile.pyi:53: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/reshape/concat.pyi:27: error: Overloaded function signatures 1 and 4 overlap with incompatible return types [overload-overlap]
+ pandas-stubs/core/indexes/interval.pyi:309: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:69: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:80: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:91: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:102: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:113: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:128: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:140: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:151: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:162: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:173: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:184: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:195: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:206: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:217: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/indexes/base.pyi:422: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/groupby/generic.pyi:188: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/core/groupby/generic.pyi:323: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/_libs/interval.pyi:204: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/_libs/interval.pyi:212: error: Unused "type: ignore" comment [unused-ignore]
+ pandas-stubs/_libs/tslibs/timedeltas.pyi:251: error: Unused "type: ignore" comment [unused-ignore]
jax (https://github.com/google/jax)
+ jax/_src/api.py:2280: error: Unused "type: ignore" comment [unused-ignore]
- jax/_src/numpy/lax_numpy.py:1866: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
- jax/numpy/__init__.pyi:914: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
operator (https://github.com/canonical/operator)
- ops/pebble.py:2534: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
- ops/model.py:2748: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
streamlit (https://github.com/streamlit/streamlit)
- lib/streamlit/elements/widgets/multiselect.py:61: error: Unused "type: ignore" comment, use narrower [overload-overlap] instead of [misc] code [unused-ignore]
+ lib/streamlit/elements/widgets/multiselect.py:61: error: Unused "type: ignore" comment [unused-ignore]
ibis (https://github.com/ibis-project/ibis)
- ibis/expr/operations/udf.py:183: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
- ibis/expr/operations/udf.py:258: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
- ibis/expr/operations/udf.py:378: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
- ibis/expr/operations/udf.py:475: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
- ibis/expr/operations/udf.py:568: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
discord.py (https://github.com/Rapptz/discord.py)
- discord/state.py:1225: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
- discord/channel.py:291: error: Overloaded function signatures 1 and 3 overlap with incompatible return types [overload-overlap]
- discord/channel.py:295: error: Overloaded function signatures 2 and 3 overlap with incompatible return types [overload-overlap]
- discord/channel.py:1351: error: Overloaded function signatures 1 and 3 overlap with incompatible return types [overload-overlap]
- discord/channel.py:1355: error: Overloaded function signatures 2 and 3 overlap with incompatible return types [overload-overlap]
- discord/channel.py:1692: error: Overloaded function signatures 1 and 3 overlap with incompatible return types [overload-overlap]
- discord/channel.py:1696: error: Overloaded function signatures 2 and 3 overlap with incompatible return types [overload-overlap]
- discord/channel.py:1876: error: Overloaded function signatures 1 and 3 overlap with incompatible return types [overload-overlap]
- discord/channel.py:1880: error: Overloaded function signatures 2 and 3 overlap with incompatible return types [overload-overlap]
- discord/channel.py:2395: error: Overloaded function signatures 1 and 3 overlap with incompatible return types [overload-overlap]
- discord/channel.py:2399: error: Overloaded function signatures 2 and 3 overlap with incompatible return types [overload-overlap]
- discord/app_commands/tree.py:611: error: Overloaded function signatures 1 and 4 overlap with incompatible return types [overload-overlap]
- discord/app_commands/tree.py:620: error: Overloaded function signatures 2 and 4 overlap with incompatible return types [overload-overlap]
- discord/app_commands/tree.py:629: error: Overloaded function signatures 3 and 4 overlap with incompatible return types [overload-overlap]
- discord/ext/commands/core.py:1729: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
- discord/ext/commands/core.py:1799: error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
bokeh (https://github.com/bokeh/bokeh)
+ src/bokeh/embed/standalone.py:136: error: Unused "type: ignore" comment [unused-ignore]
+ src/bokeh/embed/standalone.py:143: error: Unused "type: ignore" comment [unused-ignore]
+ src/bokeh/embed/standalone.py:150: error: Unused "type: ignore" comment [unused-ignore]
werkzeug (https://github.com/pallets/werkzeug)
+ src/werkzeug/wrappers/request.py:373: error: Unused "type: ignore" comment [unused-ignore]
hydra-zen (https://github.com/mit-ll-responsible-ai/hydra-zen)
- src/hydra_zen/typing/_builds_overloads.py:46: error: Overloaded function signatures 1 and 4 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:46: error: Overloaded function signatures 1 and 6 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:66: error: Overloaded function signatures 2 and 3 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:86: error: Overloaded function signatures 3 and 5 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:86: error: Overloaded function signatures 3 and 6 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:106: error: Overloaded function signatures 4 and 5 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:106: error: Overloaded function signatures 4 and 6 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:127: error: Overloaded function signatures 5 and 8 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:269: error: Overloaded function signatures 1 and 5 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:269: error: Overloaded function signatures 1 and 7 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:288: error: Overloaded function signatures 2 and 6 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:288: error: Overloaded function signatures 2 and 7 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:307: error: Overloaded function signatures 3 and 4 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:307: error: Overloaded function signatures 3 and 6 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:307: error: Overloaded function signatures 3 and 7 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:326: error: Overloaded function signatures 4 and 6 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:326: error: Overloaded function signatures 4 and 7 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:346: error: Overloaded function signatures 5 and 6 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:346: error: Overloaded function signatures 5 and 7 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:367: error: Overloaded function signatures 6 and 9 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/typing/_builds_overloads.py:507: error: Overloaded function signatures 1 and 6 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/structured_configs/_implementations.py:1377: error: Overloaded function signatures 1 and 4 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/structured_configs/_implementations.py:1377: error: Overloaded function signatures 1 and 6 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/structured_configs/_implementations.py:1397: error: Overloaded function signatures 2 and 3 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/structured_configs/_implementations.py:1418: error: Overloaded function signatures 3 and 5 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/structured_configs/_implementations.py:1418: error: Overloaded function signatures 3 and 6 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/structured_configs/_implementations.py:1440: error: Overloaded function signatures 4 and 5 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/structured_configs/_implementations.py:1440: error: Overloaded function signatures 4 and 6 overlap with incompatible return types [overload-overlap]
- src/hydra_zen/structured_configs/_implementations.py:1462: error: Overloaded function signatures 5 and 8 overlap with incompatible return types [overload-overlap]
+ src/hydra_zen/structured_configs/_implementations.py:2973: error: Overloaded function signatures 3 and 4 overlap with incompatible return types [overload-overlap]
+ src/hydra_zen/structured_configs/_just.py:48: error: Overloaded function signatures 3 and 4 overlap with incompatible return types [overload-overlap]
|
Fixes #5510
OK, so I noticed during last couple years, that every other time I change something about type variables, a few unsafe overload overlap errors either appears or disappears. At some point I almost stopped looking at them. The problem is that unsafe overload overlap detection for generic callables is currently ad-hoc. However, as I started working on it, I discovered a bunch of foundational problems (and few smaller issues), so I decided to re-work the unsafe overload overlap detection. Here is a detailed summary:
IMO this is wrong(I was wrong). Although it is technically correct, in most cases there is nothing wrong if first overload returnslist[Subtype]
and second returnslist[Supertype]
. All the unsafe overload story is about runtime values, not static types, so we should useis_subset()
instead ofis_subtype()
, which is IIUC easy to implement: we simply need to consider all invariant types covariant.<never>
) if the right to left unification fails. TBH I never understood this. What we need is to find some set of type variable values that makes two overloads unsafely overlapping. Constraint inference may be used as a (good) source of such guesses, but is not decisive in any way. So instead I simply try all combinations of upper bounds and values. The main benefit of such approach is that it is guaranteed false-positive free. If such algorithm finds an overlap it is definitely an overlap. There are however false negatives, but we can incrementally tighten them in the future.Any
overlap nothing when considering overloads. Currently it overlaps everything (i.e. it is not different fromobject
), but this violates the rule that replacing a precise type withAny
should not generate an error. IOW I essentially treatAny
as "too dynamic or not imported".None
special-casing to be more uniform. Now essentially it only overlaps with explicitly optional types. This is important for descriptor-like signatures.is_overlapping_types()
, most notably flags were not passed down to various (recursive) helpers, andParamSpec
/Parameters
were treated a bit arbitrary.Pros/cons of the outcome:
So here a two new false negatives and motivation on why I think they are OK. First example is
This is obviously unsafe (consider
T = float
), but not flagged after this PR. I think this is ~fine for two reasons:(str | T) -> int | T
is a bad idea because unions with type variables are not only imprecise, but also highly problematic for inference.bound=float
in this example), the error will be still reported.Second example is signatures like
These are also unsafe because one can fool mypy with
x: tuple[str, ...] = ("x", "y"); foo(*x)
andx: dict[str, str] = {"x": "x", "y": "y"}; bar(**x)
. I think this is OK because while such unsafe calls are quite rare, this kind of catch-all fallback as last overload is relatively common.