use crate::func_at::FuncAtMut;
use crate::qptr::{self, QPtrAttr, QPtrMemUsage, QPtrMemUsageKind, QPtrOp, QPtrUsage};
use crate::{
    cfg, spv, AddrSpace, Attr, AttrSet, AttrSetDef, Const, ConstCtor, ConstDef, ControlNode,
    ControlNodeDef, ControlNodeKind, ControlNodeOutputDecl, ControlRegion, ControlRegionDef,
    ControlRegionInputDecl, DataInst, DataInstDef, DataInstForm, DataInstFormDef, DataInstKind,
    DeclDef, EntityListIter, ExportKey, Exportee, Func, FuncDecl, FuncDefBody, FuncParam,
    GlobalVar, GlobalVarDecl, GlobalVarDefBody, Import, Module, ModuleDebugInfo, ModuleDialect,
    OrdAssertEq, SelectionKind, Type, TypeCtor, TypeCtorArg, TypeDef, Value,
};
use std::cmp::Ordering;
use std::rc::Rc;
use std::slice;
#[must_use]
#[derive(Copy, Clone)]
pub enum Transformed<T> {
    Unchanged,
    Changed(T),
}
impl<T> Transformed<T> {
    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Transformed<U> {
        match self {
            Transformed::Unchanged => Transformed::Unchanged,
            Transformed::Changed(new) => Transformed::Changed(f(new)),
        }
    }
    pub fn apply_to(self, dest: &mut T) {
        match self {
            Transformed::Unchanged => {}
            Transformed::Changed(new) => *dest = new,
        }
    }
}
impl Transformed<()> {
    pub fn map_iter<'a, T: 'a + Clone>(
        iter: impl Iterator<Item = &'a T> + Clone + 'a,
        mut transform_elem: impl FnMut(&'a T) -> Transformed<T> + 'a,
    ) -> Transformed<impl Iterator<Item = T> + 'a> {
        for (i, elem_i) in iter.clone().enumerate() {
            if let Transformed::Changed(new_elem_i) = transform_elem(elem_i) {
                let mut new_elem_i = Some(new_elem_i);
                return Transformed::Changed(iter.enumerate().map(move |(j, elem_j)| {
                    match j.cmp(&i) {
                        Ordering::Less => elem_j.clone(),
                        Ordering::Equal => new_elem_i.take().unwrap(),
                        Ordering::Greater => match transform_elem(elem_j) {
                            Transformed::Unchanged => elem_j.clone(),
                            Transformed::Changed(new_elem_j) => new_elem_j,
                        },
                    }
                }));
            }
        }
        Transformed::Unchanged
    }
}
enum TransformedWithOriginal<'a, T> {
    Original(&'a T),
    Changed(T),
}
impl<T> Transformed<T> {
    fn with_original(self, original: &T) -> TransformedWithOriginal<'_, T> {
        match self {
            Transformed::Unchanged => TransformedWithOriginal::Original(original),
            Transformed::Changed(new) => TransformedWithOriginal::Changed(new),
        }
    }
}
impl<T: Clone> TransformedWithOriginal<'_, T> {
    fn is_changed(&self) -> bool {
        matches!(self, TransformedWithOriginal::Changed(_))
    }
    fn changed_or_original_cloned(self) -> T {
        match self {
            TransformedWithOriginal::Original(original) => original.clone(),
            TransformedWithOriginal::Changed(new) => new,
        }
    }
}
trait AutoRef {
    fn auto_ref(&self) -> &Self {
        self
    }
}
impl<T> AutoRef for T {}
macro_rules! transform {
    ({ $($input:ident -> $input_transformed:expr),+ $(,)? } => $output:expr) => {{
        let ($($input,)+) = ($($input_transformed.with_original($input.auto_ref()),)+);
        if $($input.is_changed())||+ {
            let ($($input,)*) = ($($input.changed_or_original_cloned(),)+);
            Transformed::Changed($output)
        } else {
            Transformed::Unchanged
        }
    }};
}
pub trait Transformer: Sized {
    fn transform_attr_set_use(&mut self, _attrs: AttrSet) -> Transformed<AttrSet> {
        Transformed::Unchanged
    }
    fn transform_type_use(&mut self, _ty: Type) -> Transformed<Type> {
        Transformed::Unchanged
    }
    fn transform_const_use(&mut self, _ct: Const) -> Transformed<Const> {
        Transformed::Unchanged
    }
    fn transform_data_inst_form_use(
        &mut self,
        _data_inst_form: DataInstForm,
    ) -> Transformed<DataInstForm> {
        Transformed::Unchanged
    }
    fn transform_global_var_use(&mut self, _gv: GlobalVar) -> Transformed<GlobalVar> {
        Transformed::Unchanged
    }
    fn transform_func_use(&mut self, _func: Func) -> Transformed<Func> {
        Transformed::Unchanged
    }
    fn in_place_transform_spv_dialect(&mut self, _dialect: &mut spv::Dialect) {}
    fn in_place_transform_spv_module_debug_info(&mut self, _debug_info: &mut spv::ModuleDebugInfo) {
    }
    fn transform_attr_set_def(&mut self, attrs_def: &AttrSetDef) -> Transformed<AttrSetDef> {
        attrs_def.inner_transform_with(self)
    }
    fn transform_attr(&mut self, attr: &Attr) -> Transformed<Attr> {
        attr.inner_transform_with(self)
    }
    fn transform_type_def(&mut self, ty_def: &TypeDef) -> Transformed<TypeDef> {
        ty_def.inner_transform_with(self)
    }
    fn transform_const_def(&mut self, ct_def: &ConstDef) -> Transformed<ConstDef> {
        ct_def.inner_transform_with(self)
    }
    fn transform_data_inst_form_def(
        &mut self,
        data_inst_form_def: &DataInstFormDef,
    ) -> Transformed<DataInstFormDef> {
        data_inst_form_def.inner_transform_with(self)
    }
    fn transform_value_use(&mut self, v: &Value) -> Transformed<Value> {
        v.inner_transform_with(self)
    }
    fn in_place_transform_module(&mut self, module: &mut Module) {
        module.inner_in_place_transform_with(self);
    }
    fn in_place_transform_module_dialect(&mut self, dialect: &mut ModuleDialect) {
        dialect.inner_in_place_transform_with(self);
    }
    fn in_place_transform_module_debug_info(&mut self, debug_info: &mut ModuleDebugInfo) {
        debug_info.inner_in_place_transform_with(self);
    }
    fn in_place_transform_global_var_decl(&mut self, gv_decl: &mut GlobalVarDecl) {
        gv_decl.inner_in_place_transform_with(self);
    }
    fn in_place_transform_func_decl(&mut self, func_decl: &mut FuncDecl) {
        func_decl.inner_in_place_transform_with(self);
    }
    fn in_place_transform_control_node_def(
        &mut self,
        mut func_at_control_node: FuncAtMut<'_, ControlNode>,
    ) {
        func_at_control_node.inner_in_place_transform_with(self);
    }
    fn in_place_transform_data_inst_def(&mut self, mut func_at_data_inst: FuncAtMut<'_, DataInst>) {
        func_at_data_inst.inner_in_place_transform_with(self);
    }
}
pub trait InnerTransform: Sized {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self>;
}
pub trait InnerInPlaceTransform {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer);
}
impl InnerInPlaceTransform for Module {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer) {
        let Self { dialect, debug_info, global_vars: _, funcs: _, exports, .. } = self;
        transformer.in_place_transform_module_dialect(dialect);
        transformer.in_place_transform_module_debug_info(debug_info);
        for exportee in exports.values_mut() {
            exportee.inner_transform_with(transformer).apply_to(exportee);
        }
        Transformed::map_iter(exports.keys(), |export_key| {
            export_key.inner_transform_with(transformer)
        })
        .map(|new_keys_iter| {
            new_keys_iter.zip(exports.values().cloned()).collect()
        })
        .apply_to(exports);
    }
}
impl InnerInPlaceTransform for ModuleDialect {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer) {
        match self {
            Self::Spv(dialect) => transformer.in_place_transform_spv_dialect(dialect),
        }
    }
}
impl InnerInPlaceTransform for ModuleDebugInfo {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer) {
        match self {
            Self::Spv(debug_info) => {
                transformer.in_place_transform_spv_module_debug_info(debug_info);
            }
        }
    }
}
impl InnerTransform for ExportKey {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        match self {
            Self::LinkName(_) => Transformed::Unchanged,
            Self::SpvEntryPoint { imms, interface_global_vars } => transform!({
                imms -> Transformed::Unchanged,
                interface_global_vars -> Transformed::map_iter(
                    interface_global_vars.iter(),
                    |&gv| transformer.transform_global_var_use(gv),
                ).map(|new_iter| new_iter.collect()),
            } => Self::SpvEntryPoint {
                imms,
                interface_global_vars,
            }),
        }
    }
}
impl InnerTransform for Exportee {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        match *self {
            Self::GlobalVar(gv) => transform!({
                gv -> transformer.transform_global_var_use(gv),
            } => Self::GlobalVar(gv)),
            Self::Func(func) => transform!({
                func -> transformer.transform_func_use(func),
            } => Self::Func(func)),
        }
    }
}
impl InnerTransform for AttrSetDef {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        let Self { attrs } = self;
        transform!({
            attrs -> Transformed::map_iter(
                attrs.iter(),
                |attr| transformer.transform_attr(attr),
            ).map(|new_iter| new_iter.collect()),
        } => Self {
            attrs,
        })
    }
}
impl InnerTransform for Attr {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        match self {
            Attr::Diagnostics(_)
            | Attr::SpvAnnotation(_)
            | Attr::SpvDebugLine { .. }
            | Attr::SpvBitflagsOperand(_) => Transformed::Unchanged,
            Attr::QPtr(attr) => transform!({
                attr -> match attr {
                    &QPtrAttr::ToSpvPtrInput { input_idx, pointee } => transform!({
                        pointee -> transformer.transform_type_use(pointee.0).map(OrdAssertEq),
                    } => QPtrAttr::ToSpvPtrInput { input_idx, pointee }),
                    &QPtrAttr::FromSpvPtrOutput {
                        addr_space,
                        pointee,
                    } => transform!({
                        pointee -> transformer.transform_type_use(pointee.0).map(OrdAssertEq),
                    } => QPtrAttr::FromSpvPtrOutput {
                        addr_space,
                        pointee,
                    }),
                    QPtrAttr::Usage(OrdAssertEq(usage)) => transform!({
                        usage -> match usage {
                            &QPtrUsage::Handles(qptr::shapes::Handle::Opaque(ty)) => transform!({
                                ty -> transformer.transform_type_use(ty),
                            } => QPtrUsage::Handles(qptr::shapes::Handle::Opaque(ty))),
                            QPtrUsage::Handles(qptr::shapes::Handle::Buffer(addr_space, data_usage)) => transform!({
                                data_usage -> data_usage.inner_transform_with(transformer),
                            } => QPtrUsage::Handles(qptr::shapes::Handle::Buffer(*addr_space, data_usage))),
                            QPtrUsage::Memory(usage) => transform!({
                                usage -> usage.inner_transform_with(transformer),
                            } => QPtrUsage::Memory(usage)),
                        }
                    } => QPtrAttr::Usage(OrdAssertEq(usage))),
                }
            } => Attr::QPtr(attr)),
        }
    }
}
impl<T: InnerTransform> InnerTransform for Rc<T> {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        (**self).inner_transform_with(transformer).map(Rc::new)
    }
}
impl InnerTransform for QPtrMemUsage {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        let Self { max_size, kind } = self;
        transform!({
            kind -> kind.inner_transform_with(transformer)
        } => Self {
            max_size: *max_size,
            kind,
        })
    }
}
impl InnerTransform for QPtrMemUsageKind {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        match self {
            Self::Unused => Transformed::Unchanged,
            &Self::StrictlyTyped(ty) => transform!({
                ty -> transformer.transform_type_use(ty),
            } => Self::StrictlyTyped(ty)),
            &Self::DirectAccess(ty) => transform!({
                ty -> transformer.transform_type_use(ty),
            } => Self::DirectAccess(ty)),
            Self::OffsetBase(entries) => transform!({
                entries -> Transformed::map_iter(entries.values(), |sub_usage| {
                    sub_usage.inner_transform_with(transformer)
                }).map(|new_iter| {
                    entries.keys().copied().zip(new_iter).collect()
                }).map(Rc::new)
            } => Self::OffsetBase(entries)),
            Self::DynOffsetBase { element, stride } => transform!({
                element -> element.inner_transform_with(transformer),
            } => Self::DynOffsetBase { element, stride: *stride }),
        }
    }
}
impl InnerTransform for TypeDef {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        let Self { attrs, ctor, ctor_args } = self;
        transform!({
            attrs -> transformer.transform_attr_set_use(*attrs),
            ctor -> match ctor {
                TypeCtor::QPtr
                | TypeCtor::SpvInst(_)
                | TypeCtor::SpvStringLiteralForExtInst => Transformed::Unchanged,
            },
            ctor_args -> Transformed::map_iter(ctor_args.iter(), |arg| match *arg {
                TypeCtorArg::Type(ty) => transform!({
                    ty -> transformer.transform_type_use(ty),
                } => TypeCtorArg::Type(ty)),
                TypeCtorArg::Const(ct) => transform!({
                    ct -> transformer.transform_const_use(ct),
                } => TypeCtorArg::Const(ct)),
            }).map(|new_iter| new_iter.collect()),
        } => Self {
            attrs,
            ctor,
            ctor_args,
        })
    }
}
impl InnerTransform for ConstDef {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        let Self { attrs, ty, ctor, ctor_args } = self;
        transform!({
            attrs -> transformer.transform_attr_set_use(*attrs),
            ty -> transformer.transform_type_use(*ty),
            ctor -> match ctor {
                ConstCtor::PtrToGlobalVar(gv) => transform!({
                    gv -> transformer.transform_global_var_use(*gv),
                } => ConstCtor::PtrToGlobalVar(gv)),
                ConstCtor::SpvInst(_)
                | ConstCtor::SpvStringLiteralForExtInst(_) => Transformed::Unchanged
            },
            ctor_args -> Transformed::map_iter(
                ctor_args.iter(),
                |&ct| transformer.transform_const_use(ct),
            ).map(|new_iter| new_iter.collect()),
        } => Self {
            attrs,
            ty,
            ctor,
            ctor_args,
        })
    }
}
impl<D: InnerInPlaceTransform> InnerInPlaceTransform for DeclDef<D> {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer) {
        match self {
            Self::Imported(import) => match import {
                Import::LinkName(_) => {}
            },
            Self::Present(def) => def.inner_in_place_transform_with(transformer),
        }
    }
}
impl InnerInPlaceTransform for GlobalVarDecl {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer) {
        let Self { attrs, type_of_ptr_to, shape, addr_space, def } = self;
        transformer.transform_attr_set_use(*attrs).apply_to(attrs);
        transformer.transform_type_use(*type_of_ptr_to).apply_to(type_of_ptr_to);
        if let Some(shape) = shape {
            match shape {
                qptr::shapes::GlobalVarShape::TypedInterface(ty) => {
                    transformer.transform_type_use(*ty).apply_to(ty);
                }
                qptr::shapes::GlobalVarShape::Handles { .. }
                | qptr::shapes::GlobalVarShape::UntypedData(_) => {}
            }
        }
        match addr_space {
            AddrSpace::Handles | AddrSpace::SpvStorageClass(_) => {}
        }
        def.inner_in_place_transform_with(transformer);
    }
}
impl InnerInPlaceTransform for GlobalVarDefBody {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer) {
        let Self { initializer } = self;
        if let Some(initializer) = initializer {
            transformer.transform_const_use(*initializer).apply_to(initializer);
        }
    }
}
impl InnerInPlaceTransform for FuncDecl {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer) {
        let Self { attrs, ret_type, params, def } = self;
        transformer.transform_attr_set_use(*attrs).apply_to(attrs);
        transformer.transform_type_use(*ret_type).apply_to(ret_type);
        for param in params {
            param.inner_transform_with(transformer).apply_to(param);
        }
        def.inner_in_place_transform_with(transformer);
    }
}
impl InnerTransform for FuncParam {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        let Self { attrs, ty } = self;
        transform!({
            attrs -> transformer.transform_attr_set_use(*attrs),
            ty -> transformer.transform_type_use(*ty),
        } => Self {
            attrs,
            ty,
        })
    }
}
impl InnerInPlaceTransform for FuncDefBody {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer) {
        match &self.unstructured_cfg {
            None => self.at_mut_body().inner_in_place_transform_with(transformer),
            Some(cfg) => {
                let rpo = cfg.rev_post_order(self);
                for region in rpo {
                    self.at_mut(region).inner_in_place_transform_with(transformer);
                    let cfg = self.unstructured_cfg.as_mut().unwrap();
                    if let Some(control_inst) = cfg.control_inst_on_exit_from.get_mut(region) {
                        control_inst.inner_in_place_transform_with(transformer);
                    }
                }
            }
        }
    }
}
impl InnerInPlaceTransform for FuncAtMut<'_, ControlRegion> {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer) {
        let ControlRegionDef { inputs, children: _, outputs: _ } = self.reborrow().def();
        for input in inputs {
            input.inner_transform_with(transformer).apply_to(input);
        }
        self.reborrow().at_children().into_iter().inner_in_place_transform_with(transformer);
        let ControlRegionDef { inputs: _, children: _, outputs } = self.reborrow().def();
        for v in outputs {
            transformer.transform_value_use(v).apply_to(v);
        }
    }
}
impl InnerTransform for ControlRegionInputDecl {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        let Self { attrs, ty } = self;
        transform!({
            attrs -> transformer.transform_attr_set_use(*attrs),
            ty -> transformer.transform_type_use(*ty),
        } => Self {
            attrs,
            ty,
        })
    }
}
impl InnerInPlaceTransform for FuncAtMut<'_, EntityListIter<ControlNode>> {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer) {
        let mut iter = self.reborrow();
        while let Some(func_at_control_node) = iter.next() {
            transformer.in_place_transform_control_node_def(func_at_control_node);
        }
    }
}
impl FuncAtMut<'_, ControlNode> {
    fn child_regions(&mut self) -> &mut [ControlRegion] {
        match &mut self.reborrow().def().kind {
            ControlNodeKind::Block { .. } => &mut [][..],
            ControlNodeKind::Select { cases, .. } => cases,
            ControlNodeKind::Loop { body, .. } => slice::from_mut(body),
        }
    }
}
impl InnerInPlaceTransform for FuncAtMut<'_, ControlNode> {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer) {
        match &mut self.reborrow().def().kind {
            &mut ControlNodeKind::Block { insts } => {
                let mut func_at_inst_iter = self.reborrow().at(insts).into_iter();
                while let Some(func_at_inst) = func_at_inst_iter.next() {
                    transformer.in_place_transform_data_inst_def(func_at_inst);
                }
            }
            ControlNodeKind::Select {
                kind: SelectionKind::BoolCond | SelectionKind::SpvInst(_),
                scrutinee,
                cases: _,
            } => {
                transformer.transform_value_use(scrutinee).apply_to(scrutinee);
            }
            ControlNodeKind::Loop { initial_inputs, body: _, repeat_condition: _ } => {
                for v in initial_inputs {
                    transformer.transform_value_use(v).apply_to(v);
                }
            }
        }
        for child_region_idx in 0..self.child_regions().len() {
            let child_region = self.child_regions()[child_region_idx];
            self.reborrow().at(child_region).inner_in_place_transform_with(transformer);
        }
        let ControlNodeDef { kind, outputs } = self.reborrow().def();
        match kind {
            ControlNodeKind::Block { insts: _ }
            | ControlNodeKind::Select { kind: _, scrutinee: _, cases: _ } => {}
            ControlNodeKind::Loop { initial_inputs: _, body: _, repeat_condition } => {
                transformer.transform_value_use(repeat_condition).apply_to(repeat_condition);
            }
        };
        for output in outputs {
            output.inner_transform_with(transformer).apply_to(output);
        }
    }
}
impl InnerTransform for ControlNodeOutputDecl {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        let Self { attrs, ty } = self;
        transform!({
            attrs -> transformer.transform_attr_set_use(*attrs),
            ty -> transformer.transform_type_use(*ty),
        } => Self {
            attrs,
            ty,
        })
    }
}
impl InnerInPlaceTransform for FuncAtMut<'_, DataInst> {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer) {
        let DataInstDef { attrs, form, inputs } = self.reborrow().def();
        transformer.transform_attr_set_use(*attrs).apply_to(attrs);
        transformer.transform_data_inst_form_use(*form).apply_to(form);
        for v in inputs {
            transformer.transform_value_use(v).apply_to(v);
        }
    }
}
impl InnerTransform for DataInstFormDef {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        let Self { kind, output_type } = self;
        transform!({
            kind -> match kind {
                DataInstKind::FuncCall(func) => transformer.transform_func_use(*func).map(DataInstKind::FuncCall),
                DataInstKind::QPtr(op) => match op {
                    QPtrOp::FuncLocalVar(_)
                    | QPtrOp::HandleArrayIndex
                    | QPtrOp::BufferData
                    | QPtrOp::BufferDynLen { .. }
                    | QPtrOp::Offset(_)
                    | QPtrOp::DynOffset { .. }
                    | QPtrOp::Load
                    | QPtrOp::Store => Transformed::Unchanged,
                },
                DataInstKind::SpvInst(_) | DataInstKind::SpvExtInst { .. } => Transformed::Unchanged,
            },
            output_type -> output_type.map(|ty| transformer.transform_type_use(ty))
                .map_or(Transformed::Unchanged, |t| t.map(Some)),
        } => Self {
            kind,
            output_type,
        })
    }
}
impl InnerInPlaceTransform for cfg::ControlInst {
    fn inner_in_place_transform_with(&mut self, transformer: &mut impl Transformer) {
        let Self { attrs, kind, inputs, targets: _, target_inputs } = self;
        transformer.transform_attr_set_use(*attrs).apply_to(attrs);
        match kind {
            cfg::ControlInstKind::Unreachable
            | cfg::ControlInstKind::Return
            | cfg::ControlInstKind::ExitInvocation(cfg::ExitInvocationKind::SpvInst(_))
            | cfg::ControlInstKind::Branch
            | cfg::ControlInstKind::SelectBranch(
                SelectionKind::BoolCond | SelectionKind::SpvInst(_),
            ) => {}
        }
        for v in inputs {
            transformer.transform_value_use(v).apply_to(v);
        }
        for inputs in target_inputs.values_mut() {
            for v in inputs {
                transformer.transform_value_use(v).apply_to(v);
            }
        }
    }
}
impl InnerTransform for Value {
    fn inner_transform_with(&self, transformer: &mut impl Transformer) -> Transformed<Self> {
        match self {
            Self::Const(ct) => transform!({
                ct -> transformer.transform_const_use(*ct),
            } => Self::Const(ct)),
            Self::ControlRegionInput { region: _, input_idx: _ }
            | Self::ControlNodeOutput { control_node: _, output_idx: _ }
            | Self::DataInstOutput(_) => Transformed::Unchanged,
        }
    }
}