Skip to content

Commit

Permalink
refactor(transformer): exponentiation transform: do not wrap in `Sequ…
Browse files Browse the repository at this point in the history
…enceExpression` if not needed (#6343)

`left **= right` is transformed to `left = Math.pow(left, right)`. There is no need to wrap it in a `SequenceExpression`.
  • Loading branch information
overlookmotel committed Oct 8, 2024
1 parent 0dd9a2e commit 4aa4e6b
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 9 deletions.
24 changes: 16 additions & 8 deletions crates/oxc_transformer/src/es2016/exponentiation_operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use oxc_ast::{ast::*, NONE};
use oxc_semantic::{ReferenceFlags, SymbolFlags};
use oxc_span::SPAN;
use oxc_syntax::operator::{AssignmentOperator, BinaryOperator};
use oxc_traverse::{BoundIdentifier, Traverse, TraverseCtx};
use oxc_traverse::{Ancestor, BoundIdentifier, Traverse, TraverseCtx};

use crate::TransformCtx;

Expand Down Expand Up @@ -142,7 +142,7 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> {
/// Get left side of `Math.pow(pow_left, ...)` for identifier
fn get_pow_left_identifier(
&mut self,
ident: &IdentifierReference<'a>,
ident: &mut IdentifierReference<'a>,
ctx: &mut TraverseCtx<'a>,
) -> (
// Left side of `Math.pow(pow_left, ...)`
Expand All @@ -153,10 +153,16 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> {
let mut temp_var_inits = ctx.ast.vec();

// Make sure side-effects of evaluating `left` only happen once
let symbol_id = ctx.symbols().get_reference(ident.reference_id().unwrap()).symbol_id();
let pow_left = if let Some(symbol_id) = symbol_id {
let reference = ctx.scoping.symbols_mut().get_reference_mut(ident.reference_id().unwrap());
let pow_left = if let Some(symbol_id) = reference.symbol_id() {
// This variable is declared in scope so evaluating it multiple times can't trigger a getter.
// No need for a temp var.
// `left **= right` is being transformed to `left = Math.pow(left, right)`,
// so if `left` is no longer being read from, update its `ReferenceFlags`.
if matches!(ctx.ancestry.parent(), Ancestor::ExpressionStatementExpression(_)) {
*reference.flags_mut() = ReferenceFlags::Write;
}

ctx.ast.expression_from_identifier_reference(ctx.create_bound_reference_id(
SPAN,
ident.name.clone(),
Expand Down Expand Up @@ -447,15 +453,17 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> {
assign_expr.operator = AssignmentOperator::Assign;
}

/// Replace expression `expr` with `(temp1, temp2, expr)` (temp1, temp2 etc from `temp_var_inits`)
/// If needs temp var initializers, replace expression `expr` with `(temp1, temp2, expr)`.
fn revise_expression(
expr: &mut Expression<'a>,
mut temp_var_inits: Vec<'a, Expression<'a>>,
ctx: &mut TraverseCtx<'a>,
) {
temp_var_inits.reserve_exact(1);
temp_var_inits.push(ctx.ast.move_expression(expr));
*expr = ctx.ast.expression_sequence(SPAN, temp_var_inits);
if !temp_var_inits.is_empty() {
temp_var_inits.reserve_exact(1);
temp_var_inits.push(ctx.ast.move_expression(expr));
*expr = ctx.ast.expression_sequence(SPAN, temp_var_inits);
}
}

/// `Math.pow(left, right)`
Expand Down
2 changes: 1 addition & 1 deletion tasks/transform_conformance/snapshots/oxc.snap.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
commit: 3bcfee23

Passed: 59/68
Passed: 60/69

# All Passed:
* babel-plugin-transform-nullish-coalescing-operator
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
let bound, boundObj, boundProp;

x = bound **= 1;
x = unbound **= 2;

x = boundObj.prop **= 3;
x = unboundObj.prop **= 4;
x = boundObj.foo.bar.qux **= 5;
x = unboundObj.foo.bar.qux **= 6;

x = boundObj[boundProp] **= 7;
x = boundObj[unboundProp] **= 8;
x = unboundObj[boundProp] **= 9;
x = unboundObj[unboundProp] **= 10;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
var _unbound, _unboundObj, _boundObj$foo$bar, _unboundObj$foo$bar, _boundProp, _unboundProp, _unboundObj2, _boundProp2, _unboundObj3, _unboundProp2;
let bound, boundObj, boundProp;

x = bound = Math.pow(bound, 1);
x = (_unbound = unbound, unbound = Math.pow(_unbound, 2));

x = boundObj["prop"] = Math.pow(boundObj["prop"], 3);
x = (_unboundObj = unboundObj, _unboundObj["prop"] = Math.pow(_unboundObj["prop"], 4));
x = (_boundObj$foo$bar = boundObj.foo.bar, _boundObj$foo$bar["qux"] = Math.pow(_boundObj$foo$bar["qux"], 5));
x = (_unboundObj$foo$bar = unboundObj.foo.bar, _unboundObj$foo$bar["qux"] = Math.pow(_unboundObj$foo$bar["qux"], 6));

x = (_boundProp = boundProp, boundObj[_boundProp] = Math.pow(boundObj[_boundProp], 7));
x = (_unboundProp = unboundProp, boundObj[_unboundProp] = Math.pow(boundObj[_unboundProp], 8));
x = (_unboundObj2 = unboundObj, _boundProp2 = boundProp, _unboundObj2[_boundProp2] = Math.pow(_unboundObj2[_boundProp2], 9));
x = (_unboundObj3 = unboundObj, _unboundProp2 = unboundProp, _unboundObj3[_unboundProp2] = Math.pow(_unboundObj3[_unboundProp2], 10));

0 comments on commit 4aa4e6b

Please sign in to comment.