Skip to content

Commit ba86157

Browse files
committed
disallow exactly same overloads with different return value
1 parent ba26d12 commit ba86157

File tree

2 files changed

+42
-12
lines changed

2 files changed

+42
-12
lines changed

mypy/checker.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8059,8 +8059,6 @@ def get_type_var_group_variants(
80598059

80608060
def expand_callable_self(c: CallableType) -> CallableType:
80618061
for tv in c.variables:
8062-
# We need to expand self-type before other variables, because this is the only
8063-
# type variable that can have other type variables in the upper bound.
80648062
if tv.id.is_self():
80658063
return expand_type(c, {tv.id: tv.upper_bound}).copy_modified(
80668064
variables=[v for v in c.variables if not v.id.is_self()]
@@ -8142,14 +8140,32 @@ def is_unsafe_overlapping_overload_signatures(
81428140
# Using the same `allow_partial_overlap` flag as before, can cause false
81438141
# negatives in case where star argument is used in a catch-all fallback overload.
81448142
# But again, practicality beats purity here.
8145-
if not partial_only or not is_callable_compatible(
8146-
other_variant,
8147-
sig_variant,
8148-
is_compat=is_subset_no_promote,
8149-
check_args_covariantly=True,
8150-
is_proper_subtype=False,
8151-
ignore_return=True,
8152-
allow_partial_overlap=True,
8143+
8144+
# Also earlier overload may not be more general overall but is more general when
8145+
# narrowed to common calls is handled here, so there is no unsafe overlap because
8146+
# it will still be caught by the earlier overload.
8147+
# Exeption here is when signature variants are exactly the same, in which case we
8148+
# should still consider them overlapping.
8149+
if (
8150+
not partial_only
8151+
or not is_callable_compatible(
8152+
other_variant,
8153+
sig_variant,
8154+
is_compat=is_subset_no_promote,
8155+
check_args_covariantly=True,
8156+
is_proper_subtype=False,
8157+
ignore_return=True,
8158+
allow_partial_overlap=True,
8159+
)
8160+
or is_callable_compatible(
8161+
sig_variant,
8162+
other_variant,
8163+
is_compat=lambda l, r: l == r,
8164+
check_args_covariantly=False,
8165+
is_proper_subtype=False,
8166+
ignore_return=True,
8167+
allow_partial_overlap=False,
8168+
)
81538169
):
81548170
return True
81558171
return False

test-data/unit/check-overloading.test

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,9 +1327,8 @@ def h(x: Sequence[str]) -> int: pass
13271327
@overload
13281328
def h(x: Sequence[T]) -> None: pass # E: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader
13291329

1330-
# Safety of this highly depends on the implementation, so we lean towards being silent.
13311330
@overload
1332-
def i(x: List[str]) -> int: pass
1331+
def i(x: List[str]) -> int: pass # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
13331332
@overload
13341333
def i(x: List[T]) -> None: pass
13351334
[builtins fixtures/list.pyi]
@@ -6768,3 +6767,18 @@ class D(Generic[T]):
67686767
a: D[str] # E: Type argument "str" of "D" must be a subtype of "C"
67696768
reveal_type(a.f(1)) # N: Revealed type is "builtins.int"
67706769
reveal_type(a.f("x")) # N: Revealed type is "builtins.str"
6770+
6771+
6772+
[case testOverloadOnExactSameTypeVariantWithIncompetibleReturnTypes]
6773+
from typing import TypeVar, overload
6774+
6775+
class A: pass
6776+
class B: pass
6777+
6778+
T = TypeVar('T', A, B)
6779+
6780+
@overload
6781+
def f(x: B) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
6782+
@overload
6783+
def f(x: T) -> str: ...
6784+
def f(x): ...

0 commit comments

Comments
 (0)