Skip to content

Commit 50ac875

Browse files
authored
Better diagnostic for conditional function mismatch (#13604)
Fixes #10575
1 parent a4c32d1 commit 50ac875

7 files changed

+84
-17
lines changed

mypy/checker.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -950,8 +950,9 @@ def _visit_func_def(self, defn: FuncDef) -> None:
950950
new_type = self.function_type(defn)
951951
if isinstance(defn.original_def, FuncDef):
952952
# Function definition overrides function definition.
953-
if not is_same_type(new_type, self.function_type(defn.original_def)):
954-
self.msg.incompatible_conditional_function_def(defn)
953+
old_type = self.function_type(defn.original_def)
954+
if not is_same_type(new_type, old_type):
955+
self.msg.incompatible_conditional_function_def(defn, old_type, new_type)
955956
else:
956957
# Function definition overrides a variable initialized via assignment or a
957958
# decorated function.

mypy/messages.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1302,8 +1302,17 @@ def incompatible_self_argument(
13021302
context,
13031303
)
13041304

1305-
def incompatible_conditional_function_def(self, defn: FuncDef) -> None:
1305+
def incompatible_conditional_function_def(
1306+
self, defn: FuncDef, old_type: FunctionLike, new_type: FunctionLike
1307+
) -> None:
13061308
self.fail("All conditional function variants must have identical signatures", defn)
1309+
if isinstance(old_type, (CallableType, Overloaded)) and isinstance(
1310+
new_type, (CallableType, Overloaded)
1311+
):
1312+
self.note("Original:", defn)
1313+
self.pretty_callable_or_overload(old_type, defn, offset=4)
1314+
self.note("Redefinition:", defn)
1315+
self.pretty_callable_or_overload(new_type, defn, offset=4)
13071316

13081317
def cannot_instantiate_abstract_class(
13091318
self, class_name: str, abstract_attributes: dict[str, bool], context: Context

test-data/unit/check-functions.test

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,23 +1393,35 @@ x = None # type: Any
13931393
if x:
13941394
def f(x: int) -> None: pass
13951395
else:
1396-
def f(x): pass # E: All conditional function variants must have identical signatures
1396+
def f(x): pass # E: All conditional function variants must have identical signatures \
1397+
# N: Original: \
1398+
# N: def f(x: int) -> None \
1399+
# N: Redefinition: \
1400+
# N: def f(x: Any) -> Any
13971401

13981402
[case testIncompatibleConditionalFunctionDefinition2]
13991403
from typing import Any
14001404
x = None # type: Any
14011405
if x:
14021406
def f(x: int) -> None: pass
14031407
else:
1404-
def f(y: int) -> None: pass # E: All conditional function variants must have identical signatures
1408+
def f(y: int) -> None: pass # E: All conditional function variants must have identical signatures \
1409+
# N: Original: \
1410+
# N: def f(x: int) -> None \
1411+
# N: Redefinition: \
1412+
# N: def f(y: int) -> None
14051413

14061414
[case testIncompatibleConditionalFunctionDefinition3]
14071415
from typing import Any
14081416
x = None # type: Any
14091417
if x:
14101418
def f(x: int) -> None: pass
14111419
else:
1412-
def f(x: int = 0) -> None: pass # E: All conditional function variants must have identical signatures
1420+
def f(x: int = 0) -> None: pass # E: All conditional function variants must have identical signatures \
1421+
# N: Original: \
1422+
# N: def f(x: int) -> None \
1423+
# N: Redefinition: \
1424+
# N: def f(x: int = ...) -> None
14131425

14141426
[case testConditionalFunctionDefinitionUsingDecorator1]
14151427
from typing import Callable
@@ -1467,14 +1479,22 @@ from typing import Any
14671479
def f(x: str) -> None: pass
14681480
x = None # type: Any
14691481
if x:
1470-
def f(x: int) -> None: pass # E: All conditional function variants must have identical signatures
1482+
def f(x: int) -> None: pass # E: All conditional function variants must have identical signatures \
1483+
# N: Original: \
1484+
# N: def f(x: str) -> None \
1485+
# N: Redefinition: \
1486+
# N: def f(x: int) -> None
14711487

14721488
[case testConditionalRedefinitionOfAnUnconditionalFunctionDefinition2]
14731489
from typing import Any
14741490
def f(x: int) -> None: pass # N: "f" defined here
14751491
x = None # type: Any
14761492
if x:
1477-
def f(y: int) -> None: pass # E: All conditional function variants must have identical signatures
1493+
def f(y: int) -> None: pass # E: All conditional function variants must have identical signatures \
1494+
# N: Original: \
1495+
# N: def f(x: int) -> None \
1496+
# N: Redefinition: \
1497+
# N: def f(y: int) -> None
14781498
f(x=1) # The first definition takes precedence.
14791499
f(y=1) # E: Unexpected keyword argument "y" for "f"
14801500

@@ -1640,7 +1660,11 @@ class A:
16401660
if x:
16411661
def f(self, x: int) -> None: pass
16421662
else:
1643-
def f(self, x): pass # E: All conditional function variants must have identical signatures
1663+
def f(self, x): pass # E: All conditional function variants must have identical signatures \
1664+
# N: Original: \
1665+
# N: def f(self: A, x: int) -> None \
1666+
# N: Redefinition: \
1667+
# N: def f(self: A, x: Any) -> Any
16441668
[out]
16451669

16461670
[case testConditionalFunctionDefinitionInTry]

test-data/unit/check-modules.test

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,11 @@ try:
625625
from m import f, g
626626
except:
627627
def f(x): pass
628-
def g(x): pass # E: All conditional function variants must have identical signatures
628+
def g(x): pass # E: All conditional function variants must have identical signatures \
629+
# N: Original: \
630+
# N: def g(x: Any, y: Any) -> Any \
631+
# N: Redefinition: \
632+
# N: def g(x: Any) -> Any
629633
[file m.py]
630634
def f(x): pass
631635
def g(x, y): pass

test-data/unit/check-newsemanal.test

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1864,7 +1864,11 @@ if int():
18641864
elif bool():
18651865
def f(x: int) -> None:
18661866
1() # E: "int" not callable
1867-
def g(x: str) -> None: # E: All conditional function variants must have identical signatures
1867+
def g(x: str) -> None: # E: All conditional function variants must have identical signatures \
1868+
# N: Original: \
1869+
# N: def g(x: int) -> None \
1870+
# N: Redefinition: \
1871+
# N: def g(x: str) -> None
18681872
pass
18691873
else:
18701874
def f(x: int) -> None:
@@ -1881,7 +1885,12 @@ if int():
18811885
else:
18821886
def f(x: A) -> None:
18831887
1() # E: "int" not callable
1884-
def g(x: str) -> None: # E: All conditional function variants must have identical signatures
1888+
def g(x: str) -> None: # E: All conditional function variants must have identical signatures \
1889+
# N: Original: \
1890+
# N: def g(x: A) -> None \
1891+
# N: Redefinition: \
1892+
# N: def g(x: str) -> None
1893+
18851894
pass
18861895

18871896
reveal_type(g) # N: Revealed type is "def (x: __main__.A)"

test-data/unit/check-unions.test

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,19 @@ elif foo():
193193
elif foo():
194194
def f(x: Union[int, str, int, int, str]) -> None: pass
195195
elif foo():
196-
def f(x: Union[int, str, float]) -> None: pass # E: All conditional function variants must have identical signatures
196+
def f(x: Union[int, str, float]) -> None: pass # E: All conditional function variants must have identical signatures \
197+
# N: Original: \
198+
# N: def f(x: Union[int, str]) -> None \
199+
# N: Redefinition: \
200+
# N: def f(x: Union[int, str, float]) -> None
197201
elif foo():
198202
def f(x: Union[S, T]) -> None: pass
199203
elif foo():
200-
def f(x: Union[str]) -> None: pass # E: All conditional function variants must have identical signatures
204+
def f(x: Union[str]) -> None: pass # E: All conditional function variants must have identical signatures \
205+
# N: Original: \
206+
# N: def f(x: Union[int, str]) -> None \
207+
# N: Redefinition: \
208+
# N: def f(x: str) -> None
201209
else:
202210
def f(x: Union[Union[int, T], Union[S, T], str]) -> None: pass
203211

@@ -206,7 +214,11 @@ else:
206214
if foo():
207215
def g(x: Union[int, str, bytes]) -> None: pass
208216
else:
209-
def g(x: Union[int, str]) -> None: pass # E: All conditional function variants must have identical signatures
217+
def g(x: Union[int, str]) -> None: pass # E: All conditional function variants must have identical signatures \
218+
# N: Original: \
219+
# N: def g(x: Union[int, str, bytes]) -> None \
220+
# N: Redefinition: \
221+
# N: def g(x: Union[int, str]) -> None
210222

211223
[case testUnionSimplificationSpecialCases]
212224
from typing import Any, TypeVar, Union

test-data/unit/check-unreachable-code.test

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,11 @@ import sys
242242
if sys.version_info >= (3, 5, 0):
243243
def foo() -> int: return 0
244244
else:
245-
def foo() -> str: return '' # E: All conditional function variants must have identical signatures
245+
def foo() -> str: return '' # E: All conditional function variants must have identical signatures \
246+
# N: Original: \
247+
# N: def foo() -> int \
248+
# N: Redefinition: \
249+
# N: def foo() -> str
246250
[builtins fixtures/ops.pyi]
247251
[out]
248252

@@ -253,7 +257,11 @@ import sys
253257
if sys.version_info[1:] >= (5, 0):
254258
def foo() -> int: return 0
255259
else:
256-
def foo() -> str: return '' # E: All conditional function variants must have identical signatures
260+
def foo() -> str: return '' # E: All conditional function variants must have identical signatures \
261+
# N: Original: \
262+
# N: def foo() -> int \
263+
# N: Redefinition: \
264+
# N: def foo() -> str
257265
[builtins fixtures/ops.pyi]
258266
[out]
259267

0 commit comments

Comments
 (0)