Skip to content

Commit ac193cf

Browse files
committed
Merge pull request #1361 from python/star2infer
Don't use an arg type corresponding to ** arg kind as inference context for the argument
2 parents 1423a54 + 4012dbf commit ac193cf

File tree

8 files changed

+87
-44
lines changed

8 files changed

+87
-44
lines changed

mypy/checkexpr.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

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

4444

@@ -319,15 +319,15 @@ def infer_arg_types_in_context2(
319319
"""Infer argument expression types using a callable type as context.
320320
321321
For example, if callee argument 2 has type List[int], infer the
322-
argument exprsession with List[int] type context.
322+
argument expression with List[int] type context.
323323
324324
Returns the inferred types of *actual arguments*.
325325
"""
326326
res = [None] * len(args) # type: List[Type]
327327

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

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

@@ -618,11 +618,12 @@ def check_argument_types(self, arg_types: List[Type], arg_kinds: List[int],
618618
actual_type = get_actual_type(arg_type,
619619
arg_kinds[actual],
620620
tuple_counter)
621-
check_arg(actual_type, arg_type,
621+
check_arg(actual_type, arg_type, arg_kinds[actual],
622622
callee.arg_types[i],
623623
actual + 1, i + 1, callee, context, messages)
624624

625625
def check_arg(self, caller_type: Type, original_caller_type: Type,
626+
caller_kind: int,
626627
callee_type: Type, n: int, m: int, callee: CallableType,
627628
context: Context, messages: MessageBuilder) -> None:
628629
"""Check the type of a single argument in a call."""
@@ -632,7 +633,7 @@ def check_arg(self, caller_type: Type, original_caller_type: Type,
632633
messages.deleted_as_rvalue(caller_type, context)
633634
elif not is_subtype(caller_type, callee_type):
634635
messages.incompatible_argument(n, m, callee, original_caller_type,
635-
context)
636+
caller_kind, context)
636637

637638
def overload_call_target(self, arg_types: List[Type], arg_kinds: List[int],
638639
arg_names: List[str],
@@ -713,7 +714,7 @@ def erased_signature_similarity(self, arg_types: List[Type], arg_kinds: List[int
713714

714715
similarity = 2
715716

716-
def check_arg(caller_type: Type, original_caller_type: Type,
717+
def check_arg(caller_type: Type, original_caller_type: Type, caller_kind: int,
717718
callee_type: Type, n: int, m: int, callee: CallableType,
718719
context: Context, messages: MessageBuilder) -> None:
719720
nonlocal similarity
@@ -747,7 +748,7 @@ def match_signature_types(self, arg_types: List[Type], arg_kinds: List[int],
747748
lambda i: arg_types[i])
748749
ok = True
749750

750-
def check_arg(caller_type: Type, original_caller_type: Type,
751+
def check_arg(caller_type: Type, original_caller_type: Type, caller_kind: int,
751752
callee_type: Type, n: int, m: int, callee: CallableType,
752753
context: Context, messages: MessageBuilder) -> None:
753754
nonlocal ok

mypy/messages.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
Type, CallableType, Instance, TypeVarType, TupleType, UnionType, Void, NoneTyp, AnyType,
1414
Overloaded, FunctionLike, DeletedType
1515
)
16-
from mypy.nodes import TypeInfo, Context, MypyFile, op_methods, FuncDef, reverse_type_aliases
16+
from mypy.nodes import (
17+
TypeInfo, Context, MypyFile, op_methods, FuncDef, reverse_type_aliases,
18+
ARG_STAR, ARG_STAR2
19+
)
1720

1821

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

402405
def incompatible_argument(self, n: int, m: int, callee: CallableType, arg_type: Type,
403-
context: Context) -> None:
406+
arg_kind: int, context: Context) -> None:
404407
"""Report an error about an incompatible argument type.
405408
406409
The argument type is arg_type, argument number is n and the
@@ -465,6 +468,10 @@ def incompatible_argument(self, n: int, m: int, callee: CallableType, arg_type:
465468
except IndexError: # Varargs callees
466469
expected_type = callee.arg_types[-1]
467470
arg_type_str, expected_type_str = self.format_distinctly(arg_type, expected_type)
471+
if arg_kind == ARG_STAR:
472+
arg_type_str = '*' + arg_type_str
473+
elif arg_kind == ARG_STAR2:
474+
arg_type_str = '**' + arg_type_str
468475
msg = 'Argument {} {}has incompatible type {}; expected {}'.format(
469476
n, target, arg_type_str, expected_type_str)
470477
self.fail(msg, context)

mypy/myunit/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ def main(args: List[str] = None) -> None:
228228
patterns.append(a)
229229
else:
230230
sys.exit('Usage: python -m mypy.myunit [-v] [-q] [-u | -i]'
231-
+ ' -m test.module [-m test.module ...] [filter ...]')
231+
+ ' -m mypy.test.module [-m mypy.test.module ...] [filter ...]')
232232
i += 1
233233
if len(patterns) == 0:
234234
patterns.append('*')

mypy/test/data/check-inference-context.test

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,3 +721,12 @@ def g(y: object) -> None: pass
721721
a = [1]
722722
g(f(a))
723723
[builtins fixtures/list.py]
724+
725+
[case testStar2Context]
726+
from typing import Any, Dict, Tuple, Iterable
727+
def f1(iterable: Iterable[Tuple[str, Any]] = None) -> None:
728+
f2(**dict(iterable))
729+
def f2(iterable: Iterable[Tuple[str, Any]], **kw: Any) -> None:
730+
pass
731+
[builtins fixtures/dict.py]
732+
[out]

mypy/test/data/check-kwargs.test

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,8 @@ d = None # type: Dict[str, A]
205205
f(**d)
206206
f(x=A(), **d)
207207
d2 = None # type: Dict[str, B]
208-
f(**d2) # E: Argument 1 to "f" has incompatible type Dict[str, B]; expected "A"
209-
f(x=A(), **d2) # E: Argument 2 to "f" has incompatible type Dict[str, B]; expected "A"
208+
f(**d2) # E: Argument 1 to "f" has incompatible type **Dict[str, B]; expected "A"
209+
f(x=A(), **d2) # E: Argument 2 to "f" has incompatible type **Dict[str, B]; expected "A"
210210
class A: pass
211211
class B: pass
212212
[builtins fixtures/dict.py]
@@ -226,7 +226,7 @@ def f(a: 'A', b: 'B') -> None: pass
226226
d = None # type: Dict[str, Any]
227227
f(**d)
228228
d2 = None # type: Dict[str, A]
229-
f(**d2) # E: Argument 1 to "f" has incompatible type Dict[str, A]; expected "B"
229+
f(**d2) # E: Argument 1 to "f" has incompatible type **Dict[str, A]; expected "B"
230230
class A: pass
231231
class B: pass
232232
[builtins fixtures/dict.py]
@@ -286,3 +286,22 @@ f(1, 2) # E: Argument 2 to "f" has incompatible type "int"; expected "str"
286286
f(1, y=1) # E: Argument 2 to "f" has incompatible type "int"; expected "A"
287287
f(1, z=1) # E: Argument 2 to "f" has incompatible type "int"; expected "B"
288288
[builtins fixtures/dict.py]
289+
290+
[case testCallsWithStars]
291+
def f(a: int) -> None:
292+
pass
293+
294+
s = ('',)
295+
f(*s) # E: Argument 1 to "f" has incompatible type *"Tuple[str]"; expected "int"
296+
297+
a = {'': 0}
298+
f(a) # E: Argument 1 to "f" has incompatible type Dict[str, int]; expected "int"
299+
f(**a) # okay
300+
301+
b = {'': ''}
302+
f(b) # E: Argument 1 to "f" has incompatible type Dict[str, str]; expected "int"
303+
f(**b) # E: Argument 1 to "f" has incompatible type **Dict[str, str]; expected "int"
304+
305+
c = {0: 0}
306+
f(**c) # E: Keywords must be strings
307+
[builtins fixtures/dict.py]

mypy/test/data/check-varargs.test

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ it1 = None # type: Iterable[int]
109109
it2 = None # type: Iterable[str]
110110
def f(*x: int) -> None: pass
111111
f(*it1)
112-
f(*it2) # E: Argument 1 to "f" has incompatible type Iterable[str]; expected "int"
112+
f(*it2) # E: Argument 1 to "f" has incompatible type *Iterable[str]; expected "int"
113113
[builtins fixtures/for.py]
114114

115115

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

195195
[case testCallingWithTupleVarArgs]
196196

@@ -199,9 +199,9 @@ b = None # type: B
199199
c = None # type: C
200200
cc = None # type: CC
201201

202-
f(*(a, b, b)) # E: Argument 1 to "f" has incompatible type "Tuple[A, B, B]"; expected "C"
203-
f(*(b, b, c)) # E: Argument 1 to "f" has incompatible type "Tuple[B, B, C]"; expected "A"
204-
f(a, *(b, b)) # E: Argument 2 to "f" has incompatible type "Tuple[B, B]"; expected "C"
202+
f(*(a, b, b)) # E: Argument 1 to "f" has incompatible type *"Tuple[A, B, B]"; expected "C"
203+
f(*(b, b, c)) # E: Argument 1 to "f" has incompatible type *"Tuple[B, B, C]"; expected "A"
204+
f(a, *(b, b)) # E: Argument 2 to "f" has incompatible type *"Tuple[B, B]"; expected "C"
205205
f(b, *(b, c)) # E: Argument 1 to "f" has incompatible type "B"; expected "A"
206206
f(*(a, b)) # E: Too few arguments for "f"
207207
f(*(a, b, c, c)) # E: Too many arguments for "f"
@@ -259,26 +259,26 @@ class A: pass
259259
class B: pass
260260
[builtins fixtures/list.py]
261261
[out]
262-
main:3: error: Argument 1 to "f" has incompatible type List[A]; expected "B"
263-
main:4: error: Argument 2 to "f" has incompatible type List[A]; expected "B"
262+
main:3: error: Argument 1 to "f" has incompatible type *List[A]; expected "B"
263+
main:4: error: Argument 2 to "f" has incompatible type *List[A]; expected "B"
264264
main:5: error: Argument 1 to "f" has incompatible type "B"; expected "A"
265265
main:6: error: Argument 2 to "f" has incompatible type "A"; expected "B"
266-
main:7: error: Argument 3 to "f" has incompatible type List[A]; expected "B"
266+
main:7: error: Argument 3 to "f" has incompatible type *List[A]; expected "B"
267267
main:8: error: Argument 1 to "f" has incompatible type "B"; expected "A"
268-
main:9: error: Argument 1 to "g" has incompatible type List[B]; expected "A"
268+
main:9: error: Argument 1 to "g" has incompatible type *List[B]; expected "A"
269269

270270
[case testCallingVarArgsFunctionWithTupleVarArgs]
271271

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

274-
f(*(b, b, b)) # E: Argument 1 to "f" has incompatible type "Tuple[B, B, B]"; expected "A"
275-
f(*(a, a, b)) # E: Argument 1 to "f" has incompatible type "Tuple[A, A, B]"; expected "B"
276-
f(*(a, b, a)) # E: Argument 1 to "f" has incompatible type "Tuple[A, B, A]"; expected "B"
277-
f(a, *(a, b)) # E: Argument 2 to "f" has incompatible type "Tuple[A, B]"; expected "B"
274+
f(*(b, b, b)) # E: Argument 1 to "f" has incompatible type *"Tuple[B, B, B]"; expected "A"
275+
f(*(a, a, b)) # E: Argument 1 to "f" has incompatible type *"Tuple[A, A, B]"; expected "B"
276+
f(*(a, b, a)) # E: Argument 1 to "f" has incompatible type *"Tuple[A, B, A]"; expected "B"
277+
f(a, *(a, b)) # E: Argument 2 to "f" has incompatible type *"Tuple[A, B]"; expected "B"
278278
f(b, *(b, b)) # E: Argument 1 to "f" has incompatible type "B"; expected "A"
279279
f(b, b, *(b,)) # E: Argument 1 to "f" has incompatible type "B"; expected "A"
280280
f(a, a, *(b,)) # E: Argument 2 to "f" has incompatible type "A"; expected "B"
281-
f(a, b, *(a,)) # E: Argument 3 to "f" has incompatible type "Tuple[A]"; expected "B"
281+
f(a, b, *(a,)) # E: Argument 3 to "f" has incompatible type *"Tuple[A]"; expected "B"
282282
f(*()) # E: Too few arguments for "f"
283283
f(*(a, b, b))
284284
f(a, *(b, b))
@@ -322,7 +322,7 @@ from typing import List
322322
aa = None # type: List[A]
323323
ab = None # type: List[B]
324324

325-
g(*aa) # E: Argument 1 to "g" has incompatible type List[A]; expected "B"
325+
g(*aa) # E: Argument 1 to "g" has incompatible type *List[A]; expected "B"
326326
f(*aa)
327327
f(*ab)
328328
g(*ab)
@@ -359,25 +359,25 @@ class B: pass
359359
[builtins fixtures/list.py]
360360
[out]
361361
main:3: error: Too few arguments for "f"
362-
main:4: error: Argument 2 to "f" has incompatible type List[A]; expected "B"
363-
main:5: error: Argument 3 to "f" has incompatible type List[A]; expected "B"
364-
main:6: error: Argument 1 to "f" has incompatible type "Tuple[A, A, B]"; expected "B"
362+
main:4: error: Argument 2 to "f" has incompatible type *List[A]; expected "B"
363+
main:5: error: Argument 3 to "f" has incompatible type *List[A]; expected "B"
364+
main:6: error: Argument 1 to "f" has incompatible type *"Tuple[A, A, B]"; expected "B"
365365

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

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

382382
[case testVarArgsAfterKeywordArgInCall3]
383383
def f(x: int, y: str) -> None: pass
@@ -469,11 +469,11 @@ class A: pass
469469
class B: pass
470470
[builtins fixtures/list.py]
471471
[out]
472-
main:6: error: Argument 1 to "f" has incompatible type List[A]; expected "B"
473-
main:7: error: Argument 1 to "f" has incompatible type List[A]; expected "B"
472+
main:6: error: Argument 1 to "f" has incompatible type *List[A]; expected "B"
473+
main:7: error: Argument 1 to "f" has incompatible type *List[A]; expected "B"
474474
main:8: error: Argument 1 to "f" has incompatible type "B"; expected "A"
475-
main:9: error: Argument 2 to "f" has incompatible type List[A]; expected "B"
476-
main:10: error: Argument 3 to "f" has incompatible type List[A]; expected "B"
475+
main:9: error: Argument 2 to "f" has incompatible type *List[A]; expected "B"
476+
main:10: error: Argument 3 to "f" has incompatible type *List[A]; expected "B"
477477
main:11: error: List or tuple expected as variable arguments
478478
main:12: error: List or tuple expected as variable arguments
479479

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

486-
a, a = f(*(a, b)) # E: Argument 1 to "f" has incompatible type "Tuple[A, B]"; expected "A"
486+
a, a = f(*(a, b)) # E: Argument 1 to "f" has incompatible type *"Tuple[A, B]"; expected "A"
487487
b, b = f(a, *(b,)) # E: Argument 1 to "f" has incompatible type "A"; expected "B"
488-
a, a = f(*(a, b)) # E: Argument 1 to "f" has incompatible type "Tuple[A, B]"; expected "A"
488+
a, a = f(*(a, b)) # E: Argument 1 to "f" has incompatible type *"Tuple[A, B]"; expected "A"
489489
b, b = f(a, *(b,)) # E: Argument 1 to "f" has incompatible type "A"; expected "B"
490490
a, b = f(*(a, b, b)) # E: Too many arguments for "f"
491491

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

531531

mypy/test/data/fixtures/dict.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Builtins stub used in dictionary-related test cases.
22

3-
from typing import TypeVar, Generic, Iterable, Iterator, Any
3+
from typing import TypeVar, Generic, Iterable, Iterator, Tuple
44

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

1111
class type: pass
1212

13-
class dict(Generic[T, S]):
14-
def __init__(self, arg: Any = None) -> None: pass
13+
class dict(Iterable[T], Generic[T, S]):
14+
def __init__(self, arg: Iterable[Tuple[T, S]] = None) -> None: pass
1515
def __setitem__(self, k: T, v: S) -> None: pass
16+
def __iter__(self) -> Iterator[T]: pass
1617
def update(self, a: 'dict[T, S]') -> None: pass
1718
class int: pass # for convenience
1819
class str: pass # for keyword argument key type

mypy/test/testinfer.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,12 @@ def test_special_cases(self):
158158
self.assert_map([ARG_STAR, ARG_STAR2],
159159
[ARG_STAR, ARG_STAR2],
160160
[[0], [1]])
161+
self.assert_map([ARG_STAR2],
162+
[(ARG_POS, 'x'), ARG_STAR2],
163+
[[0], [0]])
164+
self.assert_map([ARG_STAR2],
165+
[ARG_STAR2],
166+
[[0]])
161167

162168
def assert_map(self, caller_kinds, callee_kinds, expected):
163169
caller_kinds, caller_names = expand_caller_kinds(caller_kinds)

0 commit comments

Comments
 (0)