swc-project/swc · error

object rest pattern should be removed by es2018::object_rest

Error message

object rest pattern should be removed by es2018::object_rest_spread pass

What it means

The es2015 destructuring pass (swc_ecma_compat_es2015::destructure) rewrites object binding patterns into a sequence of assignments. While expanding the properties of an object pattern it explicitly asserts that ObjectPatProp::Rest never appears, because rest elements (e.g. `const {a, ...rest} = obj`) are supposed to be lowered earlier by the es2018::object_rest_spread pass. Hitting this unreachable! means the compat pass chain ran in the wrong order or was hand-assembled without the es2018 pass.

Source

Thrown at crates/swc_ecma_compat_es2015/src/destructuring.rs:1028

                                    }
                                    None => {
                                        exprs.push(
                                            AssignExpr {
                                                span,
                                                left: key.clone().into(),
                                                op: op!("="),
                                                right: Box::new(make_ref_prop_expr(
                                                    &ref_ident,
                                                    key.clone().into(),
                                                    computed,
                                                )),
                                            }
                                            .into(),
                                        );
                                    }
                                }
                            }
                            ObjectPatProp::Rest(_) => unreachable!(
                                "object rest pattern should be removed by \
                                 es2018::object_rest_spread pass"
                            ),
                            #[cfg(swc_ast_unknown)]
                            _ => panic!("unable to access unknown nodes"),
                        }
                    }

                    // Last one should be object itself.
                    exprs.push(ref_ident.into());

                    *expr = SeqExpr {
                        span: DUMMY_SP,
                        exprs,
                    }
                    .into();
                }

View on GitHub (pinned to 5176682b65)

Solutions

  1. If you build a manual pass chain, insert swc_ecma_compat_es2018::object_rest_spread(Default::default()) BEFORE swc_ecma_compat_es2015::destructure (and before es2015::generator).
  2. Prefer the standard pipelines (swc_ecma_preset_env / CompatEnv / full `es` compat chain) which order passes correctly, instead of hand-picking passes.
  3. Align all swc crates on one swc_core version so pass wiring is consistent.
  4. If ordering is already correct in your version, file an swc issue with a minimal repro of the rest-element input.

Example fix

// before: rest element panics because es2018 pass never ran
let pass = Chain::new(swc_ecma_compat_es2015::destructure());

// after: lower object rest/spread first, then destructure
let pass = Chain::new(
    swc_ecma_compat_es2018::object_rest_spread(Default::default()),
    swc_ecma_compat_es2015::destructure(),
);
Defensive patterns

Strategy: validation

Validate before calling

// Before applying es2015::destructure, assert no object-rest remains
use swc_ecma_ast::*; use swc_ecma_visit::{Visit, VisitWith};
struct RestChecker; impl Visit for RestChecker {
    fn visit_object_pat_prop(&mut self, p: &ObjectPatProp) {
        if let ObjectPatProp::Rest(_) = p { panic!("run object_rest_spread before destructure"); }
        p.visit_children_with(self);
    }
}
// program.visit_with(&mut RestChecker);

Try / catch

// Rust panics cross FFI/thread boundaries; contain them at your driver edge
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    program.apply_mut(chain)
}));
if result.is_err() { /* extract payload, surface 'pass ordering' error to user */ }

Prevention

When it happens

Trigger: Compiling source containing an object destructuring rest element while invoking swc_ecma_compat_es2015::destructure directly (or in a custom swc_core Pass chain) without running swc_ecma_compat_es2018::object_rest_spread first. Also triggered by swc_core version skew where the preset-env/compat pass ordering changed.

Common situations: Codemod or bundler authors building custom `Chain`s of compat passes instead of using preset_env/CompatEnv; projects mixing swc_core versions across crates (e.g. swc_ecma_compat_es2015 from a different version than the driver); downgrading swc after a pass-list refactor.

Related errors


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