forked from VimPlug/jedi
reversed and for loops now produce strings in the correct order.
This commit is contained in:
@@ -147,12 +147,16 @@ class Evaluator(object):
|
||||
name = str(stmt.get_defined_names()[0])
|
||||
parent = self.wrap(stmt.get_parent_scope())
|
||||
left = self.find_types(parent, name, stmt.start_pos, search_global=True)
|
||||
if isinstance(stmt.get_parent_until(tree.ForStmt), tree.ForStmt):
|
||||
|
||||
for_stmt = stmt.get_parent_until(tree.ForStmt)
|
||||
if isinstance(for_stmt, tree.ForStmt):
|
||||
# Iterate through result and add the values, that's possible
|
||||
# only in for loops without clutter, because they are
|
||||
# predictable.
|
||||
for r in types:
|
||||
left = precedence.calculate(self, left, operator, set([r]))
|
||||
for_iterable = self.eval_element(for_stmt.children[3])
|
||||
ordered = iterable.ordered_elements_of_iterable(self, for_iterable, types)
|
||||
for index_types in ordered:
|
||||
left = precedence.calculate(self, left, operator, index_types)
|
||||
types = left
|
||||
else:
|
||||
types = precedence.calculate(self, left, operator, types)
|
||||
|
||||
@@ -29,6 +29,7 @@ from jedi.evaluate import compiled
|
||||
from jedi.evaluate import helpers
|
||||
from jedi.evaluate.cache import CachedMetaClass, memoize_default
|
||||
from jedi.evaluate import analysis
|
||||
from jedi.evaluate.precedence import literals_to_types
|
||||
|
||||
|
||||
class IterableWrapper(tree.Base):
|
||||
@@ -390,6 +391,28 @@ class MergedArray(_FakeArray):
|
||||
return sum(len(a) for a in self._arrays)
|
||||
|
||||
|
||||
def ordered_elements_of_iterable(evaluator, iterable_type, all_values):
|
||||
"""
|
||||
This function returns the ordered types of an iterable. If the input is not
|
||||
an Array, we just return all types as the first and only item of the
|
||||
output list.
|
||||
"""
|
||||
ordered = []
|
||||
# Unpack the iterator values
|
||||
for sequence in iterable_type:
|
||||
if not isinstance(sequence, Array):
|
||||
ordered = [literals_to_types(evaluator, all_values)]
|
||||
break
|
||||
else:
|
||||
# Try
|
||||
for i, types in enumerate(sequence.per_index_values()):
|
||||
try:
|
||||
ordered[i] |= types
|
||||
except IndexError:
|
||||
ordered.append(set(types))
|
||||
return ordered
|
||||
|
||||
|
||||
def get_iterator_types(evaluator, element):
|
||||
"""Returns the types of any iterator (arrays, yields, __iter__, etc)."""
|
||||
iterators = []
|
||||
|
||||
@@ -23,17 +23,19 @@ COMPARISON_OPERATORS = {
|
||||
}
|
||||
|
||||
|
||||
def _literals_to_types(evaluator, result):
|
||||
def literals_to_types(evaluator, result):
|
||||
# Changes literals ('a', 1, 1.0, etc) to its type instances (str(),
|
||||
# int(), float(), etc).
|
||||
result = list(result)
|
||||
for i, r in enumerate(result):
|
||||
if is_literal(r):
|
||||
new_result = set()
|
||||
for typ in result:
|
||||
if is_literal(typ):
|
||||
# Literals are only valid as long as the operations are
|
||||
# correct. Otherwise add a value-free instance.
|
||||
cls = builtin.get_by_name(r.name.get_code())
|
||||
result[i] = list(evaluator.execute(cls))[0]
|
||||
return set(result)
|
||||
cls = builtin.get_by_name(typ.name.get_code())
|
||||
new_result.add(list(evaluator.execute(cls))[0])
|
||||
else:
|
||||
new_result.add(typ)
|
||||
return new_result
|
||||
|
||||
|
||||
def calculate_children(evaluator, children):
|
||||
@@ -69,13 +71,13 @@ def calculate(evaluator, left_result, operator, right_result):
|
||||
if not left_result or not right_result:
|
||||
# illegal slices e.g. cause left/right_result to be None
|
||||
result = (left_result or set()) | (right_result or set())
|
||||
result = _literals_to_types(evaluator, result)
|
||||
result = literals_to_types(evaluator, result)
|
||||
else:
|
||||
# I don't think there's a reasonable chance that a string
|
||||
# operation is still correct, once we pass something like six
|
||||
# objects.
|
||||
if len(left_result) * len(right_result) > 6:
|
||||
result = _literals_to_types(evaluator, left_result | right_result)
|
||||
result = literals_to_types(evaluator, left_result | right_result)
|
||||
else:
|
||||
for left in left_result:
|
||||
for right in right_result:
|
||||
|
||||
@@ -155,9 +155,14 @@ def get_iterable_content(evaluator, arguments, argument_index):
|
||||
|
||||
@argument_clinic('sequence, /', want_obj=True, want_arguments=True)
|
||||
def builtins_reversed(evaluator, sequences, obj, arguments):
|
||||
# Unpack the iterator values
|
||||
objects = get_iterable_content(evaluator, arguments, 0)
|
||||
rev = [iterable.AlreadyEvaluated([o]) for o in reversed(list(objects))]
|
||||
# While we could do without this variable (just by using sequences), we
|
||||
# want static analysis to work well. Therefore we need to generated the
|
||||
# values again.
|
||||
all_sequence_types = get_iterable_content(evaluator, arguments, 0)
|
||||
|
||||
ordered = iterable.ordered_elements_of_iterable(evaluator, sequences, all_sequence_types)
|
||||
|
||||
rev = [iterable.AlreadyEvaluated(o) for o in reversed(ordered)]
|
||||
# Repack iterator values and then run it the normal way. This is
|
||||
# necessary, because `reversed` is a function and autocompletion
|
||||
# would fail in certain cases like `reversed(x).__iter__` if we
|
||||
|
||||
Reference in New Issue
Block a user