Skip to content

Commit

Permalink
Remove old code
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Dec 18, 2024
1 parent dce52c0 commit ce65a26
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 282 deletions.
267 changes: 21 additions & 246 deletions crates/oxc_transformer/src/es2022/class_properties/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {

// Exit if no instance properties (public or private)
if instance_prop_count == 0 {
// TODO: Comment why we do this. Or don't early exit here.
self.current_class_mut().bindings.static_private_fields_use_temp = false;
return;
}

Expand Down Expand Up @@ -242,6 +244,21 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
self.create_super_function_outside_constructor(instance_inits, &super_binding, ctx);
}
}

// Flag that static private fields should be transpiled using name binding,
// while traversing class body.
//
// Static private fields reference class name (not temp var) in class declarations.
// `class Class { static #prop; method() { return obj.#prop; } }`
// -> `method() { return _assertClassBrand(Class, obj, _prop)._; }`
// (note `Class` in `_assertClassBrand(Class, ...)`, not `_Class`)
//
// Also see comments on `ClassBindings`.
//
// Note: If declaration is `export default class {}` with no name, and class has static props,
// then class has had name binding created already in `transform_class`.
// So name binding is always `Some`.
self.current_class_mut().bindings.static_private_fields_use_temp = false;
}

pub(super) fn transform_class_on_exit(
Expand Down Expand Up @@ -357,7 +374,10 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {

self.transform_class_on_exit_impl(class, ctx);

// Insert expressions before / after class
// Insert expressions before / after class.
// `C = class { [x()] = 1; static y = 2 };`
// -> `C = (_x = x(), _Class = class C { constructor() { this[_x] = 1; } }, _Class.y = 2, _Class)`

// TODO: Name class if had no name, and name is statically knowable (as in example above).
// If class name shadows var which is referenced within class, rename that var.
// `var C = class { prop = C }; var C2 = C;`
Expand Down Expand Up @@ -480,240 +500,6 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
});
}

/// Transform class expression.
// `#[inline]` so that compiler sees that `expr` is an `Expression::ClassExpression`.
// Main guts of transform is broken out into `transform_class_expression_start` and
// `transform_class_expression_finish` to keep this function as small as possible.
// Want it to be inlined into `enter_expression` and for `enter_expression` to be inlined into parent.
#[expect(dead_code)]
#[inline]
pub(super) fn transform_class_expression(
&mut self,
expr: &mut Expression<'a>,
ctx: &mut TraverseCtx<'a>,
) {
let Expression::ClassExpression(class) = expr else { unreachable!() };

let class_address = class.address();
let expr_count = self.transform_class_expression_start(class, class_address, ctx);
if expr_count > 0 {
self.transform_class_expression_finish(expr, expr_count, ctx);
}
}

fn transform_class_expression_start(
&mut self,
class: &mut Class<'a>,
_class_address: Address,
ctx: &mut TraverseCtx<'a>,
) -> usize {
self.transform_class(class, false, ctx);

// Return number of expressions to be inserted before/after the class
let mut expr_count = self.insert_before.len() + self.insert_after_exprs.len();
if let Some(private_props) = &self.current_class().private_props {
expr_count += private_props.len();
}

expr_count
}

