Skip to content

Don't use an arg type corresponding to ** arg kind as inference context for the argument #1361

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 6 commits into from
Apr 11, 2016
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
17 changes: 9 additions & 8 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

# Type of callback user for checking individual function arguments. See
# check_args() below for details.
ArgChecker = Callable[[Type, Type, Type, int, int, CallableType, Context, MessageBuilder],
ArgChecker = Callable[[Type, Type, int, Type, int, int, CallableType, Context, MessageBuilder],
None]


Expand Down Expand Up @@ -319,15 +319,15 @@ def infer_arg_types_in_context2(
"""Infer argument expression types using a callable type as context.

For example, if callee argument 2 has type List[int], infer the
argument exprsession with List[int] type context.
argument expression with List[int] type context.

Returns the inferred types of *actual arguments*.
"""
res = [None] * len(args) # type: List[Type]

for i, actuals in enumerate(formal_to_actual):
for ai in actuals:
if arg_kinds[ai] != nodes.ARG_STAR:
if arg_kinds[ai] not in (nodes.ARG_STAR, nodes.ARG_STAR2):
res[ai] = self.accept(args[ai], callee.arg_types[i])

# Fill in the rest of the argument types.
Expand Down Expand Up @@ -604,7 +604,7 @@ def check_argument_types(self, arg_types: List[Type], arg_kinds: List[int],
# and **args this is the item type, not the collection type).
actual_type = get_actual_type(arg_type, arg_kinds[actual],
tuple_counter)
check_arg(actual_type, arg_type,
check_arg(actual_type, arg_type, arg_kinds[actual],
callee.arg_types[i],
actual + 1, i + 1, callee, context, messages)

Expand All @@ -618,11 +618,12 @@ def check_argument_types(self, arg_types: List[Type], arg_kinds: List[int],
actual_type = get_actual_type(arg_type,
arg_kinds[actual],
tuple_counter)
check_arg(actual_type, arg_type,
check_arg(actual_type, arg_type, arg_kinds[actual],
callee.arg_types[i],
actual + 1, i + 1, callee, context, messages)

def check_arg(self, caller_type: Type, original_caller_type: Type,
caller_kind: int,
callee_type: Type, n: int, m: int, callee: CallableType,
context: Context, messages: MessageBuilder) -> None:
"""Check the type of a single argument in a call."""
Expand All @@ -632,7 +633,7 @@ def check_arg(self, caller_type: Type, original_caller_type: Type,
messages.deleted_as_rvalue(caller_type, context)
elif not is_subtype(caller_type, callee_type):
messages.incompatible_argument(n, m, callee, original_caller_type,
context)
caller_kind, context)

def overload_call_target(self, arg_types: List[Type], arg_kinds: List[int],
arg_names: List[str],
Expand Down Expand Up @@ -713,7 +714,7 @@ def erased_signature_similarity(self, arg_types: List[Type], arg_kinds: List[int

similarity = 2

def check_arg(caller_type: Type, original_caller_type: Type,
def check_arg(caller_type: Type, original_caller_type: Type, caller_kind: int,
callee_type: Type, n: int, m: int, callee: CallableType,
context: Context, messages: MessageBuilder) -> None:
nonlocal similarity
Expand Down Expand Up @@ -747,7 +748,7 @@ def match_signature_types(self, arg_types: List[Type], arg_kinds: List[int],
lambda i: arg_types[i])
ok = True

def check_arg(caller_type: Type, original_caller_type: Type,
def check_arg(caller_type: Type, original_caller_type: Type, caller_kind: int,
callee_type: Type, n: int, m: int, callee: CallableType,
context: Context, messages: MessageBuilder) -> None:
nonlocal ok
Expand Down
11 changes: 9 additions & 2 deletions mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
Type, CallableType, Instance, TypeVarType, TupleType, UnionType, Void, NoneTyp, AnyType,
Overloaded, FunctionLike, DeletedType
)
from mypy.nodes import TypeInfo, Context, MypyFile, op_methods, FuncDef, reverse_type_aliases
from mypy.nodes import (
TypeInfo, Context, MypyFile, op_methods, FuncDef, reverse_type_aliases,
ARG_STAR, ARG_STAR2
)


# Constants that represent simple type checker error message, i.e. messages
Expand Down Expand Up @@ -400,7 +403,7 @@ def untyped_function_call(self, callee: CallableType, context: Context) -> Type:
return AnyType()

def incompatible_argument(self, n: int, m: int, callee: CallableType, arg_type: Type,
context: Context) -> None:
arg_kind: int, context: Context) -> None:
"""Report an error about an incompatible argument type.

The argument type is arg_type, argument number is n and the
Expand Down Expand Up @@ -465,6 +468,10 @@ def incompatible_argument(self, n: int, m: int, callee: CallableType, arg_type:
except IndexError: # Varargs callees
expected_type = callee.arg_types[-1]
arg_type_str, expected_type_str = self.format_distinctly(arg_type, expected_type)
if arg_kind == ARG_STAR:
arg_type_str = '*' + arg_type_str
elif arg_kind == ARG_STAR2:
arg_type_str = '**' + arg_type_str
msg = 'Argument {} {}has incompatible type {}; expected {}'.format(
n, target, arg_type_str, expected_type_str)
self.fail(msg, context)
Expand Down
2 changes: 1 addition & 1 deletion mypy/myunit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def main(args: List[str] = None) -> None:
patterns.append(a)
else:
sys.exit('Usage: python -m mypy.myunit [-v] [-q] [-u | -i]'
+ ' -m test.module [-m test.module ...] [filter ...]')
+ ' -m mypy.test.module [-m mypy.test.module ...] [filter ...]')
i += 1
if len(patterns) == 0:
patterns.append('*')
Expand Down
9 changes: 9 additions & 0 deletions mypy/test/data/check-inference-context.test
Original file line number Diff line number Diff line change
Expand Up @@ -721,3 +721,12 @@ def g(y: object) -> None: pass
a = [1]
g(f(a))
[builtins fixtures/list.py]

[case testStar2Context]
from typing import Any, Dict, Tuple, Iterable
def f1(iterable: Iterable[Tuple[str, Any]] = None) -> None:
f2(**dict(iterable))
def f2(iterable: Iterable[Tuple[str, Any]], **kw: Any) -> None:
pass
[builtins fixtures/dict.py]
[out]
25 changes: 22 additions & 3 deletions mypy/test/data/check-kwargs.test
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,8 @@ d = None # type: Dict[str, A]
f(**d)
f(x=A(), **d)
d2 = None # type: Dict[str, B]
f(**d2) # E: Argument 1 to "f" has incompatible type Dict[str, B]; expected "A"
f(x=A(), **d2) # E: Argument 2 to "f" has incompatible type Dict[str, B]; expected "A"
f(**d2) # E: Argument 1 to "f" has incompatible type **Dict[str, B]; expected "A"
f(x=A(), **d2) # E: Argument 2 to "f" has incompatible type **Dict[str, B]; expected "A"
class A: pass
class B: pass
[builtins fixtures/dict.py]
Expand All @@ -226,7 +226,7 @@ def f(a: 'A', b: 'B') -> None: pass
d = None # type: Dict[str, Any]
f(**d)
d2 = None # type: Dict[str, A]
f(**d2) # E: Argument 1 to "f" has incompatible type Dict[str, A]; expected "B"
f(**d2) # E: Argument 1 to "f" has incompatible type **Dict[str, A]; expected "B"
class A: pass
class B: pass
[builtins fixtures/dict.py]
Expand Down Expand Up @@ -286,3 +286,22 @@ f(1, 2) # E: Argument 2 to "f" has incompatible type "int"; expected "str"
f(1, y=1) # E: Argument 2 to "f" has incompatible type "int"; expected "A"
f(1, z=1) # E: Argument 2 to "f" has incompatible type "int"; expected "B"
[builtins fixtures/dict.py]

[case testCallsWithStars]
def f(a: int) -> None:
pass

s = ('',)
f(*s) # E: Argument 1 to "f" has incompatible type *"Tuple[str]"; expected "int"

a = {'': 0}
f(a) # E: Argument 1 to "f" has incompatible type Dict[str, int]; expected "int"
f(**a) # okay

b = {'': ''}
f(b) # E: Argument 1 to "f" has incompatible type Dict[str, str]; expected "int"
f(**b) # E: Argument 1 to "f" has incompatible type **Dict[str, str]; expected "int"

c = {0: 0}
f(**c) # E: Keywords must be strings
[builtins fixtures/dict.py]
54 changes: 27 additions & 27 deletions mypy/test/data/check-varargs.test
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ it1 = None # type: Iterable[int]
it2 = None # type: Iterable[str]
def f(*x: int) -> None: pass
f(*it1)
f(*it2) # E: Argument 1 to "f" has incompatible type Iterable[str]; expected "int"
f(*it2) # E: Argument 1 to "f" has incompatible type *Iterable[str]; expected "int"
[builtins fixtures/for.py]


Expand Down Expand Up @@ -190,7 +190,7 @@ class A: pass
class B: pass
[builtins fixtures/list.py]
[out]
main:7: error: Argument 1 to "f" has incompatible type List[A]; expected "B"
main:7: error: Argument 1 to "f" has incompatible type *List[A]; expected "B"

[case testCallingWithTupleVarArgs]

Expand All @@ -199,9 +199,9 @@ b = None # type: B
c = None # type: C
cc = None # type: CC

f(*(a, b, b)) # E: Argument 1 to "f" has incompatible type "Tuple[A, B, B]"; expected "C"
f(*(b, b, c)) # E: Argument 1 to "f" has incompatible type "Tuple[B, B, C]"; expected "A"
f(a, *(b, b)) # E: Argument 2 to "f" has incompatible type "Tuple[B, B]"; expected "C"
f(*(a, b, b)) # E: Argument 1 to "f" has incompatible type *"Tuple[A, B, B]"; expected "C"
f(*(b, b, c)) # E: Argument 1 to "f" has incompatible type *"Tuple[B, B, C]"; expected "A"
f(a, *(b, b)) # E: Argument 2 to "f" has incompatible type *"Tuple[B, B]"; expected "C"
f(b, *(b, c)) # E: Argument 1 to "f" has incompatible type "B"; expected "A"
f(*(a, b)) # E: Too few arguments for "f"
f(*(a, b, c, c)) # E: Too many arguments for "f"
Expand Down Expand Up @@ -259,26 +259,26 @@ class A: pass
class B: pass
[builtins fixtures/list.py]
[out]
main:3: error: Argument 1 to "f" has incompatible type List[A]; expected "B"
main:4: error: Argument 2 to "f" has incompatible type List[A]; expected "B"
main:3: error: Argument 1 to "f" has incompatible type *List[A]; expected "B"
main:4: error: Argument 2 to "f" has incompatible type *List[A]; expected "B"
main:5: error: Argument 1 to "f" has incompatible type "B"; expected "A"
main:6: error: Argument 2 to "f" has incompatible type "A"; expected "B"
main:7: error: Argument 3 to "f" has incompatible type List[A]; expected "B"
main:7: error: Argument 3 to "f" has incompatible type *List[A]; expected "B"
main:8: error: Argument 1 to "f" has incompatible type "B"; expected "A"
main:9: error: Argument 1 to "g" has incompatible type List[B]; expected "A"
main:9: error: Argument 1 to "g" has incompatible type *List[B]; expected "A"

[case testCallingVarArgsFunctionWithTupleVarArgs]

a, b, c, cc = None, None, None, None # type: (A, B, C, CC)

f(*(b, b, b)) # E: Argument 1 to "f" has incompatible type "Tuple[B, B, B]"; expected "A"
f(*(a, a, b)) # E: Argument 1 to "f" has incompatible type "Tuple[A, A, B]"; expected "B"
f(*(a, b, a)) # E: Argument 1 to "f" has incompatible type "Tuple[A, B, A]"; expected "B"
f(a, *(a, b)) # E: Argument 2 to "f" has incompatible type "Tuple[A, B]"; expected "B"
f(*(b, b, b)) # E: Argument 1 to "f" has incompatible type *"Tuple[B, B, B]"; expected "A"
f(*(a, a, b)) # E: Argument 1 to "f" has incompatible type *"Tuple[A, A, B]"; expected "B"
f(*(a, b, a)) # E: Argument 1 to "f" has incompatible type *"Tuple[A, B, A]"; expected "B"
f(a, *(a, b)) # E: Argument 2 to "f" has incompatible type *"Tuple[A, B]"; expected "B"
f(b, *(b, b)) # E: Argument 1 to "f" has incompatible type "B"; expected "A"
f(b, b, *(b,)) # E: Argument 1 to "f" has incompatible type "B"; expected "A"
f(a, a, *(b,)) # E: Argument 2 to "f" has incompatible type "A"; expected "B"
f(a, b, *(a,)) # E: Argument 3 to "f" has incompatible type "Tuple[A]"; expected "B"
f(a, b, *(a,)) # E: Argument 3 to "f" has incompatible type *"Tuple[A]"; expected "B"
f(*()) # E: Too few arguments for "f"
f(*(a, b, b))
f(a, *(b, b))
Expand Down Expand Up @@ -322,7 +322,7 @@ from typing import List
aa = None # type: List[A]
ab = None # type: List[B]

g(*aa) # E: Argument 1 to "g" has incompatible type List[A]; expected "B"
g(*aa) # E: Argument 1 to "g" has incompatible type *List[A]; expected "B"
f(*aa)
f(*ab)
g(*ab)
Expand Down Expand Up @@ -359,25 +359,25 @@ class B: pass
[builtins fixtures/list.py]
[out]
main:3: error: Too few arguments for "f"
main:4: error: Argument 2 to "f" has incompatible type List[A]; expected "B"
main:5: error: Argument 3 to "f" has incompatible type List[A]; expected "B"
main:6: error: Argument 1 to "f" has incompatible type "Tuple[A, A, B]"; expected "B"
main:4: error: Argument 2 to "f" has incompatible type *List[A]; expected "B"
main:5: error: Argument 3 to "f" has incompatible type *List[A]; expected "B"
main:6: error: Argument 1 to "f" has incompatible type *"Tuple[A, A, B]"; expected "B"

[case testVarArgsAfterKeywordArgInCall1]
def f(x: int, y: str) -> None: pass
f(x=1, *[2])
[builtins fixtures/list.py]
[out]
main:2: error: "f" gets multiple values for keyword argument "x"
main:2: error: Argument 2 to "f" has incompatible type List[int]; expected "str"
main:2: error: Argument 2 to "f" has incompatible type *List[int]; expected "str"

[case testVarArgsAfterKeywordArgInCall2]
def f(x: int, y: str) -> None: pass
f(y='x', *[1])
[builtins fixtures/list.py]
[out]
main:2: error: "f" gets multiple values for keyword argument "y"
main:2: error: Argument 2 to "f" has incompatible type List[int]; expected "str"
main:2: error: Argument 2 to "f" has incompatible type *List[int]; expected "str"

[case testVarArgsAfterKeywordArgInCall3]
def f(x: int, y: str) -> None: pass
Expand Down Expand Up @@ -469,11 +469,11 @@ class A: pass
class B: pass
[builtins fixtures/list.py]
[out]
main:6: error: Argument 1 to "f" has incompatible type List[A]; expected "B"
main:7: error: Argument 1 to "f" has incompatible type List[A]; expected "B"
main:6: error: Argument 1 to "f" has incompatible type *List[A]; expected "B"
main:7: error: Argument 1 to "f" has incompatible type *List[A]; expected "B"
main:8: error: Argument 1 to "f" has incompatible type "B"; expected "A"
main:9: error: Argument 2 to "f" has incompatible type List[A]; expected "B"
main:10: error: Argument 3 to "f" has incompatible type List[A]; expected "B"
main:9: error: Argument 2 to "f" has incompatible type *List[A]; expected "B"
main:10: error: Argument 3 to "f" has incompatible type *List[A]; expected "B"
main:11: error: List or tuple expected as variable arguments
main:12: error: List or tuple expected as variable arguments

Expand All @@ -483,9 +483,9 @@ S = TypeVar('S')
T = TypeVar('T')
a, b = None, None # type: (A, B)

a, a = f(*(a, b)) # E: Argument 1 to "f" has incompatible type "Tuple[A, B]"; expected "A"
a, a = f(*(a, b)) # E: Argument 1 to "f" has incompatible type *"Tuple[A, B]"; expected "A"
b, b = f(a, *(b,)) # E: Argument 1 to "f" has incompatible type "A"; expected "B"
a, a = f(*(a, b)) # E: Argument 1 to "f" has incompatible type "Tuple[A, B]"; expected "A"
a, a = f(*(a, b)) # E: Argument 1 to "f" has incompatible type *"Tuple[A, B]"; expected "A"
b, b = f(a, *(b,)) # E: Argument 1 to "f" has incompatible type "A"; expected "B"
a, b = f(*(a, b, b)) # E: Too many arguments for "f"

Expand Down Expand Up @@ -525,7 +525,7 @@ class B: pass
main:9: error: Incompatible types in assignment (expression has type List[A], variable has type "A")
main:9: error: Incompatible types in assignment (expression has type List[None], variable has type List[A])
main:10: error: Incompatible types in assignment (expression has type List[None], variable has type "A")
main:11: error: Argument 1 to "f" of "G" has incompatible type List[A]; expected "B"
main:11: error: Argument 1 to "f" of "G" has incompatible type *List[A]; expected "B"
main:11: error: Incompatible types in assignment (expression has type List[None], variable has type List[A])


Expand Down
7 changes: 4 additions & 3 deletions mypy/test/data/fixtures/dict.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Builtins stub used in dictionary-related test cases.

from typing import TypeVar, Generic, Iterable, Iterator, Any
from typing import TypeVar, Generic, Iterable, Iterator, Tuple

T = TypeVar('T')
S = TypeVar('S')
Expand All @@ -10,9 +10,10 @@ def __init__(self) -> None: pass

class type: pass

class dict(Generic[T, S]):
def __init__(self, arg: Any = None) -> None: pass
class dict(Iterable[T], Generic[T, S]):
def __init__(self, arg: Iterable[Tuple[T, S]] = None) -> None: pass
def __setitem__(self, k: T, v: S) -> None: pass
def __iter__(self) -> Iterator[T]: pass
def update(self, a: 'dict[T, S]') -> None: pass
class int: pass # for convenience
class str: pass # for keyword argument key type
Expand Down
6 changes: 6 additions & 0 deletions mypy/test/testinfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ def test_special_cases(self):
self.assert_map([ARG_STAR, ARG_STAR2],
[ARG_STAR, ARG_STAR2],
[[0], [1]])
self.assert_map([ARG_STAR2],
[(ARG_POS, 'x'), ARG_STAR2],
[[0], [0]])
self.assert_map([ARG_STAR2],
[ARG_STAR2],
[[0]])

def assert_map(self, caller_kinds, callee_kinds, expected):
caller_kinds, caller_names = expand_caller_kinds(caller_kinds)
Expand Down