diff --git a/jedi/evaluate/context.py b/jedi/evaluate/context.py index 88521a77..2aaf47c4 100644 --- a/jedi/evaluate/context.py +++ b/jedi/evaluate/context.py @@ -25,12 +25,12 @@ class Context(object): from jedi.evaluate.param import ValueArguments return self.execute(ValueArguments(value_list)) - -class TreeContext(Context): def eval_node(self, node): return self._evaluator.eval_element(self, node) +class TreeContext(Context): + pass class FlowContext(TreeContext): def get_parent_flow_context(self): if 1: diff --git a/jedi/evaluate/filters.py b/jedi/evaluate/filters.py index a870b5be..75ae6a27 100644 --- a/jedi/evaluate/filters.py +++ b/jedi/evaluate/filters.py @@ -68,7 +68,7 @@ class ParamName(ContextName): self.name = name def infer(self): - return self._get_param().infer(self.parent_context._evaluator) + return self._get_param().infer() def _get_param(self): params = self.parent_context.get_params() diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index 7060f909..ee494bb6 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -360,8 +360,8 @@ def _name_to_types(evaluator, context, name, scope): types = pep0484.find_type_from_comment_hint_with(evaluator, typ, name) if types: return types - if typ.isinstance(tree.ForStmt, tree.CompFor): - container_types = evaluator.eval_element(typ.children[3]) + if typ.type in ('for_stmt', 'comp_for'): + container_types = context.eval_node(typ.children[3]) for_types = iterable.py__iter__types(evaluator, container_types, typ.children[3]) types = check_tuple_assignments(evaluator, for_types, name) elif isinstance(typ, tree.Param): diff --git a/jedi/evaluate/flow_analysis.py b/jedi/evaluate/flow_analysis.py index 385b4099..f1de9352 100644 --- a/jedi/evaluate/flow_analysis.py +++ b/jedi/evaluate/flow_analysis.py @@ -41,10 +41,10 @@ def reachability_check(context, context_scope, node, origin_scope=None): # e.g. `if 0:` would cause all name lookup within the flow make # unaccessible. This is not a "problem" in Python, because the code is # never called. In Jedi though, we still want to infer types. - while origin_scope is not None: - if flow_scope == origin_scope: - return REACHABLE - origin_scope = origin_scope.parent + #while origin_scope is not None: + #if flow_scope == origin_scope: + #return REACHABLE + #origin_scope = origin_scope.parent return _break_check(context, context_scope, flow_scope, node) diff --git a/jedi/evaluate/iterable.py b/jedi/evaluate/iterable.py index 4e6ae34b..5e5c7b0a 100644 --- a/jedi/evaluate/iterable.py +++ b/jedi/evaluate/iterable.py @@ -41,9 +41,7 @@ class AbstractSequence(Context): @property def name(self): - raise NotImplementedError - #return compiled.CompiledContextName( - return helpers.FakeName(self.type, parent=self) + return compiled.CompiledContextName(self, self.type) class IterableWrapper(tree.Base): @@ -137,19 +135,15 @@ class GeneratorMixin(object): return gen_obj.py__class__() -class Generator(use_metaclass(CachedMetaClass, IterableWrapper, GeneratorMixin)): +class Generator(Context, GeneratorMixin): """Handling of `yield` functions.""" - def __init__(self, evaluator, func, var_args): - super(Generator, self).__init__() - self._evaluator = evaluator - self.func = func - self.var_args = var_args + def __init__(self, evaluator, func_execution_context): + super(Generator, self).__init__(evaluator) + self._func_execution_context = func_execution_context def py__iter__(self): - from jedi.evaluate.representation import FunctionExecution - f = FunctionExecution(self._evaluator, self.func, self.var_args) - return f.get_yield_types() + return self._func_execution_context.get_yield_values() def __getattr__(self, name): raise NotImplementedError @@ -389,13 +383,6 @@ class ArrayLiteralContext(AbstractSequence, ArrayMixin): else: return self.parent_context.eval_node(self._items()[index]) - def __getattr__(self, name): - raise NotImplementedError - if name not in ['start_pos', 'get_only_subelement', 'parent', - 'get_parent_until', 'items']: - raise AttributeError('Strange access on %s: %s.' % (self, name)) - return getattr(self.atom, name) - # @memoize_default() def py__iter__(self): """ @@ -413,7 +400,7 @@ class ArrayLiteralContext(AbstractSequence, ArrayMixin): yield types else: for value in self._items(): - yield self._evaluator.eval_element(value) + yield self.parent_context.eval_node(value) additions = check_array_additions(self._evaluator, self) if additions: diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index 056ae9fc..1a5eb1f2 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -8,7 +8,6 @@ from jedi.parser import tree from jedi.evaluate import iterable from jedi.evaluate import analysis from jedi.evaluate import precedence -from jedi.evaluate.context import Context def try_iter_content(types, depth=0): @@ -130,21 +129,19 @@ class TreeArguments(AbstractArguments): named_args = [] for stars, el in self._split(): if stars == 1: - raise NotImplementedError arrays = self._evaluator.eval_element(self._context, el) iterators = [_iterate_star_args(self._evaluator, a, el, func) for a in arrays] iterators = list(iterators) for values in list(zip_longest(*iterators)): - yield None, [v for v in values if v is not None] + yield None, MergedLazyContexts(values) elif stars == 2: - raise NotImplementedError arrays = self._evaluator.eval_element(self._context, el) dicts = [_star_star_dict(self._evaluator, a, el, func) for a in arrays] for dct in dicts: for key, values in dct.items(): - yield key, LazyContext(*values) + yield key, values else: if tree.is_node(el, 'argument'): c = el.children @@ -187,6 +184,14 @@ class KnownContext(object): return set([self._value]) +class KnownContexts(object): + def __init__(self, values): + self._values = values + + def infer(self): + return self._values + + class UnknownContext(object): def infer(self): return set() @@ -201,6 +206,14 @@ class LazyContext(object): return self._context.eval_node(self._node) +class MergedLazyContexts(object): + def __init__(self, lazy_contexts): + self._lazy_contexts = lazy_contexts + + def infer(self): + return common.unite(l.infer() for l in self._lazy_contexts) + + class ValueArguments(AbstractArguments): def __init__(self, value_list): self._value_list = value_list @@ -225,7 +238,7 @@ class ExecutedParam(object): self._lazy_context = lazy_context self.string_name = self._original_param.name.value - def infer(self, evaluator): + def infer(self): return self._lazy_context.infer() @property @@ -238,6 +251,7 @@ def _get_calling_var_args(evaluator, var_args): old_var_args = None while var_args != old_var_args: old_var_args = var_args + continue#TODO REMOVE for name, default, stars in reversed(list(var_args.as_tuple())): if not stars or not isinstance(name, tree.Name): continue @@ -329,7 +343,7 @@ def get_params(evaluator, parent_context, func, var_args): non_matching_keys = {} else: # normal param - if argument is not None: + if argument is None: # No value: Return an empty container result_arg = UnknownContext() if not keys_only: @@ -352,7 +366,8 @@ def get_params(evaluator, parent_context, func, var_args): # there's nothing to find for certain names. for k in set(param_dict) - set(keys_used): param = param_dict[k] - result_arg = UnknownContext() if param.default is None else LazyContext(param.default) + result_arg = (UnknownContext() if param.default is None else + LazyContext(parent_context, param.default)) result_params.append(ExecutedParam(param, var_args, result_arg)) if not (non_matching_keys or had_multiple_value_error or @@ -399,12 +414,13 @@ def get_params(evaluator, parent_context, func, var_args): def _iterate_star_args(evaluator, array, input_node, func=None): from jedi.evaluate.representation import Instance if isinstance(array, iterable.AbstractSequence): + raise DeprecationWarning('_items? seriously?') # TODO ._items is not the call we want here. Replace in the future. for node in array._items(): yield node elif isinstance(array, iterable.Generator): for types in array.py__iter__(): - yield iterable.AlreadyEvaluated(types) + yield KnownContexts(types) elif isinstance(array, Instance) and array.name.get_code() == 'tuple': debug.warning('Ignored a tuple *args input %s' % array) else: diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index d96eeb05..2fe22a3f 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -603,15 +603,16 @@ class FunctionContext(use_metaclass(CachedMetaClass, TreeContext, Wrapper)): @Python3Method def py__call__(self, params): + function_execution = FunctionExecutionContext( + self._evaluator, + self.parent_context, + self.base, + params + ) if self.base.is_generator(): - return set([iterable.Generator(self._evaluator, self, params)]) + return set([iterable.Generator(self._evaluator, function_execution)]) else: - return FunctionExecutionContext( - self._evaluator, - self.parent_context, - self.base, - params - ).get_return_types() + return function_execution.get_return_values() def py__class__(self): # This differentiation is only necessary for Python2. Python3 does not @@ -663,7 +664,7 @@ class FunctionExecutionContext(Executed): @memoize_default(default=set()) @recursion.execution_recursion_decorator - def get_return_types(self, check_yields=False): + def get_return_values(self, check_yields=False): funcdef = self.funcdef if funcdef.type in ('lambdef', 'lambdef_nocond'): return self._evaluator.eval_element(self.children[-1]) @@ -713,8 +714,8 @@ class FunctionExecutionContext(Executed): yield self.eval_node(node) @recursion.execution_recursion_decorator - def get_yield_types(self): - yields = self.yields + def get_yield_values(self): + yields = self.funcdef.yields stopAt = tree.ForStmt, tree.WhileStmt, tree.IfStmt for_parents = [(x, x.get_parent_until((stopAt))) for x in yields] @@ -736,7 +737,7 @@ class FunctionExecutionContext(Executed): elif for_stmt == self: yields_order.append((None, [yield_])) else: - yield self.get_return_types(check_yields=True) + yield self.get_return_values(check_yields=True) return last_for_stmt = for_stmt