Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ def __init__(self) -> None:
from mypy.typeanal import check_for_explicit_any, has_any_from_unimported_type, make_optional_type
from mypy.typeops import (
bind_self,
callable_corresponding_argument,
can_have_shared_disjoint_base,
coerce_to_literal,
custom_special_method,
Expand Down Expand Up @@ -1144,7 +1145,28 @@ def check_overlapping_overloads(self, defn: OverloadedFuncDef) -> None:
if not is_callable_compatible(
impl, sig1, is_compat=is_subtype, is_proper_subtype=False, ignore_return=True
):
self.msg.overloaded_signatures_param_specific(i + 1, defn.impl)
positional_only_args: list[str] = []
if is_callable_compatible(
impl,
sig1,
is_compat=is_subtype,
is_proper_subtype=False,
ignore_return=True,
ignore_pos_arg_names=True,
):
normalized_impl = impl.with_unpacked_kwargs().with_normalized_var_args()
normalized_sig = sig1.with_unpacked_kwargs().with_normalized_var_args()
for arg in normalized_sig.formal_arguments():
impl_arg = callable_corresponding_argument(normalized_impl, arg)
if (
arg.name is not None
and impl_arg is not None
and arg.name != impl_arg.name
):
positional_only_args.append(arg.name)
self.msg.overloaded_signatures_param_specific(
i + 1, defn.impl, positional_only_args
)

# Is the overload alternative's return type a subtype of the implementation's?
if not (
Expand Down
7 changes: 6 additions & 1 deletion mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -1755,14 +1755,19 @@ def overloaded_signatures_typevar_specific(self, index: int, context: Context) -
context,
)

def overloaded_signatures_param_specific(self, index: int, context: Context) -> None:
def overloaded_signatures_param_specific(
self, index: int, context: Context, positional_only_args: list[str]
) -> None:
self.fail(
(
f"Overloaded function implementation does not accept all possible parameters "
f"of signature {index}"
),
context,
)
if positional_only_args:
names = ", ".join(f'"{name}"' for name in positional_only_args)
self.note(f"Consider marking {names} positional-only in signature {index}", context)

def overloaded_signatures_ret_specific(self, index: int, context: Context) -> None:
self.fail(
Expand Down
19 changes: 19 additions & 0 deletions test-data/unit/check-overloading.test
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,25 @@ reveal_type(f(A())) # N: Revealed type is "__main__.B"
reveal_type(f(B())) # N: Revealed type is "__main__.A"
[builtins fixtures/isinstance.pyi]

[case testOverloadImplementationArgumentNames]
from typing import overload

@overload
def f(x: int, y: int) -> None: ...
@overload
def f(x: str, y: int, /) -> None: ...
def f(a: int | str, /, b: int) -> None: # E: Overloaded function implementation does not accept all possible parameters of signature 1 \
# N: Consider marking "x", "y" positional-only in signature 1
pass

@overload
def h(x: int = 0, y: int = 0) -> None: ...
@overload
def h(x: str, /, y: int = 0) -> None: ...
def h(a: int | str = 0, b: int = 0, /, *, y: int = 0) -> None: # E: Overloaded function implementation does not accept all possible parameters of signature 1 \
# N: Consider marking "x" positional-only in signature 1
pass

[case testTypeCheckOverloadImplOverlapVarArgsAndKwargs]
from __future__ import annotations
from typing import overload
Expand Down
3 changes: 2 additions & 1 deletion test-data/unit/check-python38.test
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,8 @@ class Foo:
@overload
def f(self, *, b: bool = False) -> None: ...

def f(self, a: Optional[str] = None, /, *, b: bool = False) -> None: # E: Overloaded function implementation does not accept all possible parameters of signature 2
def f(self, a: Optional[str] = None, /, *, b: bool = False) -> None: # E: Overloaded function implementation does not accept all possible parameters of signature 2 \
# N: Consider marking "self" positional-only in signature 2
...

class Bar:
Expand Down
Loading