1+ use std:: cell:: RefCell ;
2+
13use oxc:: {
2- allocator:: { self , Allocator } ,
4+ allocator,
35 ast:: {
46 NONE ,
57 ast:: {
6- Class , ClassBody , ClassElement , ClassType , MethodDefinition , MethodDefinitionKind ,
7- PropertyDefinitionType , PropertyKind , StaticBlock ,
8+ Class , ClassBody , ClassElement , ClassType , MethodDefinitionKind , PropertyDefinitionType ,
9+ PropertyKind , StaticBlock ,
810 } ,
911 } ,
1012 span:: GetSpan ,
@@ -16,35 +18,30 @@ use crate::{
1618 dep:: DepAtom ,
1719 entity:: Entity ,
1820 transformer:: Transformer ,
19- utils:: { CalleeNode , DefaultIn } ,
21+ utils:: { CalleeNode , ClassData } ,
2022 value:: { ObjectPrototype , cache:: FnCacheTrackingData , call:: FnCallInfo } ,
2123} ;
2224
23- struct Data < ' a > {
24- pub value : Option < Entity < ' a > > ,
25- pub constructor : Option < & ' a MethodDefinition < ' a > > ,
26- pub keys : allocator:: Vec < ' a , Option < Entity < ' a > > > ,
27- pub super_class : Option < Entity < ' a > > ,
28- }
29-
30- impl < ' a > DefaultIn < ' a > for Data < ' a > {
31- fn default_in ( allocator : & ' a Allocator ) -> Self {
32- Data {
33- value : None ,
25+ impl < ' a > Analyzer < ' a > {
26+ pub fn exec_class ( & mut self , node : & ' a Class < ' a > ) -> Entity < ' a > {
27+ let data_cell = self . allocator . alloc ( RefCell :: new ( ClassData {
28+ initializing : true ,
29+ included : false ,
3430 constructor : None ,
35- keys : allocator :: Vec :: new_in ( allocator ) ,
31+ keys : self . factory . vec ( ) ,
3632 super_class : None ,
37- }
38- }
39- }
33+ } ) ) ;
4034
41- impl < ' a > Analyzer < ' a > {
42- pub fn exec_class ( & mut self , node : & ' a Class < ' a > ) -> Entity < ' a > {
43- let data = self . load_data :: < Data > ( AstKind2 :: Class ( node ) ) ;
44- let ( class , prototype ) = self . new_function_with_prototype ( CalleeNode :: ClassConstructor ( node ) ) ;
35+ let ( class , prototype ) = self . new_function ( CalleeNode :: ClassConstructor ( node , data_cell ) , true ) ;
36+ let prototype = prototype . unwrap ( ) ;
37+ let mut data = data_cell . borrow_mut ( ) ;
38+ data . initializing = false ;
4539
4640 // 1. Execute super class
47- data. super_class = node. super_class . as_ref ( ) . map ( |node| self . exec_expression ( node) ) ;
41+ data. super_class = node
42+ . super_class
43+ . as_ref ( )
44+ . map ( |node| self . factory . computed ( self . exec_expression ( node) , AstKind2 :: SuperExpr ( node) ) ) ;
4845 if let Some ( super_class) = & data. super_class {
4946 // Because we can't re-define the "prototype" property, this should be side-effect free
5047 if let Some ( ( prototype_dep, super_statics, super_prototype) ) =
@@ -80,6 +77,8 @@ impl<'a> Analyzer<'a> {
8077 data. constructor = Some ( method) ;
8178 }
8279 }
80+ drop ( data) ;
81+ let data = data_cell. borrow ( ) ;
8382
8483 // 3. Register methods
8584 for ( key, element) in data. keys . iter ( ) . zip ( node. body . body . iter ( ) ) {
@@ -155,14 +154,17 @@ impl<'a> Analyzer<'a> {
155154
156155 // 5. Execute class decorators (ES2025 Stage 3)
157156 let class = class. into ( ) ;
158- let final_class = if !node. decorators . is_empty ( ) {
157+ let class = if !node. decorators . is_empty ( ) {
159158 self . exec_decorators ( & node. decorators , class)
160159 } else {
161160 class
162161 } ;
163162
164- data. value = Some ( final_class) ;
165- final_class
163+ if data. included {
164+ self . include ( class) ;
165+ }
166+
167+ class
166168 }
167169
168170 pub fn declare_class ( & mut self , node : & ' a Class < ' a > , exporting : Option < DepAtom > ) {
@@ -180,10 +182,18 @@ impl<'a> Analyzer<'a> {
180182 pub fn call_class_constructor (
181183 & mut self ,
182184 node : & ' a Class < ' a > ,
185+ data_cell : & RefCell < ClassData < ' a > > ,
183186 info : FnCallInfo < ' a > ,
184187 ) -> ( Entity < ' a > , FnCacheTrackingData < ' a > ) {
188+ let data = data_cell. borrow ( ) ;
189+ if info. include && data. initializing {
190+ drop ( data) ;
191+ let mut data = data_cell. borrow_mut ( ) ;
192+ data. included = true ;
193+ return ( self . factory . undefined , FnCacheTrackingData :: worst_case ( ) ) ;
194+ }
195+
185196 let factory = self . factory ;
186- let data = self . load_data :: < Data > ( AstKind2 :: Class ( node) ) ;
187197
188198 self . push_call_scope ( info, false , false ) ;
189199 let super_class = data. super_class . unwrap_or ( self . factory . undefined ) ;
@@ -195,7 +205,11 @@ impl<'a> Analyzer<'a> {
195205
196206 if let Some ( id) = & node. id {
197207 self . declare_binding_identifier ( id, None , DeclarationKind :: NamedFunctionInBody ) ;
198- self . init_binding_identifier ( id, DeclarationKind :: NamedFunctionInBody , data. value ) ;
208+ self . init_binding_identifier (
209+ id,
210+ DeclarationKind :: NamedFunctionInBody ,
211+ Some ( info. func . into ( ) ) ,
212+ ) ;
199213 }
200214
201215 // 1. Init properties
@@ -256,8 +270,11 @@ impl<'a> Transformer<'a> {
256270 transformed_id
257271 } ;
258272
259- let super_class = super_class. as_ref ( ) . and_then ( |node| self . transform_expression ( node, true ) ) ;
273+ let super_class = super_class. as_ref ( ) . and_then ( |node| {
274+ self . transform_expression ( node, self . is_included ( AstKind2 :: SuperExpr ( node) ) )
275+ } ) ;
260276
277+ self . has_super_class . borrow_mut ( ) . push ( super_class. is_some ( ) ) ;
261278 let body = {
262279 let ClassBody { span, body } = body. as_ref ( ) ;
263280
@@ -298,6 +315,7 @@ impl<'a> Transformer<'a> {
298315
299316 self . ast . class_body ( * span, transformed_body)
300317 } ;
318+ self . has_super_class . borrow_mut ( ) . pop ( ) ;
301319
302320 let decorators = self . transform_decorators ( & node. decorators ) ;
303321
@@ -335,6 +353,7 @@ impl<'a> Transformer<'a> {
335353 }
336354 }
337355
356+ self . has_super_class . borrow_mut ( ) . push ( false ) ;
338357 for element in & body. body {
339358 match element {
340359 ClassElement :: StaticBlock ( node) => {
@@ -354,6 +373,7 @@ impl<'a> Transformer<'a> {
354373 _ => { }
355374 }
356375 }
376+ self . has_super_class . borrow_mut ( ) . pop ( ) ;
357377
358378 if statements. is_empty ( ) {
359379 None
0 commit comments