Skip to content

Commit

Permalink
fix(transformer): arrow func transform maintain scope ID (#3633)
Browse files Browse the repository at this point in the history
In arrow function transform, set `scope_id` of new `function () {}` to `scope_id` of arrow function it replaces, and alter scope flags.
  • Loading branch information
overlookmotel committed Jun 12, 2024
1 parent 82efa58 commit 95825d6
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 21 deletions.
61 changes: 44 additions & 17 deletions crates/oxc_transformer/src/es2015/arrow_functions.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use std::cell::Cell;

use oxc_allocator::Vec;
use oxc_ast::ast::*;
use oxc_span::{Atom, SPAN};
use oxc_syntax::scope::ScopeFlags;
use oxc_traverse::TraverseCtx;
use serde::Deserialize;

use crate::context::Ctx;
Expand Down Expand Up @@ -140,6 +144,7 @@ impl<'a> ArrowFunctions<'a> {
fn transform_arrow_function_expression(
&mut self,
arrow_function_expr: &mut ArrowFunctionExpression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let mut body = self.ctx.ast.copy(&arrow_function_expr.body);

Expand All @@ -154,21 +159,39 @@ impl<'a> ArrowFunctions<'a> {
}
}

let new_function = self.ctx.ast.function(
FunctionType::FunctionExpression,
arrow_function_expr.span,
None,
false,
arrow_function_expr.r#async,
None,
self.ctx.ast.copy(&arrow_function_expr.params),
Some(body),
self.ctx.ast.copy(&arrow_function_expr.type_parameters),
self.ctx.ast.copy(&arrow_function_expr.return_type),
Modifiers::empty(),
);

Expression::FunctionExpression(new_function)
// There shouldn't need to be a conditional here. Every arrow function should have a scope ID.
// But at present TS transforms don't seem to set `scope_id` in some cases, so this test case
// fails if just unwrap `scope_id`:
// `typescript/tests/cases/compiler/classFieldSuperAccessible.ts`.
// ```ts
// class D {
// accessor b = () => {}
// }
// ```
// TODO: Change to `arrow_function_expr.scope_id.get().unwrap()` once scopes are correct
// in TS transforms.
let scope_id = arrow_function_expr.scope_id.get();
if let Some(scope_id) = scope_id {
let flags = ctx.scopes_mut().get_flags_mut(scope_id);
*flags &= !ScopeFlags::Arrow;
}

let new_function = Function {
r#type: FunctionType::FunctionExpression,
span: arrow_function_expr.span,
id: None,
generator: false,
r#async: arrow_function_expr.r#async,
this_param: None,
params: self.ctx.ast.copy(&arrow_function_expr.params),
body: Some(body),
type_parameters: self.ctx.ast.copy(&arrow_function_expr.type_parameters),
return_type: self.ctx.ast.copy(&arrow_function_expr.return_type),
modifiers: Modifiers::empty(),
scope_id: Cell::new(scope_id),
};

Expression::FunctionExpression(self.ctx.ast.alloc(new_function))
}

pub fn transform_expression(&mut self, expr: &mut Expression<'a>) {
Expand All @@ -181,7 +204,11 @@ impl<'a> ArrowFunctions<'a> {
}
}

pub fn transform_expression_on_exit(&mut self, expr: &mut Expression<'a>) {
pub fn transform_expression_on_exit(
&mut self,
expr: &mut Expression<'a>,
ctx: &mut TraverseCtx<'a>,
) {
match expr {
Expression::ThisExpression(this_expr) => {
if !self.is_inside_arrow_function() {
Expand All @@ -195,7 +222,7 @@ impl<'a> ArrowFunctions<'a> {
));
}
Expression::ArrowFunctionExpression(arrow_function_expr) => {
*expr = self.transform_arrow_function_expression(arrow_function_expr);
*expr = self.transform_arrow_function_expression(arrow_function_expr, ctx);
self.stacks.pop();
}
Expression::FunctionExpression(_) => {
Expand Down
9 changes: 7 additions & 2 deletions crates/oxc_transformer/src/es2015/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub use options::ES2015Options;

use oxc_allocator::Vec;
use oxc_ast::ast::*;
use oxc_traverse::TraverseCtx;
use std::rc::Rc;

use crate::context::Ctx;
Expand Down Expand Up @@ -61,9 +62,13 @@ impl<'a> ES2015<'a> {
}
}

pub fn transform_expression_on_exit(&mut self, expr: &mut Expression<'a>) {
pub fn transform_expression_on_exit(
&mut self,
expr: &mut Expression<'a>,
ctx: &mut TraverseCtx<'a>,
) {
if self.options.arrow_function.is_some() {
self.arrow_functions.transform_expression_on_exit(expr);
self.arrow_functions.transform_expression_on_exit(expr, ctx);
}
}

Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_transformer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ impl<'a> Traverse<'a> for Transformer<'a> {
self.x3_es2015.transform_expression(expr);
}

fn exit_expression(&mut self, expr: &mut Expression<'a>, _ctx: &mut TraverseCtx<'a>) {
self.x3_es2015.transform_expression_on_exit(expr);
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
self.x3_es2015.transform_expression_on_exit(expr, ctx);
}

fn enter_simple_assignment_target(
Expand Down

0 comments on commit 95825d6

Please sign in to comment.