Skip to content

Commit

Permalink
Allow referencing super within initializer of static private proper…
Browse files Browse the repository at this point in the history
…ty (#4121)

* Allow referencing `super` within initializer of static private property

* Add test

* field -> intializer

* cargo fmt

* cargo clippy

* Add test for public initializers

* Update core/engine/src/tests/class.rs

Co-authored-by: Hans Larsen <[email protected]>

---------

Co-authored-by: Hans Larsen <[email protected]>
  • Loading branch information
jedel1043 and hansl authored Jan 17, 2025
1 parent 0913629 commit 95aa4cd
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 115 deletions.
69 changes: 43 additions & 26 deletions core/ast/src/function/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ pub enum ClassElement {

/// A private static field definition, only accessible from static methods and fields inside the
/// class declaration.
PrivateStaticFieldDefinition(PrivateName, Option<Expression>),
PrivateStaticFieldDefinition(PrivateFieldDefinition),

/// A static block, where a class can have initialization logic for its static fields.
StaticBlock(StaticBlockBody),
Expand All @@ -406,7 +406,7 @@ pub enum ClassElement {
#[derive(Clone, Debug, PartialEq)]
pub struct ClassFieldDefinition {
pub(crate) name: PropertyName,
pub(crate) field: Option<Expression>,
pub(crate) initializer: Option<Expression>,

#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) scope: Scope,
Expand All @@ -416,10 +416,10 @@ impl ClassFieldDefinition {
/// Creates a new class field definition.
#[inline]
#[must_use]
pub fn new(name: PropertyName, field: Option<Expression>) -> Self {
pub fn new(name: PropertyName, initializer: Option<Expression>) -> Self {
Self {
name,
field,
initializer,
scope: Scope::default(),
}
}
Expand All @@ -431,11 +431,11 @@ impl ClassFieldDefinition {
&self.name
}

/// Returns the field of the class field definition.
/// Returns the initializer of the class field definition.
#[inline]
#[must_use]
pub const fn field(&self) -> Option<&Expression> {
self.field.as_ref()
pub const fn initializer(&self) -> Option<&Expression> {
self.initializer.as_ref()
}

/// Returns the scope of the class field definition.
Expand All @@ -457,7 +457,7 @@ impl ClassFieldDefinition {
#[derive(Clone, Debug, PartialEq)]
pub struct PrivateFieldDefinition {
pub(crate) name: PrivateName,
pub(crate) field: Option<Expression>,
pub(crate) initializer: Option<Expression>,

#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) scope: Scope,
Expand All @@ -467,10 +467,10 @@ impl PrivateFieldDefinition {
/// Creates a new private field definition.
#[inline]
#[must_use]
pub fn new(name: PrivateName, field: Option<Expression>) -> Self {
pub fn new(name: PrivateName, initializer: Option<Expression>) -> Self {
Self {
name,
field,
initializer,
scope: Scope::default(),
}
}
Expand All @@ -482,11 +482,11 @@ impl PrivateFieldDefinition {
&self.name
}

/// Returns the field of the private field definition.
/// Returns the initializer of the private field definition.
#[inline]
#[must_use]
pub const fn field(&self) -> Option<&Expression> {
self.field.as_ref()
pub const fn initializer(&self) -> Option<&Expression> {
self.initializer.as_ref()
}

/// Returns the scope of the private field definition.
Expand All @@ -502,7 +502,7 @@ impl ToIndentedString for ClassElement {
let indentation = " ".repeat(indent_n + 1);
match self {
Self::MethodDefinition(m) => m.to_indented_string(interner, indent_n),
Self::FieldDefinition(field) => match &field.field {
Self::FieldDefinition(field) => match &field.initializer {
Some(expr) => {
format!(
"{indentation}{} = {};\n",
Expand All @@ -517,7 +517,7 @@ impl ToIndentedString for ClassElement {
)
}
},
Self::StaticFieldDefinition(field) => match &field.field {
Self::StaticFieldDefinition(field) => match &field.initializer {
Some(expr) => {
format!(
"{indentation}static {} = {};\n",
Expand All @@ -532,8 +532,9 @@ impl ToIndentedString for ClassElement {
)
}
},
Self::PrivateFieldDefinition(PrivateFieldDefinition { name, field, .. }) => match field
{
Self::PrivateFieldDefinition(PrivateFieldDefinition {
name, initializer, ..
}) => match initializer {
Some(expr) => {
format!(
"{indentation}#{} = {};\n",
Expand All @@ -548,7 +549,11 @@ impl ToIndentedString for ClassElement {
)
}
},
Self::PrivateStaticFieldDefinition(name, field) => match field {
Self::PrivateStaticFieldDefinition(PrivateFieldDefinition {
name,
initializer,
..
}) => match initializer {
Some(expr) => {
format!(
"{indentation}static #{} = {};\n",
Expand Down Expand Up @@ -593,16 +598,22 @@ impl VisitWith for ClassElement {
}
Self::FieldDefinition(field) | Self::StaticFieldDefinition(field) => {
visitor.visit_property_name(&field.name)?;
if let Some(expr) = &field.field {
if let Some(expr) = &field.initializer {
visitor.visit_expression(expr)
} else {
ControlFlow::Continue(())
}
}
Self::PrivateFieldDefinition(PrivateFieldDefinition { name, field, .. })
| Self::PrivateStaticFieldDefinition(name, field) => {
Self::PrivateFieldDefinition(PrivateFieldDefinition {
name, initializer, ..
})
| Self::PrivateStaticFieldDefinition(PrivateFieldDefinition {
name,
initializer,
..
}) => {
visitor.visit_private_name(name)?;
if let Some(expr) = field {
if let Some(expr) = initializer {
visitor.visit_expression(expr)
} else {
ControlFlow::Continue(())
Expand Down Expand Up @@ -631,16 +642,22 @@ impl VisitWith for ClassElement {
}
Self::FieldDefinition(field) | Self::StaticFieldDefinition(field) => {
visitor.visit_property_name_mut(&mut field.name)?;
if let Some(expr) = &mut field.field {
if let Some(expr) = &mut field.initializer {
visitor.visit_expression_mut(expr)
} else {
ControlFlow::Continue(())
}
}
Self::PrivateFieldDefinition(PrivateFieldDefinition { name, field, .. })
| Self::PrivateStaticFieldDefinition(name, field) => {
Self::PrivateFieldDefinition(PrivateFieldDefinition {
name, initializer, ..
})
| Self::PrivateStaticFieldDefinition(PrivateFieldDefinition {
name,
initializer,
..
}) => {
visitor.visit_private_name_mut(name)?;
if let Some(expr) = field {
if let Some(expr) = initializer {
visitor.visit_expression_mut(expr)
} else {
ControlFlow::Continue(())
Expand Down
36 changes: 26 additions & 10 deletions core/ast/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1180,7 +1180,9 @@ impl<'ast> Visitor<'ast> for AllPrivateIdentifiersValidVisitor {
}
}
ClassElement::PrivateFieldDefinition(PrivateFieldDefinition { name, .. })
| ClassElement::PrivateStaticFieldDefinition(name, _) => {
| ClassElement::PrivateStaticFieldDefinition(PrivateFieldDefinition {
name, ..
}) => {
names.push(name.description());
}
_ => {}
Expand All @@ -1205,13 +1207,19 @@ impl<'ast> Visitor<'ast> for AllPrivateIdentifiersValidVisitor {
ClassElement::FieldDefinition(field)
| ClassElement::StaticFieldDefinition(field) => {
visitor.visit(&field.name)?;
if let Some(expression) = &field.field {
if let Some(expression) = &field.initializer {
visitor.visit(expression)?;
}
}
ClassElement::PrivateFieldDefinition(PrivateFieldDefinition { field, .. })
| ClassElement::PrivateStaticFieldDefinition(_, field) => {
if let Some(expression) = field {
ClassElement::PrivateFieldDefinition(PrivateFieldDefinition {
initializer,
..
})
| ClassElement::PrivateStaticFieldDefinition(PrivateFieldDefinition {
initializer,
..
}) => {
if let Some(expression) = initializer {
visitor.visit(expression)?;
}
}
Expand Down Expand Up @@ -1241,7 +1249,9 @@ impl<'ast> Visitor<'ast> for AllPrivateIdentifiersValidVisitor {
}
}
ClassElement::PrivateFieldDefinition(PrivateFieldDefinition { name, .. })
| ClassElement::PrivateStaticFieldDefinition(name, _) => {
| ClassElement::PrivateStaticFieldDefinition(PrivateFieldDefinition {
name, ..
}) => {
names.push(name.description());
}
_ => {}
Expand All @@ -1266,13 +1276,19 @@ impl<'ast> Visitor<'ast> for AllPrivateIdentifiersValidVisitor {
ClassElement::FieldDefinition(field)
| ClassElement::StaticFieldDefinition(field) => {
visitor.visit(&field.name)?;
if let Some(expression) = &field.field {
if let Some(expression) = &field.initializer {
visitor.visit(expression)?;
}
}
ClassElement::PrivateFieldDefinition(PrivateFieldDefinition { field, .. })
| ClassElement::PrivateStaticFieldDefinition(_, field) => {
if let Some(expression) = field {
ClassElement::PrivateFieldDefinition(PrivateFieldDefinition {
initializer,
..
})
| ClassElement::PrivateStaticFieldDefinition(PrivateFieldDefinition {
initializer,
..
}) => {
if let Some(expression) = initializer {
visitor.visit(expression)?;
}
}
Expand Down
39 changes: 12 additions & 27 deletions core/ast/src/scope_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,19 +434,14 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> {
),
ClassElement::FieldDefinition(field) | ClassElement::StaticFieldDefinition(field) => {
self.visit_property_name_mut(&mut field.name)?;
if let Some(e) = &mut field.field {
if let Some(e) = &mut field.initializer {
self.visit_expression_mut(e)?;
}
ControlFlow::Continue(())
}
ClassElement::PrivateFieldDefinition(field) => {
if let Some(e) = &mut field.field {
self.visit_expression_mut(e)?;
}
ControlFlow::Continue(())
}
ClassElement::PrivateStaticFieldDefinition(_, e) => {
if let Some(e) = e {
ClassElement::PrivateFieldDefinition(field)
| ClassElement::PrivateStaticFieldDefinition(field) => {
if let Some(e) = &mut field.initializer {
self.visit_expression_mut(e)?;
}
ControlFlow::Continue(())
Expand Down Expand Up @@ -816,29 +811,24 @@ impl<'ast> VisitorMut<'ast> for BindingCollectorVisitor<'_> {
self.visit_property_name_mut(&mut field.name)?;
let mut scope = Scope::new(self.scope.clone(), true);
std::mem::swap(&mut self.scope, &mut scope);
if let Some(e) = &mut field.field {
if let Some(e) = &mut field.initializer {
self.visit_expression_mut(e)?;
}
std::mem::swap(&mut self.scope, &mut scope);
field.scope = scope;
ControlFlow::Continue(())
}
ClassElement::PrivateFieldDefinition(field) => {
ClassElement::PrivateFieldDefinition(field)
| ClassElement::PrivateStaticFieldDefinition(field) => {
let mut scope = Scope::new(self.scope.clone(), true);
std::mem::swap(&mut self.scope, &mut scope);
if let Some(e) = &mut field.field {
if let Some(e) = &mut field.initializer {
self.visit_expression_mut(e)?;
}
std::mem::swap(&mut self.scope, &mut scope);
field.scope = scope;
ControlFlow::Continue(())
}
ClassElement::PrivateStaticFieldDefinition(_, e) => {
if let Some(e) = e {
self.visit_expression_mut(e)?;
}
ControlFlow::Continue(())
}
ClassElement::StaticBlock(node) => {
let strict = node.body.strict();
self.visit_function_like(
Expand Down Expand Up @@ -1423,28 +1413,23 @@ impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor {
let index = self.index;
self.index += 1;
field.scope.set_index(self.index);
if let Some(e) = &mut field.field {
if let Some(e) = &mut field.initializer {
self.visit_expression_mut(e)?;
}
self.index = index;
ControlFlow::Continue(())
}
ClassElement::PrivateFieldDefinition(field) => {
ClassElement::PrivateFieldDefinition(field)
| ClassElement::PrivateStaticFieldDefinition(field) => {
let index = self.index;
self.index += 1;
field.scope.set_index(self.index);
if let Some(e) = &mut field.field {
if let Some(e) = &mut field.initializer {
self.visit_expression_mut(e)?;
}
self.index = index;
ControlFlow::Continue(())
}
ClassElement::PrivateStaticFieldDefinition(_, e) => {
if let Some(e) = e {
self.visit_expression_mut(e)?;
}
ControlFlow::Continue(())
}
ClassElement::StaticBlock(node) => {
let contains_direct_eval = contains(node.statements(), ContainsSymbol::DirectEval);
self.visit_function_like(
Expand Down
Loading

0 comments on commit 95aa4cd

Please sign in to comment.