swc-project/swc · error

Binder for union type

Error message

Binder for union type

What it means

swc_macros_common supplies the derive-macro engine behind SWC's AST macros (#[ast_node(...)], Spanned, Take, and their serde impls). Binder::variants() decomposes the annotated item into per-variant binders: Data::Enum yields one VariantBinder per variant and Data::Struct one binder for the struct — Data::Union falls into the unimplemented!("Binder for union type") arm, so applying any binder-backed derive to a Rust union panics during macro expansion (at compile time).

Source

Thrown at crates/swc_macros_common/src/binder.rs:76

    }

    pub fn new_from(input: &'a DeriveInput) -> Self {
        Self::new(&input.ident, &input.data, &input.attrs)
    }

    pub fn variants(&self) -> Vec<VariantBinder<'a>> {
        match *self.body {
            Data::Enum(DataEnum { ref variants, .. }) => {
                let enum_name = &self.ident;
                variants
                    .iter()
                    .map(|v| VariantBinder::new(Some(enum_name), &v.ident, &v.fields, &v.attrs))
                    .collect()
            }
            Data::Struct(DataStruct { ref fields, .. }) => {
                vec![VariantBinder::new(None, self.ident, fields, self.attrs)]
            }
            Data::Union(_) => unimplemented!("Binder for union type"),
        }
    }
}

/// Variant.
#[derive(Debug, Clone)]
pub struct VariantBinder<'a> {
    /// None for struct.
    enum_name: Option<&'a Ident>,
    /// Name of variant.
    name: &'a Ident,
    data: &'a Fields,
    attrs: &'a [Attribute],
}

impl<'a> VariantBinder<'a> {
    pub const fn new(
        enum_name: Option<&'a Ident>,

View on GitHub (pinned to 5176682b65)

Solutions

  1. Model the data as a struct or an enum instead — both are fully supported by the binder.
  2. Remove the swc derive(s) from the union and implement the required traits manually.
  3. Wrap the union in a plain struct and derive the traits on the wrapper only.

Example fix

// before: compile-time panic 'Binder for union type'
#[ast_node("BinaryOp")]
union Op {
    add: u8,
    sub: u8,
}

// after: model as an enum (or struct) — binder-supported
#[ast_node("BinaryOp")]
enum Op {
    Add,
    Sub,
}
Defensive patterns

Strategy: validation

Validate before calling

# CI: fail when a union appears in files that also use swc derive macros
rg -l '#\[ast_node|derive\([^)]*(Spanned|Take)' src/ \
  | xargs -r rg -n '^[[:space:]]*(pub[[:space:]]+)?union[[:space:]]' \
  && { echo 'union used with swc derive macro'; exit 1; } || true

Prevention

When it happens

Trigger: Writing `union U { a: u32, b: f32 }` in a crate and putting a swc derive on it — e.g. #[ast_node("Tag")], #[derive(Spanned)], #[derive(Take)], or the swc-flavored Serialize/Deserialize — invokes Binder::variants() on a union and panics.

Common situations: Adding an FFI-style or layout-sensitive union to an AST crate whose convention is to annotate every node with #[ast_node]; copy-pasting an existing node's attribute block onto a new union item; third-party crates deriving swc traits over memory-layout types.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/ec6b2d4722ce3b78. Report an issue: GitHub.