Format: text/x-python
⬇ Download File (35.5 KB)
   1  """
   2  Functions inferring the syntax tree.
   3  """
   4  import copy
   5  import itertools
   6  
   7  from parso.python import tree
   8  
   9  from jedi import debug
  10  from jedi import parser_utils
  11  from jedi.inference.base_value import ValueSet, NO_VALUES, ContextualizedNode, \
  12      iterator_to_value_set, iterate_values
  13  from jedi.inference.lazy_value import LazyTreeValue
  14  from jedi.inference import compiled
  15  from jedi.inference import recursion
  16  from jedi.inference import analysis
  17  from jedi.inference import imports
  18  from jedi.inference import arguments
  19  from jedi.inference.value import ClassValue, FunctionValue
  20  from jedi.inference.value import iterable
  21  from jedi.inference.value.dynamic_arrays import ListModification, DictModification
  22  from jedi.inference.value import TreeInstance
  23  from jedi.inference.helpers import is_string, is_literal, is_number, \
  24      get_names_of_node, is_big_annoying_library
  25  from jedi.inference.compiled.access import COMPARISON_OPERATORS
  26  from jedi.inference.cache import inference_state_method_cache
  27  from jedi.inference.gradual.stub_value import VersionInfo
  28  from jedi.inference.gradual import annotation
  29  from jedi.inference.names import TreeNameDefinition
  30  from jedi.inference.context import CompForContext
  31  from jedi.inference.value.decorator import Decoratee
  32  from jedi.plugins import plugin_manager
  33  
  34  operator_to_magic_method = {
  35      '+': '__add__',
  36      '-': '__sub__',
  37      '*': '__mul__',
  38      '@': '__matmul__',
  39      '/': '__truediv__',
  40      '//': '__floordiv__',
  41      '%': '__mod__',
  42      '**': '__pow__',
  43      '<<': '__lshift__',
  44      '>>': '__rshift__',
  45      '&': '__and__',
  46      '|': '__or__',
  47      '^': '__xor__',
  48  }
  49  
  50  reverse_operator_to_magic_method = {
  51      k: '__r' + v[2:] for k, v in operator_to_magic_method.items()
  52  }
  53  
  54  
  55  def _limit_value_infers(func):
  56      """
  57      This is for now the way how we limit type inference going wild. There are
  58      other ways to ensure recursion limits as well. This is mostly necessary
  59      because of instance (self) access that can be quite tricky to limit.
  60  
  61      I'm still not sure this is the way to go, but it looks okay for now and we
  62      can still go anther way in the future. Tests are there. ~ dave
  63      """
  64      def wrapper(context, *args, **kwargs):
  65          n = context.tree_node
  66          inference_state = context.inference_state
  67          try:
  68              inference_state.inferred_element_counts[n] += 1
  69              maximum = 300
  70              if context.parent_context is None \
  71                      and context.get_value() is inference_state.builtins_module:
  72                  # Builtins should have a more generous inference limit.
  73                  # It is important that builtins can be executed, otherwise some
  74                  # functions that depend on certain builtins features would be
  75                  # broken, see e.g. GH #1432
  76                  maximum *= 100
  77  
  78              if inference_state.inferred_element_counts[n] > maximum:
  79                  debug.warning('In value %s there were too many inferences.', n)
  80                  return NO_VALUES
  81          except KeyError:
  82              inference_state.inferred_element_counts[n] = 1
  83          return func(context, *args, **kwargs)
  84  
  85      return wrapper
  86  
  87  
  88  def infer_node(context, element):
  89      if isinstance(context, CompForContext):
  90          return _infer_node(context, element)
  91  
  92      if_stmt = element
  93      while if_stmt is not None:
  94          if_stmt = if_stmt.parent
  95          if if_stmt.type in ('if_stmt', 'for_stmt'):
  96              break
  97          if parser_utils.is_scope(if_stmt):
  98              if_stmt = None
  99              break
 100      predefined_if_name_dict = context.predefined_names.get(if_stmt)
 101      # TODO there's a lot of issues with this one. We actually should do
 102      # this in a different way. Caching should only be active in certain
 103      # cases and this all sucks.
 104      if predefined_if_name_dict is None and if_stmt \
 105              and if_stmt.type == 'if_stmt' and context.inference_state.is_analysis:
 106          if_stmt_test = if_stmt.children[1]
 107          name_dicts = [{}]
 108          # If we already did a check, we don't want to do it again -> If
 109          # value.predefined_names is filled, we stop.
 110          # We don't want to check the if stmt itself, it's just about
 111          # the content.
 112          if element.start_pos > if_stmt_test.end_pos:
 113              # Now we need to check if the names in the if_stmt match the
 114              # names in the suite.
 115              if_names = get_names_of_node(if_stmt_test)
 116              element_names = get_names_of_node(element)
 117              str_element_names = [e.value for e in element_names]
 118              if any(i.value in str_element_names for i in if_names):
 119                  for if_name in if_names:
 120                      definitions = context.inference_state.infer(context, if_name)
 121                      # Every name that has multiple different definitions
 122                      # causes the complexity to rise. The complexity should
 123                      # never fall below 1.
 124                      if len(definitions) > 1:
 125                          if len(name_dicts) * len(definitions) > 16:
 126                              debug.dbg('Too many options for if branch inference %s.', if_stmt)
 127                              # There's only a certain amount of branches
 128                              # Jedi can infer, otherwise it will take to
 129                              # long.
 130                              name_dicts = [{}]
 131                              break
 132  
 133                          original_name_dicts = list(name_dicts)
 134                          name_dicts = []
 135                          for definition in definitions:
 136                              new_name_dicts = list(original_name_dicts)
 137                              for i, name_dict in enumerate(new_name_dicts):
 138                                  new_name_dicts[i] = name_dict.copy()
 139                                  new_name_dicts[i][if_name.value] = ValueSet([definition])
 140  
 141                              name_dicts += new_name_dicts
 142                      else:
 143                          for name_dict in name_dicts:
 144                              name_dict[if_name.value] = definitions
 145          if len(name_dicts) > 1:
 146              result = NO_VALUES
 147              for name_dict in name_dicts:
 148                  with context.predefine_names(if_stmt, name_dict):
 149                      result |= _infer_node(context, element)
 150              return result
 151          else:
 152              return _infer_node_if_inferred(context, element)
 153      else:
 154          if predefined_if_name_dict:
 155              return _infer_node(context, element)
 156          else:
 157              return _infer_node_if_inferred(context, element)
 158  
 159  
 160  def _infer_node_if_inferred(context, element):
 161      """
 162      TODO This function is temporary: Merge with infer_node.
 163      """
 164      parent = element
 165      while parent is not None:
 166          parent = parent.parent
 167          predefined_if_name_dict = context.predefined_names.get(parent)
 168          if predefined_if_name_dict is not None:
 169              return _infer_node(context, element)
 170      return _infer_node_cached(context, element)
 171  
 172  
 173  @inference_state_method_cache(default=NO_VALUES)
 174  def _infer_node_cached(context, element):
 175      return _infer_node(context, element)
 176  
 177  
 178  @debug.increase_indent
 179  @_limit_value_infers
 180  def _infer_node(context, element):
 181      debug.dbg('infer_node %s@%s in %s', element, element.start_pos, context)
 182      inference_state = context.inference_state
 183      typ = element.type
 184      if typ in ('name', 'number', 'string', 'atom', 'strings', 'keyword', 'fstring'):
 185          return infer_atom(context, element)
 186      elif typ == 'lambdef':
 187          return ValueSet([FunctionValue.from_context(context, element)])
 188      elif typ == 'expr_stmt':
 189          return infer_expr_stmt(context, element)
 190      elif typ in ('power', 'atom_expr'):
 191          first_child = element.children[0]
 192          children = element.children[1:]
 193          had_await = False
 194          if first_child.type == 'keyword' and first_child.value == 'await':
 195              had_await = True
 196              first_child = children.pop(0)
 197  
 198          value_set = context.infer_node(first_child)
 199          for (i, trailer) in enumerate(children):
 200              if trailer == '**':  # has a power operation.
 201                  right = context.infer_node(children[i + 1])
 202                  value_set = _infer_comparison(
 203                      context,
 204                      value_set,
 205                      trailer,
 206                      right
 207                  )
 208                  break
 209              value_set = infer_trailer(context, value_set, trailer)
 210  
 211          if had_await:
 212              return value_set.py__await__().py__stop_iteration_returns()
 213          return value_set
 214      elif typ in ('testlist_star_expr', 'testlist',):
 215          # The implicit tuple in statements.
 216          return ValueSet([iterable.SequenceLiteralValue(inference_state, context, element)])
 217      elif typ in ('not_test', 'factor'):
 218          value_set = context.infer_node(element.children[-1])
 219          for operator in element.children[:-1]:
 220              value_set = infer_factor(value_set, operator)
 221          return value_set
 222      elif typ == 'test':
 223          # `x if foo else y` case.
 224          return (context.infer_node(element.children[0])
 225                  | context.infer_node(element.children[-1]))
 226      elif typ == 'operator':
 227          # Must be an ellipsis, other operators are not inferred.
 228          if element.value != '...':
 229              origin = element.parent
 230              raise AssertionError("unhandled operator %s in %s " % (repr(element.value), origin))
 231          return ValueSet([compiled.builtin_from_name(inference_state, 'Ellipsis')])
 232      elif typ == 'dotted_name':
 233          value_set = infer_atom(context, element.children[0])
 234          for next_name in element.children[2::2]:
 235              value_set = value_set.py__getattribute__(next_name, name_context=context)
 236          return value_set
 237      elif typ == 'eval_input':
 238          return context.infer_node(element.children[0])
 239      elif typ == 'annassign':
 240          return annotation.infer_annotation(context, element.children[1]) \
 241              .execute_annotation()
 242      elif typ == 'yield_expr':
 243          if len(element.children) and element.children[1].type == 'yield_arg':
 244              # Implies that it's a yield from.
 245              element = element.children[1].children[1]
 246              generators = context.infer_node(element) \
 247                  .py__getattribute__('__iter__').execute_with_values()
 248              return generators.py__stop_iteration_returns()
 249  
 250          # Generator.send() is not implemented.
 251          return NO_VALUES
 252      elif typ == 'namedexpr_test':
 253          return context.infer_node(element.children[2])
 254      else:
 255          return infer_or_test(context, element)
 256  
 257  
 258  def infer_trailer(context, atom_values, trailer):
 259      trailer_op, node = trailer.children[:2]
 260      if node == ')':  # `arglist` is optional.
 261          node = None
 262  
 263      if trailer_op == '[':
 264          trailer_op, node, _ = trailer.children
 265          return atom_values.get_item(
 266              _infer_subscript_list(context, node),
 267              ContextualizedNode(context, trailer)
 268          )
 269      else:
 270          debug.dbg('infer_trailer: %s in %s', trailer, atom_values)
 271          if trailer_op == '.':
 272              return atom_values.py__getattribute__(
 273                  name_context=context,
 274                  name_or_str=node
 275              )
 276          else:
 277              assert trailer_op == '(', 'trailer_op is actually %s' % trailer_op
 278              args = arguments.TreeArguments(context.inference_state, context, node, trailer)
 279              return atom_values.execute(args)
 280  
 281  
 282  def infer_atom(context, atom):
 283      """
 284      Basically to process ``atom`` nodes. The parser sometimes doesn't
 285      generate the node (because it has just one child). In that case an atom
 286      might be a name or a literal as well.
 287      """
 288      state = context.inference_state
 289      if atom.type == 'name':
 290          # This is the first global lookup.
 291          stmt = tree.search_ancestor(atom, 'expr_stmt', 'lambdef', 'if_stmt') or atom
 292          if stmt.type == 'if_stmt':
 293              if not any(n.start_pos <= atom.start_pos < n.end_pos for n in stmt.get_test_nodes()):
 294                  stmt = atom
 295          elif stmt.type == 'lambdef':
 296              stmt = atom
 297          position = stmt.start_pos
 298          if _is_annotation_name(atom):
 299              # Since Python 3.7 (with from __future__ import annotations),
 300              # annotations are essentially strings and can reference objects
 301              # that are defined further down in code. Therefore just set the
 302              # position to None, so the finder will not try to stop at a certain
 303              # position in the module.
 304              position = None
 305          return context.py__getattribute__(atom, position=position)
 306      elif atom.type == 'keyword':
 307          # For False/True/None
 308          if atom.value in ('False', 'True', 'None'):
 309              return ValueSet([compiled.builtin_from_name(state, atom.value)])
 310          elif atom.value == 'yield':
 311              # Contrary to yield from, yield can just appear alone to return a
 312              # value when used with `.send()`.
 313              return NO_VALUES
 314          assert False, 'Cannot infer the keyword %s' % atom
 315  
 316      elif isinstance(atom, tree.Literal):
 317          string = state.compiled_subprocess.safe_literal_eval(atom.value)
 318          return ValueSet([compiled.create_simple_object(state, string)])
 319      elif atom.type == 'strings':
 320          # Will be multiple string.
 321          value_set = infer_atom(context, atom.children[0])
 322          for string in atom.children[1:]:
 323              right = infer_atom(context, string)
 324              value_set = _infer_comparison(context, value_set, '+', right)
 325          return value_set
 326      elif atom.type == 'fstring':
 327          return compiled.get_string_value_set(state)
 328      else:
 329          c = atom.children
 330          # Parentheses without commas are not tuples.
 331          if c[0] == '(' and not len(c) == 2 \
 332                  and not (c[1].type == 'testlist_comp'
 333                           and len(c[1].children) > 1):
 334              return context.infer_node(c[1])
 335  
 336          try:
 337              comp_for = c[1].children[1]
 338          except (IndexError, AttributeError):
 339              pass
 340          else:
 341              if comp_for == ':':
 342                  # Dict comprehensions have a colon at the 3rd index.
 343                  try:
 344                      comp_for = c[1].children[3]
 345                  except IndexError:
 346                      pass
 347  
 348              if comp_for.type in ('comp_for', 'sync_comp_for'):
 349                  return ValueSet([iterable.comprehension_from_atom(
 350                      state, context, atom
 351                  )])
 352  
 353          # It's a dict/list/tuple literal.
 354          array_node = c[1]
 355          try:
 356              array_node_c = array_node.children
 357          except AttributeError:
 358              array_node_c = []
 359          if c[0] == '{' and (array_node == '}' or ':' in array_node_c
 360                              or '**' in array_node_c):
 361              new_value = iterable.DictLiteralValue(state, context, atom)
 362          else:
 363              new_value = iterable.SequenceLiteralValue(state, context, atom)
 364          return ValueSet([new_value])
 365  
 366  
 367  @_limit_value_infers
 368  def infer_expr_stmt(context, stmt, seek_name=None):
 369      with recursion.execution_allowed(context.inference_state, stmt) as allowed:
 370          if allowed:
 371              if seek_name is not None:
 372                  pep0484_values = \
 373                      annotation.find_type_from_comment_hint_assign(context, stmt, seek_name)
 374                  if pep0484_values:
 375                      return pep0484_values
 376  
 377              return _infer_expr_stmt(context, stmt, seek_name)
 378      return NO_VALUES
 379  
 380  
 381  @debug.increase_indent
 382  def _infer_expr_stmt(context, stmt, seek_name=None):
 383      """
 384      The starting point of the completion. A statement always owns a call
 385      list, which are the calls, that a statement does. In case multiple
 386      names are defined in the statement, `seek_name` returns the result for
 387      this name.
 388  
 389      expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) |
 390                       ('=' (yield_expr|testlist_star_expr))*)
 391      annassign: ':' test ['=' test]
 392      augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' |
 393                  '<<=' | '>>=' | '**=' | '//=')
 394  
 395      :param stmt: A `tree.ExprStmt`.
 396      """
 397      def check_setitem(stmt):
 398          atom_expr = stmt.children[0]
 399          if atom_expr.type not in ('atom_expr', 'power'):
 400              return False, None
 401          name = atom_expr.children[0]
 402          if name.type != 'name' or len(atom_expr.children) != 2:
 403              return False, None
 404          trailer = atom_expr.children[-1]
 405          return trailer.children[0] == '[', trailer.children[1]
 406  
 407      debug.dbg('infer_expr_stmt %s (%s)', stmt, seek_name)
 408      rhs = stmt.get_rhs()
 409  
 410      value_set = context.infer_node(rhs)
 411  
 412      if seek_name:
 413          n = TreeNameDefinition(context, seek_name)
 414          value_set = check_tuple_assignments(n, value_set)
 415  
 416      first_operator = next(stmt.yield_operators(), None)
 417      is_setitem, subscriptlist = check_setitem(stmt)
 418      is_annassign = first_operator not in ('=', None) and first_operator.type == 'operator'
 419      if is_annassign or is_setitem:
 420          # `=` is always the last character in aug assignments -> -1
 421          name = stmt.get_defined_names(include_setitem=True)[0].value
 422          left_values = context.py__getattribute__(name, position=stmt.start_pos)
 423  
 424          if is_setitem:
 425              def to_mod(v):
 426                  c = ContextualizedSubscriptListNode(context, subscriptlist)
 427                  if v.array_type == 'dict':
 428                      return DictModification(v, value_set, c)
 429                  elif v.array_type == 'list':
 430                      return ListModification(v, value_set, c)
 431                  return v
 432  
 433              value_set = ValueSet(to_mod(v) for v in left_values)
 434          else:
 435              operator = copy.copy(first_operator)
 436              operator.value = operator.value[:-1]
 437              for_stmt = tree.search_ancestor(stmt, 'for_stmt')
 438              if for_stmt is not None and for_stmt.type == 'for_stmt' and value_set \
 439                      and parser_utils.for_stmt_defines_one_name(for_stmt):
 440                  # Iterate through result and add the values, that's possible
 441                  # only in for loops without clutter, because they are
 442                  # predictable. Also only do it, if the variable is not a tuple.
 443                  node = for_stmt.get_testlist()
 444                  cn = ContextualizedNode(context, node)
 445                  ordered = list(cn.infer().iterate(cn))
 446  
 447                  for lazy_value in ordered:
 448                      dct = {for_stmt.children[1].value: lazy_value.infer()}
 449                      with context.predefine_names(for_stmt, dct):
 450                          t = context.infer_node(rhs)
 451                          left_values = _infer_comparison(context, left_values, operator, t)
 452                  value_set = left_values
 453              else:
 454                  value_set = _infer_comparison(context, left_values, operator, value_set)
 455      debug.dbg('infer_expr_stmt result %s', value_set)
 456      return value_set
 457  
 458  
 459  def infer_or_test(context, or_test):
 460      iterator = iter(or_test.children)
 461      types = context.infer_node(next(iterator))
 462      for operator in iterator:
 463          right = next(iterator)
 464          if operator.type == 'comp_op':  # not in / is not
 465              operator = ' '.join(c.value for c in operator.children)
 466  
 467          # handle type inference of and/or here.
 468          if operator in ('and', 'or'):
 469              left_bools = set(left.py__bool__() for left in types)
 470              if left_bools == {True}:
 471                  if operator == 'and':
 472                      types = context.infer_node(right)
 473              elif left_bools == {False}:
 474                  if operator != 'and':
 475                      types = context.infer_node(right)
 476              # Otherwise continue, because of uncertainty.
 477          else:
 478              types = _infer_comparison(context, types, operator,
 479                                        context.infer_node(right))
 480      debug.dbg('infer_or_test types %s', types)
 481      return types
 482  
 483  
 484  @iterator_to_value_set
 485  def infer_factor(value_set, operator):
 486      """
 487      Calculates `+`, `-`, `~` and `not` prefixes.
 488      """
 489      for value in value_set:
 490          if operator == '-':
 491              if is_number(value):
 492                  yield value.negate()
 493          elif operator == 'not':
 494              b = value.py__bool__()
 495              if b is None:  # Uncertainty.
 496                  yield list(value.inference_state.builtins_module.py__getattribute__('bool')
 497                             .execute_annotation()).pop()
 498              else:
 499                  yield compiled.create_simple_object(value.inference_state, not b)
 500          else:
 501              yield value
 502  
 503  
 504  def _literals_to_types(inference_state, result):
 505      # Changes literals ('a', 1, 1.0, etc) to its type instances (str(),
 506      # int(), float(), etc).
 507      new_result = NO_VALUES
 508      for typ in result:
 509          if is_literal(typ):
 510              # Literals are only valid as long as the operations are
 511              # correct. Otherwise add a value-free instance.
 512              cls = compiled.builtin_from_name(inference_state, typ.name.string_name)
 513              new_result |= cls.execute_with_values()
 514          else:
 515              new_result |= ValueSet([typ])
 516      return new_result
 517  
 518  
 519  def _infer_comparison(context, left_values, operator, right_values):
 520      state = context.inference_state
 521      if isinstance(operator, str):
 522          operator_str = operator
 523      else:
 524          operator_str = str(operator.value)
 525      if not left_values or not right_values:
 526          # illegal slices e.g. cause left/right_result to be None
 527          result = (left_values or NO_VALUES) | (right_values or NO_VALUES)
 528          return _literals_to_types(state, result)
 529      elif operator_str == "|" and all(
 530          value.is_class() or value.is_compiled()
 531          for value in itertools.chain(left_values, right_values)
 532      ):
 533          # ^^^ A naive hack for PEP 604
 534          return ValueSet.from_sets((left_values, right_values))
 535      else:
 536          # I don't think there's a reasonable chance that a string
 537          # operation is still correct, once we pass something like six
 538          # objects.
 539          if len(left_values) * len(right_values) > 6:
 540              return _literals_to_types(state, left_values | right_values)
 541          else:
 542              return ValueSet.from_sets(
 543                  _infer_comparison_part(state, context, left, operator, right)
 544                  for left in left_values
 545                  for right in right_values
 546              )
 547  
 548  
 549  def _is_annotation_name(name):
 550      ancestor = tree.search_ancestor(name, 'param', 'funcdef', 'expr_stmt')
 551      if ancestor is None:
 552          return False
 553  
 554      if ancestor.type in ('param', 'funcdef'):
 555          ann = ancestor.annotation
 556          if ann is not None:
 557              return ann.start_pos <= name.start_pos < ann.end_pos
 558      elif ancestor.type == 'expr_stmt':
 559          c = ancestor.children
 560          if len(c) > 1 and c[1].type == 'annassign':
 561              return c[1].start_pos <= name.start_pos < c[1].end_pos
 562      return False
 563  
 564  
 565  def _is_list(value):
 566      return value.array_type == 'list'
 567  
 568  
 569  def _is_tuple(value):
 570      return value.array_type == 'tuple'
 571  
 572  
 573  def _bool_to_value(inference_state, bool_):
 574      return compiled.builtin_from_name(inference_state, str(bool_))
 575  
 576  
 577  def _get_tuple_ints(value):
 578      if not isinstance(value, iterable.SequenceLiteralValue):
 579          return None
 580      numbers = []
 581      for lazy_value in value.py__iter__():
 582          if not isinstance(lazy_value, LazyTreeValue):
 583              return None
 584          node = lazy_value.data
 585          if node.type != 'number':
 586              return None
 587          try:
 588              numbers.append(int(node.value))
 589          except ValueError:
 590              return None
 591      return numbers
 592  
 593  
 594  def _infer_comparison_part(inference_state, context, left, operator, right):
 595      l_is_num = is_number(left)
 596      r_is_num = is_number(right)
 597      if isinstance(operator, str):
 598          str_operator = operator
 599      else:
 600          str_operator = str(operator.value)
 601  
 602      if str_operator == '*':
 603          # for iterables, ignore * operations
 604          if isinstance(left, iterable.Sequence) or is_string(left):
 605              return ValueSet([left])
 606          elif isinstance(right, iterable.Sequence) or is_string(right):
 607              return ValueSet([right])
 608      elif str_operator == '+':
 609          if l_is_num and r_is_num or is_string(left) and is_string(right):
 610              return left.execute_operation(right, str_operator)
 611          elif _is_list(left) and _is_list(right) or _is_tuple(left) and _is_tuple(right):
 612              return ValueSet([iterable.MergedArray(inference_state, (left, right))])
 613      elif str_operator == '-':
 614          if l_is_num and r_is_num:
 615              return left.execute_operation(right, str_operator)
 616      elif str_operator == '%':
 617          # With strings and numbers the left type typically remains. Except for
 618          # `int() % float()`.
 619          return ValueSet([left])
 620      elif str_operator in COMPARISON_OPERATORS:
 621          if left.is_compiled() and right.is_compiled():
 622              # Possible, because the return is not an option. Just compare.
 623              result = left.execute_operation(right, str_operator)
 624              if result:
 625                  return result
 626          else:
 627              if str_operator in ('is', '!=', '==', 'is not'):
 628                  operation = COMPARISON_OPERATORS[str_operator]
 629                  bool_ = operation(left, right)
 630                  # Only if == returns True or != returns False, we can continue.
 631                  # There's no guarantee that they are not equal. This can help
 632                  # in some cases, but does not cover everything.
 633                  if (str_operator in ('is', '==')) == bool_:
 634                      return ValueSet([_bool_to_value(inference_state, bool_)])
 635  
 636              if isinstance(left, VersionInfo):
 637                  version_info = _get_tuple_ints(right)
 638                  if version_info is not None:
 639                      bool_result = compiled.access.COMPARISON_OPERATORS[operator](
 640                          inference_state.environment.version_info,
 641                          tuple(version_info)
 642                      )
 643                      return ValueSet([_bool_to_value(inference_state, bool_result)])
 644  
 645          return ValueSet([
 646              _bool_to_value(inference_state, True),
 647              _bool_to_value(inference_state, False)
 648          ])
 649      elif str_operator in ('in', 'not in'):
 650          return inference_state.builtins_module.py__getattribute__('bool').execute_annotation()
 651  
 652      def check(obj):
 653          """Checks if a Jedi object is either a float or an int."""
 654          return isinstance(obj, TreeInstance) and \
 655              obj.name.string_name in ('int', 'float')
 656  
 657      # Static analysis, one is a number, the other one is not.
 658      if str_operator in ('+', '-') and l_is_num != r_is_num \
 659              and not (check(left) or check(right)):
 660          message = "TypeError: unsupported operand type(s) for +: %s and %s"
 661          analysis.add(context, 'type-error-operation', operator,
 662                       message % (left, right))
 663  
 664      if left.is_class() or right.is_class():
 665          return NO_VALUES
 666  
 667      method_name = operator_to_magic_method[str_operator]
 668      magic_methods = left.py__getattribute__(method_name)
 669      if magic_methods:
 670          result = magic_methods.execute_with_values(right)
 671          if result:
 672              return result
 673  
 674      if not magic_methods:
 675          reverse_method_name = reverse_operator_to_magic_method[str_operator]
 676          magic_methods = right.py__getattribute__(reverse_method_name)
 677  
 678          result = magic_methods.execute_with_values(left)
 679          if result:
 680              return result
 681  
 682      result = ValueSet([left, right])
 683      debug.dbg('Used operator %s resulting in %s', operator, result)
 684      return result
 685  
 686  
 687  @plugin_manager.decorate()
 688  def tree_name_to_values(inference_state, context, tree_name):
 689      value_set = NO_VALUES
 690      module_node = context.get_root_context().tree_node
 691      # First check for annotations, like: `foo: int = 3`
 692      if module_node is not None:
 693          names = module_node.get_used_names().get(tree_name.value, [])
 694          found_annotation = False
 695          for name in names:
 696              expr_stmt = name.parent
 697  
 698              if expr_stmt.type == "expr_stmt" and expr_stmt.children[1].type == "annassign":
 699                  correct_scope = parser_utils.get_parent_scope(name) == context.tree_node
 700                  ann_assign = expr_stmt.children[1]
 701                  if correct_scope:
 702                      found_annotation = True
 703                      if (
 704                          (ann_assign.children[1].type == 'name')
 705                          and (ann_assign.children[1].value == tree_name.value)
 706                          and context.parent_context
 707                      ):
 708                          context = context.parent_context
 709                      value_set |= annotation.infer_annotation(
 710                          context, expr_stmt.children[1].children[1]
 711                      ).execute_annotation()
 712          if found_annotation:
 713              return value_set
 714  
 715      types = []
 716      node = tree_name.get_definition(import_name_always=True, include_setitem=True)
 717      if node is None:
 718          node = tree_name.parent
 719          if node.type == 'global_stmt':
 720              c = context.create_context(tree_name)
 721              if c.is_module():
 722                  # In case we are already part of the module, there is no point
 723                  # in looking up the global statement anymore, because it's not
 724                  # valid at that point anyway.
 725                  return NO_VALUES
 726              # For global_stmt lookups, we only need the first possible scope,
 727              # which means the function itself.
 728              filter = next(c.get_filters())
 729              names = filter.get(tree_name.value)
 730              return ValueSet.from_sets(name.infer() for name in names)
 731          elif node.type not in ('import_from', 'import_name'):
 732              c = context.create_context(tree_name)
 733              return infer_atom(c, tree_name)
 734  
 735      typ = node.type
 736      if typ == 'for_stmt':
 737          types = annotation.find_type_from_comment_hint_for(context, node, tree_name)
 738          if types:
 739              return types
 740      if typ == 'with_stmt':
 741          types = annotation.find_type_from_comment_hint_with(context, node, tree_name)
 742          if types:
 743              return types
 744  
 745      if typ in ('for_stmt', 'comp_for', 'sync_comp_for'):
 746          try:
 747              types = context.predefined_names[node][tree_name.value]
 748          except KeyError:
 749              cn = ContextualizedNode(context, node.children[3])
 750              for_types = iterate_values(
 751                  cn.infer(),
 752                  contextualized_node=cn,
 753                  is_async=node.parent.type == 'async_stmt',
 754              )
 755              n = TreeNameDefinition(context, tree_name)
 756              types = check_tuple_assignments(n, for_types)
 757      elif typ == 'expr_stmt':
 758          types = infer_expr_stmt(context, node, tree_name)
 759      elif typ == 'with_stmt':
 760          value_managers = context.infer_node(node.get_test_node_from_name(tree_name))
 761          if node.parent.type == 'async_stmt':
 762              # In the case of `async with` statements, we need to
 763              # first get the coroutine from the `__aenter__` method,
 764              # then "unwrap" via the `__await__` method
 765              enter_methods = value_managers.py__getattribute__('__aenter__')
 766              coro = enter_methods.execute_with_values()
 767              return coro.py__await__().py__stop_iteration_returns()
 768          enter_methods = value_managers.py__getattribute__('__enter__')
 769          return enter_methods.execute_with_values()
 770      elif typ in ('import_from', 'import_name'):
 771          types = imports.infer_import(context, tree_name)
 772      elif typ in ('funcdef', 'classdef'):
 773          types = _apply_decorators(context, node)
 774      elif typ == 'try_stmt':
 775          # TODO an exception can also be a tuple. Check for those.
 776          # TODO check for types that are not classes and add it to
 777          # the static analysis report.
 778          exceptions = context.infer_node(tree_name.get_previous_sibling().get_previous_sibling())
 779          types = exceptions.execute_with_values()
 780      elif typ == 'param':
 781          types = NO_VALUES
 782      elif typ == 'del_stmt':
 783          types = NO_VALUES
 784      elif typ == 'namedexpr_test':
 785          types = infer_node(context, node)
 786      else:
 787          raise ValueError("Should not happen. type: %s" % typ)
 788      return types
 789  
 790  
 791  # We don't want to have functions/classes that are created by the same
 792  # tree_node.
 793  @inference_state_method_cache()
 794  def _apply_decorators(context, node):
 795      """
 796      Returns the function, that should to be executed in the end.
 797      This is also the places where the decorators are processed.
 798      """
 799      if node.type == 'classdef':
 800          decoratee_value = ClassValue(
 801              context.inference_state,
 802              parent_context=context,
 803              tree_node=node
 804          )
 805      else:
 806          decoratee_value = FunctionValue.from_context(context, node)
 807      initial = values = ValueSet([decoratee_value])
 808  
 809      if is_big_annoying_library(context):
 810          return values
 811  
 812      for dec in reversed(node.get_decorators()):
 813          debug.dbg('decorator: %s %s', dec, values, color="MAGENTA")
 814          with debug.increase_indent_cm():
 815              dec_values = context.infer_node(dec.children[1])
 816              trailer_nodes = dec.children[2:-1]
 817              if trailer_nodes:
 818                  # Create a trailer and infer it.
 819                  trailer = tree.PythonNode('trailer', trailer_nodes)
 820                  trailer.parent = dec
 821                  dec_values = infer_trailer(context, dec_values, trailer)
 822  
 823              if not len(dec_values):
 824                  code = dec.get_code(include_prefix=False)
 825                  # For the short future, we don't want to hear about the runtime
 826                  # decorator in typing that was intentionally omitted. This is not
 827                  # "correct", but helps with debugging.
 828                  if code != '@runtime\n':
 829                      debug.warning('decorator not found: %s on %s', dec, node)
 830                  return initial
 831  
 832              values = dec_values.execute(arguments.ValuesArguments([values]))
 833              if not len(values):
 834                  debug.warning('not possible to resolve wrappers found %s', node)
 835                  return initial
 836  
 837          debug.dbg('decorator end %s', values, color="MAGENTA")
 838      if values != initial:
 839          return ValueSet([Decoratee(c, decoratee_value) for c in values])
 840      return values
 841  
 842  
 843  def check_tuple_assignments(name, value_set):
 844      """
 845      Checks if tuples are assigned.
 846      """
 847      lazy_value = None
 848      for index, node in name.assignment_indexes():
 849          cn = ContextualizedNode(name.parent_context, node)
 850          iterated = value_set.iterate(cn)
 851          if isinstance(index, slice):
 852              # For no star unpacking is not possible.
 853              return NO_VALUES
 854          i = 0
 855          while i <= index:
 856              try:
 857                  lazy_value = next(iterated)
 858              except StopIteration:
 859                  # We could do this with the default param in next. But this
 860                  # would allow this loop to run for a very long time if the
 861                  # index number is high. Therefore break if the loop is
 862                  # finished.
 863                  return NO_VALUES
 864              else:
 865                  i += lazy_value.max
 866          value_set = lazy_value.infer()
 867      return value_set
 868  
 869  
 870  class ContextualizedSubscriptListNode(ContextualizedNode):
 871      def infer(self):
 872          return _infer_subscript_list(self.context, self.node)
 873  
 874  
 875  def _infer_subscript_list(context, index):
 876      """
 877      Handles slices in subscript nodes.
 878      """
 879      if index == ':':
 880          # Like array[:]
 881          return ValueSet([iterable.Slice(context, None, None, None)])
 882  
 883      elif index.type == 'subscript' and not index.children[0] == '.':
 884          # subscript basically implies a slice operation
 885          # e.g. array[:3]
 886          result = []
 887          for el in index.children:
 888              if el == ':':
 889                  if not result:
 890                      result.append(None)
 891              elif el.type == 'sliceop':
 892                  if len(el.children) == 2:
 893                      result.append(el.children[1])
 894              else:
 895                  result.append(el)
 896          result += [None] * (3 - len(result))
 897  
 898          return ValueSet([iterable.Slice(context, *result)])
 899      elif index.type == 'subscriptlist':
 900          return ValueSet([iterable.SequenceLiteralValue(context.inference_state, context, index)])
 901  
 902      # No slices
 903      return context.infer_node(index)
 904