89
89
90
90
use compact_str:: CompactString ;
91
91
use indexmap:: IndexMap ;
92
- use rustc_hash:: { FxBuildHasher , FxHashSet } ;
92
+ use rustc_hash:: { FxBuildHasher , FxHashMap , FxHashSet } ;
93
93
94
- use oxc_allocator:: { Box as ArenaBox , Vec as ArenaVec } ;
94
+ use oxc_allocator:: { Address , Box as ArenaBox , GetAddress , Vec as ArenaVec } ;
95
95
use oxc_ast:: { ast:: * , NONE } ;
96
96
use oxc_data_structures:: stack:: { NonEmptyStack , SparseStack } ;
97
97
use oxc_semantic:: { ReferenceFlags , SymbolId } ;
@@ -102,7 +102,7 @@ use oxc_syntax::{
102
102
} ;
103
103
use oxc_traverse:: { Ancestor , BoundIdentifier , Traverse , TraverseCtx } ;
104
104
105
- use crate :: EnvOptions ;
105
+ use crate :: { context :: TransformCtx , EnvOptions } ;
106
106
107
107
type FxIndexMap < K , V > = IndexMap < K , V , FxBuildHasher > ;
108
108
@@ -135,9 +135,12 @@ struct SuperMethodInfo<'a> {
135
135
is_computed : bool ,
136
136
}
137
137
138
- pub struct ArrowFunctionConverter < ' a > {
138
+ pub struct ArrowFunctionConverter < ' a , ' ctx > {
139
+ ctx : & ' ctx TransformCtx < ' a > ,
139
140
mode : ArrowFunctionConverterMode ,
140
141
this_var_stack : SparseStack < BoundIdentifier < ' a > > ,
142
+ /// Stores the address of statement of containing `super()` expression
143
+ super_call_addresses : FxHashMap < ScopeId , Address > ,
141
144
arguments_var_stack : SparseStack < BoundIdentifier < ' a > > ,
142
145
arguments_needs_transform_stack : NonEmptyStack < bool > ,
143
146
renamed_arguments_symbol_ids : FxHashSet < SymbolId > ,
@@ -146,8 +149,8 @@ pub struct ArrowFunctionConverter<'a> {
146
149
super_methods : Option < FxIndexMap < SuperMethodKey < ' a > , SuperMethodInfo < ' a > > > ,
147
150
}
148
151
149
- impl < ' a > ArrowFunctionConverter < ' a > {
150
- pub fn new ( env : & EnvOptions ) -> Self {
152
+ impl < ' a , ' ctx > ArrowFunctionConverter < ' a , ' ctx > {
153
+ pub fn new ( env : & EnvOptions , ctx : & ' ctx TransformCtx < ' a > ) -> Self {
151
154
let mode = if env. es2015 . arrow_function . is_some ( ) {
152
155
ArrowFunctionConverterMode :: Enabled
153
156
} else if env. es2017 . async_to_generator || env. es2018 . async_generator_functions {
@@ -157,8 +160,10 @@ impl<'a> ArrowFunctionConverter<'a> {
157
160
} ;
158
161
// `SparseStack`s are created with 1 empty entry, for `Program`
159
162
Self {
163
+ ctx,
160
164
mode,
161
165
this_var_stack : SparseStack :: new ( ) ,
166
+ super_call_addresses : FxHashMap :: default ( ) ,
162
167
arguments_var_stack : SparseStack :: new ( ) ,
163
168
arguments_needs_transform_stack : NonEmptyStack :: new ( false ) ,
164
169
renamed_arguments_symbol_ids : FxHashSet :: default ( ) ,
@@ -167,7 +172,7 @@ impl<'a> ArrowFunctionConverter<'a> {
167
172
}
168
173
}
169
174
170
- impl < ' a > Traverse < ' a > for ArrowFunctionConverter < ' a > {
175
+ impl < ' a , ' ctx > Traverse < ' a > for ArrowFunctionConverter < ' a , ' ctx > {
171
176
// Note: No visitors for `TSModuleBlock` because `this` is not legal in TS module blocks.
172
177
// <https://www.typescriptlang.org/play/?#code/HYQwtgpgzgDiDGEAEAxA9mpBvAsAKCSXjWCgBckANJAXiQAoBKWgPiTIAsBLKAbnwC++fGDQATAK4AbZACEQAJ2z5CxUhWp0mrdtz6D8QA>
173
178
@@ -397,7 +402,7 @@ impl<'a> Traverse<'a> for ArrowFunctionConverter<'a> {
397
402
}
398
403
}
399
404
400
- impl < ' a > ArrowFunctionConverter < ' a > {
405
+ impl < ' a , ' ctx > ArrowFunctionConverter < ' a , ' ctx > {
401
406
/// Check if arrow function conversion is disabled
402
407
fn is_disabled ( & self ) -> bool {
403
408
self . mode == ArrowFunctionConverterMode :: Disabled
@@ -436,6 +441,26 @@ impl<'a> ArrowFunctionConverter<'a> {
436
441
. unwrap ( ) ;
437
442
ctx. generate_uid ( "this" , target_scope_id, SymbolFlags :: FunctionScopedVariable )
438
443
} ) ;
444
+
445
+ if !self . super_call_addresses . is_empty ( ) {
446
+ let address = ctx
447
+ . scopes ( )
448
+ . get_parent_id ( arrow_scope_id)
449
+ . and_then ( |scope_id| self . super_call_addresses . remove ( & scope_id) ) ;
450
+ if let Some ( address) = address {
451
+ // Insert a dummy address to indicate that should inserting `var _this;`
452
+ // without `init` at the top of the statements.
453
+ self . super_call_addresses . insert ( arrow_scope_id, Address :: DUMMY ) ;
454
+ let assignment = ctx. ast . expression_assignment (
455
+ SPAN ,
456
+ AssignmentOperator :: Assign ,
457
+ this_var. create_write_target ( ctx) ,
458
+ ctx. ast . expression_this ( SPAN ) ,
459
+ ) ;
460
+ let statement = ctx. ast . statement_expression ( SPAN , assignment) ;
461
+ self . ctx . statement_injector . insert_after ( & address, statement) ;
462
+ }
463
+ }
439
464
Some ( ctx. ast . alloc ( this_var. create_spanned_read_reference ( span, ctx) ) )
440
465
}
441
466
@@ -703,6 +728,25 @@ impl<'a> ArrowFunctionConverter<'a> {
703
728
ctx : & mut TraverseCtx < ' a > ,
704
729
) -> Option < Expression < ' a > > {
705
730
if self . super_methods . is_none ( ) || !call. callee . is_member_expression ( ) {
731
+ // `super()`
732
+ // Store the address in case we need to insert `var _this;` after it.
733
+ if call. callee . is_super ( ) {
734
+ let scope_id = ctx. current_scope_id ( ) ;
735
+ self . super_call_addresses . entry ( scope_id) . or_insert_with ( || {
736
+ ctx. ancestors ( )
737
+ . find ( |ancestor| {
738
+ matches ! (
739
+ ancestor,
740
+ // const A = super():
741
+ Ancestor :: VariableDeclarationDeclarations ( _)
742
+ // super();
743
+ | Ancestor :: ExpressionStatementExpression ( _)
744
+ )
745
+ } )
746
+ . unwrap ( )
747
+ . address ( )
748
+ } ) ;
749
+ }
706
750
return None ;
707
751
}
708
752
@@ -1070,12 +1114,19 @@ impl<'a> ArrowFunctionConverter<'a> {
1070
1114
1071
1115
// `_this = this;`
1072
1116
if let Some ( this_var) = this_var {
1117
+ let init = if self . super_call_addresses . is_empty ( ) {
1118
+ Some ( ctx. ast . expression_this ( SPAN ) )
1119
+ } else {
1120
+ // Clear the dummy address.
1121
+ self . super_call_addresses . clear ( ) ;
1122
+ None
1123
+ } ;
1073
1124
Self :: adjust_binding_scope ( target_scope_id, & this_var, ctx) ;
1074
1125
let variable_declarator = ctx. ast . variable_declarator (
1075
1126
SPAN ,
1076
1127
VariableDeclarationKind :: Var ,
1077
1128
this_var. create_binding_pattern ( ctx) ,
1078
- Some ( ctx . ast . expression_this ( SPAN ) ) ,
1129
+ init ,
1079
1130
false ,
1080
1131
) ;
1081
1132
declarations. push ( variable_declarator) ;
0 commit comments