8000 Fix #1855: Multiassign from Union (take 2) by elazarg · Pull Request #2219 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

Fix #1855: Multiassign from Union (take 2) #2219

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

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c53a1c4
NewType+namedtuple: common method for typeinfo
elazarg Sep 3, 2016
7e043d0
handle union, add test
elazarg Sep 18, 2016
9a50d73
kill blank
elazarg Sep 18, 2016
5c4d86e
more tests
elazarg Sep 18, 2016
60cfbbb
handle binding
elazarg Sep 19, 2016
5e9e0f2
try to minimize visual difference
elazarg Sep 19, 2016
71f8475
(cont.)
elazarg Sep 19, 2016
42b6e73
add tests
elazarg Sep 21, 2016
0560bd8
no binder yet
elazarg Sep 23, 2016
da3a516
Support rebinding on multiassignment from union
elazarg Sep 27, 2016
ab60317
Merge remo 8000 te-tracking branch 'upstream/master' into multiassign_union
elazarg Sep 27, 2016
6bb5519
more tests
elazarg Sep 27, 2016
3b4cd13
Merge remote-tracking branch 'upstream/master'
elazarg Oct 2, 2016
38651c4
handle union, add test
elazarg Sep 18, 2016
9000099
kill blank
elazarg Sep 18, 2016
f20f3d6
more tests
elazarg Sep 18, 2016
61be4e9
handle binding
elazarg Sep 19, 2016
9830cb4
try to minimize visual difference
elazarg Sep 19, 2016
59dc8b7
(cont.)
elazarg Sep 19, 2016
7f304e4
add tests
elazarg Sep 21, 2016
ff1ca80
no binder yet
elazarg Sep 23, 2016
168087e
Support rebinding on multiassignment from union
elazarg Sep 27, 2016
3f198cf
more tests
elazarg Sep 27, 2016
4fa059f
Rebase
elazarg Oct 5, 2016
ab35a4c
Merge
elazarg Oct 5, 2016
00f34ce
small merge fix
elazarg Oct 5, 2016
0cccb4b
Merge
elazarg Oct 7, 2016
a3ef3d5
what typeshed?
elazarg Oct 7, 2016
60c032f
Merge remote-tracking branch 'upstream/master' into multiassign_union2
elazarg Oct 11, 2016
21ac123
Merge remote-tracking branch 'upstream/master' into multiassign_union2
elazarg Oct 18, 2016
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
Apply and reload
Diff view
Prev Previous commit
Next Next commit
handle union, add test
  • Loading branch information
