Skip to content

Commit ed18fea

Browse files
authored
Document and rename overload-overlap error code (#16074)
A new error code was introduced in #16061 As per #16068, we didn't previously run doc builds on changes to errorcodes.py, causing tests to fail on master when this was merged. Renaming the code as per: #16061 (comment) All type ignores should be unsafe, so we should save the unsafe adjective for things that are really unsafe. As it stands, there are many cases where overloads overlap somewhat benignly. Fixes #8656
1 parent f9dc561 commit ed18fea

File tree

6 files changed

+44
-6
lines changed

6 files changed

+44
-6
lines changed

docs/source/error_code_list.rst

+35
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,41 @@ Warn about cases where a bytes object may be converted to a string in an unexpec
11141114
print(f"The alphabet starts with {b!r}") # The alphabet starts with b'abc'
11151115
print(f"The alphabet starts with {b.decode('utf-8')}") # The alphabet starts with abc
11161116
1117+
.. _code-overload-overlap:
1118+
1119+
Check that overloaded functions don't overlap [overload-overlap]
1120+
----------------------------------------------------------------
1121+
1122+
Warn if multiple ``@overload`` variants overlap in potentially unsafe ways.
1123+
This guards against the following situation:
1124+
1125+
.. code-block:: python
1126+
1127+
from typing import overload
1128+
1129+
class A: ...
1130+
class B(A): ...
1131+
1132+
@overload
1133+
def foo(x: B) -> int: ... # Error: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
1134+
@overload
1135+
def foo(x: A) -> str: ...
1136+
def foo(x): ...
1137+
1138+
def takes_a(a: A) -> str:
1139+
return foo(a)
1140+
1141+
a: A = B()
1142+
value = takes_a(a)
1143+
# mypy will think that value is a str, but it could actually be an int
1144+
reveal_type(value) # Revealed type is "builtins.str"
1145+
1146+
1147+
Note that in cases where you ignore this error, mypy will usually still infer the
1148+
types you expect.
1149+
1150+
See :ref:`overloading <function-overloading>` for more explanation.
1151+
11171152
.. _code-annotation-unchecked:
11181153

11191154
Notify about an annotation in an unchecked function [annotation-unchecked]

docs/source/more_types.rst

+4-1
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ To prevent these kinds of issues, mypy will detect and prohibit inherently unsaf
501501
overlapping overloads on a best-effort basis. Two variants are considered unsafely
502502
overlapping when both of the following are true:
503503

504-
1. All of the arguments of the first variant are compatible with the second.
504+
1. All of the arguments of the first variant are potentially compatible with the second.
505505
2. The return type of the first variant is *not* compatible with (e.g. is not a
506506
subtype of) the second.
507507

@@ -510,6 +510,9 @@ the ``object`` argument in the second, yet the ``int`` return type is not a subt
510510
``str``. Both conditions are true, so mypy will correctly flag ``unsafe_func`` as
511511
being unsafe.
512512

513+
Note that in cases where you ignore the overlapping overload error, mypy will usually
514+
still infer the types you expect at callsites.
515+
513516
However, mypy will not detect *all* unsafe uses of overloads. For example,
514517
suppose we modify the above snippet so it calls ``summarize`` instead of
515518
``unsafe_func``:

mypy/errorcodes.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,8 @@ def __hash__(self) -> int:
262262
# This is a catch-all for remaining uncategorized errors.
263263
MISC: Final = ErrorCode("misc", "Miscellaneous other checks", "General")
264264

265-
UNSAFE_OVERLOAD: Final[ErrorCode] = ErrorCode(
266-
"unsafe-overload",
265+
OVERLOAD_OVERLAP: Final[ErrorCode] = ErrorCode(
266+
"overload-overlap",
267267
"Warn if multiple @overload variants overlap in unsafe ways",
268268
"General",
269269
sub_code_of=MISC,

mypy/messages.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1604,7 +1604,7 @@ def overloaded_signatures_overlap(self, index1: int, index2: int, context: Conte
16041604
"Overloaded function signatures {} and {} overlap with "
16051605
"incompatible return types".format(index1, index2),
16061606
context,
1607-
code=codes.UNSAFE_OVERLOAD,
1607+
code=codes.OVERLOAD_OVERLAP,
16081608
)
16091609

16101610
def overloaded_signature_will_never_match(

mypy/types.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3019,7 +3019,7 @@ def get_proper_type(typ: Type | None) -> ProperType | None:
30193019

30203020

30213021
@overload
3022-
def get_proper_types(types: list[Type] | tuple[Type, ...]) -> list[ProperType]: # type: ignore[unsafe-overload]
3022+
def get_proper_types(types: list[Type] | tuple[Type, ...]) -> list[ProperType]: # type: ignore[overload-overlap]
30233023
...
30243024

30253025

test-data/unit/check-errorcodes.test

+1-1
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,7 @@ x = 1 # type: ignore # E: Unused "type: ignore" comment [unused-ignore]
10771077
from typing import overload, Union
10781078

10791079
@overload
1080-
def unsafe_func(x: int) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types [unsafe-overload]
1080+
def unsafe_func(x: int) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types [overload-overlap]
10811081
@overload
10821082
def unsafe_func(x: object) -> str: ...
10831083
def unsafe_func(x: object) -> Union[int, str]:

0 commit comments

Comments
 (0)