Fix an issue with global stmts. They caused recursionerrors when used wrong. Fixes #610.

This commit is contained in:
Dave Halter
2016-07-18 19:23:08 +02:00
parent 9eee0d6635
commit 2776af3db5
4 changed files with 44 additions and 20 deletions

View File

@@ -140,7 +140,7 @@ class Evaluator(object):
scopes = f.scopes(search_global)
if is_goto:
return f.filter_name(scopes)
return f.find(scopes, search_global)
return f.find(scopes, attribute_lookup=not search_global)
#@memoize_default(default=[], evaluator_is_first_arg=True)
#@recursion.recursion_decorator

View File

@@ -26,7 +26,7 @@ from jedi.evaluate.cache import memoize_default
from jedi.evaluate import imports
MAX_PARAM_SEARCHES = 10
MAX_PARAM_SEARCHES = 20
class ParamListener(object):

View File

@@ -90,27 +90,31 @@ class NameFinder(object):
self._found_predefined_if_name = None
@debug.increase_indent
def find(self, scopes, search_global=False):
def find(self, scopes, attribute_lookup):
"""
:params bool attribute_lookup: Tell to logic if we're accessing the
attribute or the contents of e.g. a function.
"""
# TODO rename scopes to names_dicts
names = self.filter_name(scopes)
if self._found_predefined_if_name is not None:
return self._found_predefined_if_name
types = self._names_to_types(names, search_global)
types = self._names_to_types(names, attribute_lookup)
if not names and not types \
and not (isinstance(self.name_str, tree.Name)
and isinstance(self.name_str.parent.parent, tree.Param)):
and not (isinstance(self.name_str, tree.Name) and
isinstance(self.name_str.parent.parent, tree.Param)):
if not isinstance(self.name_str, (str, unicode)): # TODO Remove?
if search_global:
if attribute_lookup:
analysis.add_attribute_error(self._evaluator,
self.scope, self.name_str)
else:
message = ("NameError: name '%s' is not defined."
% self.name_str)
analysis.add(self._evaluator, 'name-error', self.name_str,
message)
else:
analysis.add_attribute_error(self._evaluator,
self.scope, self.name_str)
debug.dbg('finder._names_to_types: %s -> %s', names, types)
return types
@@ -267,7 +271,7 @@ class NameFinder(object):
result = inst.execute_subscope_by_name('__getattribute__', name)
return result
def _names_to_types(self, names, search_global):
def _names_to_types(self, names, attribute_lookup):
types = set()
# Add isinstance and other if/assert knowledge.
@@ -287,7 +291,7 @@ class NameFinder(object):
for name in names:
new_types = _name_to_types(self._evaluator, name, self.scope)
if isinstance(self.scope, (er.Class, er.Instance)) and not search_global:
if isinstance(self.scope, (er.Class, er.Instance)) and attribute_lookup:
types |= set(self._resolve_descriptors(name, new_types))
else:
types |= set(new_types)
@@ -316,8 +320,17 @@ class NameFinder(object):
return result
def _get_global_stmt_scopes(evaluator, global_stmt, name):
global_stmt_scope = global_stmt.get_parent_scope()
module = global_stmt_scope.get_parent_until()
for used_name in module.used_names[str(name)]:
if used_name.parent.type == 'global_stmt':
yield evaluator.wrap(used_name.get_parent_scope())
@memoize_default(set(), evaluator_is_first_arg=True)
def _name_to_types(evaluator, name, scope):
types = []
typ = name.get_definition()
if typ.isinstance(tree.ForStmt):
types = pep0484.find_type_from_comment_hint_for(evaluator, typ, name)
@@ -339,14 +352,14 @@ def _name_to_types(evaluator, name, scope):
types = evaluator.eval_element(typ.node_from_name(name))
elif isinstance(typ, tree.Import):
types = imports.ImportWrapper(evaluator, name).follow()
elif isinstance(typ, tree.GlobalStmt):
# TODO theoretically we shouldn't be using search_global here, it
# doesn't make sense, because it's a local search (for that name)!
# However, globals are not that important and resolving them doesn't
# guarantee correctness in any way, because we don't check for when
# something is executed.
types = evaluator.find_types(typ.get_parent_scope(), str(name),
search_global=True)
elif typ.type == 'global_stmt':
for s in _get_global_stmt_scopes(evaluator, typ, name):
finder = NameFinder(evaluator, s, str(name))
names_dicts = finder.scopes(search_global=True)
# For global_stmt lookups, we only need the first possible scope,
# which means the function itself.
names_dicts = [next(names_dicts)]
types += finder.find(names_dicts, attribute_lookup=False)
elif isinstance(typ, tree.TryStmt):
# TODO an exception can also be a tuple. Check for those.
# TODO check for types that are not classes and add it to

View File

@@ -165,6 +165,17 @@ def global_define():
#? int()
global_var_in_func
def funct1():
# From issue #610
global global_dict_var
global_dict_var = dict()
def funct2():
global global_dict_var
#? dict()
global_dict_var
# -----------------
# within docstrs
# -----------------