class_docstr: Very basic type inference.
  
  Note: in order to support cross-closure type inference, this must be
  applies to nested scopes in top-down order.
class_docstr_tok: ["Very","basic","type","inference",".","Note",":","in","order","to","support","cross-closure","type","inference",",","this","must","be","applies","to","nested","scopes","in","top-down","order","."]
code: def infer_types(self, scope):
      enabled = scope.directives["infer_types"]
      verbose = scope.directives["infer_types.verbose"]
  
      if enabled == True:
          spanning_type = aggressive_spanning_type
      elif enabled is None:  # safe mode
          spanning_type = safe_spanning_type
      else:
          for entry in scope.entries.values():
              if entry.type is unspecified_type:
                  self.set_entry_type(entry, py_object_type)
          return
  
      # Set of assignments
      assignments = set()
      assmts_resolved = set()
      dependencies = {}
      assmt_to_names = {}
  
      for name, entry in scope.entries.items():
          for assmt in entry.cf_assignments:
              names = assmt.type_dependencies()
              assmt_to_names[assmt] = names
              assmts = set()
              for node in names:
                  assmts.update(node.cf_state)
              dependencies[assmt] = assmts
          if entry.type is unspecified_type:
              assignments.update(entry.cf_assignments)
          else:
              assmts_resolved.update(entry.cf_assignments)
  
      def infer_name_node_type(node):
          types = [assmt.inferred_type for assmt in node.cf_state]
          if not types:
              node_type = py_object_type
          else:
              entry = node.entry
              node_type = spanning_type(
                  types, entry.might_overflow, entry.pos, scope
              )
          node.inferred_type = node_type
  
      def infer_name_node_type_partial(node):
          types = [
              assmt.inferred_type
              for assmt in node.cf_state
              if assmt.inferred_type is not None
          ]
          if not types:
              return
          entry = node.entry
          return spanning_type(
              types, entry.might_overflow, entry.pos, scope
          )
  
      def inferred_types(entry):
          has_none = False
          has_pyobjects = False
          types = []
          for assmt in entry.cf_assignments:
              if assmt.rhs.is_none:
                  has_none = True
              else:
                  rhs_type = assmt.inferred_type
                  if rhs_type and rhs_type.is_pyobject:
                      has_pyobjects = True
                  types.append(rhs_type)
          # Ignore None assignments as long as there are concrete Python type assignments.
          # but include them if None is the only assigned Python object.
          if has_none and not has_pyobjects:
              types.append(py_object_type)
          return types
  
      def resolve_assignments(assignments):
          resolved = set()
          for assmt in assignments:
              deps = dependencies[assmt]
              # All assignments are resolved
              if assmts_resolved.issuperset(deps):
                  for node in assmt_to_names[assmt]:
                      infer_name_node_type(node)
                  # Resolve assmt
                  inferred_type = assmt.infer_type()
                  assmts_resolved.add(assmt)
                  resolved.add(assmt)
          assignments.difference_update(resolved)
          return resolved
  
      def partial_infer(assmt):
          partial_types = []
          for node in assmt_to_names[assmt]:
              partial_type = infer_name_node_type_partial(node)
              if partial_type is None:
                  return False
              partial_types.append((node, partial_type))
          for node, partial_type in partial_types:
              node.inferred_type = partial_type
          assmt.infer_type()
          return True
  
      partial_assmts = set()
  
      def resolve_partial(assignments):
          # try to handle circular references
          partials = set()
          for assmt in assignments:
              if assmt in partial_assmts:
                  continue
              if partial_infer(assmt):
                  partials.add(assmt)
                  assmts_resolved.add(assmt)
          partial_assmts.update(partials)
          return partials
  
      # Infer assignments
      while True:
          if not resolve_assignments(assignments):
              if not resolve_partial(assignments):
                  break
      inferred = set()
      # First pass
      for entry in scope.entries.values():
          if entry.type is not unspecified_type:
              continue
          entry_type = py_object_type
          if assmts_resolved.issuperset(entry.cf_assignments):
              types = inferred_types(entry)
              if types and all(types):
                  entry_type = spanning_type(
                      types, entry.might_overflow, entry.pos, scope
                  )
                  inferred.add(entry)
          self.set_entry_type(entry, entry_type)
  
      def reinfer():
          dirty = False
          for entry in inferred:
              for assmt in entry.cf_assignments:
                  assmt.infer_type()
              types = inferred_types(entry)
              new_type = spanning_type(
                  types, entry.might_overflow, entry.pos, scope
              )
              if new_type != entry.type:
                  self.set_entry_type(entry, new_type)
                  dirty = True
          return dirty
  
      # types propagation
      while reinfer():
          pass
  
      if verbose:
          for entry in inferred:
              message(
                  entry.pos,
                  "inferred '%s' to be of type '%s'"
                  % (entry.name, entry.type),
              )
  
imports: from __future__ import absolute_import
  from .Errors import error, message
  from .None import ExprNodes
  from .None import Nodes
  from .None import Builtin
  from .None import PyrexTypes
  from ..None import Utils
  from .PyrexTypes import py_object_type, unspecified_type
  from .Visitor import CythonTransform, EnvTransform
label_desc: Use image node_id 2 for calling the SimpleAssignmentTypeInferer obj's underlying member method code with example usage: obj.infer_types(scope) and returns: spanning_type, types, resolved, True, partials, dirty, False