forked from VimPlug/jedi
More fixes to *args type inference.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
from jedi.common import unite
|
||||||
class Context(object):
|
class Context(object):
|
||||||
type = None # TODO remove
|
type = None # TODO remove
|
||||||
|
|
||||||
@@ -35,3 +36,56 @@ class FlowContext(TreeContext):
|
|||||||
def get_parent_flow_context(self):
|
def get_parent_flow_context(self):
|
||||||
if 1:
|
if 1:
|
||||||
return self.parent_context
|
return self.parent_context
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractLazyContext(object):
|
||||||
|
def __init__(self, data):
|
||||||
|
self._data = data
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<%s: %s>' % (self.__class__.__name__, self._data)
|
||||||
|
|
||||||
|
def infer(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class LazyKnownContext(AbstractLazyContext):
|
||||||
|
"""data is a context."""
|
||||||
|
def infer(self):
|
||||||
|
return set([self._data])
|
||||||
|
|
||||||
|
|
||||||
|
class LazyKnownContexts(AbstractLazyContext):
|
||||||
|
"""data is a set of contexts."""
|
||||||
|
def infer(self):
|
||||||
|
return self._data
|
||||||
|
|
||||||
|
|
||||||
|
class LazyUnknownContext(AbstractLazyContext):
|
||||||
|
def __init__(self):
|
||||||
|
super(LazyUnknownContext, self).__init__(None)
|
||||||
|
|
||||||
|
def infer(self):
|
||||||
|
return set()
|
||||||
|
|
||||||
|
|
||||||
|
class LazyTreeContext(AbstractLazyContext):
|
||||||
|
def __init__(self, context, node):
|
||||||
|
self._context = context
|
||||||
|
self._data = node
|
||||||
|
|
||||||
|
def infer(self):
|
||||||
|
return self._context.eval_node(self._data)
|
||||||
|
|
||||||
|
|
||||||
|
def get_merged_lazy_context(lazy_contexts):
|
||||||
|
if len(lazy_contexts) > 1:
|
||||||
|
return MergedLazyContexts(lazy_contexts)
|
||||||
|
else:
|
||||||
|
return lazy_contexts[0]
|
||||||
|
|
||||||
|
|
||||||
|
class MergedLazyContexts(AbstractLazyContext):
|
||||||
|
"""data is a list of lazy contexts."""
|
||||||
|
def infer(self):
|
||||||
|
return unite(l.infer() for l in self._data)
|
||||||
|
|||||||
@@ -32,16 +32,18 @@ from jedi.evaluate import analysis
|
|||||||
from jedi.evaluate import pep0484
|
from jedi.evaluate import pep0484
|
||||||
from jedi import common
|
from jedi import common
|
||||||
from jedi.evaluate.filters import DictFilter
|
from jedi.evaluate.filters import DictFilter
|
||||||
from jedi.evaluate.context import Context
|
from jedi.evaluate import context
|
||||||
|
|
||||||
|
|
||||||
class AbstractSequence(Context):
|
class AbstractSequence(context.Context):
|
||||||
|
_array_type = None
|
||||||
|
|
||||||
def get_filters(self, search_global, until_position=None, origin_scope=None):
|
def get_filters(self, search_global, until_position=None, origin_scope=None):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return compiled.CompiledContextName(self, self.type)
|
return compiled.CompiledContextName(self, self._array_type)
|
||||||
|
|
||||||
|
|
||||||
class IterableWrapper(tree.Base):
|
class IterableWrapper(tree.Base):
|
||||||
@@ -135,7 +137,7 @@ class GeneratorMixin(object):
|
|||||||
return gen_obj.py__class__()
|
return gen_obj.py__class__()
|
||||||
|
|
||||||
|
|
||||||
class Generator(Context, GeneratorMixin):
|
class Generator(context.Context, GeneratorMixin):
|
||||||
"""Handling of `yield` functions."""
|
"""Handling of `yield` functions."""
|
||||||
|
|
||||||
def __init__(self, evaluator, func_execution_context):
|
def __init__(self, evaluator, func_execution_context):
|
||||||
@@ -145,17 +147,8 @@ class Generator(Context, GeneratorMixin):
|
|||||||
def py__iter__(self):
|
def py__iter__(self):
|
||||||
return self._func_execution_context.get_yield_values()
|
return self._func_execution_context.get_yield_values()
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
raise NotImplementedError
|
|
||||||
if name not in ['start_pos', 'end_pos', 'parent', 'get_imports',
|
|
||||||
'doc', 'docstr', 'get_parent_until',
|
|
||||||
'get_code', 'subscopes']:
|
|
||||||
raise AttributeError("Accessing %s of %s is not allowed."
|
|
||||||
% (self, name))
|
|
||||||
return getattr(self.func, name)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s of %s>" % (type(self).__name__, self.func)
|
return "<%s of %s>" % (type(self).__name__, self._func_execution_context)
|
||||||
|
|
||||||
|
|
||||||
class Comprehension(IterableWrapper):
|
class Comprehension(IterableWrapper):
|
||||||
@@ -235,6 +228,7 @@ class Comprehension(IterableWrapper):
|
|||||||
yield result
|
yield result
|
||||||
|
|
||||||
def py__iter__(self):
|
def py__iter__(self):
|
||||||
|
raise NotImplementedError
|
||||||
return self._iterate()
|
return self._iterate()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@@ -319,6 +313,7 @@ class DictComprehension(Comprehension, ArrayMixin):
|
|||||||
return self._get_comprehension().children[3]
|
return self._get_comprehension().children[3]
|
||||||
|
|
||||||
def py__iter__(self):
|
def py__iter__(self):
|
||||||
|
raise NotImplementedError
|
||||||
for keys, values in self._iterate():
|
for keys, values in self._iterate():
|
||||||
yield keys
|
yield keys
|
||||||
|
|
||||||
@@ -351,9 +346,10 @@ class ArrayLiteralContext(AbstractSequence, ArrayMixin):
|
|||||||
'[': 'list',
|
'[': 'list',
|
||||||
'{': 'dict'}
|
'{': 'dict'}
|
||||||
|
|
||||||
def __init__(self, evaluator, parent_context, atom):
|
def __init__(self, evaluator, defining_context, atom):
|
||||||
super(ArrayLiteralContext, self).__init__(evaluator, parent_context)
|
super(ArrayLiteralContext, self).__init__(evaluator, evaluator.BUILTINS)
|
||||||
self.atom = atom
|
self.atom = atom
|
||||||
|
self._defining_context = defining_context
|
||||||
|
|
||||||
if self.atom.type in ('testlist_star_expr', 'testlist'):
|
if self.atom.type in ('testlist_star_expr', 'testlist'):
|
||||||
self._array_type = 'tuple'
|
self._array_type = 'tuple'
|
||||||
@@ -381,7 +377,7 @@ class ArrayLiteralContext(AbstractSequence, ArrayMixin):
|
|||||||
if isinstance(index, slice):
|
if isinstance(index, slice):
|
||||||
return set([self])
|
return set([self])
|
||||||
else:
|
else:
|
||||||
return self.parent_context.eval_node(self._items()[index])
|
return self._defining_context.eval_node(self._items()[index])
|
||||||
|
|
||||||
# @memoize_default()
|
# @memoize_default()
|
||||||
def py__iter__(self):
|
def py__iter__(self):
|
||||||
@@ -399,8 +395,8 @@ class ArrayLiteralContext(AbstractSequence, ArrayMixin):
|
|||||||
for _ in types:
|
for _ in types:
|
||||||
yield types
|
yield types
|
||||||
else:
|
else:
|
||||||
for value in self._items():
|
for node in self._items():
|
||||||
yield self.parent_context.eval_node(value)
|
yield context.LazyTreeContext(self._defining_context, node)
|
||||||
|
|
||||||
additions = check_array_additions(self._evaluator, self)
|
additions = check_array_additions(self._evaluator, self)
|
||||||
if additions:
|
if additions:
|
||||||
@@ -520,6 +516,7 @@ class FakeDict(_FakeArray):
|
|||||||
self._dct = dct
|
self._dct = dct
|
||||||
|
|
||||||
def py__iter__(self):
|
def py__iter__(self):
|
||||||
|
raise NotImplementedError
|
||||||
yield set(compiled.create(self._evaluator, key) for key in self._dct)
|
yield set(compiled.create(self._evaluator, key) for key in self._dct)
|
||||||
|
|
||||||
def py__getitem__(self, index):
|
def py__getitem__(self, index):
|
||||||
@@ -537,6 +534,7 @@ class MergedArray(_FakeArray):
|
|||||||
self._arrays = arrays
|
self._arrays = arrays
|
||||||
|
|
||||||
def py__iter__(self):
|
def py__iter__(self):
|
||||||
|
raise NotImplementedError
|
||||||
for array in self._arrays:
|
for array in self._arrays:
|
||||||
for types in array.py__iter__():
|
for types in array.py__iter__():
|
||||||
yield types
|
yield types
|
||||||
@@ -603,11 +601,9 @@ def py__iter__(evaluator, types, node=None):
|
|||||||
message="TypeError: '%s' object is not iterable" % typ)
|
message="TypeError: '%s' object is not iterable" % typ)
|
||||||
else:
|
else:
|
||||||
type_iters.append(iter_method())
|
type_iters.append(iter_method())
|
||||||
#for result in iter_method():
|
|
||||||
#yield result
|
|
||||||
|
|
||||||
for t in zip_longest(*type_iters, fillvalue=set()):
|
for lazy_contexts in zip_longest(*type_iters, fillvalue=set()):
|
||||||
yield unite(t)
|
yield context.get_merged_lazy_context(lazy_contexts)
|
||||||
|
|
||||||
|
|
||||||
def py__iter__types(evaluator, types, node=None):
|
def py__iter__types(evaluator, types, node=None):
|
||||||
@@ -615,7 +611,7 @@ def py__iter__types(evaluator, types, node=None):
|
|||||||
Calls `py__iter__`, but ignores the ordering in the end and just returns
|
Calls `py__iter__`, but ignores the ordering in the end and just returns
|
||||||
all types that it contains.
|
all types that it contains.
|
||||||
"""
|
"""
|
||||||
return unite(py__iter__(evaluator, types, node))
|
return unite(lazy_context.infer() for lazy_context in py__iter__(evaluator, types, node))
|
||||||
|
|
||||||
|
|
||||||
def py__getitem__(evaluator, context, types, trailer):
|
def py__getitem__(evaluator, context, types, trailer):
|
||||||
@@ -820,6 +816,7 @@ class _ArrayInstance(IterableWrapper):
|
|||||||
self.var_args = instance.var_args
|
self.var_args = instance.var_args
|
||||||
|
|
||||||
def py__iter__(self):
|
def py__iter__(self):
|
||||||
|
raise NotImplementedError
|
||||||
try:
|
try:
|
||||||
_, first_nodes = next(self.var_args.unpack())
|
_, first_nodes = next(self.var_args.unpack())
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from jedi.parser import tree
|
|||||||
from jedi.evaluate import iterable
|
from jedi.evaluate import iterable
|
||||||
from jedi.evaluate import analysis
|
from jedi.evaluate import analysis
|
||||||
from jedi.evaluate import precedence
|
from jedi.evaluate import precedence
|
||||||
|
from jedi.evaluate import context
|
||||||
|
|
||||||
|
|
||||||
def try_iter_content(types, depth=0):
|
def try_iter_content(types, depth=0):
|
||||||
@@ -134,7 +135,7 @@ class TreeArguments(AbstractArguments):
|
|||||||
for a in arrays]
|
for a in arrays]
|
||||||
iterators = list(iterators)
|
iterators = list(iterators)
|
||||||
for values in list(zip_longest(*iterators)):
|
for values in list(zip_longest(*iterators)):
|
||||||
yield None, MergedLazyContexts(values)
|
yield None, context.get_merged_lazy_context(values)
|
||||||
elif stars == 2:
|
elif stars == 2:
|
||||||
arrays = self._evaluator.eval_element(self._context, el)
|
arrays = self._evaluator.eval_element(self._context, el)
|
||||||
dicts = [_star_star_dict(self._evaluator, a, el, func)
|
dicts = [_star_star_dict(self._evaluator, a, el, func)
|
||||||
@@ -146,14 +147,14 @@ class TreeArguments(AbstractArguments):
|
|||||||
if tree.is_node(el, 'argument'):
|
if tree.is_node(el, 'argument'):
|
||||||
c = el.children
|
c = el.children
|
||||||
if len(c) == 3: # Keyword argument.
|
if len(c) == 3: # Keyword argument.
|
||||||
named_args.append((c[0].value, LazyContext(self._context, c[2]),))
|
named_args.append((c[0].value, context.LazyTreeContext(self._context, c[2]),))
|
||||||
else: # Generator comprehension.
|
else: # Generator comprehension.
|
||||||
# Include the brackets with the parent.
|
# Include the brackets with the parent.
|
||||||
comp = iterable.GeneratorComprehension(
|
comp = iterable.GeneratorComprehension(
|
||||||
self._evaluator, self.argument_node.parent)
|
self._evaluator, self.argument_node.parent)
|
||||||
yield None, KnownContext(comp)
|
yield None, context.LazyKnownContext(comp)
|
||||||
else:
|
else:
|
||||||
yield None, LazyContext(self._context, el)
|
yield None, context.LazyTreeContext(self._context, el)
|
||||||
|
|
||||||
# Reordering var_args is necessary, because star args sometimes appear
|
# Reordering var_args is necessary, because star args sometimes appear
|
||||||
# after named argument, but in the actual order it's prepended.
|
# after named argument, but in the actual order it's prepended.
|
||||||
@@ -176,51 +177,13 @@ class TreeArguments(AbstractArguments):
|
|||||||
return _get_calling_var_args(self._evaluator, self)
|
return _get_calling_var_args(self._evaluator, self)
|
||||||
|
|
||||||
|
|
||||||
class KnownContext(object):
|
|
||||||
def __init__(self, value):
|
|
||||||
self._value = value
|
|
||||||
|
|
||||||
def infer(self):
|
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
class LazyContext(object):
|
|
||||||
def __init__(self, context, node):
|
|
||||||
self._context = context
|
|
||||||
self._node = node
|
|
||||||
|
|
||||||
def infer(self):
|
|
||||||
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):
|
class ValueArguments(AbstractArguments):
|
||||||
def __init__(self, value_list):
|
def __init__(self, value_list):
|
||||||
self._value_list = value_list
|
self._value_list = value_list
|
||||||
|
|
||||||
def unpack(self, func=None):
|
def unpack(self, func=None):
|
||||||
for value in self._value_list:
|
for value in self._value_list:
|
||||||
yield None, KnownContext(value)
|
yield None, context.LazyKnownContext(value)
|
||||||
|
|
||||||
def get_calling_var_args(self):
|
def get_calling_var_args(self):
|
||||||
return None
|
return None
|
||||||
@@ -295,7 +258,10 @@ def get_params(evaluator, parent_context, func, var_args):
|
|||||||
# args / kwargs will just be empty arrays / dicts, respectively.
|
# args / kwargs will just be empty arrays / dicts, respectively.
|
||||||
# Wrong value count is just ignored. If you try to test cases that are
|
# Wrong value count is just ignored. If you try to test cases that are
|
||||||
# not allowed in Python, Jedi will maybe not show any completions.
|
# not allowed in Python, Jedi will maybe not show any completions.
|
||||||
default = None if param.default is None else LazyContext(parent_context, param.default)
|
default = None
|
||||||
|
if param.default is not None:
|
||||||
|
default = context.LazyTreeContext(parent_context, param.default)
|
||||||
|
|
||||||
key, argument = next(var_arg_iterator, (None, default))
|
key, argument = next(var_arg_iterator, (None, default))
|
||||||
while key is not None:
|
while key is not None:
|
||||||
keys_only = True
|
keys_only = True
|
||||||
@@ -335,17 +301,17 @@ def get_params(evaluator, parent_context, func, var_args):
|
|||||||
break
|
break
|
||||||
values_list.append([argument])
|
values_list.append([argument])
|
||||||
seq = iterable.FakeSequence(evaluator, 'tuple', values_list)
|
seq = iterable.FakeSequence(evaluator, 'tuple', values_list)
|
||||||
result_arg = KnownContext(seq)
|
result_arg = context.LazyKnownContext(seq)
|
||||||
elif param.stars == 2:
|
elif param.stars == 2:
|
||||||
# **kwargs param
|
# **kwargs param
|
||||||
dct = iterable.FakeDict(evaluator, dict(non_matching_keys))
|
dct = iterable.FakeDict(evaluator, dict(non_matching_keys))
|
||||||
result_arg = KnownContext(dct)
|
result_arg = context.LazyKnownContext(dct)
|
||||||
non_matching_keys = {}
|
non_matching_keys = {}
|
||||||
else:
|
else:
|
||||||
# normal param
|
# normal param
|
||||||
if argument is None:
|
if argument is None:
|
||||||
# No value: Return an empty container
|
# No value: Return an empty container
|
||||||
result_arg = UnknownContext()
|
result_arg = context.LazyUnknownContext()
|
||||||
if not keys_only:
|
if not keys_only:
|
||||||
calling_va = var_args.get_calling_var_args()
|
calling_va = var_args.get_calling_var_args()
|
||||||
if calling_va is not None:
|
if calling_va is not None:
|
||||||
@@ -366,8 +332,8 @@ def get_params(evaluator, parent_context, func, var_args):
|
|||||||
# there's nothing to find for certain names.
|
# there's nothing to find for certain names.
|
||||||
for k in set(param_dict) - set(keys_used):
|
for k in set(param_dict) - set(keys_used):
|
||||||
param = param_dict[k]
|
param = param_dict[k]
|
||||||
result_arg = (UnknownContext() if param.default is None else
|
result_arg = (context.LazyUnknownContext() if param.default is None else
|
||||||
LazyContext(parent_context, param.default))
|
context.LazyTreeContext(parent_context, param.default))
|
||||||
result_params.append(ExecutedParam(param, var_args, result_arg))
|
result_params.append(ExecutedParam(param, var_args, result_arg))
|
||||||
|
|
||||||
if not (non_matching_keys or had_multiple_value_error or
|
if not (non_matching_keys or had_multiple_value_error or
|
||||||
@@ -412,22 +378,17 @@ def get_params(evaluator, parent_context, func, var_args):
|
|||||||
|
|
||||||
|
|
||||||
def _iterate_star_args(evaluator, array, input_node, func=None):
|
def _iterate_star_args(evaluator, array, input_node, func=None):
|
||||||
from jedi.evaluate.representation import Instance
|
try:
|
||||||
if isinstance(array, iterable.AbstractSequence):
|
iter_ = array.py__iter__
|
||||||
raise DeprecationWarning('_items? seriously?')
|
except AttributeError:
|
||||||
# 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 KnownContexts(types)
|
|
||||||
elif isinstance(array, Instance) and array.name.get_code() == 'tuple':
|
|
||||||
debug.warning('Ignored a tuple *args input %s' % array)
|
|
||||||
else:
|
|
||||||
if func is not None:
|
if func is not None:
|
||||||
|
# TODO this func should not be needed.
|
||||||
m = "TypeError: %s() argument after * must be a sequence, not %s" \
|
m = "TypeError: %s() argument after * must be a sequence, not %s" \
|
||||||
% (func.name.value, array)
|
% (func.name.value, array)
|
||||||
analysis.add(evaluator, 'type-error-star', input_node, message=m)
|
analysis.add(evaluator, 'type-error-star', input_node, message=m)
|
||||||
|
else:
|
||||||
|
for lazy_context in iter_():
|
||||||
|
yield lazy_context
|
||||||
|
|
||||||
|
|
||||||
def _star_star_dict(evaluator, array, input_node, func):
|
def _star_star_dict(evaluator, array, input_node, func):
|
||||||
|
|||||||
@@ -117,12 +117,12 @@ def is_literal(obj):
|
|||||||
|
|
||||||
def _is_tuple(obj):
|
def _is_tuple(obj):
|
||||||
from jedi.evaluate import iterable
|
from jedi.evaluate import iterable
|
||||||
return isinstance(obj, iterable.Array) and obj.type == 'tuple'
|
return isinstance(obj, iterable.AbstractSequence) and obj.type == 'tuple'
|
||||||
|
|
||||||
|
|
||||||
def _is_list(obj):
|
def _is_list(obj):
|
||||||
from jedi.evaluate import iterable
|
from jedi.evaluate import iterable
|
||||||
return isinstance(obj, iterable.Array) and obj.type == 'list'
|
return isinstance(obj, iterable.AbstractSequence) and obj.type == 'list'
|
||||||
|
|
||||||
|
|
||||||
def _element_calculate(evaluator, left, operator, right):
|
def _element_calculate(evaluator, left, operator, right):
|
||||||
|
|||||||
@@ -57,11 +57,11 @@ from jedi.evaluate import flow_analysis
|
|||||||
from jedi.evaluate import imports
|
from jedi.evaluate import imports
|
||||||
from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \
|
from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \
|
||||||
GlobalNameFilter, DictFilter, ContextName
|
GlobalNameFilter, DictFilter, ContextName
|
||||||
from jedi.evaluate.context import TreeContext
|
from jedi.evaluate import context
|
||||||
from jedi.evaluate.instance import TreeInstance
|
from jedi.evaluate.instance import TreeInstance
|
||||||
|
|
||||||
|
|
||||||
class Executed(TreeContext):
|
class Executed(context.TreeContext):
|
||||||
"""
|
"""
|
||||||
An instance is also an executable - because __init__ is called
|
An instance is also an executable - because __init__ is called
|
||||||
:param var_args: The param input array, consist of a parser node or a list.
|
:param var_args: The param input array, consist of a parser node or a list.
|
||||||
@@ -412,7 +412,7 @@ class Wrapper(tree.Base):
|
|||||||
return ContextName(self, name)
|
return ContextName(self, name)
|
||||||
|
|
||||||
|
|
||||||
class ClassContext(use_metaclass(CachedMetaClass, TreeContext, Wrapper)):
|
class ClassContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper)):
|
||||||
"""
|
"""
|
||||||
This class is not only important to extend `tree.Class`, it is also a
|
This class is not only important to extend `tree.Class`, it is also a
|
||||||
important for descriptors (if the descriptor methods are evaluated or not).
|
important for descriptors (if the descriptor methods are evaluated or not).
|
||||||
@@ -518,7 +518,7 @@ class ClassContext(use_metaclass(CachedMetaClass, TreeContext, Wrapper)):
|
|||||||
return "<e%s of %s>" % (type(self).__name__, self.base)
|
return "<e%s of %s>" % (type(self).__name__, self.base)
|
||||||
|
|
||||||
|
|
||||||
class FunctionContext(use_metaclass(CachedMetaClass, TreeContext, Wrapper)):
|
class FunctionContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper)):
|
||||||
"""
|
"""
|
||||||
Needed because of decorators. Decorators are evaluated here.
|
Needed because of decorators. Decorators are evaluated here.
|
||||||
"""
|
"""
|
||||||
@@ -689,18 +689,19 @@ class FunctionExecutionContext(Executed):
|
|||||||
types |= set(pep0484.find_return_types(self._evaluator, funcdef))
|
types |= set(pep0484.find_return_types(self._evaluator, funcdef))
|
||||||
|
|
||||||
for r in returns:
|
for r in returns:
|
||||||
types |= self.eval_node(r.children[1])
|
|
||||||
check = flow_analysis.reachability_check(self, funcdef, r)
|
check = flow_analysis.reachability_check(self, funcdef, r)
|
||||||
if check is flow_analysis.UNREACHABLE:
|
if check is flow_analysis.UNREACHABLE:
|
||||||
debug.dbg('Return unreachable: %s', r)
|
debug.dbg('Return unreachable: %s', r)
|
||||||
else:
|
else:
|
||||||
if check_yields:
|
if check_yields:
|
||||||
types |= iterable.unite(self._eval_yield(r))
|
types |= set(self._eval_yield(r))
|
||||||
else:
|
else:
|
||||||
types |= self.eval_node(r.children[1])
|
types |= self.eval_node(r.children[1])
|
||||||
if check is flow_analysis.REACHABLE:
|
if check is flow_analysis.REACHABLE:
|
||||||
debug.dbg('Return reachable: %s', r)
|
debug.dbg('Return reachable: %s', r)
|
||||||
break
|
break
|
||||||
|
if check_yields:
|
||||||
|
return context.get_merged_lazy_context(list(types))
|
||||||
return types
|
return types
|
||||||
|
|
||||||
def _eval_yield(self, yield_expr):
|
def _eval_yield(self, yield_expr):
|
||||||
@@ -708,10 +709,10 @@ class FunctionExecutionContext(Executed):
|
|||||||
if node.type == 'yield_arg':
|
if node.type == 'yield_arg':
|
||||||
# It must be a yield from.
|
# It must be a yield from.
|
||||||
yield_from_types = self.eval_node(node)
|
yield_from_types = self.eval_node(node)
|
||||||
for result in iterable.py__iter__(self._evaluator, yield_from_types, node):
|
for lazy_context in iterable.py__iter__(self._evaluator, yield_from_types, node):
|
||||||
yield result
|
yield lazy_context
|
||||||
else:
|
else:
|
||||||
yield self.eval_node(node)
|
yield context.LazyTreeContext(self, node)
|
||||||
|
|
||||||
@recursion.execution_recursion_decorator
|
@recursion.execution_recursion_decorator
|
||||||
def get_yield_values(self):
|
def get_yield_values(self):
|
||||||
@@ -784,7 +785,7 @@ class GlobalName(helpers.FakeName):
|
|||||||
name.start_pos, is_definition=True)
|
name.start_pos, is_definition=True)
|
||||||
|
|
||||||
|
|
||||||
class ModuleContext(use_metaclass(CachedMetaClass, TreeContext, Wrapper)):
|
class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper)):
|
||||||
parent_context = None
|
parent_context = None
|
||||||
|
|
||||||
def __init__(self, evaluator, module, parent_module=None):
|
def __init__(self, evaluator, module, parent_module=None):
|
||||||
|
|||||||
Reference in New Issue
Block a user