Skip to content

Commit

Permalink
refactor(transformer): duplicate_expression take `mutated_symbol_ne…
Browse files Browse the repository at this point in the history
…eds_temp_var` param
  • Loading branch information
overlookmotel committed Dec 9, 2024
1 parent 99542f4 commit 04f6445
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 10 deletions.
36 changes: 28 additions & 8 deletions crates/oxc_transformer/src/common/duplicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,19 @@ impl<'a> TransformCtx<'a> {
/// * Unbound identifier `foo` -> `_foo = foo`, `_foo`
/// * Anything else `foo()` -> `_foo = foo()`, `_foo`
///
/// If `mutated_symbol_needs_temp_var` is `true`, temp var will be created for a bound identifier,
/// if it's mutated (assigned to) anywhere in AST.
///
/// Returns 2 `Expression`s. The first may be an `AssignmentExpression`,
/// and must be inserted into output first.
pub(crate) fn duplicate_expression(
&self,
expr: Expression<'a>,
mutated_symbol_needs_temp_var: bool,
ctx: &mut TraverseCtx<'a>,
) -> (Expression<'a>, Expression<'a>) {
let (maybe_assignment, references) = self.duplicate_expression_multiple::<1>(expr, ctx);
let (maybe_assignment, references) =
self.duplicate_expression_multiple::<1>(expr, mutated_symbol_needs_temp_var, ctx);
let [reference] = references;
(maybe_assignment, reference)
}
Expand All @@ -43,15 +48,20 @@ impl<'a> TransformCtx<'a> {
/// * Unbound identifier `foo` -> `_foo = foo`, `_foo`, `_foo`
/// * Anything else `foo()` -> `_foo = foo()`, `_foo`, `_foo`
///
/// If `mutated_symbol_needs_temp_var` is `true`, temp var will be created for a bound identifier,
/// if it's mutated (assigned to) anywhere in AST.
///
/// Returns 3 `Expression`s. The first may be an `AssignmentExpression`,
/// and must be inserted into output first.
#[expect(clippy::similar_names)]
pub(crate) fn duplicate_expression_twice(
&self,
expr: Expression<'a>,
mutated_symbol_needs_temp_var: bool,
ctx: &mut TraverseCtx<'a>,
) -> (Expression<'a>, Expression<'a>, Expression<'a>) {
let (maybe_assignment, references) = self.duplicate_expression_multiple::<2>(expr, ctx);
let (maybe_assignment, references) =
self.duplicate_expression_multiple::<2>(expr, mutated_symbol_needs_temp_var, ctx);
let [reference1, reference2] = references;
(maybe_assignment, reference1, reference2)
}
Expand All @@ -65,26 +75,36 @@ impl<'a> TransformCtx<'a> {
/// * Unbound identifier `foo` -> `_foo = foo`, [`_foo`; N]
/// * Anything else `foo()` -> `_foo = foo()`, [`_foo`; N]
///
/// If `mutated_symbol_needs_temp_var` is `true`, temp var will be created for a bound identifier,
/// if it's mutated (assigned to) anywhere in AST.
///
/// Returns `N + 1` x `Expression`s. The first may be an `AssignmentExpression`,
/// and must be inserted into output first.
pub(crate) fn duplicate_expression_multiple<const N: usize>(
&self,
expr: Expression<'a>,
mutated_symbol_needs_temp_var: bool,
ctx: &mut TraverseCtx<'a>,
) -> (Expression<'a>, [Expression<'a>; N]) {
// TODO: Handle if in a function's params
let temp_var_binding = match &expr {
Expression::Identifier(ident) => {
let reference = ctx.symbols_mut().get_reference_mut(ident.reference_id());
let reference_id = ident.reference_id();
let reference = ctx.symbols().get_reference(reference_id);
if let Some(symbol_id) = reference.symbol_id() {
// Reading bound identifier cannot have side effects, so no need for temp var
let binding = BoundIdentifier::new(ident.name.clone(), symbol_id);
let references =
create_array(|| binding.create_spanned_read_expression(ident.span, ctx));
return (expr, references);
if !mutated_symbol_needs_temp_var || !ctx.symbols().symbol_is_mutated(symbol_id)
{
// Reading bound identifier cannot have side effects, so no need for temp var
let binding = BoundIdentifier::new(ident.name.clone(), symbol_id);
let references = create_array(|| {
binding.create_spanned_read_expression(ident.span, ctx)
});
return (expr, references);
}
}

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

self.var_declarations.create_uid_var(&ident.name, ctx)
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_transformer/src/es2022/class_properties/private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1463,7 +1463,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
ctx: &mut TraverseCtx<'a>,
) -> (Expression<'a>, Expression<'a>) {
assert_expr_neither_parenthesis_nor_typescript_syntax(&object);
self.ctx.duplicate_expression(object, ctx)
self.ctx.duplicate_expression(object, false, ctx)
}

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

/// `_classPrivateFieldGet2(_prop, object)`
Expand Down

0 comments on commit 04f6445

Please sign in to comment.