mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
fix(transformer/class-properties): unwrap failed when private field expression doesn't contain optional expression in ChainExpression (#7798)
The root cause is due to transform wrongly a PrivateFieldExpression that doesn't contain any optional expression, so call `to_member_expression_mut` causes unwrap to fail. I have fixed the incorrect transform and changed `to_member_expression_mut` to `as_member_expression_mut`.
This commit is contained in:
parent
6fa6785d0d
commit
2964a61546
4 changed files with 34 additions and 16 deletions
|
|
@ -959,8 +959,13 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
|
||||||
if matches!(element, ChainElement::PrivateFieldExpression(_)) {
|
if matches!(element, ChainElement::PrivateFieldExpression(_)) {
|
||||||
// The PrivateFieldExpression must be transformed, so we can convert it to a normal expression here.
|
// The PrivateFieldExpression must be transformed, so we can convert it to a normal expression here.
|
||||||
let mut chain_expr = Self::convert_chain_expression_to_expression(expr, ctx);
|
let mut chain_expr = Self::convert_chain_expression_to_expression(expr, ctx);
|
||||||
let result =
|
let result = self
|
||||||
self.transform_private_field_expression_of_chain_expression(&mut chain_expr, ctx);
|
.transform_private_field_expression_of_chain_expression(&mut chain_expr, ctx)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
unreachable!(
|
||||||
|
"The ChainExpression must contains at least one optional expression, so it never be `None` here."
|
||||||
|
)
|
||||||
|
});
|
||||||
Some((result, chain_expr))
|
Some((result, chain_expr))
|
||||||
} else if let Some(result) = self.transform_chain_expression_element(element, ctx) {
|
} else if let Some(result) = self.transform_chain_expression_element(element, ctx) {
|
||||||
let chain_expr = Self::convert_chain_expression_to_expression(expr, ctx);
|
let chain_expr = Self::convert_chain_expression_to_expression(expr, ctx);
|
||||||
|
|
@ -1003,7 +1008,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
|
||||||
) -> Option<Expression<'a>> {
|
) -> Option<Expression<'a>> {
|
||||||
match expr {
|
match expr {
|
||||||
Expression::PrivateFieldExpression(_) => {
|
Expression::PrivateFieldExpression(_) => {
|
||||||
Some(self.transform_private_field_expression_of_chain_expression(expr, ctx))
|
self.transform_private_field_expression_of_chain_expression(expr, ctx)
|
||||||
}
|
}
|
||||||
match_member_expression!(Expression) => self
|
match_member_expression!(Expression) => self
|
||||||
.transform_member_expression_of_chain_expression(
|
.transform_member_expression_of_chain_expression(
|
||||||
|
|
@ -1086,17 +1091,20 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
|
||||||
Some(result)
|
Some(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transform private field expression of chain expression.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the `expr` doesn't contain any optional expression.
|
||||||
fn transform_private_field_expression_of_chain_expression(
|
fn transform_private_field_expression_of_chain_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
expr: &mut Expression<'a>,
|
expr: &mut Expression<'a>,
|
||||||
ctx: &mut TraverseCtx<'a>,
|
ctx: &mut TraverseCtx<'a>,
|
||||||
) -> Expression<'a> {
|
) -> Option<Expression<'a>> {
|
||||||
let Expression::PrivateFieldExpression(field_expr) = expr else { unreachable!() };
|
let Expression::PrivateFieldExpression(field_expr) = expr else { unreachable!() };
|
||||||
|
|
||||||
let is_optional = field_expr.optional;
|
let is_optional = field_expr.optional;
|
||||||
let object = &mut field_expr.object;
|
let object = &mut field_expr.object;
|
||||||
|
|
||||||
let left = if is_optional {
|
let result = if is_optional {
|
||||||
Some(self.transform_expression_to_wrap_nullish_check(object, ctx))
|
Some(self.transform_expression_to_wrap_nullish_check(object, ctx))
|
||||||
} else {
|
} else {
|
||||||
self.transform_first_optional_expression(object, ctx)
|
self.transform_first_optional_expression(object, ctx)
|
||||||
|
|
@ -1110,13 +1118,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
|
||||||
self.transform_private_field_expression(expr, ctx);
|
self.transform_private_field_expression(expr, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
left.unwrap_or_else(|| {
|
result
|
||||||
// `o.Foo.#x?.self` -> `(_babelHelpers$assertC = expr === null || _babelHelpers$assertC === void 0 ?
|
|
||||||
// void 0 : _babelHelpers$assertC?.self;`
|
|
||||||
// `expr` is `o.Foo.#x` that has transformed to `babelHelpers.assertClassBrand(Foo, o.Foo, _x)._)` by
|
|
||||||
// `self.transform_private_field_expression`.
|
|
||||||
self.transform_expression_to_wrap_nullish_check(expr, ctx)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_member_expression_of_chain_expression(
|
fn transform_member_expression_of_chain_expression(
|
||||||
|
|
@ -1145,6 +1147,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
|
||||||
ctx: &mut TraverseCtx<'a>,
|
ctx: &mut TraverseCtx<'a>,
|
||||||
) -> Option<Expression<'a>> {
|
) -> Option<Expression<'a>> {
|
||||||
let is_optional = call_expr.optional;
|
let is_optional = call_expr.optional;
|
||||||
|
|
||||||
let callee = call_expr.callee.get_inner_expression_mut();
|
let callee = call_expr.callee.get_inner_expression_mut();
|
||||||
if matches!(callee, Expression::PrivateFieldExpression(_)) {
|
if matches!(callee, Expression::PrivateFieldExpression(_)) {
|
||||||
let result = self.transform_first_optional_expression(callee, ctx);
|
let result = self.transform_first_optional_expression(callee, ctx);
|
||||||
|
|
@ -1157,9 +1160,8 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = self.transform_chain_element_recursively(callee, ctx)?;
|
|
||||||
if !is_optional {
|
if !is_optional {
|
||||||
return Some(result);
|
return self.transform_chain_element_recursively(callee, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// `o?.Foo.#self.getSelf?.()?.self.#m();`
|
// `o?.Foo.#self.getSelf?.()?.self.#m();`
|
||||||
|
|
@ -1168,6 +1170,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
|
||||||
// then use it as a first argument of `getSelf` call.
|
// then use it as a first argument of `getSelf` call.
|
||||||
//
|
//
|
||||||
// TODO(improve-on-babel): Consider remove this logic, because it seems no runtime behavior change.
|
// TODO(improve-on-babel): Consider remove this logic, because it seems no runtime behavior change.
|
||||||
|
let result = self.transform_chain_element_recursively(callee, ctx)?;
|
||||||
let object = callee.to_member_expression_mut().object_mut();
|
let object = callee.to_member_expression_mut().object_mut();
|
||||||
let (assignment, context) = self.duplicate_object(ctx.ast.move_expression(object), ctx);
|
let (assignment, context) = self.duplicate_object(ctx.ast.move_expression(object), ctx);
|
||||||
*object = assignment;
|
*object = assignment;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
commit: 54a8389f
|
commit: 54a8389f
|
||||||
|
|
||||||
Passed: 106/120
|
Passed: 107/121
|
||||||
|
|
||||||
# All Passed:
|
# All Passed:
|
||||||
* babel-plugin-transform-class-static-block
|
* babel-plugin-transform-class-static-block
|
||||||
|
|
@ -16,7 +16,7 @@ Passed: 106/120
|
||||||
* regexp
|
* regexp
|
||||||
|
|
||||||
|
|
||||||
# babel-plugin-transform-class-properties (7/10)
|
# babel-plugin-transform-class-properties (8/11)
|
||||||
* private-loose-tagged-template/input.js
|
* private-loose-tagged-template/input.js
|
||||||
Scope children mismatch:
|
Scope children mismatch:
|
||||||
after transform: ScopeId(1): [ScopeId(2), ScopeId(3), ScopeId(4)]
|
after transform: ScopeId(1): [ScopeId(2), ScopeId(3), ScopeId(4)]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
class A {
|
||||||
|
#a = {};
|
||||||
|
method() {
|
||||||
|
this.#a.get(message.id)?.(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
var _a = /*#__PURE__*/ new WeakMap();
|
||||||
|
class A {
|
||||||
|
constructor() {
|
||||||
|
babelHelpers.classPrivateFieldInitSpec(this, _a, {});
|
||||||
|
}
|
||||||
|
method() {
|
||||||
|
babelHelpers.classPrivateFieldGet2(_a, this).get(message.id)?.(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue