Skip to content

Commit

Permalink
fix(transformer): fix arrow function transform (#5933)
Browse files Browse the repository at this point in the history
Fix arrow function transform's treatment of `this` within classes.
  • Loading branch information
overlookmotel committed Sep 21, 2024
1 parent 12d4888 commit 4e9e838
Show file tree
Hide file tree
Showing 16 changed files with 199 additions and 28 deletions.
58 changes: 48 additions & 10 deletions crates/oxc_transformer/src/es2015/arrow_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ use oxc_allocator::Vec;
use oxc_ast::{ast::*, NONE};
use oxc_span::SPAN;
use oxc_syntax::{scope::ScopeFlags, symbol::SymbolFlags};
use oxc_traverse::{Traverse, TraverseCtx};
use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
use serde::Deserialize;

use crate::{context::Ctx, helpers::bindings::BoundIdentifier};
Expand Down Expand Up @@ -174,24 +174,18 @@ impl<'a> Traverse<'a> for ArrowFunctions<'a> {
self.inside_arrow_function_stack.pop().unwrap();
}

fn enter_class(&mut self, _class: &mut Class<'a>, _ctx: &mut TraverseCtx<'a>) {
self.inside_arrow_function_stack.push(false);
}

fn exit_class(&mut self, _class: &mut Class<'a>, _ctx: &mut TraverseCtx<'a>) {
self.inside_arrow_function_stack.pop().unwrap();
}

fn enter_static_block(&mut self, _block: &mut StaticBlock<'a>, _ctx: &mut TraverseCtx<'a>) {
self.this_var_stack.push(None);
// No need to push to `inside_arrow_function_stack` because `enter_class` already pushed `false`
self.inside_arrow_function_stack.push(false);
}

fn exit_static_block(&mut self, block: &mut StaticBlock<'a>, _ctx: &mut TraverseCtx<'a>) {
let this_var = self.this_var_stack.pop().unwrap();
if let Some(this_var) = this_var {
self.insert_this_var_statement_at_the_top_of_statements(&mut block.body, &this_var);
}

self.inside_arrow_function_stack.pop().unwrap();
}

fn enter_jsx_element_name(
Expand Down Expand Up @@ -225,6 +219,45 @@ impl<'a> Traverse<'a> for ArrowFunctions<'a> {
}

fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
// `this` inside a class resolves to `this` *outside* the class in:
// * `extends` clause
// * Computed method key
// * Computed property key
//
// ```js
// // All these `this` refer to global `this`
// class C extends this {
// [this] = 123;
// static [this] = 123;
// [this]() {}
// static [this]() {}
// }
// ```
//
// `this` resolves to the class / class instance (i.e. `this` defined *within* the class) in:
// * Class method bodies
// * Class property bodies
// * Class static blocks
//
// ```js
// // All these `this` refer to `this` defined within the class
// class C {
// a = this;
// static b = this;
// #c = this;
// d() { this }
// static e() { this }
// #f() { this }
// static { this }
// }
// ```
//
// Class method bodies are caught by `enter_function`, static blocks caught by `enter_static_block`.
// Handle property bodies here.
if matches!(ctx.parent(), Ancestor::PropertyDefinitionValue(_)) {
self.inside_arrow_function_stack.push(false);
}

if let Expression::ThisExpression(this_expr) = expr {
if !self.is_inside_arrow_function() {
return;
Expand All @@ -245,6 +278,11 @@ impl<'a> Traverse<'a> for ArrowFunctions<'a> {

*expr = self.transform_arrow_function_expression(arrow_function_expr.unbox(), ctx);
}

// See comment in `enter_expression`
if matches!(ctx.parent(), Ancestor::PropertyDefinitionValue(_)) {
self.inside_arrow_function_stack.pop().unwrap();
}
}
}

Expand Down
12 changes: 0 additions & 12 deletions crates/oxc_transformer/src/es2015/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,6 @@ impl<'a> Traverse<'a> for ES2015<'a> {
}
}

fn enter_class(&mut self, class: &mut Class<'a>, ctx: &mut TraverseCtx<'a>) {
if self.options.arrow_function.is_some() {
self.arrow_functions.enter_class(class, ctx);
}
}

fn exit_class(&mut self, class: &mut Class<'a>, ctx: &mut TraverseCtx<'a>) {
if self.options.arrow_function.is_some() {
self.arrow_functions.exit_class(class, ctx);
}
}

fn enter_static_block(&mut self, block: &mut StaticBlock<'a>, ctx: &mut TraverseCtx<'a>) {
if self.options.arrow_function.is_some() {
self.arrow_functions.enter_static_block(block, ctx);
Expand Down
5 changes: 0 additions & 5 deletions crates/oxc_transformer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,6 @@ impl<'a> Traverse<'a> for Transformer<'a> {

fn enter_class(&mut self, class: &mut Class<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.enter_class(class, ctx);
self.x3_es2015.enter_class(class, ctx);
}

fn exit_class(&mut self, class: &mut Class<'a>, ctx: &mut TraverseCtx<'a>) {
self.x3_es2015.exit_class(class, ctx);
}

fn enter_class_body(&mut self, body: &mut ClassBody<'a>, ctx: &mut TraverseCtx<'a>) {
Expand Down
2 changes: 1 addition & 1 deletion tasks/transform_conformance/snapshots/oxc.snap.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
commit: 3bcfee23

Passed: 49/58
Passed: 55/64

# All Passed:
* babel-plugin-transform-nullish-coalescing-operator
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
let f;

class C {
[f = () => this] = 1;
}

function outer() {
class C {
[f = () => this] = 1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
var _this = this;

let f;

class C {
[f = function() { return _this; }] = 1;
}

function outer() {
var _this2 = this;
class C {
[f = function() { return _this2; }] = 1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function outer() {
return () => {
class C extends this {}
};
}

function outer2() {
class C extends this {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function outer() {
var _this = this;
return function() {
class C extends _this {}
};
}

function outer2() {
class C extends this {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
function outer() {
return () => {
class C {
[this]() {}
}
};
}

function outer2() {
class C {
[this]() {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
function outer() {
var _this = this;
return function() {
class C {
[_this]() {}
}
};
}

function outer2() {
class C {
[this]() {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
function outer() {
return () => {
class C {
[this] = 1;
}
};
}

function outer2() {
class C {
[this] = 1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
function outer() {
var _this = this;
return function() {
class C {
[_this] = 1;
}
};
}

function outer2() {
class C {
[this] = 1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class C {
x = this;
}

f = () => {
class C {
x = this;
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class C {
x = this;
}

f = function() {
class C {
x = this;
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
function outer() {
return () => {
class C {
static {
t = this;
}
}
};
}

function outer2() {
class C {
static {
t = this;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
function outer() {
return function() {
class C {
static {
t = this;
}
}
};
}

function outer2() {
class C {
static {
t = this;
}
}
}

0 comments on commit 4e9e838

Please sign in to comment.