Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions crates/oxc_transformer/src/common/helper_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ pub enum Helper {
ToSetter,
ClassPrivateFieldLooseKey,
ClassPrivateFieldLooseBase,
SuperPropGet,
}

impl Helper {
Expand All @@ -181,6 +182,7 @@ impl Helper {
Self::ToSetter => "toSetter",
Self::ClassPrivateFieldLooseKey => "classPrivateFieldLooseKey",
Self::ClassPrivateFieldLooseBase => "classPrivateFieldLooseBase",
Self::SuperPropGet => "superPropGet",
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/oxc_transformer/src/es2022/class_properties/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
//! * `private_props.rs`: Structures storing details of private properties.
//! * `static_prop_init.rs`: Transform of static property initializers.
//! * `class_bindings.rs`: Structure containing bindings for class name and temp var.
//! * `super.rs`: Transform `super` expressions.
//! * `utils.rs`: Utility functions.
//!
//! ## References
Expand Down Expand Up @@ -159,6 +160,7 @@ mod constructor;
mod private;
mod private_props;
mod static_prop_init;
mod supers;
mod utils;
use class_bindings::ClassBindings;
use private_props::PrivatePropsStack;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,14 @@ impl<'a, 'ctx, 'v> VisitMut<'a> for StaticInitializerVisitor<'a, 'ctx, 'v> {
}
}
}
// `super.prop`
Expression::StaticMemberExpression(_) => {
self.class_properties.transform_static_member_expression(expr, self.ctx);
}
// `super[prop]`
Expression::ComputedMemberExpression(_) => {
self.class_properties.transform_computed_member_expression(expr, self.ctx);
}
// `object.#prop`
Expression::PrivateFieldExpression(_) => {
self.class_properties.transform_private_field_expression(expr, self.ctx);
Expand Down Expand Up @@ -453,7 +461,7 @@ impl<'a, 'ctx, 'v> StaticInitializerVisitor<'a, 'ctx, 'v> {
}

impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
fn get_temp_binding(&mut self, ctx: &mut TraverseCtx<'a>) -> &BoundIdentifier<'a> {
pub(super) fn get_temp_binding(&mut self, ctx: &mut TraverseCtx<'a>) -> &BoundIdentifier<'a> {
// `PrivateProps` is the source of truth for bindings if class has private props
// because other visitors which transform private fields may create a temp binding
// and store it on `PrivateProps`
Expand Down
86 changes: 86 additions & 0 deletions crates/oxc_transformer/src/es2022/class_properties/supers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//! ES2022: Class Properties
//! Transform of `super` expressions.

use oxc_ast::ast::*;
use oxc_traverse::TraverseCtx;

use crate::Helper;

use super::ClassProperties;

impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
/// Transform static member expression where object is `super`.
///
/// `super.prop` -> `_superPropGet(_Class, "prop", _Class)`
//
// `#[inline]` so that compiler sees that `expr` is an `Expression::StaticMemberExpression`.
#[inline]
pub(super) fn transform_static_member_expression(
&mut self,
expr: &mut Expression<'a>,
ctx: &mut TraverseCtx<'a>,
) {
let Expression::StaticMemberExpression(member) = expr else { unreachable!() };
if matches!(member.object, Expression::Super(_)) {
*expr = self.transform_static_member_expression_impl(member, ctx);
}
}

fn transform_static_member_expression_impl(
&mut self,
member: &mut StaticMemberExpression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let property = &member.property;
let property = ctx.ast.expression_string_literal(
property.span,
property.name.clone(),
Some(property.name.clone()),
);
self.create_super_prop_get(member.span, property, ctx)
}

/// Transform computed member expression where object is `super`.
///
/// `super[prop]` -> `_superPropGet(_Class, prop, _Class)`
//
// `#[inline]` so that compiler sees that `expr` is an `Expression::ComputedMemberExpression`.
#[inline]
pub(super) fn transform_computed_member_expression(
&mut self,
expr: &mut Expression<'a>,
ctx: &mut TraverseCtx<'a>,
) {
let Expression::ComputedMemberExpression(member) = expr else { unreachable!() };
if matches!(member.object, Expression::Super(_)) {
*expr = self.transform_computed_member_expression_impl(member, ctx);
}
}

fn transform_computed_member_expression_impl(
&mut self,
member: &mut ComputedMemberExpression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let property = ctx.ast.move_expression(&mut member.expression);
self.create_super_prop_get(member.span, property, ctx)
}

/// `_superPropGet(_Class, prop, _Class)`
fn create_super_prop_get(
&mut self,
span: Span,
property: Expression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let class_binding = self.get_temp_binding(ctx);
// `(_Class, prop, _Class)`
let arguments = ctx.ast.vec_from_array([
Argument::from(class_binding.create_read_expression(ctx)),
Argument::from(property),
Argument::from(class_binding.create_read_expression(ctx)),
]);
// `_superPropGet(_Class, prop, _Class)`
self.ctx.helper_call_expr(Helper::SuperPropGet, span, arguments, ctx)
}
}
20 changes: 11 additions & 9 deletions tasks/transform_conformance/snapshots/babel.snap.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
commit: 54a8389f

Passed: 562/927
Passed: 564/927

# All Passed:
* babel-plugin-transform-class-static-block
Expand Down Expand Up @@ -276,7 +276,7 @@ x Output mismatch
x Output mismatch


# babel-plugin-transform-class-properties (176/264)
# babel-plugin-transform-class-properties (178/264)
* assumption-constantSuper/complex-super-class/input.js
x Output mismatch

Expand Down Expand Up @@ -341,9 +341,6 @@ rebuilt : ScopeId(9): Some(ScopeId(8))
* assumption-setPublicClassFields/static-infer-name/input.js
x Output mismatch

* assumption-setPublicClassFields/static-super/input.js
x Output mismatch

* assumption-setPublicClassFields/static-super-loose/input.js
x Output mismatch

Expand Down Expand Up @@ -645,9 +642,6 @@ rebuilt : ScopeId(9): Some(ScopeId(8))
* public/static-infer-name/input.js
x Output mismatch

* public/static-super/input.js
x Output mismatch

* public/super-with-collision/input.js
x Output mismatch

Expand Down Expand Up @@ -713,7 +707,15 @@ x Output mismatch
x Output mismatch

* regression/6154/input.js
x Output mismatch
Scope children mismatch:
after transform: ScopeId(3): [ScopeId(4), ScopeId(6)]
rebuilt : ScopeId(3): [ScopeId(4)]
Scope children mismatch:
after transform: ScopeId(6): []
rebuilt : ScopeId(4): [ScopeId(5)]
Scope parent mismatch:
after transform: ScopeId(4): Some(ScopeId(3))
rebuilt : ScopeId(5): Some(ScopeId(4))

* regression/7951/input.mjs
x Output mismatch
Expand Down
14 changes: 3 additions & 11 deletions tasks/transform_conformance/snapshots/babel_exec.snap.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ commit: 54a8389f

node: v22.12.0

Passed: 186 of 215 (86.51%)
Passed: 189 of 215 (87.91%)

Failures:

Expand All @@ -13,9 +13,6 @@ Failures:
AssertionError: expected '_Class' to be 'Foo' // Object.is equality
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-assumption-setPublicClassFields-static-infer-name-exec.test.js:8:19

./fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-assumption-setPublicClassFields-static-super-exec.test.js
Invalid access to super

./fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-nested-class-super-call-in-decorator-exec.test.js
AssertionError: expected undefined to be 'hello' // Object.is equality
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-nested-class-super-call-in-decorator-exec.test.js:21:28
Expand Down Expand Up @@ -98,22 +95,17 @@ AssertionError: expected [Function] to throw error including '@@toPrimitive must
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-computed-toPrimitive-exec.test.js:37:5

./fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-delete-super-property-exec.test.js
Invalid access to super
AssertionError: expected function to throw an error, but it didn't
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-delete-super-property-exec.test.js:25:5

./fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-loose-static-infer-name-exec.test.js
AssertionError: expected '_Class' to be 'Foo' // Object.is equality
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-loose-static-infer-name-exec.test.js:8:19

./fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-loose-static-super-exec.test.js
Invalid access to super

./fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-static-infer-name-exec.test.js
AssertionError: expected '_Class' to be 'Foo' // Object.is equality
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-static-infer-name-exec.test.js:9:19

./fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-static-super-exec.test.js
Invalid access to super

./fixtures/babel/babel-plugin-transform-optional-chaining-test-fixtures-assumption-noDocumentAll-parenthesized-expression-member-call-exec.test.js
TypeError: Cannot read properties of undefined (reading 'x')
at m (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-optional-chaining-test-fixtures-assumption-noDocumentAll-parenthesized-expression-member-call-exec.test.js:10:16)
Expand Down