@@ -22,31 +22,29 @@ use oxc_traverse::{BoundIdentifier, TraverseCtx};
22
22
/// is unfortunately rather complicated.
23
23
///
24
24
/// Transpiled private fields referring to a static private prop use:
25
- /// * Class name when field is within class body and class has a name
26
- /// e.g. `class C { static #x; method() { return obj.#x; } }`
27
- /// * Temp var when field is within class body and class has no name
28
- /// e.g. `C = class { static #x; method() { return obj.#x; } }`
29
- /// * Temp var when field is within a static prop initializer.
30
- /// e.g. `class C { static #x; y = obj.#x; }`
31
- ///
32
- /// To cover all these cases, the meaning of `temp` binding here changes while traversing the class body.
33
- /// [`ClassProperties::transform_class_declaration`] sets `temp` binding to be a copy of the
34
- /// `name` binding before that traversal begins. So the name `temp` is misleading at that point.
35
25
///
36
- /// Debug assertions are used to make sure this complex logic is correct.
26
+ /// * Class name when field is within body of class declaration
27
+ /// e.g. `class C { static #x; method() { return obj.#x; } }`
28
+ /// -> `_assertClassBrand(C, obj, _x)._`
29
+ /// * Temp var when field is within body of class expression
30
+ /// e.g. `C = class C { static #x; method() { return obj.#x; } }`
31
+ /// -> `_assertClassBrand(_C, obj, _x)._`
32
+ /// * Temp var when field is within a static prop initializer
33
+ /// e.g. `class C { static #x; static y = obj.#x; }`
34
+ /// -> `_assertClassBrand(_C, obj, _x)._`
37
35
///
38
- /// [`ClassProperties::transform_class_declaration`]: super::ClassProperties::transform_class_declaration
36
+ /// `static_private_fields_use_temp` is updated as transform moves through the class,
37
+ /// to indicate which binding to use.
39
38
#[ derive( Default , Clone ) ]
40
39
pub ( super ) struct ClassBindings < ' a > {
41
40
/// Binding for class name, if class has name
42
41
pub name : Option < BoundIdentifier < ' a > > ,
43
42
/// Temp var for class.
44
43
/// e.g. `_Class` in `_Class = class {}, _Class.x = 1, _Class`
45
44
pub temp : Option < BoundIdentifier < ' a > > ,
46
- /// `true` if currently transforming static property initializers.
47
- /// Only used in debug builds to check logic is correct.
48
- #[ cfg( debug_assertions) ]
49
- pub currently_transforming_static_property_initializers : bool ,
45
+ /// `true` if should use temp binding for references to class in transpiled static private fields,
46
+ /// `false` if can use name binding
47
+ pub static_private_fields_use_temp : bool ,
50
48
}
51
49
52
50
impl < ' a > ClassBindings < ' a > {
@@ -55,37 +53,43 @@ impl<'a> ClassBindings<'a> {
55
53
name_binding : Option < BoundIdentifier < ' a > > ,
56
54
temp_binding : Option < BoundIdentifier < ' a > > ,
57
55
) -> Self {
58
- Self {
59
- name : name_binding,
60
- temp : temp_binding,
61
- #[ cfg( debug_assertions) ]
62
- currently_transforming_static_property_initializers : false ,
63
- }
56
+ Self { name : name_binding, temp : temp_binding, static_private_fields_use_temp : true }
64
57
}
65
58
66
59
/// Get `SymbolId` of name binding.
67
60
pub fn name_symbol_id ( & self ) -> Option < SymbolId > {
68
61
self . name . as_ref ( ) . map ( |binding| binding. symbol_id )
69
62
}
70
63
71
- /// Create a binding for temp var, if there isn't one already.
72
- pub fn get_or_init_temp_binding ( & mut self , ctx : & mut TraverseCtx < ' a > ) -> & BoundIdentifier < ' a > {
73
- if self . temp . is_none ( ) {
74
- // This should only be possible if we are currently transforming static prop initializers
75
- #[ cfg( debug_assertions) ]
76
- {
77
- assert ! (
78
- self . currently_transforming_static_property_initializers,
79
- "Should be unreachable"
80
- ) ;
81
- }
82
-
83
- self . temp = Some ( Self :: create_temp_binding ( self . name . as_ref ( ) , ctx) ) ;
64
+ /// Get binding to use for referring to class in transpiled static private fields.
65
+ ///
66
+ /// e.g. `Class` in `_assertClassBrand(Class, object, _prop)._` (class name)
67
+ /// or `_Class` in `_assertClassBrand(_Class, object, _prop)._` (temp var)
68
+ ///
69
+ /// * In class expressions, this is always be temp binding.
70
+ /// * In class declarations, it's the name binding when code is inside class body,
71
+ /// and temp binding when code is outside class body.
72
+ ///
73
+ /// `static_private_fields_use_temp` is set accordingly at the right moments
74
+ /// elsewhere in this transform.
75
+ ///
76
+ /// If a temp binding is required, and one doesn't already exist, a temp binding is created.
77
+ pub fn get_or_init_static_binding (
78
+ & mut self ,
79
+ ctx : & mut TraverseCtx < ' a > ,
80
+ ) -> & BoundIdentifier < ' a > {
81
+ if self . static_private_fields_use_temp {
82
+ // Create temp binding if doesn't already exist
83
+ self . temp . get_or_insert_with ( || Self :: create_temp_binding ( self . name . as_ref ( ) , ctx) )
84
+ } else {
85
+ // `static_private_fields_use_temp` is always `true` for class expressions.
86
+ // Class declarations always have a name binding if they have any static props.
87
+ // So `unwrap` here cannot panic.
88
+ self . name . as_ref ( ) . unwrap ( )
84
89
}
85
- self . temp . as_ref ( ) . unwrap ( )
86
90
}
87
91
88
- /// Generate a binding for temp var.
92
+ /// Generate binding for temp var.
89
93
pub fn create_temp_binding (
90
94
name_binding : Option < & BoundIdentifier < ' a > > ,
91
95
ctx : & mut TraverseCtx < ' a > ,
0 commit comments