Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 44 additions & 51 deletions crates/oxc_transformer/src/es2022/class_properties/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ impl<'a> ClassProperties<'a, '_> {
let mut has_static_private_method_or_static_block = false;
// TODO: Store `FxIndexMap`s in a pool and re-use them
let mut private_props = FxIndexMap::default();
let mut constructor = None;
for element in &mut body.body {
match element {
ClassElement::PropertyDefinition(prop) => {
Expand Down Expand Up @@ -107,11 +106,7 @@ impl<'a> ClassProperties<'a, '_> {
}
}
ClassElement::MethodDefinition(method) => {
if method.kind == MethodDefinitionKind::Constructor {
if method.value.body.is_some() {
constructor = Some(method);
}
} else if let PropertyKey::PrivateIdentifier(ident) = &method.key {
if let PropertyKey::PrivateIdentifier(ident) = &method.key {
if method.r#static {
has_static_private_method_or_static_block = true;
} else {
Expand Down Expand Up @@ -239,51 +234,6 @@ impl<'a> ClassProperties<'a, '_> {
return;
}

// Scope that instance property initializers will be inserted into.
// This is usually class constructor, but can also be a `_super` function which is created.
let instance_inits_scope_id;
// Scope of class constructor, if instance property initializers will be inserted into constructor.
// Used for checking for variable name clashes.
// e.g. `class C { prop = x(); constructor(x) {} }`
// - `x` in constructor needs to be renamed when `x()` is moved into constructor body.
// `None` if class has no existing constructor, as then there can't be any clashes.
let mut instance_inits_constructor_scope_id = None;

// Determine where to insert instance property initializers in constructor
let instance_inits_insert_location = if let Some(constructor) = constructor {
// Existing constructor
let constructor = constructor.value.as_mut();
if has_super_class {
let (insert_scopes, insert_location) =
Self::replace_super_in_constructor(constructor, ctx);
instance_inits_scope_id = insert_scopes.insert_in_scope_id;
instance_inits_constructor_scope_id = insert_scopes.constructor_scope_id;
insert_location
} else {
let constructor_scope_id = constructor.scope_id();
instance_inits_scope_id = constructor_scope_id;
// Only record `constructor_scope_id` if constructor's scope has some bindings.
// If it doesn't, no need to check for shadowed symbols in instance prop initializers,
// because no bindings to clash with.
instance_inits_constructor_scope_id =
if ctx.scoping().get_bindings(constructor_scope_id).is_empty() {
None
} else {
Some(constructor_scope_id)
};
InstanceInitsInsertLocation::ExistingConstructor(0)
}
} else {
// No existing constructor - create scope for one
let constructor_scope_id = ctx.scoping_mut().add_scope(
Some(class_scope_id),
NodeId::DUMMY,
ScopeFlags::Function | ScopeFlags::Constructor | ScopeFlags::StrictMode,
);
instance_inits_scope_id = constructor_scope_id;
InstanceInitsInsertLocation::NewConstructor
};

// Extract instance properties initializers.
//
// We leave the properties themselves in place, but take the initializers.
Expand Down Expand Up @@ -326,6 +276,49 @@ impl<'a> ClassProperties<'a, '_> {
}
}

// Scope that instance property initializers will be inserted into.
// This is usually class constructor, but can also be a `_super` function which is created.
let instance_inits_scope_id;
// Scope of class constructor, if instance property initializers will be inserted into constructor.
// Used for checking for variable name clashes.
// e.g. `class C { prop = x(); constructor(x) {} }`
// - `x` in constructor needs to be renamed when `x()` is moved into constructor body.
// `None` if class has no existing constructor, as then there can't be any clashes.
let mut instance_inits_constructor_scope_id = None;

// Determine where to insert instance property initializers in constructor
let instance_inits_insert_location = if let Some(constructor) = constructor.as_deref_mut() {
if has_super_class {
let (insert_scopes, insert_location) =
Self::replace_super_in_constructor(constructor, ctx);
instance_inits_scope_id = insert_scopes.insert_in_scope_id;
instance_inits_constructor_scope_id = insert_scopes.constructor_scope_id;
insert_location
} else {
let constructor_scope_id = constructor.scope_id();
instance_inits_scope_id = constructor_scope_id;
// Only record `constructor_scope_id` if constructor's scope has some bindings.
// If it doesn't, no need to check for shadowed symbols in instance prop initializers,
// because no bindings to clash with.
instance_inits_constructor_scope_id =
if ctx.scoping().get_bindings(constructor_scope_id).is_empty() {
None
} else {
Some(constructor_scope_id)
};
InstanceInitsInsertLocation::ExistingConstructor(0)
}
} else {
// No existing constructor - create scope for one
let constructor_scope_id = ctx.scoping_mut().add_scope(
Some(class_scope_id),
NodeId::DUMMY,
ScopeFlags::Function | ScopeFlags::Constructor | ScopeFlags::StrictMode,
);
instance_inits_scope_id = constructor_scope_id;
InstanceInitsInsertLocation::NewConstructor
};

// Reparent property initializers scope to `instance_inits_scope_id`.
self.reparent_initializers_scope(
instance_inits.as_slice(),
Expand Down
Loading