swc-project/swc · error
using declaration must be removed by previous pass
Error message
using declaration must be removed by previous pass
What it means
The es2015 for-of lowering (swc_ecma_compat_es2015::for_of, array-iteration strategy) rewrites `for (... of ...)` heads into index-based ForStmt loops. It only knows how to emit the element assignment for VarDecl and Pat heads; ForHead::UsingDecl (`for (using x of xs)`, the explicit-resource-management proposal) must already have been rewritten by swc_ecma_transforms_proposal::explicit_resource_management, so seeing it is an invariant violation and panics.
Source
Thrown at crates/swc_ecma_compat_es2015/src/for_of.rs:184
..Default::default()
}
.into(),
)
}
ForHead::Pat(pat) => prepend_stmt(
&mut body.stmts,
AssignExpr {
span: DUMMY_SP,
left: pat.try_into().unwrap(),
op: op!("="),
right: arr.computed_member(i).into(),
}
.into_stmt(),
),
ForHead::UsingDecl(..) => {
unreachable!("using declaration must be removed by previous pass")
}
#[cfg(swc_ast_unknown)]
_ => panic!("unable to access unknown nodes"),
}
let stmt = ForStmt {
span,
init: Some(
VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Let,
declare: false,
decls,
..Default::default()
}
.into(),
),View on GitHub (pinned to 5176682b65)
Solutions
- Run swc_ecma_transforms_proposal::explicit_resource_management() before any swc_ecma_compat_es2015 for-of/generator pass in your chain.
- Use the standard preset_env/CompatEnv pipeline, which schedules the using-declaration lowering before compat passes.
- Align all swc crates on a single swc_core version.
- As a stopgap, avoid `using` bindings in for-of heads until your pipeline lowers them.
Example fix
// before: for-of lowering panics on `for (using res of resources)`
let pass = Chain::new(swc_ecma_compat_es2015::for_of());
// after: lower using-declarations first
let pass = Chain::new(
swc_ecma_transforms_proposal::explicit_resource_management(),
swc_ecma_compat_es2015::for_of(),
); Defensive patterns
Strategy: validation
Validate before calling
use swc_ecma_ast::{ForHead, Program}; use swc_ecma_visit::{Visit, VisitWith};
struct UsingInForOf; impl Visit for UsingInForOf {
fn visit_for_of_stmt(&mut self, n: &ForOfStmt) {
if let ForHead::UsingDecl(_) = n.left {
panic!("explicit_resource_management pass must run before compat es2015");
}
n.visit_children_with(self);
}
}
// program.visit_with(&mut UsingInForOf); Try / catch
let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| for_of_pass.apply(cm, &mut program))); r.map_err(|p| map_payload_to_config_error(p, "run explicit_resource_management first"))?;
Prevention
- Always pair `using` syntax support with the explicit_resource_management pass.
- Run a pre-flight AST scan for ForHead::UsingDecl before es2015 lowering.
- Test your pipeline with TS 5.2 explicit-resource-management fixtures.
When it happens
Trigger: Compiling `for (using x of xs) { ... }` (or `for await (using x of xs)`) through es2015 for-of lowering when the explicit_resource_management pass has not run first — typically a hand-built compat chain, or a driver that enables `using` parsing without wiring its lowering pass.
Common situations: Adopting TypeScript 5.2+ `using` declarations while targeting ES5/ES2015 via custom swc integrations; codemods/bundlers embedding swc_core that assemble compat passes manually; swc_core version mismatch dropping the proposal pass.
Related errors
- using declaration must be removed by previous pass
- object rest pattern should be removed by es2018::object_rest
- spread should be removed before applying generator
- unknown compound assignment operator
- assignment property be removed before generator pass
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/7561b3721ee3c1a8.
Report an issue: GitHub.