From 6ecbd1fd15de2d538410de0e467c0d0ffd343560 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Sun, 18 Aug 2013 18:45:59 +0100 Subject: [PATCH] Fix type inference with iterable initializer --- mypy/checker.py | 23 ++++++++++++++--------- mypy/test/data/check-inference.test | 15 +++++++++++++-- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 2baf5b56cbfc..2cca91ef8715 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -526,10 +526,12 @@ def infer_variable_type(self, names: List[Var], lvalues: List[Node], self.msg.incompatible_value_count_in_assignment( len(names), len(init_type.items), context) elif (isinstance(init_type, Instance) and - cast(Instance, init_type).type.fullname() == - 'builtins.list'): - # Initializer with an array type. - item_type = cast(Instance, init_type).args[0] + is_subtype(init_type, + self.named_generic_type('builtins.Iterable', + [AnyType()]))): + # Initializer with an iterable type. + item_type = self.iterable_item_type(cast(Instance, + init_type)) for i in range(len(names)): self.set_inferred_type(names[i], lvalues[i], item_type) elif isinstance(init_type, AnyType): @@ -614,10 +616,7 @@ def check_multi_assignment(self, lvalue_types: List[Type], [AnyType()])) and isinstance(rvalue_type, Instance)): # Rvalue is iterable. - iterable = map_instance_to_supertype( - cast(Instance, rvalue_type), - self.lookup_typeinfo('builtins.Iterable')) - item_type = iterable.args[0] + item_type = self.iterable_item_type(cast(Instance, rvalue_type)) for k in range(len(lvalue_types)): self.check_single_assignment(lvalue_types[k], index_lvalues[k], @@ -625,7 +624,7 @@ def check_multi_assignment(self, lvalue_types: List[Type], context, msg) else: self.fail(msg, context) - + def check_single_assignment(self, lvalue_type: Type, index_lvalue: IndexExpr, rvalue: Node, context: Context, @@ -1158,6 +1157,12 @@ def fail(self, msg: str, context: Context) -> None: """Produce an error message.""" self.msg.fail(msg, context) + def iterable_item_type(self, instance: Instance) -> Type: + iterable = map_instance_to_supertype( + instance, + self.lookup_typeinfo('builtins.Iterable')) + return iterable.args[0] + def map_type_from_supertype(typ: Type, sub_info: TypeInfo, super_info: TypeInfo) -> Type: diff --git a/mypy/test/data/check-inference.test b/mypy/test/data/check-inference.test index db87e622bf8a..78edaa9f2039 100644 --- a/mypy/test/data/check-inference.test +++ b/mypy/test/data/check-inference.test @@ -174,8 +174,8 @@ class A: pass main: In function "f": --- Inferring local variable types in multiple definition --- ----------------------------------------------------- +-- Inferring variable types in multiple definition +-- ----------------------------------------------- [case testInferringLvarTypesInMultiDef] @@ -270,6 +270,17 @@ def f(d: Any) -> None: a.x b.x +[case testInferringTypesFromIterable] +from typing import Iterable +class Nums(Iterable[int]): + def __iter__(self): pass + def __next__(self): pass +a, b = Nums() +a = b = 1 +a = '' # E: Incompatible types in assignment +b = '' # E: Incompatible types in assignment +[builtins fixtures/for.py] + -- Type variable inference for generic functions -- ---------------------------------------------