Skip to content

Commit 72661cb

Browse files
committed
A more principled fix for the subtyping issue
1 parent f6caf00 commit 72661cb

File tree

2 files changed

+30
-6
lines changed

2 files changed

+30
-6
lines changed

mypy/subtypes.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1719,11 +1719,16 @@ def _incompatible(left_arg: FormalArgument | None, right_arg: FormalArgument | N
17191719
):
17201720
return False
17211721

1722+
if trivial_suffix:
1723+
# For trivial right suffix we *only* check that every non-star right argument
1724+
# has a valid match on the left.
1725+
return True
1726+
17221727
# Phase 1c: Check var args. Right has an infinite series of optional positional
17231728
# arguments. Get all further positional args of left, and make sure
17241729
# they're more general than the corresponding member in right.
17251730
# TODO: are we handling UnpackType correctly here?
1726-
if right_star is not None and not trivial_suffix:
1731+
if right_star is not None:
17271732
# Synthesize an anonymous formal argument for the right
17281733
right_by_position = right.try_synthesizing_arg_from_vararg(None)
17291734
assert right_by_position is not None
@@ -1750,7 +1755,7 @@ def _incompatible(left_arg: FormalArgument | None, right_arg: FormalArgument | N
17501755
# Phase 1d: Check kw args. Right has an infinite series of optional named
17511756
# arguments. Get all further named args of left, and make sure
17521757
# they're more general than the corresponding member in right.
1753-
if right_star2 is not None and not trivial_suffix:
1758+
if right_star2 is not None:
17541759
right_names = {name for name in right.arg_names if name is not None}
17551760
left_only_names = set()
17561761
for name, kind in zip(left.arg_names, left.arg_kinds):
@@ -1796,12 +1801,12 @@ def _incompatible(left_arg: FormalArgument | None, right_arg: FormalArgument | N
17961801
)
17971802

17981803
# If the left hand argument corresponds to two right-hand arguments,
1799-
# both of them can't be required.
1804+
# neither of them can be required.
18001805
if (
18011806
right_by_name is not None
18021807
and right_by_pos is not None
18031808
and right_by_name != right_by_pos
1804-
and (right_by_pos.required and right_by_name.required)
1809+
and (right_by_pos.required or right_by_name.required)
18051810
and strict_concatenate_check
18061811
and not right.imprecise_arg_kinds
18071812
):

test-data/unit/check-functions.test

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,33 @@ if int():
106106

107107
[case testSubtypingFunctionsDoubleCorrespondence]
108108
def l(x) -> None: ...
109-
def r(__a, *, x) -> None: ...
109+
def r(__x, *, x) -> None: ...
110110
r = l # E: Incompatible types in assignment (expression has type "Callable[[Any], None]", variable has type "Callable[[Any, NamedArg(Any, 'x')], None]")
111111

112112
[case testSubtypingFunctionsDoubleCorrespondenceNamedOptional]
113113
def l(x) -> None: ...
114-
def r(__a, *, x = 1) -> None: ...
114+
def r(__x, *, x = 1) -> None: ...
115115
r = l # E: Incompatible types in assignment (expression has type "Callable[[Any], None]", variable has type "Callable[[Any, DefaultNamedArg(Any, 'x')], None]")
116116

117+
[case testSubtypingFunctionsDoubleCorrespondenceBothNamedOptional]
118+
def l(x = 1) -> None: ...
119+
def r(__x, *, x = 1) -> None: ...
120+
r = l # E: Incompatible types in assignment (expression has type "Callable[[Any], None]", variable has type "Callable[[Any, DefaultNamedArg(Any, 'x')], None]")
121+
122+
[case testSubtypingFunctionsTrivialSuffixRequired]
123+
def l(__x) -> None: ...
124+
def r(x, *args, **kwargs) -> None: ...
125+
126+
r = l # E: Incompatible types in assignment (expression has type "Callable[[Any], None]", variable has type "Callable[[Arg(Any, 'x'), VarArg(Any), KwArg(Any)], None]")
127+
[builtins fixtures/dict.pyi]
128+
129+
[case testSubtypingFunctionsTrivialSuffixOptional]
130+
def l(__x = 1) -> None: ...
131+
def r(x = 1, *args, **kwargs) -> None: ...
132+
133+
r = l # E: Incompatible types in assignment (expression has type "Callable[[DefaultArg(Any)], None]", variable has type "Callable[[DefaultArg(Any, 'x'), VarArg(Any), KwArg(Any)], None]")
134+
[builtins fixtures/dict.pyi]
135+
117136
[case testSubtypingFunctionsRequiredLeftArgNotPresent]
118137
def l(x, y) -> None: ...
119138
def r(x) -> None: ...

0 commit comments

Comments
 (0)