/// Insert expressions before/after the class.
/// `C = class { [x()] = 1; static y = 2 };`
/// -> `C = (_x = x(), _Class = class C { constructor() { this[_x] = 1; } }, _Class.y = 2, _Class)`
fn transform_class_expression_finish(
&mut self,
expr: &mut Expression<'a>,
mut expr_count: usize,
ctx: &mut TraverseCtx<'a>,
) {
// TODO: Name class if had no name, and name is statically knowable (as in example above).
// If class name shadows var which is referenced within class, rename that var.
// `var C = class { prop = C }; var C2 = C;`
// -> `var _C = class C { constructor() { this.prop = _C; } }; var C2 = _C;`
// This is really difficult as need to rename all references to that binding too,
// which can be very far above the class in AST, when it's a `var`.
// Maybe for now only add class name if it doesn't shadow a var used within class?

// TODO: Deduct static private props from `expr_count`.
// Or maybe should store count and increment it when create private static props?
// They're probably pretty rare, so it'll be rarely used.
let class_details = self.classes_stack.last();
expr_count += 1 + usize::from(class_details.bindings.temp.is_some());

let mut exprs = ctx.ast.vec_with_capacity(expr_count);

// Insert `_prop = new WeakMap()` expressions for private instance props
// (or `_prop = _classPrivateFieldLooseKey("prop")` if loose mode).
// Babel has these always go first, regardless of order of class elements.
// Also insert `var _prop;` temp var declarations for private static props.
if let Some(private_props) = &class_details.private_props {
// Insert `var _prop;` declarations here rather than when binding was created to maintain
// same order of `var` declarations as Babel.
// `c = class C { #x = 1; static y = 2; }` -> `var _C, _x;`
// TODO(improve-on-babel): Simplify this.
if self.private_fields_as_properties {
exprs.extend(private_props.iter().map(|(name, prop)| {
// Insert `var _prop;` declaration
self.ctx.var_declarations.insert_var(&prop.binding, ctx);

// `_prop = _classPrivateFieldLooseKey("prop")`
let value = Self::create_private_prop_key_loose(name, self.ctx, ctx);
create_assignment(&prop.binding, value, ctx)
}));
} else {
let mut weakmap_symbol_id = None;
exprs.extend(private_props.values().filter_map(|prop| {
// Insert `var _prop;` declaration
self.ctx.var_declarations.insert_var(&prop.binding, ctx);

if prop.is_static {
return None;
}

// `_prop = new WeakMap()`
let value = create_new_weakmap(&mut weakmap_symbol_id, ctx);
Some(create_assignment(&prop.binding, value, ctx))
}));
}
}

// Insert computed key initializers
exprs.extend(self.insert_before.drain(..));

// Insert class + static property assignments + static blocks
let class_expr = ctx.ast.move_expression(expr);
if let Some(binding) = &class_details.bindings.temp {
// Insert `var _Class` statement, if it wasn't already in `transform_class`
if !class_details.bindings.temp_var_is_created {
self.ctx.var_declarations.insert_var(binding, ctx);
}

// `_Class = class {}`
let assignment = create_assignment(binding, class_expr, ctx);
exprs.push(assignment);
// Add static property assignments + static blocks
exprs.extend(self.insert_after_exprs.drain(..));
// `_Class`
exprs.push(binding.create_read_expression(ctx));
} else {
// Add static blocks (which didn't reference class name)
// TODO: If class has `extends` clause, and it may have side effects, then static block contents
// goes after class expression, and temp var is called `_temp` not `_Class`.
// `let C = class extends Unbound { static { x = 1; } };`
// -> `var _temp; let C = ((_temp = class C extends Unbound {}), (x = 1), _temp);`
// `let C = class extends Bound { static { x = 1; } };`
// -> `let C = ((x = 1), class C extends Bound {});`
exprs.extend(self.insert_after_exprs.drain(..));

exprs.push(class_expr);
}

*expr = ctx.ast.expression_sequence(SPAN, exprs);
}

/// Transform class declaration.
#[expect(dead_code)]
pub(super) fn transform_class_declaration(
&mut self,
class: &mut Class<'a>,
stmt_address: Address,
ctx: &mut TraverseCtx<'a>,
) {
// Ignore TS class declarations
// TODO: Is this correct?
// TODO: If remove this check, remove from `transform_class_on_exit` too.
if class.declare {
return;
}

self.transform_class(class, true, ctx);

// TODO: Run other transforms on inserted statements. How?

let class_details = self.classes_stack.last_mut();
if let Some(temp_binding) = &class_details.bindings.temp {
// Binding for class name is required
if let Some(ident) = &class.id {
// Insert `var _Class` statement, if it wasn't already in `transform_class`
if !class_details.bindings.temp_var_is_created {
self.ctx.var_declarations.insert_var(temp_binding, ctx);
}

// Insert `_Class = Class` after class.
// TODO(improve-on-babel): Could just insert `var _Class = Class;` after class,
// rather than separate `var _Class` declaration.
let class_name =
BoundIdentifier::from_binding_ident(ident).create_read_expression(ctx);
let expr = create_assignment(temp_binding, class_name, ctx);
let stmt = ctx.ast.statement_expression(SPAN, expr);
self.insert_after_stmts.insert(0, stmt);
} 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));
}
}

// Insert expressions before/after class
if !self.insert_before.is_empty() {
self.ctx.statement_injector.insert_many_before(
&stmt_address,
exprs_into_stmts(self.insert_before.drain(..), ctx),
);
}

