swc-project/swc · error

derive(Merge) does not support an enum

Error message

derive(Merge) does not support an enum

What it means

The #[derive(Merge)] macro from swc_config_macro generates merge code by matching on syn::Data; only structs with named or unnamed fields are supported. Deriving it on an enum reaches unimplemented!("derive(Merge) does not support an enum") at merge.rs:22, which panics during macro expansion — i.e. at compile time of the crate using the derive.

Source

Thrown at crates/swc_config_macro/src/merge.rs:22

use syn::{parse_quote, DeriveInput, Expr, Field, Fields, Stmt, Token};

pub fn expand(input: DeriveInput) -> TokenStream {
    match &input.data {
        syn::Data::Struct(s) => {
            let body = call_merge_for_fields(&quote!(self), &s.fields);
            let body = join_stmts(&body);

            let ident = &input.ident;
            parse_quote!(
                #[automatically_derived]
                impl swc_config::merge::Merge for #ident {
                    fn merge(&mut self, _other: Self) {
                        #body
                    }
                }
            )
        }
        syn::Data::Enum(_) => unimplemented!("derive(Merge) does not support an enum"),
        syn::Data::Union(_) => unimplemented!("derive(Merge) does not support a union"),
    }
}

fn call_merge_for_fields(obj: &dyn ToTokens, fields: &Fields) -> Vec<Stmt> {
    fn call_merge(obj: &dyn ToTokens, idx: usize, f: &Field) -> Expr {
        let r = quote!(_other);

        let l = access_field(obj, idx, f);
        let r = access_field(&r, idx, f);
        parse_quote!(swc_config::merge::Merge::merge(&mut #l, #r))
    }

    match fields {
        Fields::Named(fs) => fs
            .named
            .iter()
            .enumerate()

View on GitHub (pinned to d7d7434666)

Solutions

  1. Convert the enum into a struct whose fields are each merge-able (structs with named/unnamed fields are supported).
  2. Implement swc_config::merge::Merge manually for the enum with your chosen precedence (e.g. other wins when non-default).
  3. Wrap the enum in a struct and derive Merge on the wrapper, implementing Merge by hand for the inner enum.
  4. If Unit-like variants are involved, also see the unit-struct restriction.

Example fix

// before
#[derive(Merge)]
enum Mode { Fast, Slow }

// after
enum Mode { Fast, Slow }
impl swc_config::merge::Merge for Mode {
    fn merge(&mut self, other: Self) {
        // define precedence explicitly
        if matches!(self, Mode::Fast) { *self = other; }
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// The panic is at macro-expansion time; the only 'validation' is reviewing
// the derive input shape before compiling:
// - #[derive(Merge)] requires a struct (named or unnamed fields, at least one field).
// - Enums and unit structs are rejected.
// Fail fast in review/CI with a grep:
//   rg -U '#\[derive\([^)]*Merge[^)]*\)\s*(pub\s+)?enum' src/

Prevention

When it happens

Trigger: Annotating an enum with #[derive(Merge)] in a crate that depends on swc_config / swc_config_macro, e.g. trying to make a config enum overridable. rustc aborts with the macro's panic message during compilation.

Common situations: Defining SWC config option types (transforms, plugin options) as enums for ergonomics and assuming derive(Merge) behaves like serde derives; upgrading config types from structs to tagged enums; error appears as 'proc-macro derive panicked' in build output.

Related errors


AI-assisted analysis of swc-project/swc@d7d7434666 (2026-08-16). Data as JSON: /api/errors/db4d59354e59197f. Report an issue: GitHub.