Skip to content

Commit

Permalink
Simplify ClassBindings::get_or_init_temp_binding
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Dec 2, 2024
1 parent 4f9a6cc commit c594277
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 54 deletions.
29 changes: 26 additions & 3 deletions crates/oxc_transformer/src/es2022/class_properties/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
// Insert class + static property assignments + static blocks
let class_expr = ctx.ast.move_expression(expr);
if let Some(binding) = &self.class_bindings.temp {
if !self.temp_var_is_created {
self.ctx.var_declarations.insert_var(binding, None, ctx);
}

// `_Class = class {}`
let assignment = create_assignment(binding, class_expr, ctx);
exprs.push(assignment);
Expand Down Expand Up @@ -207,6 +211,10 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
// Insert `_Class = Class` after class.
// TODO(improve-on-babel): Could just insert `var _Class = Class;` after class,
// rather than separate `var _Class` declaration.
if !self.temp_var_is_created {
self.ctx.var_declarations.insert_var(temp_binding, None, ctx);
}

let class_name = ctx.create_bound_ident_expr(
SPAN,
ident.name.clone(),
Expand All @@ -219,6 +227,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
} else {
// Class must be default export `export default class {}`, as all other class declarations
// always have a name. Set class name.
*ctx.symbols_mut().get_flags_mut(temp_binding.symbol_id) = SymbolFlags::Class;
class.id = Some(temp_binding.create_binding_identifier(ctx));
}
}
Expand Down Expand Up @@ -346,9 +355,23 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
};

// Static prop in class expression or anonymous `export default class {}`
// always requires a temp var. Static prop in class declaration doesn't.
if has_static_prop && (!self.is_declaration || self.class_bindings.name.is_none()) {
self.class_bindings.get_or_init_temp_binding(self.is_declaration, self.ctx, ctx);
// always requires a temp var for class. Static prop in class declaration doesn't.
// TODO(improve-on-babel): Inserting the temp var `var _Class` statement here is only necessary
// to match Babel's output. It'd be simpler just to insert it at the end and get rid of
// `temp_var_is_created` that tracks whether it's done already or not.
let need_temp_var = has_static_prop && (!self.is_declaration || class.id.is_none());
self.temp_var_is_created = need_temp_var;

if need_temp_var {
let temp_binding = self.class_bindings.get_or_init_temp_binding(ctx);
if self.is_declaration && class.id.is_none() {
// Anonymous `export default class {}`, set class name binding to temp var.
// Actual class name will be set to this later.
self.class_bindings.name = Some(temp_binding.clone());
} else {
// Create temp var `var _Class;` statement
self.ctx.var_declarations.insert_var(temp_binding, None, ctx);
}
}

// Add entry to `private_props_stack`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use oxc_syntax::symbol::{SymbolFlags, SymbolId};
use oxc_traverse::{BoundIdentifier, TraverseCtx};

use crate::TransformCtx;

#[derive(Default, Clone)]
pub(super) struct ClassBindings<'a> {
/// Binding for class name, if class has name
Expand All @@ -19,39 +17,13 @@ impl<'a> ClassBindings<'a> {
}

/// Create a binding for temp var, if there isn't one already.
pub fn get_or_init_temp_binding(
&mut self,
is_declaration: bool,
transform_ctx: &TransformCtx<'a>,
ctx: &mut TraverseCtx<'a>,
) -> &BoundIdentifier<'a> {
if self.temp.is_none() {
pub fn get_or_init_temp_binding(&mut self, ctx: &mut TraverseCtx<'a>) -> &BoundIdentifier<'a> {
self.temp.get_or_insert_with(|| {
// Base temp binding name on class name, or "Class" if no name.
// Create a `var _Class;` statement unless this is `export default class {}`,
// in which case the class itself will receive this name (`export default class _Class {}`).
// TODO(improve-on-babel): If class name var isn't mutated, no need for temp var for class
// declaration. Can just use class binding.
let (name, flags) = if let Some(binding) = self.name.as_ref() {
(binding.name.as_str(), SymbolFlags::FunctionScopedVariable)
} else {
// Class declaration can only be nameless if it's `export default class {}`
let flags = if is_declaration {
SymbolFlags::Class
} else {
SymbolFlags::FunctionScopedVariable
};
("Class", flags)
};

let binding = ctx.generate_uid_in_current_scope(name, flags);
if flags == SymbolFlags::FunctionScopedVariable {
transform_ctx.var_declarations.insert_var(&binding, None, ctx);
} else {
self.name = Some(binding.clone());
}
self.temp = Some(binding);
}

self.temp.as_ref().unwrap()
// TODO(improve-on-babel): If class name var isn't mutated, no need for temp var for
// class declaration. Can just use class binding.
let name = self.name.as_ref().map_or("Class", |binding| binding.name.as_str());
ctx.generate_uid_in_current_scope(name, SymbolFlags::FunctionScopedVariable)
})
}
}
3 changes: 3 additions & 0 deletions crates/oxc_transformer/src/es2022/class_properties/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ pub struct ClassProperties<'a, 'ctx> {
is_declaration: bool,
/// Bindings for class name and temp var for class
class_bindings: ClassBindings<'a>,
/// `true` if temp var for class has been inserted
temp_var_is_created: bool,
/// Expressions to insert before class
insert_before: Vec<Expression<'a>>,
/// Expressions to insert after class expression
Expand Down Expand Up @@ -234,6 +236,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
// Temporary values - overwritten when entering class
is_declaration: false,
class_bindings: ClassBindings::default(),
temp_var_is_created: false,
// `Vec`s and `FxHashMap`s which are reused for every class being transformed
insert_before: vec![],
insert_after_exprs: vec![],
Expand Down
8 changes: 4 additions & 4 deletions crates/oxc_transformer/src/es2022/class_properties/private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
// Only possible to reach here if we're currently transforming static prop initializers.
// TODO: Test that we're transforming static prop initializers right now,
// and not visiting class body. Add some debug assertions for this.
class_bindings.get_or_init_temp_binding(is_declaration, self.ctx, ctx)
class_bindings.get_or_init_temp_binding(ctx)
};
let class_ident = class_binding.create_read_expression(ctx);

Expand Down Expand Up @@ -240,7 +240,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
// Only possible to reach here if we're currently transforming static prop initializers.
// TODO: Test that we're transforming static prop initializers right now,
// and not visiting class body. Add some debug assertions for this.
class_bindings.get_or_init_temp_binding(is_declaration, self.ctx, ctx)
class_bindings.get_or_init_temp_binding(ctx)
};
let class_ident = class_binding.create_read_expression(ctx);

