Skip to content

Commit

Permalink
Fine-grained: Support Python 3 unpacking expressions (and fix crash) (#…
Browse files Browse the repository at this point in the history
…4966)

Also fix crash on incompatible dictionary unpack. Fixes #4959.

Work towards #4951.
  • Loading branch information
JukkaL authored Apr 26, 2018
1 parent d6a22cf commit 7b257c8
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 2 deletions.
2 changes: 1 addition & 1 deletion mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ def incompatible_argument(self, n: int, m: int, callee: CallableType, arg_type:
# For function calls with keyword arguments, display the argument name rather than the
# number.
arg_label = str(n)
if isinstance(context, CallExpr):
if isinstance(context, CallExpr) and len(context.arg_names) >= n:
arg_name = context.arg_names[n - 1]
if arg_name is not None:
arg_label = '"{}"'.format(arg_name)
Expand Down
3 changes: 2 additions & 1 deletion mypy/server/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,8 @@ def process_lvalue(self, lvalue: Expression) -> None:
elif isinstance(lvalue, TupleExpr):
for item in lvalue.items:
self.process_lvalue(item)
# TODO: star lvalue
elif isinstance(lvalue, StarExpr):
self.process_lvalue(lvalue.expr)

def is_self_member_ref(self, memberexpr: MemberExpr) -> bool:
"""Does memberexpr to refer to an attribute of self?"""
Expand Down
17 changes: 17 additions & 0 deletions test-data/unit/deps.test
Original file line number Diff line number Diff line change
Expand Up @@ -1109,3 +1109,20 @@ class A(B):
<mod.C.__new__> -> <m.D.__new__>
<mod.C.x> -> <m.D.x>
<mod.C> -> m, m.D

[case testIndexedStarLvalue]
from typing import List, Tuple

class B:
def __setitem__(self, i: int, v: List[str]) -> None: pass

def g() -> Tuple[int, str, str]: pass

def f(b: B) -> None:
a, *b[0] = g()
[builtins fixtures/list.pyi]
[out]
<m.B.__getitem__> -> m.f
<m.B.__setitem__> -> m.f
<m.B> -> <m.f>, m.B, m.f
<m.g> -> m.f
89 changes: 89 additions & 0 deletions test-data/unit/fine-grained.test
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
--
-- Test runner can parse options from mypy.ini file. Updating this file in between
-- incremental runs is not yet supported.
--
-- Each test case run without caching and with caching (if the initial run passes),
-- unless it has one a --skip-cache or --skip-nocache suffix. We sometimes
-- skip caching test cases to speed up tests, if the caching variant is not useful.
-- The caching test case variants get an implicit _cached suffix.

[case testReprocessFunction]
import m
Expand Down Expand Up @@ -5801,6 +5806,90 @@ class M(type):
==
a.py:2: error: Argument 1 to "f" of "M" has incompatible type "int"; expected "str"

[case testExtendedUnpacking-skip-cache]
from typing import List
from a import g
def f() -> List[int]:
a, *b = g()
return b

[file a.py]
from typing import Tuple
def g() -> Tuple[str, int, int]: pass

[file a.py.2]
from typing import Tuple
def g() -> Tuple[str, str]: pass

[builtins fixtures/tuple.pyi]
[out]
==
main:5: error: Incompatible return value type (got "List[str]", expected "List[int]")

[case testUnpackInExpression1-skip-cache]
from typing import Tuple, List
from a import t

def f() -> Tuple[int, int]:
return (1, *t())

def g() -> List[int]:
return [1, *t()]

[file a.py]
from typing import Tuple
def t() -> Tuple[int]: ...

[file a.py.2]
from typing import Tuple
def t() -> Tuple[str]: ...

[builtins fixtures/list.pyi]
[out]
==
main:5: error: Incompatible return value type (got "Tuple[int, str]", expected "Tuple[int, int]")
main:8: error: List item 1 has incompatible type "Tuple[str]"; expected "int"

[case testUnpackInExpression2-skip-cache]
from typing import Set
from a import t

def f() -> Set[int]:
return {1, *t()}

[file a.py]
from typing import Tuple
def t() -> Tuple[int]: pass

[file a.py.2]
from typing import Tuple
def t() -> Tuple[str]: pass

[builtins fixtures/set.pyi]
[out]
==
main:5: error: Argument 2 to <set> has incompatible type "*Tuple[str]"; expected "int"

[case testUnpackInExpression3-skip-cache]
from typing import Dict
from a import d

def f() -> Dict[int, str]:
return {1: '', **d()}

[file a.py]
from typing import Dict
def d() -> Dict[int, str]: pass

[file a.py.2]
from typing import Dict
def d() -> Dict[int, int]: pass

[builtins fixtures/dict.pyi]
[out]
==
main:5: error: Argument 1 to "update" of "dict" has incompatible type "Dict[int, int]"; expected "Mapping[int, str]"

[case testAwaitAndAsyncDef-skip-cache]
from a import g

Expand Down
11 changes: 11 additions & 0 deletions test-data/unit/pythoneval.test
Original file line number Diff line number Diff line change
Expand Up @@ -1259,3 +1259,14 @@ class B:
[out]
_testInvalidSlots.py:2: error: Incompatible types in assignment (expression has type "int", base class "object" defined the type as "Union[str, Iterable[str], None]")
_testInvalidSlots.py:4: error: Incompatible types in assignment (expression has type "Tuple[int, int]", base class "object" defined the type as "Union[str, Iterable[str], None]")

[case testDictWithStarStarSpecialCase]
from typing import Dict

def f() -> Dict[int, str]:
return {1: '', **d()}

def d() -> Dict[int, int]:
return {}
[out]
_testDictWithStarStarSpecialCase.py:4: error: Argument 1 to "update" of "dict" has incompatible type "Dict[int, int]"; expected "Mapping[int, str]"

0 comments on commit 7b257c8

Please sign in to comment.