Skip to content

Commit 6366a02

Browse files
elazarggvanrossum
authored andcommitted
Better error message for incompatible default argument (#3783)
1 parent d7761e4 commit 6366a02

File tree

5 files changed

+57
-14
lines changed

5 files changed

+57
-14
lines changed

mypy/checker.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -740,9 +740,15 @@ def is_implicit_any(t: Type) -> bool:
740740

741741
# Type check initialization expressions.
742742
for arg in item.arguments:
743-
init = arg.initialization_statement
744-
if init:
745-
self.accept(init)
743+
if arg.initializer is not None:
744+
name = arg.variable.name()
745+
msg = 'Incompatible default for '
746+
if name.startswith('__tuple_arg_'):
747+
msg += "tuple argument {}".format(name[12:])
748+
else:
749+
msg += 'argument "{}"'.format(name)
750+
self.check_simple_assignment(arg.variable.type, arg.initializer,
751+
context=arg, msg=msg, lvalue_name='argument', rvalue_name='default')
746752

747753
# Type check body in a new scope.
748754
with self.binder.top_frame_context():

test-data/unit/check-functions.test

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -388,17 +388,54 @@ class A: pass
388388

389389
[case testDefaultArgumentExpressions2]
390390
import typing
391-
def f(x: 'A' = B()) -> None: # E: Incompatible types in assignment (expression has type "B", variable has type "A")
391+
def f(x: 'A' = B()) -> None: # E: Incompatible default for argument "x" (default has type "B", argument has type "A")
392392
b = x # type: B # E: Incompatible types in assignment (expression has type "A", variable has type "B")
393393
a = x # type: A
394394

395395
class B: pass
396396
class A: pass
397-
[out]
397+
398+
[case testDefaultArgumentExpressionsGeneric]
399+
from typing import TypeVar
400+
T = TypeVar('T', bound='A')
401+
def f(x: T = B()) -> None: # E: Incompatible default for argument "x" (default has type "B", argument has type "T")
402+
b = x # type: B # E: Incompatible types in assignment (expression has type "T", variable has type "B")
403+
a = x # type: A
404+
405+
class B: pass
406+
class A: pass
407+
408+
[case testDefaultArgumentExpressionsPython2]
409+
# flags: --python-version 2.7
410+
from typing import Tuple
411+
def f(x = B()): # E: Incompatible default for argument "x" (default has type "B", argument has type "A")
412+
# type: (A) -> None
413+
b = x # type: B # E: Incompatible types in assignment (expression has type "A", variable has type "B")
414+
a = x # type: A
415+
416+
class B: pass
417+
class A: pass
418+
419+
[case testDefaultTupleArgumentExpressionsPython2]
420+
# flags: --python-version 2.7
421+
from typing import Tuple
422+
def f((x, y) = (A(), B())): # E: Incompatible default for tuple argument 1 (default has type "Tuple[A, B]", argument has type "Tuple[B, B]")
423+
# type: (Tuple[B, B]) -> None
424+
b = x # type: B
425+
a = x # type: A # E: Incompatible types in assignment (expression has type "B", variable has type "A")
426+
def g(a, (x, y) = (A(),)): # E: Incompatible default for tuple argument 2 (default has type "Tuple[A]", argument has type "Tuple[B, B]")
427+
# type: (int, Tuple[B, B]) -> None
428+
pass
429+
def h((x, y) = (A(), B(), A())): # E: Incompatible default for tuple argument 1 (default has type "Tuple[A, B, A]", argument has type "Tuple[B, B]")
430+
# type: (Tuple[B, B]) -> None
431+
pass
432+
433+
class B: pass
434+
class A: pass
398435

399436
[case testDefaultArgumentsWithSubtypes]
400437
import typing
401-
def f(x: 'B' = A()) -> None: # E: Incompatible types in assignment (expression has type "A", variable has type "B")
438+
def f(x: 'B' = A()) -> None: # E: Incompatible default for argument "x" (default has type "A", argument has type "B")
402439
pass
403440
def g(x: 'A' = B()) -> None:
404441
pass
@@ -409,7 +446,7 @@ class B(A): pass
409446

410447
[case testMultipleDefaultArgumentExpressions]
411448
import typing
412-
def f(x: 'A' = B(), y: 'B' = B()) -> None: # E: Incompatible types in assignment (expression has type "B", variable has type "A")
449+
def f(x: 'A' = B(), y: 'B' = B()) -> None: # E: Incompatible default for argument "x" (default has type "B", argument has type "A")
413450
pass
414451
def h(x: 'A' = A(), y: 'B' = B()) -> None:
415452
pass
@@ -420,7 +457,7 @@ class B: pass
420457

421458
[case testMultipleDefaultArgumentExpressions2]
422459
import typing
423-
def g(x: 'A' = A(), y: 'B' = A()) -> None: # E: Incompatible types in assignment (expression has type "A", variable has type "B")
460+
def g(x: 'A' = A(), y: 'B' = A()) -> None: # E: Incompatible default for argument "y" (default has type "A", argument has type "B")
424461
pass
425462

426463
class A: pass

test-data/unit/check-inference.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1119,7 +1119,7 @@ from typing import Callable
11191119
def f(a: Callable[..., None] = lambda *a, **k: None):
11201120
pass
11211121

1122-
def g(a: Callable[..., None] = lambda *a, **k: 1): # E: Incompatible types in assignment (expression has type Callable[[VarArg(Any), KwArg(Any)], int], variable has type Callable[..., None])
1122+
def g(a: Callable[..., None] = lambda *a, **k: 1): # E: Incompatible default for argument "a" (default has type Callable[[VarArg(Any), KwArg(Any)], int], argument has type Callable[..., None])
11231123
pass
11241124
[builtins fixtures/dict.pyi]
11251125

test-data/unit/check-modules.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -475,11 +475,11 @@ def f(x: int = ...) -> None: pass
475475
[file m.pyi]
476476
def g(x: int = '') -> None: pass
477477
[out]
478-
tmp/m.pyi:1: error: Incompatible types in assignment (expression has type "str", variable has type "int")
479-
main:2: error: Incompatible types in assignment (expression has type "ellipsis", variable has type "int")
478+
tmp/m.pyi:1: error: Incompatible default for argument "x" (default has type "str", argument has type "int")
479+
main:2: error: Incompatible default for argument "x" (default has type "ellipsis", argument has type "int")
480480

481481
[case testEllipsisDefaultArgValueInNonStub]
482-
def f(x: int = ...) -> None: pass # E: Incompatible types in assignment (expression has type "ellipsis", variable has type "int")
482+
def f(x: int = ...) -> None: pass # E: Incompatible default for argument "x" (default has type "ellipsis", argument has type "int")
483483
[out]
484484

485485
[case testStarImportOverlapping]

test-data/unit/check-optional.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ f(None)
127127

128128
[case testNoInferOptionalFromDefaultNone]
129129
# flags: --no-implicit-optional
130-
def f(x: int = None) -> None: # E: Incompatible types in assignment (expression has type None, variable has type "int")
130+
def f(x: int = None) -> None: # E: Incompatible default for argument "x" (default has type None, argument has type "int")
131131
pass
132132
[out]
133133

@@ -140,7 +140,7 @@ f(None)
140140

141141
[case testNoInferOptionalFromDefaultNoneComment]
142142
# flags: --no-implicit-optional
143-
def f(x=None): # E: Incompatible types in assignment (expression has type None, variable has type "int")
143+
def f(x=None): # E: Incompatible default for argument "x" (default has type None, argument has type "int")
144144
# type: (int) -> None
145145
pass
146146
[out]

0 commit comments

Comments
 (0)