Expand Down Expand Up @@ -327,7 +327,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
// Only possible to reach here if we're currently transforming static prop initializers.
// TODO: Test that we're transforming static prop initializers right now,
// and not visiting class body. Add some debug assertions for this.
class_bindings.get_or_init_temp_binding(is_declaration, self.ctx, ctx)
class_bindings.get_or_init_temp_binding(ctx)
};
let class_binding = class_binding.clone();
let class_symbol_id = class_bindings.name_symbol_id();
Expand Down Expand Up @@ -727,7 +727,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
// Only possible to reach here if we're currently transforming static prop initializers.
// TODO: Test that we're transforming static prop initializers right now,
// and not visiting class body. Add some debug assertions for this.
class_bindings.get_or_init_temp_binding(is_declaration, self.ctx, ctx)
class_bindings.get_or_init_temp_binding(ctx)
};
let class_binding = class_binding.clone();

Expand Down
20 changes: 8 additions & 12 deletions crates/oxc_transformer/src/es2022/class_properties/static_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,19 +241,15 @@ impl<'a, 'ctx, 'v> StaticInitializerVisitor<'a, 'ctx, 'v> {
/// Replace `this` with reference to class name binding.
fn replace_this_with_class_name(&mut self, expr: &mut Expression<'a>, span: Span) {
if self.this_depth == 0 {
let class_properties = &mut *self.class_properties;
let class_bindings =
if let Some(private_props) = class_properties.private_props_stack.last_mut() {
&mut private_props.class_bindings
} else {
&mut class_properties.class_bindings
};
// `PrivateProps` is the source of truth for bindings if class has private props
// because other visitors which transform class fields may create a temp binding
// and store it on `PrivateProps`
let class_bindings = match self.class_properties.private_props_stack.last_mut() {
Some(private_props) => &mut private_props.class_bindings,
None => &mut self.class_properties.class_bindings,
};

let class_binding = class_bindings.get_or_init_temp_binding(
class_properties.is_declaration,
class_properties.ctx,
self.ctx,
);
let class_binding = class_bindings.get_or_init_temp_binding(self.ctx);
*expr = class_binding.create_spanned_read_expression(span, self.ctx);
}
}
Expand Down

0 comments on commit c594277

Please sign in to comment.