Skip to content

Commit 04f6445

Browse files
committed
refactor(transformer): duplicate_expression take mutated_symbol_needs_temp_var param
1 parent 99542f4 commit 04f6445

2 files changed

Lines changed: 30 additions & 10 deletions

File tree

crates/oxc_transformer/src/common/duplicate.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,19 @@ impl<'a> TransformCtx<'a> {
2222
/// * Unbound identifier `foo` -> `_foo = foo`, `_foo`
2323
/// * Anything else `foo()` -> `_foo = foo()`, `_foo`
2424
///
25+
/// If `mutated_symbol_needs_temp_var` is `true`, temp var will be created for a bound identifier,
26+
/// if it's mutated (assigned to) anywhere in AST.
27+
///
2528
/// Returns 2 `Expression`s. The first may be an `AssignmentExpression`,
2629
/// and must be inserted into output first.
2730
pub(crate) fn duplicate_expression(
2831
&self,
2932
expr: Expression<'a>,
33+
mutated_symbol_needs_temp_var: bool,
3034
ctx: &mut TraverseCtx<'a>,
3135
) -> (Expression<'a>, Expression<'a>) {
32-
let (maybe_assignment, references) = self.duplicate_expression_multiple::<1>(expr, ctx);
36+
let (maybe_assignment, references) =
37+
self.duplicate_expression_multiple::<1>(expr, mutated_symbol_needs_temp_var, ctx);
3338
let [reference] = references;
3439
(maybe_assignment, reference)
3540
}
@@ -43,15 +48,20 @@ impl<'a> TransformCtx<'a> {
4348
/// * Unbound identifier `foo` -> `_foo = foo`, `_foo`, `_foo`
4449
/// * Anything else `foo()` -> `_foo = foo()`, `_foo`, `_foo`
4550
///
51+
/// If `mutated_symbol_needs_temp_var` is `true`, temp var will be created for a bound identifier,
52+
/// if it's mutated (assigned to) anywhere in AST.
53+
///
4654
/// Returns 3 `Expression`s. The first may be an `AssignmentExpression`,
4755
/// and must be inserted into output first.
4856
#[expect(clippy::similar_names)]
4957
pub(crate) fn duplicate_expression_twice(
5058
&self,
5159
expr: Expression<'a>,
60+
mutated_symbol_needs_temp_var: bool,
5261
ctx: &mut TraverseCtx<'a>,
5362
) -> (Expression<'a>, Expression<'a>, Expression<'a>) {
54-
let (maybe_assignment, references) = self.duplicate_expression_multiple::<2>(expr, ctx);
63+
let (maybe_assignment, references) =
64+
self.duplicate_expression_multiple::<2>(expr, mutated_symbol_needs_temp_var, ctx);
5565
let [reference1, reference2] = references;
5666
(maybe_assignment, reference1, reference2)
5767
}
@@ -65,26 +75,36 @@ impl<'a> TransformCtx<'a> {
6575
/// * Unbound identifier `foo` -> `_foo = foo`, [`_foo`; N]
6676
/// * Anything else `foo()` -> `_foo = foo()`, [`_foo`; N]
6777
///
78+
/// If `mutated_symbol_needs_temp_var` is `true`, temp var will be created for a bound identifier,
79+
/// if it's mutated (assigned to) anywhere in AST.
80+
///
6881
/// Returns `N + 1` x `Expression`s. The first may be an `AssignmentExpression`,
6982
/// and must be inserted into output first.
7083
pub(crate) fn duplicate_expression_multiple<const N: usize>(
7184
&self,
7285
expr: Expression<'a>,
86+
mutated_symbol_needs_temp_var: bool,
7387
ctx: &mut TraverseCtx<'a>,
7488
) -> (Expression<'a>, [Expression<'a>; N]) {
7589
// TODO: Handle if in a function's params
7690
let temp_var_binding = match &expr {
7791
Expression::Identifier(ident) => {
78-
let reference = ctx.symbols_mut().get_reference_mut(ident.reference_id());
92+
let reference_id = ident.reference_id();
93+
let reference = ctx.symbols().get_reference(reference_id);
7994
if let Some(symbol_id) = reference.symbol_id() {
80-
// Reading bound identifier cannot have side effects, so no need for temp var
81-
let binding = BoundIdentifier::new(ident.name.clone(), symbol_id);
82-
let references =
83-
create_array(|| binding.create_spanned_read_expression(ident.span, ctx));
84-
return (expr, references);
95+
if !mutated_symbol_needs_temp_var || !ctx.symbols().symbol_is_mutated(symbol_id)
96+
{
97+
// Reading bound identifier cannot have side effects, so no need for temp var
98+
let binding = BoundIdentifier::new(ident.name.clone(), symbol_id);
99+
let references = create_array(|| {
100+
binding.create_spanned_read_expression(ident.span, ctx)
101+
});
102+
return (expr, references);
103+
}
85104
}
86105

87106
// Previously `x += 1` (`x` read + write), but moving to `_x = x` (`x` read only)
107+
let reference = ctx.symbols_mut().get_reference_mut(reference_id);
88108
*reference.flags_mut() = ReferenceFlags::Read;
89109

90110
self.var_declarations.create_uid_var(&ident.name, ctx)

crates/oxc_transformer/src/es2022/class_properties/private.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,7 +1463,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
14631463
ctx: &mut TraverseCtx<'a>,
14641464
) -> (Expression<'a>, Expression<'a>) {
14651465
assert_expr_neither_parenthesis_nor_typescript_syntax(&object);
1466-
self.ctx.duplicate_expression(object, ctx)
1466+
self.ctx.duplicate_expression(object, false, ctx)
14671467
}
14681468

14691469
/// Duplicate object to be used in triple.
@@ -1482,7 +1482,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
14821482
ctx: &mut TraverseCtx<'a>,
14831483
) -> (Expression<'a>, Expression<'a>, Expression<'a>) {
14841484
assert_expr_neither_parenthesis_nor_typescript_syntax(&object);
1485-
self.ctx.duplicate_expression_twice(object, ctx)
1485+
self.ctx.duplicate_expression_twice(object, false, ctx)
14861486
}
14871487

14881488
/// `_classPrivateFieldGet2(_prop, object)`

0 commit comments

Comments
 (0)