def _check_invalid_const_tensor_input(self):
        """
        Check if non const tensor feed into const input.
        This might happen in the early stage of conversion, for instance:
            constexpr_ -> reshape -> transpose -> linear

        However, the pattern is optimized into the following in a graph pass.
            constexpr_ -> linear
        """
        def _check_invalid_const_tensor_input_block(block):
            for op in block.operations:
                for b in op.blocks:
                    _check_invalid_const_tensor_input_block(b)

                for k, v in op.inputs.items():
                    input_type = op.input_spec.input_types[k]

                    if (
                        input_type.const
                        and not isinstance(input_type, InternalInputType)
                        and not (v.op.op_type.startswith("constexpr_") or v.val is not None)
                    ):
                        raise ValueError(
                            f"In op {op.name}. Input {k} ({v.name}) must be const or constexpr ops."
                        )

        for f in self.functions.values():
            _check_invalid_const_tensor_input_block(f)

        Check if non const tensor feed into const input.
        This might happen in the early stage of conversion, for instance:
            constexpr_ -> reshape -> transpose -> linear

        However, the pattern is optimized into the following in a graph pass.
            constexpr_ -> linear
        
coremltools/converters/mil/mil/program.py