mirror of
https://github.com/aphrody-labs/oxc.git
synced 2026-10-14 22:29:17 +00:00
fix(transformer/explicit-resource-management): lower using in catch and finally (#27142)
Lower `using` and `await using` declarations in `catch` and `finally` blocks. fixes #27139
This commit is contained in:
1 parent
ad5dd5df4d
commit
24b7015d2c
5 files changed
+162
-35
No files matched your search
@@ -310,7 +310,7 @@ impl<'a> Traverse<'a, TransformState<'a>> for ExplicitResourceManagement<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Transform try statement.
|
||||
/// Transform `using` declarations in each of the try, catch, and finally blocks.
|
||||
///
|
||||
/// ```js
|
||||
/// try {
|
||||
@@ -331,38 +331,25 @@ impl<'a> Traverse<'a, TransformState<'a>> for ExplicitResourceManagement<'a> {
|
||||
/// } catch (err) { }
|
||||
/// ```
|
||||
fn enter_try_statement(&mut self, node: &mut TryStatement<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
let scope_id = node.block.scope_id();
|
||||
|
||||
if let Some((new_stmts, needs_await, using_ctx)) =
|
||||
self.transform_statements(&mut node.block.body, scope_id, ctx)
|
||||
{
|
||||
let block_stmt_scope_id = ctx.insert_scope_between(
|
||||
ctx.scoping().scope_parent_id(scope_id).unwrap(),
|
||||
scope_id,
|
||||
ScopeFlags::empty(),
|
||||
);
|
||||
|
||||
node.block.body = ArenaVec::from_value_in(
|
||||
Self::create_try_stmt(
|
||||
BlockStatement::boxed_with_scope_id(SPAN, new_stmts, scope_id, ctx),
|
||||
&using_ctx,
|
||||
block_stmt_scope_id,
|
||||
needs_await,
|
||||
SPAN,
|
||||
ctx,
|
||||
),
|
||||
ctx,
|
||||
);
|
||||
|
||||
let current_hoist_scope_id = ctx.current_hoist_scope_id();
|
||||
node.block.set_scope_id(block_stmt_scope_id);
|
||||
ctx.scoping_mut().move_binding_by_symbol_id(
|
||||
scope_id,
|
||||
current_hoist_scope_id,
|
||||
using_ctx.symbol_id,
|
||||
);
|
||||
|
||||
ctx.scoping_mut().change_scope_parent_id(scope_id, Some(block_stmt_scope_id));
|
||||
self.transform_try_block(&mut node.block, ctx);
|
||||
if let Some(handler) = &mut node.handler {
|
||||
let original_scope_id = handler.body.scope_id();
|
||||
self.transform_try_block(&mut handler.body, ctx);
|
||||
let new_scope_id = handler.body.scope_id();
|
||||
if new_scope_id != original_scope_id
|
||||
&& let Some(param) = &handler.param
|
||||
{
|
||||
param.pattern.bound_names(&mut |ident| {
|
||||
ctx.scoping_mut().move_binding_by_symbol_id(
|
||||
original_scope_id,
|
||||
new_scope_id,
|
||||
ident.symbol_id(),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
if let Some(finalizer) = &mut node.finalizer {
|
||||
self.transform_try_block(finalizer, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,6 +585,47 @@ impl<'a> Traverse<'a, TransformState<'a>> for ExplicitResourceManagement<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ExplicitResourceManagement<'a> {
|
||||
/// Wrap a try, catch, or finally block containing `using` declarations in a disposal try.
|
||||
fn transform_try_block(
|
||||
&mut self,
|
||||
block: &mut ArenaBox<'a, BlockStatement<'a>>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
let scope_id = block.scope_id();
|
||||
|
||||
if let Some((new_stmts, needs_await, using_ctx)) =
|
||||
self.transform_statements(&mut block.body, scope_id, ctx)
|
||||
{
|
||||
let block_stmt_scope_id = ctx.insert_scope_between(
|
||||
ctx.scoping().scope_parent_id(scope_id).unwrap(),
|
||||
scope_id,
|
||||
ScopeFlags::empty(),
|
||||
);
|
||||
|
||||
block.body = ArenaVec::from_value_in(
|
||||
Self::create_try_stmt(
|
||||
BlockStatement::boxed_with_scope_id(SPAN, new_stmts, scope_id, ctx),
|
||||
&using_ctx,
|
||||
block_stmt_scope_id,
|
||||
needs_await,
|
||||
SPAN,
|
||||
ctx,
|
||||
),
|
||||
ctx,
|
||||
);
|
||||
|
||||
let current_hoist_scope_id = ctx.current_hoist_scope_id();
|
||||
block.set_scope_id(block_stmt_scope_id);
|
||||
ctx.scoping_mut().move_binding_by_symbol_id(
|
||||
scope_id,
|
||||
current_hoist_scope_id,
|
||||
using_ctx.symbol_id,
|
||||
);
|
||||
|
||||
ctx.scoping_mut().change_scope_parent_id(scope_id, Some(block_stmt_scope_id));
|
||||
}
|
||||
}
|
||||
|
||||
/// Transform block statement.
|
||||
///
|
||||
/// Input:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
commit: fd665901
|
||||
|
||||
Passed: 280/408
|
||||
Passed: 281/409
|
||||
|
||||
# All Passed:
|
||||
* babel-plugin-transform-class-static-block
|
||||
@@ -21,7 +21,7 @@ Passed: 280/408
|
||||
* plugin-tagged-template-transform
|
||||
|
||||
|
||||
# babel-plugin-transform-explicit-resource-management (3/4)
|
||||
# babel-plugin-transform-explicit-resource-management (4/5)
|
||||
* export-class-name/input.js
|
||||
Symbol reference IDs mismatch for "C":
|
||||
after transform: SymbolId(1): [ReferenceId(1), ReferenceId(2), ReferenceId(3), ReferenceId(7)]
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
function disposeSync(make) {
|
||||
try {
|
||||
using tryResource = make("try");
|
||||
throw new Error("catch");
|
||||
} catch (error) {
|
||||
using catchResource = make(error.message);
|
||||
} finally {
|
||||
using finallyResource = make("finally");
|
||||
}
|
||||
}
|
||||
|
||||
async function disposeAsync(make) {
|
||||
try {
|
||||
throw new Error("catch");
|
||||
} catch {
|
||||
await using catchResource = await make("catch");
|
||||
} finally {
|
||||
await using finallyResource = await make("finally");
|
||||
}
|
||||
}
|
||||
|
||||
function disposeDestructured(make) {
|
||||
try {
|
||||
throw { name: "catch", code: 1 };
|
||||
} catch ({ name, code }) {
|
||||
using resource = make(name, code);
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["transform-explicit-resource-management"]
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
function disposeSync(make) {
|
||||
try {
|
||||
try {
|
||||
var _usingCtx = babelHelpers.usingCtx();
|
||||
const tryResource = _usingCtx.u(make("try"));
|
||||
throw new Error("catch");
|
||||
} catch (_) {
|
||||
_usingCtx.e = _;
|
||||
} finally {
|
||||
_usingCtx.d();
|
||||
}
|
||||
} catch (error) {
|
||||
try {
|
||||
var _usingCtx2 = babelHelpers.usingCtx();
|
||||
const catchResource = _usingCtx2.u(make(error.message));
|
||||
} catch (_) {
|
||||
_usingCtx2.e = _;
|
||||
} finally {
|
||||
_usingCtx2.d();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
var _usingCtx3 = babelHelpers.usingCtx();
|
||||
const finallyResource = _usingCtx3.u(make("finally"));
|
||||
} catch (_) {
|
||||
_usingCtx3.e = _;
|
||||
} finally {
|
||||
_usingCtx3.d();
|
||||
}
|
||||
}
|
||||
}
|
||||
async function disposeAsync(make) {
|
||||
try {
|
||||
throw new Error("catch");
|
||||
} catch {
|
||||
try {
|
||||
var _usingCtx4 = babelHelpers.usingCtx();
|
||||
const catchResource = _usingCtx4.a(await make("catch"));
|
||||
} catch (_) {
|
||||
_usingCtx4.e = _;
|
||||
} finally {
|
||||
await _usingCtx4.d();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
var _usingCtx5 = babelHelpers.usingCtx();
|
||||
const finallyResource = _usingCtx5.a(await make("finally"));
|
||||
} catch (_) {
|
||||
_usingCtx5.e = _;
|
||||
} finally {
|
||||
await _usingCtx5.d();
|
||||
}
|
||||
}
|
||||
}
|
||||
function disposeDestructured(make) {
|
||||
try {
|
||||
throw { name: "catch", code: 1 };
|
||||
} catch ({ name, code }) {
|
||||
try {
|
||||
var _usingCtx6 = babelHelpers.usingCtx();
|
||||
const resource = _usingCtx6.u(make(name, code));
|
||||
} catch (_) {
|
||||
_usingCtx6.e = _;
|
||||
} finally {
|
||||
_usingCtx6.d();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user