Fix a recursion error, fixes #1173

This commit is contained in:
Dave Halter
2018-07-18 10:01:41 +02:00
parent 3cabc4b969
commit a408fb3211
3 changed files with 33 additions and 14 deletions

View File

@@ -28,8 +28,8 @@ from jedi.evaluate.helpers import is_stdlib_path
from jedi.evaluate.utils import to_list from jedi.evaluate.utils import to_list
from jedi.parser_utils import get_parent_scope from jedi.parser_utils import get_parent_scope
from jedi.evaluate.context import ModuleContext, instance from jedi.evaluate.context import ModuleContext, instance
from jedi.evaluate.base_context import ContextSet from jedi.evaluate.base_context import ContextSet, NO_CONTEXTS
from jedi.evaluate import recursion
MAX_PARAM_SEARCHES = 20 MAX_PARAM_SEARCHES = 20
@@ -39,11 +39,19 @@ class MergedExecutedParams(object):
""" """
Simulates being a parameter while actually just being multiple params. Simulates being a parameter while actually just being multiple params.
""" """
def __init__(self, executed_params):
def __init__(self, evaluator, executed_params):
self.evaluator = evaluator
self._executed_params = executed_params self._executed_params = executed_params
def infer(self): def infer(self):
return ContextSet.from_sets(p.infer() for p in self._executed_params) with recursion.execution_allowed(self.evaluator, self) as allowed:
# We need to catch recursions that may occur, because an
# anonymous functions can create an anonymous parameter that is
# more or less self referencing.
if allowed:
return ContextSet.from_sets(p.infer() for p in self._executed_params)
return NO_CONTEXTS
@debug.increase_indent @debug.increase_indent
@@ -90,15 +98,11 @@ def search_params(evaluator, execution_context, funcdef):
string_name=string_name, string_name=string_name,
) )
if function_executions: if function_executions:
if len(function_executions) == 1:
# Don't need to wrap this one.
return function_executions[0].get_params()
zipped_params = zip(*list( zipped_params = zip(*list(
function_execution.get_params() function_execution.get_params()
for function_execution in function_executions for function_execution in function_executions
)) ))
params = [MergedExecutedParams(executed_params) for executed_params in zipped_params] params = [MergedExecutedParams(evaluator, executed_params) for executed_params in zipped_params]
# Evaluate the ExecutedParams to types. # Evaluate the ExecutedParams to types.
else: else:
return create_default_params(execution_context, funcdef) return create_default_params(execution_context, funcdef)

View File

@@ -65,7 +65,7 @@ def execution_allowed(evaluator, node):
if node in pushed_nodes: if node in pushed_nodes:
debug.warning('catched stmt recursion: %s @%s', node, debug.warning('catched stmt recursion: %s @%s', node,
node.start_pos) getattr(node, 'start_pos', None))
yield False yield False
else: else:
try: try:
@@ -77,14 +77,14 @@ def execution_allowed(evaluator, node):
def execution_recursion_decorator(default=NO_CONTEXTS): def execution_recursion_decorator(default=NO_CONTEXTS):
def decorator(func): def decorator(func):
def wrapper(execution, **kwargs): def wrapper(self, **kwargs):
detector = execution.evaluator.execution_recursion_detector detector = self.evaluator.execution_recursion_detector
allowed = detector.push_execution(execution) allowed = detector.push_execution(self)
try: try:
if allowed: if allowed:
result = default result = default
else: else:
result = func(execution, **kwargs) result = func(self, **kwargs)
finally: finally:
detector.pop_execution() detector.pop_execution()
return result return result

View File

@@ -76,3 +76,18 @@ class InstanceAttributeIfs:
InstanceAttributeIfs().a1 InstanceAttributeIfs().a1
#? int() str() #? int() str()
InstanceAttributeIfs().a2 InstanceAttributeIfs().a2
class A:
def a(self, b):
for x in [self.a(i) for i in b]:
#?
x
class B:
def a(self, b):
for i in b:
for i in self.a(i):
#?
yield i