code: def _process_block(block, visited, inferred_types, backend):
      """Executes a pass of type inference on a single `Block`."""
      for op in block.instructions:
          log_debug("handle op {}".format(op))
          if isinstance(op, instructions.PrimOp):
              if not all(
                  _is_determined(inferred_types[var])
                  for var in op.vars_in
              ):
                  continue
              types_in = [inferred_types[var] for var in op.vars_in]
              # Offer type hints for cases where we need to type non-Tensor literals.
              preferred_types_out = instructions.pattern_map(
                  lambda var: inferred_types[var], op.vars_out
              )
              with _type_inferring():
                  objs_out = backend.run_on_dummies(
                      op.function, _add_incompatible_batch_dim(types_in)
                  )
              types_out = _strip_batch_dim(
                  instructions.pattern_map2(
                      lambda tp, val: type_of_pattern(
                          val, backend, preferred_type=tp
                      ),
                      preferred_types_out,
                      objs_out,
                      leaf_type=instructions.Type,
                  )
              )
              _merge_vars(
                  op.vars_out,
                  types_out,
                  inferred_types,
                  backend,
                  log_message="update PrimOp vars_out",
              )
          elif isinstance(op, instructions.FunctionCallOp):
              if not all(
                  _is_determined(inferred_types[var])
                  for var in op.vars_in
              ):
                  continue
              # First, bind op.vars_in to op.function.vars_in.
              types_in = [
                  inferred_types[var].tensors for var in op.vars_in
              ]
              _merge_vars(
                  op.function.vars_in,
                  types_in,
                  inferred_types,
                  backend,
                  log_message="init function vars_in",
              )
              # Execute type inference.
              types_out = op.function.type_inference(types_in)
              for leaf in instructions.pattern_traverse(
                  types_out, leaf_type=instructions.TensorType
              ):
                  if not isinstance(leaf, instructions.TensorType):
                      msg = (
                          "Expected function output type to be "
                          "a nested list or tuple of TensorType, found {}."
                      ).format(leaf)
                      raise TypeError(msg)
              # To help with typing recursive base-case return literals, we seed
              # return_vars types before stepping into the function.
              _merge_vars(
                  op.function.vars_out,
                  types_out,
                  inferred_types,
                  backend,
                  log_message="update function vars_out",
              )
              # Finally, update op.vars_out with the results of type inference.
              _merge_vars(
                  op.vars_out,
                  types_out,
                  inferred_types,
                  backend,
                  log_message="update FunctionCall vars_out",
              )
              # Step into function. Note: it will only be visited once, if recursive.
              _process_graph(
                  op.function.graph, visited, inferred_types, backend
              )
  
file_path: probability/tensorflow_probability/python/experimental/auto_batching/type_inference.py
imports: import contextlib
  import functools
  from absl import logging
  import six
  from tensorflow_probability.python.experimental.auto_batching import instructions
label_desc: Use image node_id 6 for calling a global function with example usage: _process_block(block, visited, inferred_types, backend) without return types