if let Some(private_props) = &class_details.private_props {
if self.private_fields_as_properties {
self.ctx.statement_injector.insert_many_before(
&stmt_address,
private_props.iter().map(|(name, prop)| {
// `var _prop = _classPrivateFieldLooseKey("prop");`
let value = Self::create_private_prop_key_loose(name, self.ctx, ctx);
create_variable_declaration(&prop.binding, value, ctx)
}),
);
} else {
// TODO: Only call `insert_many_before` if some private *instance* props
let mut weakmap_symbol_id = None;
self.ctx.statement_injector.insert_many_before(
&stmt_address,
private_props.values().filter_map(|prop| {
if prop.is_static {
return None;
}

// `var _prop = new WeakMap();`
let value = create_new_weakmap(&mut weakmap_symbol_id, ctx);
Some(create_variable_declaration(&prop.binding, value, ctx))
}),
);
}
}

if !self.insert_after_stmts.is_empty() {
self.ctx
.statement_injector
.insert_many_after(&stmt_address, self.insert_after_stmts.drain(..));
}

// Flag that static private fields should be transpiled using name binding,
// while traversing class body.
//
// Static private fields reference class name (not temp var) in class declarations.
// `class Class { static #prop; method() { return obj.#prop; } }`
// -> `method() { return _assertClassBrand(Class, obj, _prop)._; }`
// (note `Class` in `_assertClassBrand(Class, ...)`, not `_Class`)
//
// Also see comments on `ClassBindings`.
//
// Note: If declaration is `export default class {}` with no name, and class has static props,
// then class has had name binding created already in `transform_class`.
// So name binding is always `Some`.
class_details.bindings.static_private_fields_use_temp = false;
}

/// `_classPrivateFieldLooseKey("prop")`
fn create_private_prop_key_loose(
name: &Atom<'a>,
Expand All @@ -732,17 +518,6 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
)
}

/// Main guts of the transform.
#[expect(unused_variables, clippy::unused_self)]
fn transform_class(
&mut self,
class: &mut Class<'a>,
is_declaration: bool,
ctx: &mut TraverseCtx<'a>,
) {
// TODO: Delete this function
}

/// Insert an expression after the class.
pub(super) fn insert_expr_after_class(
&mut self,
Expand Down
37 changes: 1 addition & 36 deletions crates/oxc_transformer/src/es2022/class_properties/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,12 +268,6 @@ impl<'a, 'ctx> Traverse<'a> for ClassProperties<'a, 'ctx> {
// IMPORTANT: If add any other visitors here to handle private fields,
// also need to add them to visitor in `static_prop.rs`.
match expr {
/*
// `class {}`
Expression::ClassExpression(_) => {
self.transform_class_expression(expr, ctx);
}
*/
// `object.#prop`
Expression::PrivateFieldExpression(_) => {
self.transform_private_field_expression(expr, ctx);
Expand Down Expand Up @@ -316,42 +310,13 @@ impl<'a, 'ctx> Traverse<'a> for ClassProperties<'a, 'ctx> {
self.transform_assignment_target(target, ctx);
}

/*
// `#[inline]` because this is a hot path
#[inline]
fn enter_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
match stmt {
// `class C {}`
Statement::ClassDeclaration(class) => {
let stmt_address = class.address();
self.transform_class_declaration(class, stmt_address, ctx);
}
// `export class C {}`
Statement::ExportNamedDeclaration(decl) => {
let stmt_address = decl.address();
if let Some(Declaration::ClassDeclaration(class)) = &mut decl.declaration {
self.transform_class_declaration(class, stmt_address, ctx);
}
}
// `export default class {}`
Statement::ExportDefaultDeclaration(decl) => {
let stmt_address = decl.address();
if let ExportDefaultDeclarationKind::ClassDeclaration(class) = &mut decl.declaration
{
self.transform_class_declaration(class, stmt_address, ctx);
}
}
_ => {}
}
}
*/

// `#[inline]` because `transform_class_on_exit` is so small
#[inline]
fn exit_class(&mut self, class: &mut Class<'a>, ctx: &mut TraverseCtx<'a>) {
self.transform_class_on_exit(class, ctx);
}

// `#[inline]` for fast exit for expressions which are not `Class`es
#[inline]
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
if matches!(expr, Expression::ClassExpression(_)) {
Expand Down

0 comments on commit ce65a26

Please sign in to comment.