Fix: py__iter__ in dynamic list/set usages with empy params.

This commit is contained in:
Dave Halter
2015-12-01 18:35:12 +01:00
parent 0a10947ff0
commit 37c21726e7
3 changed files with 38 additions and 17 deletions
+11
View File
@@ -198,6 +198,17 @@ class CompiledObject(Base):
pass # self.obj maynot have an __iter__ method. pass # self.obj maynot have an __iter__ method.
return result return result
def py__iter__(self):
if not hasattr(self.obj, '__iter__'):
debug.warning('Tried to call __getitem__ on non-iterable.')
return
if type(self.obj) not in (str, list, tuple, unicode, bytes, bytearray, dict):
# Get rid of side effects, we won't call custom `__getitem__`s.
return
for obj in self.obj:
yield set([CompiledObject(obj)])
@property @property
def name(self): def name(self):
# might not exist sometimes (raises AttributeError) # might not exist sometimes (raises AttributeError)
+8 -9
View File
@@ -298,28 +298,27 @@ class NameFinder(object):
@memoize_default(set(), evaluator_is_first_arg=True) @memoize_default(set(), evaluator_is_first_arg=True)
def _name_to_types(evaluator, name, scope): def _name_to_types(evaluator, name, scope):
types = set()
typ = name.get_definition() typ = name.get_definition()
if typ.isinstance(tree.ForStmt, tree.CompFor): if typ.isinstance(tree.ForStmt, tree.CompFor):
container_types = evaluator.eval_element(typ.children[3]) container_types = evaluator.eval_element(typ.children[3])
for_types = common.unite(iterable.py__iter__(evaluator, container_types)) for_types = common.unite(iterable.py__iter__(evaluator, container_types))
types |= check_tuple_assignments(for_types, name) types = check_tuple_assignments(for_types, name)
elif isinstance(typ, tree.Param): elif isinstance(typ, tree.Param):
types |= _eval_param(evaluator, typ, scope) types = _eval_param(evaluator, typ, scope)
elif typ.isinstance(tree.ExprStmt): elif typ.isinstance(tree.ExprStmt):
types |= _remove_statements(evaluator, typ, name) types = _remove_statements(evaluator, typ, name)
elif typ.isinstance(tree.WithStmt): elif typ.isinstance(tree.WithStmt):
types |= evaluator.eval_element(typ.node_from_name(name)) types = evaluator.eval_element(typ.node_from_name(name))
elif isinstance(typ, tree.Import): elif isinstance(typ, tree.Import):
types |= imports.ImportWrapper(evaluator, name).follow() types = imports.ImportWrapper(evaluator, name).follow()
elif isinstance(typ, tree.GlobalStmt): elif isinstance(typ, tree.GlobalStmt):
# TODO theoretically we shouldn't be using search_global here, it # TODO theoretically we shouldn't be using search_global here, it
# doesn't make sense, because it's a local search (for that name)! # doesn't make sense, because it's a local search (for that name)!
# However, globals are not that important and resolving them doesn't # However, globals are not that important and resolving them doesn't
# guarantee correctness in any way, because we don't check for when # guarantee correctness in any way, because we don't check for when
# something is executed. # something is executed.
types |= evaluator.find_types(typ.get_parent_scope(), str(name), types = evaluator.find_types(typ.get_parent_scope(), str(name),
search_global=True) search_global=True)
elif isinstance(typ, tree.TryStmt): elif isinstance(typ, tree.TryStmt):
# TODO an exception can also be a tuple. Check for those. # TODO an exception can also be a tuple. Check for those.
# TODO check for types that are not classes and add it to # TODO check for types that are not classes and add it to
@@ -329,7 +328,7 @@ def _name_to_types(evaluator, name, scope):
else: else:
if typ.isinstance(er.Function): if typ.isinstance(er.Function):
typ = typ.get_decorated_func() typ = typ.get_decorated_func()
types.add(typ) types = set([typ])
return types return types
+19 -8
View File
@@ -316,6 +316,8 @@ class Array(IterableWrapper, ArrayMixin):
for value in iterate: for value in iterate:
yield self._evaluator.eval_element(value) yield self._evaluator.eval_element(value)
yield check_array_additions(self._evaluator, self)
def _values(self): def _values(self):
"""Returns a list of a list of node.""" """Returns a list of a list of node."""
if self.type == 'dict': if self.type == 'dict':
@@ -485,9 +487,15 @@ def unpack_tuple_to_dict(evaluator, types, exprlist):
def py__iter__(evaluator, types): def py__iter__(evaluator, types):
debug.dbg('py__iter__')
for typ in types: for typ in types:
for result in typ.py__iter__(): try:
yield result iter_method = typ.py__iter__
except AttributeError:
raise NotImplementedError
else:
for result in iter_method():
yield result
def get_iterator_types(evaluator, element): def get_iterator_types(evaluator, element):
@@ -690,15 +698,18 @@ class _ArrayInstance(IterableWrapper):
return items return items
def py__iter__(self): def py__iter__(self):
_, first_nodes = next(self.var_args.unpack()) try:
types = unite(self._evaluator.eval_element(node) for node in first_nodes) _, first_nodes = next(self.var_args.unpack())
except StopIteration:
types = set()
else:
types = unite(self._evaluator.eval_element(node) for node in first_nodes)
for typ in py__iter__(self._evaluator, types): for types in py__iter__(self._evaluator, types):
yield typ yield types
module = self.var_args.get_parent_until() module = self.var_args.get_parent_until()
is_list = str(self.instance.name) == 'list' is_list = str(self.instance.name) == 'list'
for typ in _check_array_additions(self._evaluator, self.instance, module, is_list): yield _check_array_additions(self._evaluator, self.instance, module, is_list)
yield typ
class Slice(object): class Slice(object):