Skip to content

Better error message for incompatible default argument (take 2) #3783

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 31, 2017
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
12 changes: 9 additions & 3 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -740,9 +740,15 @@ def is_implicit_any(t: Type) -> bool:

# Type check initialization expressions.
for arg in item.arguments:
init = arg.initialization_statement
if init:
self.accept(init)
if arg.initializer is not None:
name = arg.variable.name()
msg = 'Incompatible default for '
if name.startswith('__tuple_arg_'):
msg += "tuple argument {}".format(name[12:])
else:
msg += 'argument "{}"'.format(name)
self.check_simple_assignment(arg.variable.type, arg.initializer,
context=arg, msg=msg, lvalue_name='argument', rvalue_name='default')

# Type check body in a new scope.
with self.binder.top_frame_context():
Expand Down
47 changes: 42 additions & 5 deletions test-data/unit/check-functions.test
Original file line number Diff line number Diff line change
Expand Up @@ -388,17 +388,54 @@ class A: pass

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

class B: pass
class A: pass
[out]

[case testDefaultArgumentExpressionsGeneric]
from typing import TypeVar
T = TypeVar('T', bound='A')
def f(x: T = B()) -> None: # E: Incompatible default for argument "x" (default has type "B", argument has type "T")
b = x # type: B # E: Incompatible types in assignment (expression has type "T", variable has type "B")
a = x # type: A

class B: pass
class A: pass

[case testDefaultArgumentExpressionsPython2]
# flags: --python-version 2.7
from typing import Tuple
def f(x = B()): # E: Incompatible default for argument "x" (default has type "B", argument has type "A")
# type: (A) -> None
b = x # type: B # E: Incompatible types in assignment (expression has type "A", variable has type "B")
a = x # type: A

class B: pass
class A: pass

[case testDefaultTupleArgumentExpressionsPython2]
# flags: --python-version 2.7
from typing import Tuple
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]")
# type: (Tuple[B, B]) -> None
b = x # type: B
a = x # type: A # E: Incompatible types in assignment (expression has type "B", variable has type "A")
def g(a, (x, y) = (A(),)): # E: Incompatible default for tuple argument 2 (default has type "Tuple[A]", argument has type "Tuple[B, B]")
# type: (int, Tuple[B, B]) -> None
pass
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]")
# type: (Tuple[B, B]) -> None
pass

class B: pass
class A: pass

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

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

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

class A: pass
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-inference.test
Original file line number Diff line number Diff line change
Expand Up @@ -1119,7 +1119,7 @@ from typing import Callable
def f(a: Callable[..., None] = lambda *a, **k: None):
pass

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])
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])
pass
[builtins fixtures/dict.pyi]

Expand Down
6 changes: 3 additions & 3 deletions test-data/unit/check-modules.test
Original file line number Diff line number Diff line change
Expand Up @@ -475,11 +475,11 @@ def f(x: int = ...) -> None: pass
[file m.pyi]
def g(x: int = '') -> None: pass
[out]
tmp/m.pyi:1: error: Incompatible types in assignment (expression has type "str", variable has type "int")
main:2: error: Incompatible types in assignment (expression has type "ellipsis", variable has type "int")
tmp/m.pyi:1: error: Incompatible default for argument "x" (default has type "str", argument has type "int")
main:2: error: Incompatible default for argument "x" (default has type "ellipsis", argument has type "int")

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

[case testStarImportOverlapping]
Expand Down
4 changes: 2 additions & 2 deletions test-data/unit/check-optional.test
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ f(None)

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

Expand All @@ -140,7 +140,7 @@ f(None)

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