def __init__(
        self,
        name,
        sym_type,
        sym_val=None,
        op=None,
        op_output_idx=None,
    ):
        """
        sym_type (builtin type)
        sym_val (builtin value)
        op (Operation)
        op_output_idx (int)
        """
        self.name = name
        self._sym_type = sym_type
        self._sym_val = sym_val
        self._op = op
        self.op_output_idx = op_output_idx
        # An op can appear twice if it consumes a var twice (e.g.,
        # add(%1, %1), while_loop(loop_vars=(%1, %1)).
        self._child_ops = list()

        # A variable may not be consumed by any op (i.e. len(self._child_ops)
        # == 0) but is still used as block output. A var can be output of
        # multiple blocks (e.g., both current block and nested blocks)
        self.consuming_blocks = list()

        # replaceability
        self._nonreplaceable_vars_upstream = set()
        self._set_nonreplaceable_vars_upstream()

        self._adjust_sym_val()

        # Track vars constness, which requires a var to satisfy one of the following:
        # 1. var.val is not None, which's mean the converter already has its compile time value through value inference.
        # 2. Is a descendant of ``constexpr_`` ops. We don't compute the value inference of those ``constexpr_`` ops,
        #    due to the fact it can potentially results in memory issue.
        self.is_descendant_of_const = Var._propagate_constness_upstream(self)

        sym_type (builtin type)
        sym_val (builtin value)
        op (Operation)
        op_output_idx (int)
        
coremltools/converters/mil/mil/var.py