mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
fix(transformer): exponentiation transform: do not replace object when private property (#6313)
Fix exponentiation operator transform to bail out early if a private class property.
We can't transform this:
```js
class C {
#p;
method() {
this.#p **= 2;
}
}
```
But we should at least leave it alone. Previously `get_obj_ref` called `ast.move_expression(expr)` on the member expression's object before bailing out, so example above was transformed to:
```js
class C {
#p;
method() {
null.#p **= 2; // <-- `null`
}
}
```
This PR makes it spot this case early and bail out *before* calling `ast.move_expression(expr)`.
This commit is contained in:
parent
fe25b651bd
commit
ccb7bdcc56
4 changed files with 34 additions and 15 deletions
|
|
@ -171,10 +171,10 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> {
|
||||||
(ident, obj)
|
(ident, obj)
|
||||||
}
|
}
|
||||||
match_member_expression!(AssignmentTarget) => {
|
match_member_expression!(AssignmentTarget) => {
|
||||||
let obj = self.get_obj_ref(node, nodes, ctx).unwrap();
|
let obj = self.get_obj_ref(node, nodes, ctx)?;
|
||||||
let member_expr = node.to_member_expression_mut();
|
let member_expr = node.to_member_expression_mut();
|
||||||
let computed = member_expr.is_computed();
|
let computed = member_expr.is_computed();
|
||||||
let prop = self.get_prop_ref(member_expr, nodes, ctx)?;
|
let prop = self.get_prop_ref(member_expr, nodes, ctx);
|
||||||
let optional = false;
|
let optional = false;
|
||||||
let obj_clone = Self::clone_expression(&obj, ctx);
|
let obj_clone = Self::clone_expression(&obj, ctx);
|
||||||
let (reference, uid) = match &prop {
|
let (reference, uid) = match &prop {
|
||||||
|
|
@ -248,7 +248,11 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> {
|
||||||
let expr = match node.to_member_expression_mut() {
|
let expr = match node.to_member_expression_mut() {
|
||||||
MemberExpression::ComputedMemberExpression(e) => &mut e.object,
|
MemberExpression::ComputedMemberExpression(e) => &mut e.object,
|
||||||
MemberExpression::StaticMemberExpression(e) => &mut e.object,
|
MemberExpression::StaticMemberExpression(e) => &mut e.object,
|
||||||
MemberExpression::PrivateFieldExpression(e) => &mut e.object,
|
// From Babel: "We can't generate property ref for private name, please install
|
||||||
|
// `@babel/plugin-transform-class-properties`".
|
||||||
|
// TODO: Ensure this plugin interacts correctly with class private properties
|
||||||
|
// transform, so the property is transformed before this transform.
|
||||||
|
MemberExpression::PrivateFieldExpression(_) => return None,
|
||||||
};
|
};
|
||||||
let expr = ctx.ast.move_expression(expr);
|
let expr = ctx.ast.move_expression(expr);
|
||||||
// the object reference that we need to save is locally declared
|
// the object reference that we need to save is locally declared
|
||||||
|
|
@ -277,24 +281,21 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> {
|
||||||
node: &mut MemberExpression<'a>,
|
node: &mut MemberExpression<'a>,
|
||||||
nodes: &mut Vec<'a, Expression<'a>>,
|
nodes: &mut Vec<'a, Expression<'a>>,
|
||||||
ctx: &mut TraverseCtx<'a>,
|
ctx: &mut TraverseCtx<'a>,
|
||||||
) -> Option<Expression<'a>> {
|
) -> Expression<'a> {
|
||||||
let expr = match node {
|
match node {
|
||||||
MemberExpression::ComputedMemberExpression(expr) => {
|
MemberExpression::ComputedMemberExpression(expr) => {
|
||||||
let expr = ctx.ast.move_expression(&mut expr.expression);
|
let expr = ctx.ast.move_expression(&mut expr.expression);
|
||||||
if expr.is_literal() {
|
if expr.is_literal() {
|
||||||
return Some(expr);
|
return expr;
|
||||||
}
|
}
|
||||||
expr
|
self.add_new_reference(expr, nodes, ctx)
|
||||||
}
|
}
|
||||||
MemberExpression::StaticMemberExpression(expr) => {
|
MemberExpression::StaticMemberExpression(expr) => {
|
||||||
return Some(ctx.ast.expression_string_literal(SPAN, expr.property.name.clone()));
|
ctx.ast.expression_string_literal(SPAN, expr.property.name.clone())
|
||||||
}
|
}
|
||||||
MemberExpression::PrivateFieldExpression(_) => {
|
// This possibility is ruled out in earlier call to `get_obj_ref`
|
||||||
// From babel: "We can't generate property ref for private name, please install `@babel/plugin-transform-class-properties`"
|
MemberExpression::PrivateFieldExpression(_) => unreachable!(),
|
||||||
return None;
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
Some(self.add_new_reference(expr, nodes, ctx))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_new_reference(
|
fn add_new_reference(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
commit: 3bcfee23
|
commit: 3bcfee23
|
||||||
|
|
||||||
Passed: 56/65
|
Passed: 57/66
|
||||||
|
|
||||||
# All Passed:
|
# All Passed:
|
||||||
* babel-plugin-transform-nullish-coalescing-operator
|
* babel-plugin-transform-nullish-coalescing-operator
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
class C {
|
||||||
|
#p = 1;
|
||||||
|
|
||||||
|
method(obj) {
|
||||||
|
obj.x **= 2; // Transform
|
||||||
|
obj['y'] **= 3; // Transform
|
||||||
|
obj.#p **= 4; // Bail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
class C {
|
||||||
|
#p = 1;
|
||||||
|
|
||||||
|
method(obj) {
|
||||||
|
obj["x"] = Math.pow(obj["x"], 2);
|
||||||
|
obj["y"] = Math.pow(obj["y"], 3);
|
||||||
|
obj.#p **= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue