Skip to content

Commit b2bfacf

Browse files
committed
fix(transformer/class-properties): unwrap failed when private field expression doesn't contain optional expression in ChainExpression
1 parent 86bc6d2 commit b2bfacf

File tree

4 files changed

+34
-16
lines changed
  • crates/oxc_transformer/src/es2022/class_properties
  • tasks/transform_conformance
    • snapshots
    • tests/babel-plugin-transform-class-properties/test/fixtures/private-optional-call-with-non-optional-callee

4 files changed

+34
-16
lines changed

crates/oxc_transformer/src/es2022/class_properties/private.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -959,8 +959,13 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
959959
if matches!(element, ChainElement::PrivateFieldExpression(_)) {
960960
// The PrivateFieldExpression must be transformed, so we can convert it to a normal expression here.
961961
let mut chain_expr = Self::convert_chain_expression_to_expression(expr, ctx);
962-
let result =
963-
self.transform_private_field_expression_of_chain_expression(&mut chain_expr, ctx);
962+
let result = self
963+
.transform_private_field_expression_of_chain_expression(&mut chain_expr, ctx)
964+
.unwrap_or_else(|| {
965+
unreachable!(
966+
"The ChainExpression must contains at least one optional expression, so it never be `None` here."
967+
)
968+
});
964969
Some((result, chain_expr))
965970
} else if let Some(result) = self.transform_chain_expression_element(element, ctx) {
966971
let chain_expr = Self::convert_chain_expression_to_expression(expr, ctx);
@@ -1003,7 +1008,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
10031008
) -> Option<Expression<'a>> {
10041009
match expr {
10051010
Expression::PrivateFieldExpression(_) => {
1006-
Some(self.transform_private_field_expression_of_chain_expression(expr, ctx))
1011+
self.transform_private_field_expression_of_chain_expression(expr, ctx)
10071012
}
10081013
match_member_expression!(Expression) => self
10091014
.transform_member_expression_of_chain_expression(
@@ -1086,17 +1091,20 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
10861091
Some(result)
10871092
}
10881093

1094+
/// Transform private field expression of chain expression.
1095+
///
1096+
/// Returns `None` if the `expr` doesn't contain any optional expression.
10891097
fn transform_private_field_expression_of_chain_expression(
10901098
&mut self,
10911099
expr: &mut Expression<'a>,
10921100
ctx: &mut TraverseCtx<'a>,
1093-
) -> Expression<'a> {
1101+
) -> Option<Expression<'a>> {
10941102
let Expression::PrivateFieldExpression(field_expr) = expr else { unreachable!() };
10951103

10961104
let is_optional = field_expr.optional;
10971105
let object = &mut field_expr.object;
10981106

1099-
let left = if is_optional {
1107+
let result = if is_optional {
11001108
Some(self.transform_expression_to_wrap_nullish_check(object, ctx))
11011109
} else {
11021110
self.transform_first_optional_expression(object, ctx)
@@ -1110,13 +1118,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
11101118
self.transform_private_field_expression(expr, ctx);
11111119
}
11121120

1113-
left.unwrap_or_else(|| {
1114-
// `o.Foo.#x?.self` -> `(_babelHelpers$assertC = expr === null || _babelHelpers$assertC === void 0 ?
1115-
// void 0 : _babelHelpers$assertC?.self;`
1116-
// `expr` is `o.Foo.#x` that has transformed to `babelHelpers.assertClassBrand(Foo, o.Foo, _x)._)` by
1117-
// `self.transform_private_field_expression`.
1118-
self.transform_expression_to_wrap_nullish_check(expr, ctx)
1119-
})
1121+
result
11201122
}
11211123

11221124
fn transform_member_expression_of_chain_expression(
@@ -1145,6 +1147,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
11451147
ctx: &mut TraverseCtx<'a>,
11461148
) -> Option<Expression<'a>> {
11471149
let is_optional = call_expr.optional;
1150+
11481151
let callee = call_expr.callee.get_inner_expression_mut();
11491152
if matches!(callee, Expression::PrivateFieldExpression(_)) {
11501153
let result = self.transform_first_optional_expression(callee, ctx);
@@ -1157,9 +1160,8 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
11571160
return result;
11581161
}
11591162

1160-
let result = self.transform_chain_element_recursively(callee, ctx)?;
11611163
if !is_optional {
1162-
return Some(result);
1164+
return self.transform_chain_element_recursively(callee, ctx);
11631165
}
11641166

11651167
// `o?.Foo.#self.getSelf?.()?.self.#m();`
@@ -1168,6 +1170,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
11681170
// then use it as a first argument of `getSelf` call.
11691171
//
11701172
// TODO(improve-on-babel): Consider remove this logic, because it seems no runtime behavior change.
1173+
let result = self.transform_chain_element_recursively(callee, ctx)?;
11711174
let object = callee.to_member_expression_mut().object_mut();
11721175
let (assignment, context) = self.duplicate_object(ctx.ast.move_expression(object), ctx);
11731176
*object = assignment;

tasks/transform_conformance/snapshots/oxc.snap.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
commit: 54a8389f
22

3-
Passed: 104/120
3+
Passed: 105/121
44

55
# All Passed:
66
* babel-plugin-transform-class-static-block
@@ -16,7 +16,7 @@ Passed: 104/120
1616
* regexp
1717

1818

19-
# babel-plugin-transform-class-properties (5/10)
19+
# babel-plugin-transform-class-properties (6/11)
2020
* private-loose-tagged-template/input.js
2121
Scope children mismatch:
2222
after transform: ScopeId(1): [ScopeId(2), ScopeId(3), ScopeId(4)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class A {
2+
#a = {};
3+
method() {
4+
this.#a.get(message.id)?.(message);
5+
}
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
var _a = /*#__PURE__*/ new WeakMap();
2+
class A {
3+
constructor() {
4+
babelHelpers.classPrivateFieldInitSpec(this, _a, {});
5+
}
6+
method() {
7+
babelHelpers.classPrivateFieldGet2(_a, this).get(message.id)?.(message);
8+
}
9+
}

0 commit comments

Comments
 (0)