From 45f8cc018d2a0eb40f878bb8ae9a93ece394ccf6 Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Thu, 17 Apr 2025 10:15:33 +0000 Subject: [PATCH] fix(transformer/class-properties): `private_field_count` is incorrect when class only have `accessor` with private field (#10463) ```ts abstract class Foo { accessor prop: number = 1; static accessor prop2: number = 1; accessor #prop3: number = 1; accessor [prop4]: number = 1; private accessor prop5: number = 1; abstract accessor prop6: number; } ``` This case only has a `#prop3` private field with an accessor. Since we haven't supported transforming `accessor` yet, the `class_details.is_transform_required` is always `false` in this `class`, which caused the `private_field_count` to be incorrect. Moving the decremental part to the `pop` side so that we can make sure the `private_props_prop` can always be handled correctly. --- .../src/es2022/class_properties/class.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/crates/oxc_transformer/src/es2022/class_properties/class.rs b/crates/oxc_transformer/src/es2022/class_properties/class.rs index 7265cf37e7271..54c7051351759 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/class.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/class.rs @@ -1,7 +1,7 @@ //! ES2022: Class Properties //! Transform of class itself. -use indexmap::map::Entry; +use indexmap::{IndexMap, map::Entry}; use oxc_allocator::{Address, GetAddress, TakeIn}; use oxc_ast::{NONE, ast::*}; use oxc_span::SPAN; @@ -385,12 +385,11 @@ impl<'a> ClassProperties<'a, '_> { if class_details.is_transform_required { self.transform_class_declaration_on_exit_impl(class, ctx); } else { - // Note: `is_transform_required` is `true` if class has any private properties/methods, - // so no need to touch `private_field_count` here debug_assert!(class_details.bindings.temp.is_none()); } // Pop off stack. We're done! - self.classes_stack.pop(); + let class_details = self.classes_stack.pop(); + self.private_field_count -= class_details.private_props.as_ref().map_or(0, IndexMap::len); } fn transform_class_declaration_on_exit_impl( @@ -447,8 +446,6 @@ impl<'a> ClassProperties<'a, '_> { } if let Some(private_props) = &class_details.private_props { - self.private_field_count -= private_props.len(); - if self.private_fields_as_properties { let mut private_props = private_props .iter() @@ -539,13 +536,12 @@ impl<'a> ClassProperties<'a, '_> { if class_details.is_transform_required { self.transform_class_expression_on_exit_impl(expr, ctx); } else { - // Note: `is_transform_required` is `true` if class has any private properties/methods, - // so no need to touch `private_field_count` here debug_assert!(class_details.bindings.temp.is_none()); } // Pop off stack. We're done! - self.classes_stack.pop(); + let class_details = self.classes_stack.pop(); + self.private_field_count -= class_details.private_props.as_ref().map_or(0, IndexMap::len); } fn transform_class_expression_on_exit_impl( @@ -595,8 +591,6 @@ impl<'a> ClassProperties<'a, '_> { // Babel has these always go first, regardless of order of class elements. // Also insert `var _prop;` temp var declarations for private static props. if let Some(private_props) = &class_details.private_props { - self.private_field_count -= private_props.len(); - // Insert `var _prop;` declarations here rather than when binding was created to maintain // same order of `var` declarations as Babel. // `c = class C { #x = 1; static y = 2; }` -> `var _C, _x;`