diff --git a/crates/oxc_ast/src/ast/js.rs b/crates/oxc_ast/src/ast/js.rs index e0fc9805fe6ce..1b2185196a627 100644 --- a/crates/oxc_ast/src/ast/js.rs +++ b/crates/oxc_ast/src/ast/js.rs @@ -1941,8 +1941,7 @@ pub struct Class<'a> { /// // ^^^ /// ``` #[ts] - #[estree(via = ClassImplements)] - pub implements: Option>>, + pub implements: Vec<'a, TSClassImplements<'a>>, pub body: Box<'a, ClassBody<'a>>, /// Whether the class is abstract /// diff --git a/crates/oxc_ast/src/generated/ast_builder.rs b/crates/oxc_ast/src/generated/ast_builder.rs index 264a2e965b643..c0f169b669516 100644 --- a/crates/oxc_ast/src/generated/ast_builder.rs +++ b/crates/oxc_ast/src/generated/ast_builder.rs @@ -575,7 +575,7 @@ impl<'a> AstBuilder<'a> { type_parameters: T1, super_class: Option>, super_type_arguments: T2, - implements: Option>>, + implements: Vec<'a, TSClassImplements<'a>>, body: T3, r#abstract: bool, declare: bool, @@ -627,7 +627,7 @@ impl<'a> AstBuilder<'a> { type_parameters: T1, super_class: Option>, super_type_arguments: T2, - implements: Option>>, + implements: Vec<'a, TSClassImplements<'a>>, body: T3, r#abstract: bool, declare: bool, @@ -4001,7 +4001,7 @@ impl<'a> AstBuilder<'a> { type_parameters: T1, super_class: Option>, super_type_arguments: T2, - implements: Option>>, + implements: Vec<'a, TSClassImplements<'a>>, body: T3, r#abstract: bool, declare: bool, @@ -4053,7 +4053,7 @@ impl<'a> AstBuilder<'a> { type_parameters: T1, super_class: Option>, super_type_arguments: T2, - implements: Option>>, + implements: Vec<'a, TSClassImplements<'a>>, body: T3, r#abstract: bool, declare: bool, @@ -6316,7 +6316,7 @@ impl<'a> AstBuilder<'a> { type_parameters: T1, super_class: Option>, super_type_arguments: T2, - implements: Option>>, + implements: Vec<'a, TSClassImplements<'a>>, body: T3, r#abstract: bool, declare: bool, @@ -6369,7 +6369,7 @@ impl<'a> AstBuilder<'a> { type_parameters: T1, super_class: Option>, super_type_arguments: T2, - implements: Option>>, + implements: Vec<'a, TSClassImplements<'a>>, body: T3, r#abstract: bool, declare: bool, @@ -6425,7 +6425,7 @@ impl<'a> AstBuilder<'a> { type_parameters: T1, super_class: Option>, super_type_arguments: T2, - implements: Option>>, + implements: Vec<'a, TSClassImplements<'a>>, body: T3, r#abstract: bool, declare: bool, @@ -6480,7 +6480,7 @@ impl<'a> AstBuilder<'a> { type_parameters: T1, super_class: Option>, super_type_arguments: T2, - implements: Option>>, + implements: Vec<'a, TSClassImplements<'a>>, body: T3, r#abstract: bool, declare: bool, @@ -8070,7 +8070,7 @@ impl<'a> AstBuilder<'a> { type_parameters: T1, super_class: Option>, super_type_arguments: T2, - implements: Option>>, + implements: Vec<'a, TSClassImplements<'a>>, body: T3, r#abstract: bool, declare: bool, @@ -8122,7 +8122,7 @@ impl<'a> AstBuilder<'a> { type_parameters: T1, super_class: Option>, super_type_arguments: T2, - implements: Option>>, + implements: Vec<'a, TSClassImplements<'a>>, body: T3, r#abstract: bool, declare: bool, diff --git a/crates/oxc_ast/src/generated/derive_estree.rs b/crates/oxc_ast/src/generated/derive_estree.rs index db76720626839..185789480182a 100644 --- a/crates/oxc_ast/src/generated/derive_estree.rs +++ b/crates/oxc_ast/src/generated/derive_estree.rs @@ -1463,7 +1463,7 @@ impl ESTree for Class<'_> { state.serialize_ts_field("decorators", &self.decorators); state.serialize_ts_field("typeParameters", &self.type_parameters); state.serialize_ts_field("superTypeArguments", &self.super_type_arguments); - state.serialize_ts_field("implements", &crate::serialize::ClassImplements(self)); + state.serialize_ts_field("implements", &self.implements); state.serialize_ts_field("abstract", &self.r#abstract); state.serialize_ts_field("declare", &self.declare); state.end(); diff --git a/crates/oxc_ast/src/serialize.rs b/crates/oxc_ast/src/serialize.rs index efdc7ac605388..fd864288d8623 100644 --- a/crates/oxc_ast/src/serialize.rs +++ b/crates/oxc_ast/src/serialize.rs @@ -987,30 +987,6 @@ impl ESTree for ExpressionStatementDirective<'_, '_> { } } -/// Serializer for `implements` field of `Class`. -/// -/// This field is only used in TS AST. -/// `None` is serialized as empty array (`[]`). -#[ast_meta] -#[estree( - ts_type = "Array", - raw_deser = " - const classImplements = DESER[Option>](POS_OFFSET.implements); - classImplements === null ? [] : classImplements - " -)] -pub struct ClassImplements<'a, 'b>(pub &'b Class<'a>); - -impl ESTree for ClassImplements<'_, '_> { - fn serialize(&self, serializer: S) { - if let Some(implements) = &self.0.implements { - implements.serialize(serializer); - } else { - [(); 0].serialize(serializer); - } - } -} - /// Serializer for `global` field of `TSModuleDeclaration`. #[ast_meta] #[estree(ts_type = "boolean", raw_deser = "THIS.kind === 'global'")] diff --git a/crates/oxc_ast_visit/src/generated/visit.rs b/crates/oxc_ast_visit/src/generated/visit.rs index 81d0af809810e..37b39814a08f8 100644 --- a/crates/oxc_ast_visit/src/generated/visit.rs +++ b/crates/oxc_ast_visit/src/generated/visit.rs @@ -2551,9 +2551,7 @@ pub mod walk { if let Some(super_type_arguments) = &it.super_type_arguments { visitor.visit_ts_type_parameter_instantiation(super_type_arguments); } - if let Some(implements) = &it.implements { - visitor.visit_ts_class_implementses(implements); - } + visitor.visit_ts_class_implementses(&it.implements); visitor.visit_class_body(&it.body); visitor.leave_scope(); visitor.leave_node(kind); diff --git a/crates/oxc_ast_visit/src/generated/visit_mut.rs b/crates/oxc_ast_visit/src/generated/visit_mut.rs index 069b12c969bf7..bbbac565a8698 100644 --- a/crates/oxc_ast_visit/src/generated/visit_mut.rs +++ b/crates/oxc_ast_visit/src/generated/visit_mut.rs @@ -2637,9 +2637,7 @@ pub mod walk_mut { if let Some(super_type_arguments) = &mut it.super_type_arguments { visitor.visit_ts_type_parameter_instantiation(super_type_arguments); } - if let Some(implements) = &mut it.implements { - visitor.visit_ts_class_implementses(implements); - } + visitor.visit_ts_class_implementses(&mut it.implements); visitor.visit_class_body(&mut it.body); visitor.leave_scope(); visitor.leave_node(kind); diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index ab03eae65b628..2e79e582b3ebd 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -2341,9 +2341,9 @@ impl Gen for Class<'_> { super_type_parameters.print(p, ctx); } } - if let Some(implements) = self.implements.as_ref() { + if !self.implements.is_empty() { p.print_str(" implements "); - p.print_list(implements, ctx); + p.print_list(&self.implements, ctx); } p.print_soft_space(); self.body.print(p, ctx); diff --git a/crates/oxc_parser/src/js/class.rs b/crates/oxc_parser/src/js/class.rs index 87042d5365a76..f40b759ff611c 100644 --- a/crates/oxc_parser/src/js/class.rs +++ b/crates/oxc_parser/src/js/class.rs @@ -13,8 +13,6 @@ use crate::{ type Extends<'a> = Vec<'a, (Expression<'a>, Option>>, Span)>; -type Implements<'a> = Vec<'a, TSClassImplements<'a>>; - /// Section 15.7 Class Definitions impl<'a> ParserImpl<'a> { // `start_span` points at the start of all decoractors and `class` keyword. @@ -110,9 +108,9 @@ impl<'a> ParserImpl<'a> { pub(crate) fn parse_heritage_clause( &mut self, - ) -> Result<(Option>, Option>)> { + ) -> Result<(Option>, Vec<'a, TSClassImplements<'a>>)> { let mut extends = None; - let mut implements = None; + let mut implements = self.ast.vec(); loop { match self.cur_kind() { @@ -121,7 +119,7 @@ impl<'a> ParserImpl<'a> { self.error(diagnostics::extends_clause_already_seen( self.cur_token().span(), )); - } else if implements.is_some() { + } else if !implements.is_empty() { self.error(diagnostics::extends_clause_must_precede_implements( self.cur_token().span(), )); @@ -129,12 +127,12 @@ impl<'a> ParserImpl<'a> { extends = Some(self.parse_extends_clause()?); } Kind::Implements => { - if implements.is_some() { + if !implements.is_empty() { self.error(diagnostics::implements_clause_already_seen( self.cur_token().span(), )); } - implements = Some(self.parse_ts_implements_clause()?); + implements.extend(self.parse_ts_implements_clause()?); } _ => break, } diff --git a/crates/oxc_parser/src/ts/types.rs b/crates/oxc_parser/src/ts/types.rs index e5dbda4b486c2..b99f2dc5c80b2 100644 --- a/crates/oxc_parser/src/ts/types.rs +++ b/crates/oxc_parser/src/ts/types.rs @@ -157,13 +157,10 @@ impl<'a> ParserImpl<'a> { pub(crate) fn parse_ts_implements_clause(&mut self) -> Result>> { self.expect(Kind::Implements)?; let first = self.parse_ts_implement_name()?; - let mut implements = self.ast.vec(); - implements.push(first); - + let mut implements = self.ast.vec1(first); while self.eat(Kind::Comma) { implements.push(self.parse_ts_implement_name()?); } - Ok(implements) } diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 4f6fa9dbf162a..8dae18428c384 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -707,9 +707,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { if let Some(super_type_parameters) = &class.super_type_arguments { self.visit_ts_type_parameter_instantiation(super_type_parameters); } - if let Some(implements) = &class.implements { - self.visit_ts_class_implementses(implements); - } + self.visit_ts_class_implementses(&class.implements); self.visit_class_body(&class.body); self.leave_scope(); diff --git a/crates/oxc_transformer/src/typescript/annotations.rs b/crates/oxc_transformer/src/typescript/annotations.rs index 42242c9b9dc7b..1cbe9264a8171 100644 --- a/crates/oxc_transformer/src/typescript/annotations.rs +++ b/crates/oxc_transformer/src/typescript/annotations.rs @@ -215,7 +215,7 @@ impl<'a> Traverse<'a> for TypeScriptAnnotations<'a, '_> { fn enter_class(&mut self, class: &mut Class<'a>, _ctx: &mut TraverseCtx<'a>) { class.type_parameters = None; class.super_type_arguments = None; - class.implements = None; + class.implements.clear(); class.r#abstract = false; } diff --git a/crates/oxc_traverse/src/generated/ancestor.rs b/crates/oxc_traverse/src/generated/ancestor.rs index d4efb745090de..4ac4df003f231 100644 --- a/crates/oxc_traverse/src/generated/ancestor.rs +++ b/crates/oxc_traverse/src/generated/ancestor.rs @@ -7769,10 +7769,10 @@ impl<'a, 't> ClassWithoutDecorators<'a, 't> { } #[inline] - pub fn implements(self) -> &'t Option>> { + pub fn implements(self) -> &'t Vec<'a, TSClassImplements<'a>> { unsafe { &*((self.0 as *const u8).add(OFFSET_CLASS_IMPLEMENTS) - as *const Option>>) + as *const Vec<'a, TSClassImplements<'a>>) } } @@ -7852,10 +7852,10 @@ impl<'a, 't> ClassWithoutId<'a, 't> { } #[inline] - pub fn implements(self) -> &'t Option>> { + pub fn implements(self) -> &'t Vec<'a, TSClassImplements<'a>> { unsafe { &*((self.0 as *const u8).add(OFFSET_CLASS_IMPLEMENTS) - as *const Option>>) + as *const Vec<'a, TSClassImplements<'a>>) } } @@ -7937,10 +7937,10 @@ impl<'a, 't> ClassWithoutTypeParameters<'a, 't> { } #[inline] - pub fn implements(self) -> &'t Option>> { + pub fn implements(self) -> &'t Vec<'a, TSClassImplements<'a>> { unsafe { &*((self.0 as *const u8).add(OFFSET_CLASS_IMPLEMENTS) - as *const Option>>) + as *const Vec<'a, TSClassImplements<'a>>) } } @@ -8023,10 +8023,10 @@ impl<'a, 't> ClassWithoutSuperClass<'a, 't> { } #[inline] - pub fn implements(self) -> &'t Option>> { + pub fn implements(self) -> &'t Vec<'a, TSClassImplements<'a>> { unsafe { &*((self.0 as *const u8).add(OFFSET_CLASS_IMPLEMENTS) - as *const Option>>) + as *const Vec<'a, TSClassImplements<'a>>) } } @@ -8108,10 +8108,10 @@ impl<'a, 't> ClassWithoutSuperTypeArguments<'a, 't> { } #[inline] - pub fn implements(self) -> &'t Option>> { + pub fn implements(self) -> &'t Vec<'a, TSClassImplements<'a>> { unsafe { &*((self.0 as *const u8).add(OFFSET_CLASS_IMPLEMENTS) - as *const Option>>) + as *const Vec<'a, TSClassImplements<'a>>) } } @@ -8283,10 +8283,10 @@ impl<'a, 't> ClassWithoutBody<'a, 't> { } #[inline] - pub fn implements(self) -> &'t Option>> { + pub fn implements(self) -> &'t Vec<'a, TSClassImplements<'a>> { unsafe { &*((self.0 as *const u8).add(OFFSET_CLASS_IMPLEMENTS) - as *const Option>>) + as *const Vec<'a, TSClassImplements<'a>>) } } diff --git a/crates/oxc_traverse/src/generated/walk.rs b/crates/oxc_traverse/src/generated/walk.rs index dc5ca6d096ea0..4e08aa2d7fe8a 100644 --- a/crates/oxc_traverse/src/generated/walk.rs +++ b/crates/oxc_traverse/src/generated/walk.rs @@ -2509,13 +2509,11 @@ unsafe fn walk_class<'a, Tr: Traverse<'a>>( ctx.retag_stack(AncestorType::ClassSuperTypeArguments); walk_ts_type_parameter_instantiation(traverser, (&mut **field) as *mut _, ctx); } - if let Some(field) = &mut *((node as *mut u8).add(ancestor::OFFSET_CLASS_IMPLEMENTS) - as *mut Option>) + ctx.retag_stack(AncestorType::ClassImplements); + for item in &mut *((node as *mut u8).add(ancestor::OFFSET_CLASS_IMPLEMENTS) + as *mut Vec) { - ctx.retag_stack(AncestorType::ClassImplements); - for item in field.iter_mut() { - walk_ts_class_implements(traverser, item as *mut _, ctx); - } + walk_ts_class_implements(traverser, item as *mut _, ctx); } ctx.retag_stack(AncestorType::ClassBody); walk_class_body( diff --git a/napi/parser/deserialize-js.js b/napi/parser/deserialize-js.js index 404712ef4fc2b..fab1663c871be 100644 --- a/napi/parser/deserialize-js.js +++ b/napi/parser/deserialize-js.js @@ -4991,11 +4991,6 @@ function deserializeVecTSClassImplements(pos) { return arr; } -function deserializeOptionVecTSClassImplements(pos) { - if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; - return deserializeVecTSClassImplements(pos); -} - function deserializeBoxClassBody(pos) { return deserializeClassBody(uint32[pos >> 2]); } diff --git a/napi/parser/deserialize-ts.js b/napi/parser/deserialize-ts.js index 29abd96ad0c9d..5c678a23e38b9 100644 --- a/napi/parser/deserialize-ts.js +++ b/napi/parser/deserialize-ts.js @@ -884,7 +884,6 @@ function deserializeYieldExpression(pos) { } function deserializeClass(pos) { - const classImplements = deserializeOptionVecTSClassImplements(pos + 112); return { type: deserializeClassType(pos + 8), start: deserializeU32(pos), @@ -895,7 +894,7 @@ function deserializeClass(pos) { decorators: deserializeVecDecorator(pos + 16), typeParameters: deserializeOptionBoxTSTypeParameterDeclaration(pos + 80), superTypeArguments: deserializeOptionBoxTSTypeParameterInstantiation(pos + 104), - implements: classImplements === null ? [] : classImplements, + implements: deserializeVecTSClassImplements(pos + 112), abstract: deserializeBool(pos + 152), declare: deserializeBool(pos + 153), }; @@ -5079,11 +5078,6 @@ function deserializeVecTSClassImplements(pos) { return arr; } -function deserializeOptionVecTSClassImplements(pos) { - if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; - return deserializeVecTSClassImplements(pos); -} - function deserializeBoxClassBody(pos) { return deserializeClassBody(uint32[pos >> 2]); }