Fix the first issue in #1010

Somehow it was still possible with lists to recurse.
This commit is contained in:
Dave Halter
2018-03-18 17:09:44 +01:00
parent 1672613d04
commit 6042706922
4 changed files with 37 additions and 2 deletions

View File

@@ -64,7 +64,7 @@ class Context(BaseContext):
return self.execute(arguments) return self.execute(arguments)
def iterate(self, contextualized_node=None, is_async=False): def iterate(self, contextualized_node=None, is_async=False):
debug.dbg('iterate') debug.dbg('iterate %s', self)
try: try:
if is_async: if is_async:
iter_method = self.py__aiter__ iter_method = self.py__aiter__

View File

@@ -212,6 +212,8 @@ class CompiledInstance(AbstractInstanceContext):
super(CompiledInstance, self).__init__(*args, **kwargs) super(CompiledInstance, self).__init__(*args, **kwargs)
# I don't think that dynamic append lookups should happen here. That # I don't think that dynamic append lookups should happen here. That
# sounds more like something that should go to py__iter__. # sounds more like something that should go to py__iter__.
self._original_var_args = self.var_args
if self.class_context.name.string_name in ['list', 'set'] \ if self.class_context.name.string_name in ['list', 'set'] \
and self.parent_context.get_root_context() == self.evaluator.builtins_module: and self.parent_context.get_root_context() == self.evaluator.builtins_module:
# compare the module path with the builtin name. # compare the module path with the builtin name.
@@ -227,6 +229,13 @@ class CompiledInstance(AbstractInstanceContext):
else: else:
return super(CompiledInstance, self).create_instance_context(class_context, node) return super(CompiledInstance, self).create_instance_context(class_context, node)
def get_first_non_keyword_argument_contexts(self):
key, lazy_context = next(self._original_var_args.unpack(), ('', None))
if key is not None:
return None
return lazy_context.infer()
class TreeInstance(AbstractInstanceContext): class TreeInstance(AbstractInstanceContext):
def __init__(self, evaluator, parent_context, class_context, var_args): def __init__(self, evaluator, parent_context, class_context, var_args):

View File

@@ -257,7 +257,21 @@ def eval_atom(context, atom):
@_limit_context_infers @_limit_context_infers
def eval_expr_stmt(context, stmt, seek_name=None): def eval_expr_stmt(context, stmt, seek_name=None):
with recursion.execution_allowed(context.evaluator, stmt) as allowed: with recursion.execution_allowed(context.evaluator, stmt) as allowed:
if allowed or context.get_root_context() == context.evaluator.builtins_module: # Here we allow list/set to recurse under certain conditions. To make
# it possible to resolve stuff like list(set(list(x))), this is
# necessary.
if not allowed and context.get_root_context() == context.evaluator.builtins_module:
try:
instance = context.instance
except AttributeError:
pass
else:
if instance.name.string_name in ('list', 'set'):
c = instance.get_first_non_keyword_argument_contexts()
if instance not in c:
allowed = True
if allowed:
return _eval_expr_stmt(context, stmt, seek_name) return _eval_expr_stmt(context, stmt, seek_name)
return NO_CONTEXTS return NO_CONTEXTS

View File

@@ -401,6 +401,18 @@ for x in [1] + ['']:
#? int() str() #? int() str()
x x
# -----------------
# Potential Recursion Issues
# -----------------
class X():
def y(self):
self.a = [1]
def x(self):
self.a = list(self.a)
#? int()
self.a[0]
# ----------------- # -----------------
# For loops with attribute assignment. # For loops with attribute assignment.
# ----------------- # -----------------