diff --git a/.typos.toml b/.typos.toml index c83946cc636f48..c4002ac8390705 100644 --- a/.typos.toml +++ b/.typos.toml @@ -19,7 +19,11 @@ extend-exclude = [ "tasks/coverage/babel", "tasks/coverage/test262", "tasks/coverage/typescript", + "tasks/coverage/snapshots", "tasks/prettier_conformance/prettier", + "tasks/prettier_conformance/snapshots", + "tasks/transform_conformance/tests/**/output.js", + "tasks/transform_conformance/snapshots", ] [default] diff --git a/crates/oxc_transformer/src/es2016/exponentiation_operator.rs b/crates/oxc_transformer/src/es2016/exponentiation_operator.rs index d3cccb53800edf..519ea9e024edfb 100644 --- a/crates/oxc_transformer/src/es2016/exponentiation_operator.rs +++ b/crates/oxc_transformer/src/es2016/exponentiation_operator.rs @@ -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::{Traverse, TraverseCtx}; +use oxc_traverse::{ast_operations::get_var_name_from_node, Traverse, TraverseCtx}; use crate::TransformCtx; @@ -151,7 +151,8 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> { let reference = ctx.ast.expression_from_identifier_reference( ctx.create_unbound_reference_id(SPAN, ident.name.clone(), ReferenceFlags::Read), ); - self.add_new_reference(reference, &mut nodes, ctx) + let name = ident.name.as_str(); + self.add_new_reference(reference, name, &mut nodes, ctx) }; let reference = ctx.ast.move_assignment_target(assign_target); @@ -228,6 +229,7 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> { let mut obj = ctx.ast.move_expression(obj); // If the object reference that we need to save is locally declared, evaluating it multiple times // will not trigger getters or setters. `super` cannot be directly assigned, so use it directly too. + // TODO(improve-on-babel): We could also skip creating a temp var for `this.x **= 2`. let needs_temp_var = match &obj { Expression::Super(_) => false, Expression::Identifier(ident) => { @@ -236,7 +238,8 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> { _ => true, }; if needs_temp_var { - obj = self.add_new_reference(obj, nodes, ctx); + let name = get_var_name_from_node(&obj); + obj = self.add_new_reference(obj, &name, nodes, ctx); } let computed = member_expr.is_computed(); @@ -311,7 +314,8 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> { if expr.is_literal() { return expr; } - self.add_new_reference(expr, nodes, ctx) + let name = get_var_name_from_node(&expr); + self.add_new_reference(expr, &name, nodes, ctx) } MemberExpression::StaticMemberExpression(expr) => { ctx.ast.expression_string_literal(SPAN, expr.property.name.clone()) @@ -324,14 +328,10 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> { fn add_new_reference( &mut self, expr: Expression<'a>, + name: &str, nodes: &mut Vec<'a, Expression<'a>>, ctx: &mut TraverseCtx<'a>, ) -> Expression<'a> { - let name = match expr { - Expression::Identifier(ref ident) => ident.name.clone().as_str(), - _ => "ref", - }; - let binding = ctx.generate_uid_in_current_scope(name, SymbolFlags::FunctionScopedVariable); // var _name; diff --git a/tasks/transform_conformance/snapshots/oxc.snap.md b/tasks/transform_conformance/snapshots/oxc.snap.md index 8eec97bd90bd81..80325e063a7067 100644 --- a/tasks/transform_conformance/snapshots/oxc.snap.md +++ b/tasks/transform_conformance/snapshots/oxc.snap.md @@ -1,17 +1,154 @@ commit: 3bcfee23 -Passed: 57/66 +Passed: 57/68 # All Passed: * babel-plugin-transform-nullish-coalescing-operator * babel-plugin-transform-optional-catch-binding -* babel-plugin-transform-exponentiation-operator * babel-plugin-transform-arrow-functions * babel-preset-typescript * babel-plugin-transform-react-jsx-source * regexp +# babel-plugin-transform-exponentiation-operator (2/4) +* assign-to-identifier/input.js +Reference flags mismatch for "x": +after transform: ReferenceId(6): ReferenceFlags(Write) +rebuilt : ReferenceId(2): ReferenceFlags(Read) +Reference flags mismatch for "_y": +after transform: ReferenceId(9): ReferenceFlags(Write) +rebuilt : ReferenceId(3): ReferenceFlags(Read | Write) +Reference flags mismatch for "_z": +after transform: ReferenceId(13): ReferenceFlags(Write) +rebuilt : ReferenceId(8): ReferenceFlags(Read | Write) +Reference flags mismatch for "_q": +after transform: ReferenceId(17): ReferenceFlags(Write) +rebuilt : ReferenceId(14): ReferenceFlags(Read | Write) + +* assign-to-member-expression/input.js +Reference flags mismatch for "_obj$foo$bar": +after transform: ReferenceId(42): ReferenceFlags(Write) +rebuilt : ReferenceId(6): ReferenceFlags(Read | Write) +Reference flags mismatch for "_boundPropName": +after transform: ReferenceId(46): ReferenceFlags(Write) +rebuilt : ReferenceId(11): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundPropName": +after transform: ReferenceId(51): ReferenceFlags(Write) +rebuilt : ReferenceId(18): ReferenceFlags(Read | Write) +Reference flags mismatch for "_obj$foo2$bar": +after transform: ReferenceId(56): ReferenceFlags(Write) +rebuilt : ReferenceId(25): ReferenceFlags(Read | Write) +Reference flags mismatch for "_boundPropName2": +after transform: ReferenceId(58): ReferenceFlags(Write) +rebuilt : ReferenceId(27): ReferenceFlags(Read | Write) +Reference flags mismatch for "_obj$foo3$bar": +after transform: ReferenceId(63): ReferenceFlags(Write) +rebuilt : ReferenceId(34): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundPropName2": +after transform: ReferenceId(65): ReferenceFlags(Write) +rebuilt : ReferenceId(36): ReferenceFlags(Read | Write) +Reference flags mismatch for "_boundPropObj$foo$bar": +after transform: ReferenceId(70): ReferenceFlags(Write) +rebuilt : ReferenceId(43): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundPropObj$foo$b": +after transform: ReferenceId(75): ReferenceFlags(Write) +rebuilt : ReferenceId(50): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundObj": +after transform: ReferenceId(80): ReferenceFlags(Write) +rebuilt : ReferenceId(57): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundObj2": +after transform: ReferenceId(84): ReferenceFlags(Write) +rebuilt : ReferenceId(62): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundObj$foo$bar": +after transform: ReferenceId(88): ReferenceFlags(Write) +rebuilt : ReferenceId(67): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundObj3": +after transform: ReferenceId(92): ReferenceFlags(Write) +rebuilt : ReferenceId(72): ReferenceFlags(Read | Write) +Reference flags mismatch for "_boundPropName3": +after transform: ReferenceId(94): ReferenceFlags(Write) +rebuilt : ReferenceId(74): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundObj4": +after transform: ReferenceId(99): ReferenceFlags(Write) +rebuilt : ReferenceId(81): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundPropName3": +after transform: ReferenceId(101): ReferenceFlags(Write) +rebuilt : ReferenceId(83): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundObj$foo2$bar": +after transform: ReferenceId(106): ReferenceFlags(Write) +rebuilt : ReferenceId(90): ReferenceFlags(Read | Write) +Reference flags mismatch for "_boundPropName4": +after transform: ReferenceId(108): ReferenceFlags(Write) +rebuilt : ReferenceId(92): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundObj$foo3$bar": +after transform: ReferenceId(113): ReferenceFlags(Write) +rebuilt : ReferenceId(99): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundPropName4": +after transform: ReferenceId(115): ReferenceFlags(Write) +rebuilt : ReferenceId(101): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundObj5": +after transform: ReferenceId(120): ReferenceFlags(Write) +rebuilt : ReferenceId(108): ReferenceFlags(Read | Write) +Reference flags mismatch for "_boundPropObj2$foo$ba": +after transform: ReferenceId(122): ReferenceFlags(Write) +rebuilt : ReferenceId(110): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundObj6": +after transform: ReferenceId(127): ReferenceFlags(Write) +rebuilt : ReferenceId(117): ReferenceFlags(Read | Write) +Reference flags mismatch for "_unboundPropObj2$foo$": +after transform: ReferenceId(129): ReferenceFlags(Write) +rebuilt : ReferenceId(119): ReferenceFlags(Read | Write) +Reference flags mismatch for "_fn": +after transform: ReferenceId(134): ReferenceFlags(Write) +rebuilt : ReferenceId(126): ReferenceFlags(Read | Write) +Reference flags mismatch for "_fn$foo$bar": +after transform: ReferenceId(138): ReferenceFlags(Write) +rebuilt : ReferenceId(131): ReferenceFlags(Read | Write) +Reference flags mismatch for "_fn$prop": +after transform: ReferenceId(142): ReferenceFlags(Write) +rebuilt : ReferenceId(136): ReferenceFlags(Read | Write) +Reference flags mismatch for "_fn2": +after transform: ReferenceId(144): ReferenceFlags(Write) +rebuilt : ReferenceId(138): ReferenceFlags(Read | Write) +Reference flags mismatch for "_fn$prop2": +after transform: ReferenceId(149): ReferenceFlags(Write) +rebuilt : ReferenceId(145): ReferenceFlags(Read | Write) +Reference flags mismatch for "_ref": +after transform: ReferenceId(151): ReferenceFlags(Write) +rebuilt : ReferenceId(147): ReferenceFlags(Read | Write) +Reference flags mismatch for "_this": +after transform: ReferenceId(156): ReferenceFlags(Write) +rebuilt : ReferenceId(154): ReferenceFlags(Read | Write) +Reference flags mismatch for "_this$foo$bar": +after transform: ReferenceId(160): ReferenceFlags(Write) +rebuilt : ReferenceId(158): ReferenceFlags(Read | Write) +Reference flags mismatch for "_this2": +after transform: ReferenceId(164): ReferenceFlags(Write) +rebuilt : ReferenceId(162): ReferenceFlags(Read | Write) +Reference flags mismatch for "_this3": +after transform: ReferenceId(168): ReferenceFlags(Write) +rebuilt : ReferenceId(166): ReferenceFlags(Read | Write) +Reference flags mismatch for "_fn4$foo$bar$qux": +after transform: ReferenceId(170): ReferenceFlags(Write) +rebuilt : ReferenceId(167): ReferenceFlags(Read | Write) +Reference flags mismatch for "_this4": +after transform: ReferenceId(175): ReferenceFlags(Write) +rebuilt : ReferenceId(174): ReferenceFlags(Read | Write) +Reference flags mismatch for "_this$foo$bar2": +after transform: ReferenceId(179): ReferenceFlags(Write) +rebuilt : ReferenceId(178): ReferenceFlags(Read | Write) +Reference flags mismatch for "_this5": +after transform: ReferenceId(183): ReferenceFlags(Write) +rebuilt : ReferenceId(182): ReferenceFlags(Read | Write) +Reference flags mismatch for "_this6": +after transform: ReferenceId(187): ReferenceFlags(Write) +rebuilt : ReferenceId(186): ReferenceFlags(Read | Write) +Reference flags mismatch for "_fn4$foo$bar$qux2": +after transform: ReferenceId(189): ReferenceFlags(Write) +rebuilt : ReferenceId(187): ReferenceFlags(Read | Write) + + # babel-plugin-transform-typescript (1/8) * class-property-definition/input.ts Unresolved references mismatch: diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-exponentiation-operator/test/fixtures/assign-to-identifier/input.js b/tasks/transform_conformance/tests/babel-plugin-transform-exponentiation-operator/test/fixtures/assign-to-identifier/input.js new file mode 100644 index 00000000000000..b99ba921e75734 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-exponentiation-operator/test/fixtures/assign-to-identifier/input.js @@ -0,0 +1,5 @@ +let x, fn; +x **= 2; +y **= 3; +z **= fn(); +q **= unboundFn(); diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-exponentiation-operator/test/fixtures/assign-to-identifier/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-exponentiation-operator/test/fixtures/assign-to-identifier/output.js new file mode 100644 index 00000000000000..82b6554fb78c5e --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-exponentiation-operator/test/fixtures/assign-to-identifier/output.js @@ -0,0 +1,6 @@ +var _y, _z, _q; +let x, fn; +x = Math.pow(x, 2); +_y = y, y = Math.pow(_y, 3); +_z = z, z = Math.pow(_z, fn()); +_q = q, q = Math.pow(_q, unboundFn()); diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-exponentiation-operator/test/fixtures/assign-to-member-expression/input.js b/tasks/transform_conformance/tests/babel-plugin-transform-exponentiation-operator/test/fixtures/assign-to-member-expression/input.js new file mode 100644 index 00000000000000..5ba47a83e5b980 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-exponentiation-operator/test/fixtures/assign-to-member-expression/input.js @@ -0,0 +1,54 @@ +// Bound root of member expression +let obj; +obj.prop **= 2; +obj['prop blah'] **= 3; +obj.foo.bar.qux **= 4; + +let boundPropName; +obj[boundPropName] **= 5; +obj[unboundPropName] **= 6; + +let boundPropName2; +obj.foo2.bar2[boundPropName2] **= 7; +obj.foo3.bar3[unboundPropName2] **= 8; + +let boundPropObj; +obj[boundPropObj.foo.bar.qux] **= 9; +obj[unboundPropObj.foo.bar.qux] **= 10; + +// Unbound root of member expression +unboundObj.prop **= 11; +unboundObj['prop blah'] **= 12; +unboundObj.foo.bar.qux **= 13; + +let boundPropName3; +unboundObj[boundPropName3] **= 14; +unboundObj[unboundPropName3] **= 15; + +let boundPropName4; +unboundObj.foo2.bar2[boundPropName4] **= 16; +unboundObj.foo3.bar3[unboundPropName4] **= 17; + +let boundPropObj2; +unboundObj[boundPropObj2.foo.bar.qux] **= 18; +unboundObj[unboundPropObj2.foo.bar.qux] **= 19; + +// Other expressions +let fn, fn2; +fn().prop **= 20; +fn().foo().bar().qux **= 21; +fn().prop[fn2()] **= 22; +fn().prop[fn3().foo().bar().qux() + ' junk'] **= 23; + +// `this` +this.prop **= 24; +this.foo.bar.qux **= 25; +this['prop blah'] **= 26; +this[fn4().foo.bar.qux()] **= 27; + +function outer() { + this.prop **= 28; + this.foo.bar.qux **= 29; + this['prop blah'] **= 30; + this[fn4().foo.bar.qux()] **= 31; +} diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-exponentiation-operator/test/fixtures/assign-to-member-expression/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-exponentiation-operator/test/fixtures/assign-to-member-expression/output.js new file mode 100644 index 00000000000000..30cc7d09cd807f --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-exponentiation-operator/test/fixtures/assign-to-member-expression/output.js @@ -0,0 +1,141 @@ +var _obj$foo$bar, + _boundPropName, + _unboundPropName, + _obj$foo2$bar, + _boundPropName2, + _obj$foo3$bar, + _unboundPropName2, + _boundPropObj$foo$bar, + _unboundPropObj$foo$b, + _unboundObj, + _unboundObj2, + _unboundObj$foo$bar, + _unboundObj3, + _boundPropName3, + _unboundObj4, + _unboundPropName3, + _unboundObj$foo2$bar, + _boundPropName4, + _unboundObj$foo3$bar, + _unboundPropName4, + _unboundObj5, + _boundPropObj2$foo$ba, + _unboundObj6, + _unboundPropObj2$foo$, + _fn, + _fn$foo$bar, + _fn$prop, + _fn2, + _fn$prop2, + _ref, + _this, + _this$foo$bar, + _this2, + _this3, + _fn4$foo$bar$qux; + +// Bound root of member expression +let obj; +obj["prop"] = Math.pow(obj["prop"], 2); +obj["prop blah"] = Math.pow(obj["prop blah"], 3); +(_obj$foo$bar = obj.foo.bar), + (_obj$foo$bar["qux"] = Math.pow(_obj$foo$bar["qux"], 4)); +let boundPropName; +(_boundPropName = boundPropName), + (obj[_boundPropName] = Math.pow(obj[_boundPropName], 5)); +(_unboundPropName = unboundPropName), + (obj[_unboundPropName] = Math.pow(obj[_unboundPropName], 6)); +let boundPropName2; +(_obj$foo2$bar = obj.foo2.bar2), + (_boundPropName2 = boundPropName2), + (_obj$foo2$bar[_boundPropName2] = Math.pow( + _obj$foo2$bar[_boundPropName2], + 7 + )); +(_obj$foo3$bar = obj.foo3.bar3), + (_unboundPropName2 = unboundPropName2), + (_obj$foo3$bar[_unboundPropName2] = Math.pow( + _obj$foo3$bar[_unboundPropName2], + 8 + )); +let boundPropObj; +(_boundPropObj$foo$bar = boundPropObj.foo.bar.qux), + (obj[_boundPropObj$foo$bar] = Math.pow(obj[_boundPropObj$foo$bar], 9)); +(_unboundPropObj$foo$b = unboundPropObj.foo.bar.qux), + (obj[_unboundPropObj$foo$b] = Math.pow(obj[_unboundPropObj$foo$b], 10)); + +// Unbound root of member expression +(_unboundObj = unboundObj), + (_unboundObj["prop"] = Math.pow(_unboundObj["prop"], 11)); +(_unboundObj2 = unboundObj), + (_unboundObj2["prop blah"] = Math.pow(_unboundObj2["prop blah"], 12)); +(_unboundObj$foo$bar = unboundObj.foo.bar), + (_unboundObj$foo$bar["qux"] = Math.pow(_unboundObj$foo$bar["qux"], 13)); +let boundPropName3; +(_unboundObj3 = unboundObj), + (_boundPropName3 = boundPropName3), + (_unboundObj3[_boundPropName3] = Math.pow(_unboundObj3[_boundPropName3], 14)); +(_unboundObj4 = unboundObj), + (_unboundPropName3 = unboundPropName3), + (_unboundObj4[_unboundPropName3] = Math.pow( + _unboundObj4[_unboundPropName3], + 15 + )); +let boundPropName4; +(_unboundObj$foo2$bar = unboundObj.foo2.bar2), + (_boundPropName4 = boundPropName4), + (_unboundObj$foo2$bar[_boundPropName4] = Math.pow( + _unboundObj$foo2$bar[_boundPropName4], + 16 + )); +(_unboundObj$foo3$bar = unboundObj.foo3.bar3), + (_unboundPropName4 = unboundPropName4), + (_unboundObj$foo3$bar[_unboundPropName4] = Math.pow( + _unboundObj$foo3$bar[_unboundPropName4], + 17 + )); +let boundPropObj2; +(_unboundObj5 = unboundObj), + (_boundPropObj2$foo$ba = boundPropObj2.foo.bar.qux), + (_unboundObj5[_boundPropObj2$foo$ba] = Math.pow( + _unboundObj5[_boundPropObj2$foo$ba], + 18 + )); +(_unboundObj6 = unboundObj), + (_unboundPropObj2$foo$ = unboundPropObj2.foo.bar.qux), + (_unboundObj6[_unboundPropObj2$foo$] = Math.pow( + _unboundObj6[_unboundPropObj2$foo$], + 19 + )); + +// Other expressions +let fn, fn2; +(_fn = fn()), (_fn["prop"] = Math.pow(_fn["prop"], 20)); +(_fn$foo$bar = fn().foo().bar()), + (_fn$foo$bar["qux"] = Math.pow(_fn$foo$bar["qux"], 21)); +(_fn$prop = fn().prop), + (_fn2 = fn2()), + (_fn$prop[_fn2] = Math.pow(_fn$prop[_fn2], 22)); +(_fn$prop2 = fn().prop), + (_ref = fn3().foo().bar().qux() + " junk"), + (_fn$prop2[_ref] = Math.pow(_fn$prop2[_ref], 23)); + +// `this` +(_this = this), (_this["prop"] = Math.pow(_this["prop"], 24)); +(_this$foo$bar = this.foo.bar), + (_this$foo$bar["qux"] = Math.pow(_this$foo$bar["qux"], 25)); +(_this2 = this), (_this2["prop blah"] = Math.pow(_this2["prop blah"], 26)); +(_this3 = this), + (_fn4$foo$bar$qux = fn4().foo.bar.qux()), + (_this3[_fn4$foo$bar$qux] = Math.pow(_this3[_fn4$foo$bar$qux], 27)); + +function outer() { + var _this4, _this$foo$bar2, _this5, _this6, _fn4$foo$bar$qux2; + (_this4 = this), (_this4["prop"] = Math.pow(_this4["prop"], 28)); + (_this$foo$bar2 = this.foo.bar), + (_this$foo$bar2["qux"] = Math.pow(_this$foo$bar2["qux"], 29)); + (_this5 = this), (_this5["prop blah"] = Math.pow(_this5["prop blah"], 30)); + (_this6 = this), + (_fn4$foo$bar$qux2 = fn4().foo.bar.qux()), + (_this6[_fn4$foo$bar$qux2] = Math.pow(_this6[_fn4$foo$bar$qux2], 31)); +}