elazarg committed Sep 18, 2016
commit 7e043d0ee30212b5db7fe1339fa09d33a33236f0
58 changes: 30 additions & 28 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1102,6 +1102,7 @@ def check_assignment_to_multiple_lvalues(self, lvalues: List[Node], rvalue: Node
# using the type of rhs, because this allowed more fine grained
# control in cases like: a, b = [int, str] where rhs would get
# type List[object]
# Tuple is also special cased to handle mutually nested lists and tuples

rvalues = rvalue.items

Expand All @@ -1127,7 +1128,8 @@ def check_assignment_to_multiple_lvalues(self, lvalues: List[Node], rvalue: Node
for lv, rv in lr_pairs:
self.check_assignment(lv, rv, infer_lvalue_type)
else:
self.check_multi_assignment(lvalues, rvalue, context, infer_lvalue_type)
rvalue_type = self.accept(rvalue) # TODO maybe elsewhere; redundant
self.check_multi_assignment(lvalues, rvalue, rvalue_type, context, infer_lvalue_type)

def check_rvalue_count_in_assignment(self, lvalues: List[Node], rvalue_count: int,
context: Context) -> bool:
Expand All @@ -1144,13 +1146,11 @@ def check_rvalue_count_in_assignment(self, lvalues: List[Node], rvalue_count: in

def check_multi_assignment(self, lvalues: List[Node],
rvalue: Node,
rvalue_type: Type,
context: Context,
infer_lvalue_type: bool = True,
msg: str = None) -> None:
infer_lvalue_type: bool = True) -> None:
"""Check the assignment of one rvalue to a number of lvalues."""

# Infer the type of an ordinary rvalue expression.
rvalue_type = self.accept(rvalue) # TODO maybe elsewhere; redundant
undefined_rvalue = False

if isinstance(rvalue_type, AnyType):
Expand All @@ -1160,10 +1160,32 @@ def check_multi_assignment(self, lvalues: List[Node],
self.check_assignment(lv, self.temp_node(AnyType(), context), infer_lvalue_type)
elif isinstance(rvalue_type, TupleType):
self.check_multi_assignment_from_tuple(lvalues, rvalue, rvalue_type,
context, undefined_rvalue, infer_lvalue_type)
else:
context, undefined_rvalue, infer_lvalue_type)
elif isinstance(rvalue_type, UnionType):
for item in rvalue_type.items:
self.check_multi_assignment(lvalues, rvalue, item, context, infer_lvalue_type)
elif isinstance(rvalue_type, Instance) and self.type_is_iterable(rvalue_type):
self.check_multi_assignment_from_iterable(lvalues, rvalue_type,
context, infer_lvalue_type)
context, infer_lvalue_type)
else:
self.msg.type_not_iterable(rvalue_type, context)

def type_is_iterable(self, rvalue_type: Type) -> bool:
return is_subtype(rvalue_type, self.named_generic_type('typing.Iterable',
[AnyType()]))

def check_multi_assignment_from_iterable(self, lvalues: List[Node], rvalue_type: Instance,
context: Context,
infer_lvalue_type: bool = True) -> None:
item_type = self.iterable_item_type(rvalue_type)
for lv in lvalues:
if isinstance(lv, StarExpr):
self.check_assignment(lv.expr, self.temp_node(rvalue_type, context),
infer_lvalue_type)
else:
self.check_assignment(lv, self.temp_node(item_type, context),
infer_lvalue_type)


def check_multi_assignment_from_tuple(self, lvalues: List[Node], rvalue: Node,
rvalue_type: TupleType, context: Context,
Expand Down Expand Up @@ -1246,26 +1268,6 @@ def split_around_star(self, items: List[T], star_index: int,
right = items[right_index:]
return (left, star, right)

def type_is_iterable(self, type: Type) -> bool:
return (is_subtype(type, self.named_generic_type('typing.Iterable',
[AnyType()])) and
isinstance(type, Instance))

def check_multi_assignment_from_iterable(self, lvalues: List[Node], rvalue_type: Type,
context: Context,
infer_lvalue_type: bool = True) -> None:
if self.type_is_iterable(rvalue_type):
item_type = self.iterable_item_type(cast(Instance, rvalue_type))
for lv in lvalues:
if isinstance(lv, StarExpr):
self.check_assignment(lv.expr, self.temp_node(rvalue_type, context),
infer_lvalue_type)
else:
self.check_assignment(lv, self.temp_node(item_type, context),
infer_lvalue_type)
else:
self.msg.type_not_iterable(rvalue_type, context)

def check_lvalue(self, lvalue: Node) -> Tuple[Type, IndexExpr, Var]:
lvalue_type = None # type: Type
index_lvalue = None # type: IndexExpr
Expand Down
9 changes: 9 additions & 0 deletions test-data/unit/check-unions.test
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,12 @@ class C(Generic[T, U]):
a = C() # type: C[int, int]
b = a.f('a')
a.f(b) # E: Argument 1 to "f" of "C" has incompatible type "int"; expected "str"

[case testUnionMultiple]
from typing import Union, Tuple

a = None # type: Tuple[int]
(x,) = a

b = None # type: Union[Tuple[int], Tuple[float]]
(z,) = b
0