def adjust_function_output_types(self, func: Function) -> None:
        """
        Adjust output dtypes for a pymil function.
        """
        user_provided_output_types = func.output_types
        output_vars = func.outputs
        input_vars = list(func.inputs.values())
        if user_provided_output_types is None or len(user_provided_output_types) == 0:
            return
        if len(output_vars) != len(user_provided_output_types):
            msg = (
                "Number of outputs provided by the user, which is {}, "
                "does not match the number of outputs generated by the model, which is {}"
            )
            raise ValueError(msg.format(len(user_provided_output_types), len(output_vars)))

        new_outputs = []
        for i, output_type in enumerate(user_provided_output_types):
            required_output_dtype = output_type.dtype
            output_var = output_vars[i]
            if (
                required_output_dtype is None
                or not (
                    types.is_tensor(output_var.sym_type) or types.is_scalar(output_var.sym_type)
                )
                or required_output_dtype == output_var.dtype
            ):
                # no need to update the output var's dtype in this case
                new_outputs.append(output_var)
            elif output_var in input_vars:
                # Here is this rare special case, that the program input is also an output
                # For this case, we don't do anything, and throw a warning message
                new_outputs.append(output_var)
                logger.warning(
                    f"Output var '{output_var.name}' is also an input var, hence the "
                    f"dtype cannot be changed: output var '{output_var.name}' remains "
                    f"dtype {types.builtin_to_string(output_var.dtype)}"
                )
            else:
                output_var_name = output_var.name
                output_var.set_name(
                    output_var_name + "_type_" + types.builtin_to_string(output_var.dtype)
                )
                new_output_var = mb.cast(
                    x=output_var, dtype=types.builtin_to_string(required_output_dtype)
                )
                new_output_var.set_name(output_var_name)
                Block._copy_scope_info(output_var, new_output_var)
                new_outputs.append(new_output_var)

        func.set_outputs(new_outputs)

        Adjust output dtypes for a pymil function.
        
coremltools/converters/mil/mil/passes/defs/preprocess.py