diff --git a/dynamic.py b/dynamic.py index 84e36339..2756f1a4 100644 --- a/dynamic.py +++ b/dynamic.py @@ -93,6 +93,7 @@ def check_array_additions(array): current_module = array._array.parent_stmt.get_parent_until() return _check_array_additions(array, current_module, is_list) + @evaluate.memoize_default([]) def _check_array_additions(compare_array, module, is_list): """ @@ -157,10 +158,12 @@ def _check_array_additions(compare_array, module, is_list): except KeyError: continue for stmt in possible_stmts: - result += check_calls(scan_array(stmt.get_assignment_calls(), n), n) + ass = stmt.get_assignment_calls() + result += check_calls(scan_array(ass, n), n) return result + def check_array_instances(instance): ai = ArrayInstance(instance) return helpers.generate_param_array([ai]) @@ -188,8 +191,9 @@ class ArrayInstance(parsing.Base): if isinstance(temp, ArrayInstance): items += temp.iter_content() continue - items += array.get_index_types() + items += evaluate.handle_iterators([array])#array.get_index_types() module = self.var_args.parent_stmt.get_parent_until() - items += _check_array_additions(self.instance, module, str(self.instance.name) == 'list') + is_list = str(self.instance.name) == 'list' + items += _check_array_additions(self.instance, module, is_list) return items diff --git a/evaluate.py b/evaluate.py index 6eccf75d..22ab4325 100644 --- a/evaluate.py +++ b/evaluate.py @@ -439,7 +439,7 @@ class Execution(Executable): # There maybe executions of executions. stmts = [Instance(self.base, self.var_args)] elif isinstance(self.base, Generator): - return self.base.get_content() + return self.base.iter_content() else: # Don't do this with exceptions, as usual, because some deeper # exceptions could be catched - and I wouldn't know what happened. @@ -1055,6 +1055,42 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False): return descriptor_check(remove_statements(filter_name(scope_generator))) +def handle_iterators(inputs): + iterators = [] + # Take the first statement (for has always only + # one, remember `in`). And follow it. + for it in inputs: + if isinstance(it, (Generator, Array, dynamic.ArrayInstance)): + iterators.append(it) + else: + if not hasattr(it, 'execute_subscope_by_name'): + debug.warning('iterator/for loop input wrong', it) + continue + try: + iterators += it.execute_subscope_by_name('__iter__') + except KeyError: + debug.warning('iterators: No __iter__ method found.') + + result = [] + for gen in iterators: + if isinstance(gen, Array): + # Array is a little bit special, since this is an internal + # array, but there's also the list builtin, which is + # another thing. + result += gen.get_index_types() + elif isinstance(gen, Instance): + # __iter__ returned an instance. + name = '__next__' if is_py3k() else 'next' + try: + result += it.execute_subscope_by_name(name) + except KeyError: + debug.warning('Instance has no __next__ function', gen) + else: + # is a generator + result += gen.iter_content() + return result + + def assign_tuples(tup, results, seek_name): """ This is a normal assignment checker. In python functions and other things diff --git a/test/completion/dynamic.py b/test/completion/dynamic.py index 0a5261a3..e0f12003 100644 --- a/test/completion/dynamic.py +++ b/test/completion/dynamic.py @@ -202,3 +202,11 @@ lst.append({}) #? dict() int() float() str() lst[0] + +# should work with tuple conversion, too. +#? dict() int() float() str() +tuple(lst)[0] + +# but not with an iterator +#? +iter(lst)[0]