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 destructuring pass rewrites for-of/for-in loop heads. `for (using x of y)` (explicit resource management) must already be lowered to plain declarations by swc_ecma_transforms_proposal::explicit_resource_management; when destructuring encounters ForHead::UsingDecl it panics because it has no lowering for it. The pass ordering contract was violated.
Source
Thrown at crates/swc_ecma_compat_es2015/src/destructuring.rs:124
return;
}
_ => {
let left_ident = make_ref_ident_for_for_stmt();
let left = ForHead::Pat(left_ident.clone().into());
// Unpack variables
let stmt = AssignExpr {
span: DUMMY_SP,
left: pat.take().try_into().unwrap(),
op: op!("="),
right: Box::new(left_ident.into()),
}
.into_stmt();
(left, stmt)
}
},
ForHead::UsingDecl(..) => {
unreachable!("using declaration must be removed by previous pass")
}
#[cfg(swc_ast_unknown)]
_ => panic!("unable to access unknown nodes"),
};
for_stmt.left = left;
for_stmt.body = Box::new(Stmt::Block(match &mut *for_stmt.body {
Stmt::Block(BlockStmt { span, stmts, ctxt }) => BlockStmt {
span: *span,
stmts: iter::once(stmt).chain(stmts.take()).collect(),
ctxt: *ctxt,
},
body => BlockStmt {
stmts: vec![stmt, body.take()],
..Default::default()
},View on GitHub (pinned to 5176682b65)
Solutions
- Use the full compat preset (swc core build/CompatibleWith targets) so the explicit-resource-management lowering runs before destructuring
- In a manual chain, insert swc_ecma_transforms_proposal::explicit_resource_management ahead of es2015 destructuring
- Avoid `using` declarations in for-of heads when you control the pass list, or pre-transpile them
Example fix
// before (custom chain, missing the lowering pass) let passes = vec![destructuring()]; // after let passes = vec![ Box::new(swc_ecma_transforms_proposal::explicit_resource_management()), destructuring(), ];
Defensive patterns
Strategy: validation
Validate before calling
// Detect `using` declarations before running a partial es2015 chain
let uses_using = regex::Regex::new(
r#"(?:^|;|\{)\s*using\s+[A-Za-z_$]|for\s*\(?:?\s*(?:await\s+)?using\s+"#,
).unwrap();
if uses_using.is_match(&source) {
return Err("explicit_resource_management pass must run before destructuring".into());
} Try / catch
if let Err(p) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| destructuring(&mut program))) {
if panic_message(&p).contains("using declaration") {
// fix chain: insert explicit_resource_management() before destructuring and retry
} else { std::panic::resume_unwind(p); }
} Prevention
- Rely on swc's full compat preset ordering rather than hand-picked passes
- When adding new syntax features (like `using`), update the pass chain in the same change
- Smoke-test the pipeline on sources that use every enabled parser feature
When it happens
Trigger: Running swc_ecma_compat_es2015::destructuring directly (or a hand-assembled chain missing the explicit-resource-management pass) on code containing `for (using res of iterable)` or `for await (using res of asyncIterable)`.
Common situations: Enabling the explicitResourceManagement parser feature but assembling compat passes manually; targeting ES2015 with a custom pass list after swc added `using` support; old pipelines replayed against newer sources.
Related errors
- Object rest pattern should be removed by es2018::object_rest
- TsParameterProperty should be removed by typescript::strip p
- assign property in object literal is invalid
- rest pattern should handled by array pattern handler: {:?}
- internal error: entered unreachable code
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/d74727923f4af5aa.
Report an issue: GitHub.