diff --git a/crates/oxc_ast/src/ast_builder_impl.rs b/crates/oxc_ast/src/ast_builder_impl.rs
index 47d98436579ce0..e428056f0f3259 100644
--- a/crates/oxc_ast/src/ast_builder_impl.rs
+++ b/crates/oxc_ast/src/ast_builder_impl.rs
@@ -147,6 +147,45 @@ impl<'a> AstBuilder<'a> {
mem::replace(decl, empty_decl)
}
+ /// Move a formal parameters out by replacing it with an empty [FormalParameters].
+ #[inline]
+ pub fn move_formal_parameters(self, params: &mut FormalParameters<'a>) -> FormalParameters<'a> {
+ let empty_params = self.formal_parameters(Span::default(), params.kind, self.vec(), NONE);
+ mem::replace(params, empty_params)
+ }
+
+ /// Move a function out by replacing it with an empty [Function]
+ #[inline]
+ pub fn move_function(self, function: &mut Function<'a>) -> Function<'a> {
+ let params = self.formal_parameters(
+ Span::default(),
+ FormalParameterKind::FormalParameter,
+ self.vec(),
+ NONE,
+ );
+ let empty_function = self.function(
+ FunctionType::FunctionDeclaration,
+ Span::default(),
+ None,
+ false,
+ false,
+ false,
+ NONE,
+ NONE,
+ params,
+ NONE,
+ NONE,
+ );
+ mem::replace(function, empty_function)
+ }
+
+ /// Move a function body out by replacing it with an empty [FunctionBody].
+ #[inline]
+ pub fn move_function_body(self, body: &mut FunctionBody<'a>) -> FunctionBody<'a> {
+ let empty_body = self.function_body(Span::default(), self.vec(), self.vec());
+ mem::replace(body, empty_body)
+ }
+
/// Move an array element out by replacing it with an
/// [elision](ArrayExpressionElement::Elision).
pub fn move_array_expression_element(
diff --git a/crates/oxc_transformer/src/common/statement_injector.rs b/crates/oxc_transformer/src/common/statement_injector.rs
index 6a390b2b599010..d3387614e5f144 100644
--- a/crates/oxc_transformer/src/common/statement_injector.rs
+++ b/crates/oxc_transformer/src/common/statement_injector.rs
@@ -78,7 +78,6 @@ impl<'a> StatementInjectorStore<'a> {
}
/// Add a statement to be inserted immediately after the target statement.
- #[expect(dead_code)]
pub fn insert_after(&self, target: Address, stmt: Statement<'a>) {
let mut insertions = self.insertions.borrow_mut();
let adjacent_stmts = insertions.entry(target).or_default();
@@ -131,145 +130,8 @@ impl<'a> StatementInjectorStore<'a> {
new_statements.push(stmt);
new_statements.extend(adjacent_stmts.into_iter().map(|s| s.stmt));
}
- }
- }
-
- *statements = new_statements;
- }
-}
-//! Utility transform to add new statements before or after the specified statement.
-//!
-//! `StatementInjectorStore` contains a `FxHashMap
>`. It is stored on `TransformCtx`.
-//!
-//! `StatementInjector` transform inserts new statements before or after a statement which is determined by the address of the statement.
-//!
-//! Other transforms can add statements to the store with following methods:
-//!
-//! ```rs
-//! self.ctx.statement_injector.insert_before(address, statement);
-//! self.ctx.statement_injector.insert_after(address, statement);
-//! self.ctx.statement_injector.insert_many_after(address, statements);
-//! ```
-
-use std::cell::RefCell;
-
-use oxc_allocator::{Address, Vec as OxcVec};
-
-use oxc_ast::{address::GetAddress, ast::*};
-use oxc_traverse::{Traverse, TraverseCtx};
-use rustc_hash::FxHashMap;
-
-use crate::TransformCtx;
-
-/// Transform that inserts any statements which have been requested insertion via `StatementInjectorStore`
-pub struct StatementInjector<'a, 'ctx> {
- ctx: &'ctx TransformCtx<'a>,
-}
-
-impl<'a, 'ctx> StatementInjector<'a, 'ctx> {
- pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self {
- Self { ctx }
- }
-}
-
-impl<'a, 'ctx> Traverse<'a> for StatementInjector<'a, 'ctx> {
- fn exit_statements(
- &mut self,
- statements: &mut OxcVec<'a, Statement<'a>>,
- ctx: &mut TraverseCtx<'a>,
- ) {
- self.ctx.statement_injector.insert_into_statements(statements, ctx);
- }
-}
-
-enum Direction {
- Before,
- After,
-}
-
-struct AdjacentStatement<'a> {
- stmt: Statement<'a>,
- direction: Direction,
-}
-
-/// Store for statements to be added to the statements.
-pub struct StatementInjectorStore<'a> {
- insertions: RefCell>>>,
-}
-
-// Public methods
-impl<'a> StatementInjectorStore<'a> {
- /// Create new `StatementInjectorStore`.
- pub fn new() -> Self {
- Self { insertions: RefCell::new(FxHashMap::default()) }
- }
-
- /// Add a statement to be inserted immediately before the target statement.
- #[expect(dead_code)]
- pub fn insert_before(&self, target: Address, stmt: Statement<'a>) {
- let mut insertions = self.insertions.borrow_mut();
- let adjacent_stmts = insertions.entry(target).or_default();
- let index = adjacent_stmts
- .iter()
- .position(|s| matches!(s.direction, Direction::After))
- .unwrap_or(adjacent_stmts.len());
- adjacent_stmts.insert(index, AdjacentStatement { stmt, direction: Direction::Before });
- }
-
- /// Add a statement to be inserted immediately after the target statement.
- #[expect(dead_code)]
- pub fn insert_after(&self, target: Address, stmt: Statement<'a>) {
- let mut insertions = self.insertions.borrow_mut();
- let adjacent_stmts = insertions.entry(target).or_default();
- adjacent_stmts.push(AdjacentStatement { stmt, direction: Direction::After });
- }
-
- /// Add multiple statements to be inserted immediately after the target statement.
- #[expect(dead_code)]
- pub fn insert_many_after(&self, target: Address, stmts: Vec>) {
- let mut insertions = self.insertions.borrow_mut();
- let adjacent_stmts = insertions.entry(target).or_default();
- adjacent_stmts.extend(
- stmts.into_iter().map(|stmt| AdjacentStatement { stmt, direction: Direction::After }),
- );
- }
-
- /// Insert statements immediately before / after the target statement.
- pub(self) fn insert_into_statements(
- &self,
- statements: &mut OxcVec<'a, Statement<'a>>,
- ctx: &mut TraverseCtx<'a>,
- ) {
- let mut insertions = self.insertions.borrow_mut();
- if insertions.is_empty() {
- return;
- }
-
- let new_statement_count = statements
- .iter()
- .filter_map(|s| insertions.get(&s.address()).map(Vec::len))
- .sum::();
- if new_statement_count == 0 {
- return;
- }
-
- let mut new_statements = ctx.ast.vec_with_capacity(statements.len() + new_statement_count);
-
- for stmt in statements.drain(..) {
- if let Some(mut adjacent_stmts) = insertions.remove(&stmt.address()) {
- let first_after_stmt_index = adjacent_stmts
- .iter()
- .position(|s| matches!(s.direction, Direction::After))
- .unwrap_or(adjacent_stmts.len());
- if first_after_stmt_index != 0 {
- let right = adjacent_stmts.split_off(first_after_stmt_index);
- new_statements.extend(adjacent_stmts.into_iter().map(|s| s.stmt));
- new_statements.push(stmt);
- new_statements.extend(right.into_iter().map(|s| s.stmt));
- } else {
- new_statements.push(stmt);
- new_statements.extend(adjacent_stmts.into_iter().map(|s| s.stmt));
- }
+ } else {
+ new_statements.push(stmt);
}
}
diff --git a/crates/oxc_transformer/src/es2017/async_to_generator.rs b/crates/oxc_transformer/src/es2017/async_to_generator.rs
index 0e60db75e356ed..43c5a2b368ee1f 100644
--- a/crates/oxc_transformer/src/es2017/async_to_generator.rs
+++ b/crates/oxc_transformer/src/es2017/async_to_generator.rs
@@ -40,16 +40,12 @@
//! * Babel helper implementation:
//! * Async / Await TC39 proposal:
-use oxc_ast::{
- ast::{
- ArrowFunctionExpression, Expression, Function, FunctionType, Statement,
- VariableDeclarationKind,
- },
- NONE,
-};
-use oxc_semantic::ScopeFlags;
-use oxc_span::{GetSpan, SPAN};
-use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
+use oxc_allocator::{Box, GetAddress};
+use oxc_ast::ast::*;
+use oxc_ast::NONE;
+use oxc_semantic::{NodeId, ReferenceFlags, ScopeFlags, ScopeId, SymbolFlags};
+use oxc_span::{Atom, GetSpan, SPAN};
+use oxc_traverse::{Ancestor, BoundIdentifier, Traverse, TraverseCtx};
use crate::{common::helper_loader::Helper, TransformCtx};
@@ -96,11 +92,9 @@ impl<'a, 'ctx> Traverse<'a> for AsyncToGenerator<'a, 'ctx> {
);
}
} else if let Expression::FunctionExpression(func) = expr {
- if !func.r#async || func.generator {
- return;
+ if let Some(new_expr) = self.transform_function_expression(func, ctx) {
+ *expr = new_expr;
}
- let new_function = self.transform_function(func, ctx);
- *expr = ctx.ast.expression_from_function(new_function);
} else if let Expression::ArrowFunctionExpression(arrow) = expr {
if !arrow.r#async {
return;
@@ -111,80 +105,149 @@ impl<'a, 'ctx> Traverse<'a> for AsyncToGenerator<'a, 'ctx> {
fn exit_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
if let Statement::FunctionDeclaration(func) = stmt {
- if !func.r#async || func.generator {
- return;
+ if let Some(new_statement) = self.transform_function_declaration(func, ctx) {
+ self.ctx.statement_injector.insert_after(stmt.address(), new_statement);
}
- let new_function = self.transform_function(func, ctx);
- if let Some(id) = func.id.take() {
- *stmt = ctx.ast.statement_declaration(ctx.ast.declaration_variable(
+ }
+ }
+}
+
+impl<'a, 'ctx> AsyncToGenerator<'a, 'ctx> {
+ fn transform_function_expression(
+ &self,
+ func: &mut Box<'a, Function<'a>>,
+ ctx: &mut TraverseCtx<'a>,
+ ) -> Option> {
+ if !func.r#async || func.generator || func.is_typescript_syntax() {
+ return None;
+ }
+
+ func.r#async = false;
+ let id = func.id.take();
+ let body = func.body.take().unwrap();
+ let params = ctx.ast.move_formal_parameters(&mut func.params);
+ let scope_id = func.scope_id.get().unwrap();
+
+ // TODO: Handle `ignoreFunctionLength`
+ //
+ if id.is_none() && !params.has_parameter() {
+ return Some(self.apply_helper_function(scope_id, params, body, ctx));
+ }
+
+ // _ref
+ let ref_bound = ctx.generate_uid(
+ id.as_ref().map_or_else(|| "ref", |id| id.name.as_str()),
+ scope_id,
+ SymbolFlags::FunctionScopedVariable,
+ );
+
+ let apply_function = {
+ let scope_id = ctx.create_child_scope(scope_id, ScopeFlags::Function);
+ let id = id.as_ref().map(|id| {
+ // Add binding to scope
+ let symbol_id = ctx.symbols_mut().create_symbol(
SPAN,
- VariableDeclarationKind::Const,
- ctx.ast.vec1(ctx.ast.variable_declarator(
- SPAN,
- VariableDeclarationKind::Const,
- ctx.ast.binding_pattern(
- ctx.ast.binding_pattern_kind_from_binding_identifier(id),
- NONE,
- false,
- ),
- Some(ctx.ast.expression_from_function(new_function)),
- false,
- )),
- false,
- ));
+ id.name.clone().into_compact_str(),
+ SymbolFlags::FunctionScopedVariable | SymbolFlags::Function,
+ scope_id,
+ NodeId::DUMMY,
+ );
+ ctx.ast.binding_identifier_with_symbol_id(SPAN, id.name.clone(), symbol_id)
+ });
+ let params = Self::generate_placeholder_parameters(¶ms, scope_id, ctx);
+ let statements = ctx.ast.vec1(Self::generate_apply_call_statement(&ref_bound, ctx));
+ let body = ctx.ast.function_body(SPAN, ctx.ast.vec(), statements);
+ Self::create_function(id, params, body, scope_id, ctx)
+ };
+
+ {
+ let mut statements = ctx.ast.vec_with_capacity(3);
+ let expression = self.apply_helper_function(scope_id, params, body, ctx);
+ statements.push(Self::get_helper_call_declaration(&ref_bound, expression, ctx));
+
+ if let Some(id) = apply_function.id.as_ref() {
+ let reference = ctx.create_bound_reference_id(
+ SPAN,
+ id.name.clone(),
+ id.symbol_id.get().unwrap(),
+ ReferenceFlags::Read,
+ );
+ let statement = Statement::from(ctx.ast.declaration_from_function(apply_function));
+ statements.push(statement);
+ let argument = Some(ctx.ast.expression_from_identifier_reference(reference));
+ statements.push(ctx.ast.statement_return(SPAN, argument));
} else {
- *stmt =
- ctx.ast.statement_declaration(ctx.ast.declaration_from_function(new_function));
+ let statement_return = ctx
+ .ast
+ .statement_return(SPAN, Some(ctx.ast.expression_from_function(apply_function)));
+ statements.push(statement_return);
}
+
+ func.body.replace(ctx.ast.alloc_function_body(SPAN, ctx.ast.vec(), statements));
}
+
+ // Self reference call
+ let callee = ctx.ast.expression_from_function(ctx.ast.move_function(func));
+ Some(ctx.ast.expression_call(SPAN, callee, NONE, ctx.ast.vec(), false))
}
-}
-impl<'a, 'ctx> AsyncToGenerator<'a, 'ctx> {
- fn transform_function(
+ /// ```js
+ /// function NAME(PARAMS) { return REF.apply(this, arguments); }
+ /// function REF() {
+ /// REF = FUNCTION;
+ /// return REF.apply(this, arguments);
+ /// }
+ /// ```
+ fn transform_function_declaration(
&self,
- func: &mut Function<'a>,
+ func: &mut Box<'a, Function<'a>>,
ctx: &mut TraverseCtx<'a>,
- ) -> Function<'a> {
- let target = ctx.ast.function(
- func.r#type,
- SPAN,
- None,
- true,
- false,
- false,
- func.type_parameters.take(),
- func.this_param.take(),
- ctx.ast.alloc(ctx.ast.formal_parameters(
- SPAN,
- func.params.kind,
- ctx.ast.move_vec(&mut func.params.items),
- func.params.rest.take(),
- )),
- func.return_type.take(),
- func.body.take(),
+ ) -> Option> {
+ if !func.r#async || func.generator || func.is_typescript_syntax() {
+ return None;
+ }
+
+ func.r#async = false;
+ let body = func.body.take().unwrap();
+ let params = ctx.ast.move_formal_parameters(&mut func.params);
+
+ // _ref
+ let ref_bound = ctx.generate_uid_in_current_scope(
+ func.id.as_ref().map_or_else(|| "ref", |id| id.name.as_str()),
+ SymbolFlags::FunctionScopedVariable,
);
- let parameters =
- ctx.ast.vec1(ctx.ast.argument_expression(ctx.ast.expression_from_function(target)));
- let call = self.ctx.helper_call_expr(Helper::AsyncToGenerator, parameters, ctx);
- let returns = ctx.ast.return_statement(SPAN, Some(call));
- let body = Statement::ReturnStatement(ctx.ast.alloc(returns));
- let body = ctx.ast.function_body(SPAN, ctx.ast.vec(), ctx.ast.vec1(body));
- let body = ctx.ast.alloc(body);
- let params = ctx.ast.formal_parameters(SPAN, func.params.kind, ctx.ast.vec(), NONE);
- ctx.ast.function(
- FunctionType::FunctionExpression,
- SPAN,
- None,
- false,
- false,
- false,
- func.type_parameters.take(),
- func.this_param.take(),
- params,
- func.return_type.take(),
- Some(body),
- )
+
+ // Modify the wrapper function
+ {
+ func.params =
+ Self::generate_placeholder_parameters(¶ms, func.scope_id.get().unwrap(), ctx);
+ let statements = ctx.ast.vec1(Self::generate_apply_call_statement(&ref_bound, ctx));
+ func.body.replace(ctx.ast.alloc_function_body(SPAN, ctx.ast.vec(), statements));
+ }
+
+ let mut statements = ctx.ast.vec_with_capacity(2);
+
+ let expression = self.apply_helper_function(ctx.current_scope_id(), params, body, ctx);
+ statements.push(Self::get_helper_call_assignment(
+ ref_bound.create_read_write_reference(ctx),
+ expression,
+ ctx,
+ ));
+ statements.push(Self::generate_apply_call_statement(&ref_bound, ctx));
+
+ let apply_function = {
+ let params = Self::create_empty_params(ctx);
+ let body = ctx.ast.function_body(SPAN, ctx.ast.vec(), statements);
+ Self::create_function(
+ Some(ref_bound.create_binding_identifier()),
+ params,
+ body,
+ ctx.current_scope_id(),
+ ctx,
+ )
+ };
+
+ Some(Statement::from(ctx.ast.declaration_from_function(apply_function)))
}
fn transform_arrow_function(
@@ -192,11 +255,7 @@ impl<'a, 'ctx> AsyncToGenerator<'a, 'ctx> {
arrow: &mut ArrowFunctionExpression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
- let mut body = ctx.ast.function_body(
- SPAN,
- ctx.ast.move_vec(&mut arrow.body.directives),
- ctx.ast.move_vec(&mut arrow.body.statements),
- );
+ let mut body = ctx.ast.move_function_body(&mut arrow.body);
// If the arrow's expression is true, we need to wrap the only one expression with return statement.
if arrow.expression {
@@ -208,24 +267,191 @@ impl<'a, 'ctx> AsyncToGenerator<'a, 'ctx> {
*statement = ctx.ast.statement_return(expression.span(), Some(expression));
}
- let r#type = FunctionType::FunctionExpression;
- let parameters = ctx.ast.alloc(ctx.ast.formal_parameters(
+ let scope_id = arrow.scope_id.get().unwrap();
+ ctx.scopes_mut().get_flags_mut(scope_id).remove(ScopeFlags::Arrow);
+
+ self.apply_helper_function(
+ scope_id,
+ ctx.ast.move_formal_parameters(&mut arrow.params),
+ ctx.ast.alloc(body),
+ ctx,
+ )
+ }
+
+ /// Passing specified parameters to create a function.
+ fn create_function(
+ id: Option>,
+ params: Box<'a, FormalParameters<'a>>,
+ body: FunctionBody<'a>,
+ scope_id: ScopeId,
+ ctx: &mut TraverseCtx<'a>,
+ ) -> Function<'a> {
+ let r#type = if id.is_some() {
+ FunctionType::FunctionDeclaration
+ } else {
+ FunctionType::FunctionExpression
+ };
+ ctx.ast.function_with_scope_id(
+ r#type,
SPAN,
- arrow.params.kind,
- ctx.ast.move_vec(&mut arrow.params.items),
- arrow.params.rest.take(),
+ id,
+ false,
+ false,
+ false,
+ NONE,
+ NONE,
+ params,
+ NONE,
+ Some(body),
+ scope_id,
+ )
+ }
+
+ /// Call `apply` method for the passed-in reference, with `this` and `arguments` as arguments.
+ ///
+ /// ```js
+ /// ref_bound.apply(this, arguments);
+ /// ```
+ fn generate_apply_call_statement(
+ ref_bound: &BoundIdentifier<'a>,
+ ctx: &mut TraverseCtx<'a>,
+ ) -> Statement<'a> {
+ let symbol_id = ctx.scopes().find_binding(ctx.current_scope_id(), "arguments");
+ let arguments_ident =
+ ctx.create_reference_id(SPAN, Atom::from("arguments"), symbol_id, ReferenceFlags::Read);
+ let arguments_ident = ctx.ast.expression_from_identifier_reference(arguments_ident);
+
+ // (this, arguments)
+ let mut arguments = ctx.ast.vec_with_capacity(2);
+ arguments.push(ctx.ast.argument_expression(ctx.ast.expression_this(SPAN)));
+ arguments.push(ctx.ast.argument_expression(arguments_ident));
+ // _ref.apply
+ let callee = ctx.ast.expression_member(ctx.ast.member_expression_static(
+ SPAN,
+ ref_bound.create_read_expression(ctx),
+ ctx.ast.identifier_name(SPAN, "apply"),
+ false,
));
- let body = Some(body);
- let mut function = ctx
- .ast
- .function(r#type, SPAN, None, true, false, false, NONE, NONE, parameters, NONE, body);
- function.scope_id = arrow.scope_id.clone();
- if let Some(scope_id) = function.scope_id.get() {
- ctx.scopes_mut().get_flags_mut(scope_id).remove(ScopeFlags::Arrow);
- }
+ let argument = ctx.ast.expression_call(SPAN, callee, NONE, arguments, false);
+ ctx.ast.statement_return(SPAN, Some(argument))
+ }
+ /// Returns an [`Expression`] that calls [`Helper::AsyncToGenerator`] helper function with arguments
+ /// constructed from the passed-in parameters, body, and scope_id.
+ ///
+ /// The generated code looks like:
+ /// ```js
+ /// asyncToGenerator(function* (PARAMS) {
+ /// BODY
+ /// });
+ /// ```
+ fn apply_helper_function(
+ &self,
+ scope_id: ScopeId,
+ parameters: FormalParameters<'a>,
+ body: Box<'a, FunctionBody<'a>>,
+ ctx: &mut TraverseCtx<'a>,
+ ) -> Expression<'a> {
+ let r#type = FunctionType::FunctionExpression;
+ let function = ctx.ast.function_with_scope_id(
+ r#type,
+ SPAN,
+ None,
+ true,
+ false,
+ false,
+ NONE,
+ NONE,
+ parameters,
+ NONE,
+ Some(body),
+ scope_id,
+ );
let arguments =
ctx.ast.vec1(ctx.ast.argument_expression(ctx.ast.expression_from_function(function)));
self.ctx.helper_call_expr(Helper::AsyncToGenerator, arguments, ctx)
}
+
+ /// Generate a [`VariableDeclaration`] for the ref and pass the expression as init of [`VariableDeclarator`]
+ ///
+ /// The generated code looks like:
+ /// ```js
+ /// var ref = EXPRESSION;
+ /// ```
+ fn get_helper_call_declaration(
+ ref_bound: &BoundIdentifier<'a>,
+ expression: Expression<'a>,
+ ctx: &mut TraverseCtx<'a>,
+ ) -> Statement<'a> {
+ let declarations = ctx.ast.vec1(ctx.ast.variable_declarator(
+ SPAN,
+ VariableDeclarationKind::Var,
+ ref_bound.create_binding_pattern(ctx),
+ Some(expression),
+ false,
+ ));
+ ctx.ast.statement_declaration(ctx.ast.declaration_variable(
+ SPAN,
+ VariableDeclarationKind::Var,
+ declarations,
+ false,
+ ))
+ }
+
+ /// Generate an [`AssignmentExpression`] for the ident and pass the expression as the right side of the assignment.
+ ///
+ /// The generated code looks like:
+ /// ```js
+ /// ident = EXPRESSION;
+ /// ```
+ fn get_helper_call_assignment(
+ ident: IdentifierReference<'a>,
+ expression: Expression<'a>,
+ ctx: &mut TraverseCtx<'a>,
+ ) -> Statement<'a> {
+ let expression = ctx.ast.expression_assignment(
+ SPAN,
+ AssignmentOperator::Assign,
+ AssignmentTarget::from(
+ ctx.ast.simple_assignment_target_from_identifier_reference(ident),
+ ),
+ expression,
+ );
+ ctx.ast.statement_expression(SPAN, expression)
+ }
+
+ /// Generate placeholder [`FormalParameters`] which named `_x` based on the passed-in parameters.
+ ///J `function p(x, y, z, d = 0, ...rest) {}` -> `function* (_x, _x1, _x2) {}`
+ fn generate_placeholder_parameters(
+ params: &FormalParameters<'a>,
+ scope_id: ScopeId,
+ ctx: &mut TraverseCtx<'a>,
+ ) -> Box<'a, FormalParameters<'a>> {
+ let mut parameters = ctx.ast.vec_with_capacity(params.items.len());
+ for param in ¶ms.items {
+ let binding = ctx.generate_uid("x", scope_id, SymbolFlags::FunctionScopedVariable);
+ parameters.push(
+ ctx.ast.plain_formal_parameter(param.span(), binding.create_binding_pattern(ctx)),
+ );
+ }
+ let parameters = ctx.ast.alloc_formal_parameters(
+ SPAN,
+ FormalParameterKind::FormalParameter,
+ parameters,
+ NONE,
+ );
+
+ parameters
+ }
+
+ /// Create an empty [FormalParameters] with [FormalParameterKind::FormalParameter].
+ fn create_empty_params(ctx: &mut TraverseCtx<'a>) -> Box<'a, FormalParameters<'a>> {
+ let apply_function_params = ctx.ast.alloc_formal_parameters(
+ SPAN,
+ FormalParameterKind::FormalParameter,
+ ctx.ast.vec(),
+ NONE,
+ );
+ apply_function_params
+ }
}
diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs
index 2a60003e24a737..90a2efd431b474 100644
--- a/crates/oxc_transformer/src/lib.rs
+++ b/crates/oxc_transformer/src/lib.rs
@@ -241,7 +241,6 @@ impl<'a, 'ctx> Traverse<'a> for TransformerImpl<'a, 'ctx> {
fn exit_function(&mut self, func: &mut Function<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.exit_function(func, ctx);
self.x1_react.exit_function(func, ctx);
- self.x2_es2017.exit_function(func, ctx);
self.x3_es2015.exit_function(func, ctx);
}
diff --git a/tasks/transform_conformance/snapshots/babel.snap.md b/tasks/transform_conformance/snapshots/babel.snap.md
index 4faa31262c0e60..bf32e4d53bed2a 100644
--- a/tasks/transform_conformance/snapshots/babel.snap.md
+++ b/tasks/transform_conformance/snapshots/babel.snap.md
@@ -1,6 +1,6 @@
commit: d20b314c
-Passed: 348/1058
+Passed: 349/1058
# All Passed:
* babel-plugin-transform-class-static-block
@@ -1632,7 +1632,7 @@ x Output mismatch
x Output mismatch
-# babel-plugin-transform-async-to-generator (2/24)
+# babel-plugin-transform-async-to-generator (3/24)
* assumption-ignoreFunctionLength-true/basic/input.mjs
x Output mismatch
@@ -1649,19 +1649,177 @@ x Output mismatch
x Output mismatch
* async-to-generator/function-arity/input.js
-x Output mismatch
+Bindings mismatch:
+after transform: ScopeId(0): ["_foo", "foo"]
+rebuilt : ScopeId(3): ["a", "b"]
+Scope flags mismatch:
+after transform: ScopeId(0): ScopeFlags(Top)
+rebuilt : ScopeId(3): ScopeFlags(Function)
+Scope parent mismatch:
+after transform: ScopeId(0): None
+rebuilt : ScopeId(3): Some(ScopeId(2))
+Scope children mismatch:
+after transform: ScopeId(0): [ScopeId(1), ScopeId(2), ScopeId(3)]
+rebuilt : ScopeId(3): []
+Bindings mismatch:
+after transform: ScopeId(1): ["_x", "a", "b"]
+rebuilt : ScopeId(1): ["_x"]
+Scope parent mismatch:
+after transform: ScopeId(1): Some(ScopeId(0))
+rebuilt : ScopeId(1): Some(ScopeId(0))
+Bindings mismatch:
+after transform: ScopeId(2): ["_name", "a", "b", "name"]
+rebuilt : ScopeId(5): ["a", "b"]
+Scope parent mismatch:
+after transform: ScopeId(2): Some(ScopeId(0))
+rebuilt : ScopeId(5): Some(ScopeId(4))
+Scope children mismatch:
+after transform: ScopeId(2): [ScopeId(4)]
+rebuilt : ScopeId(5): []
+Scope parent mismatch:
+after transform: ScopeId(4): Some(ScopeId(2))
+rebuilt : ScopeId(6): Some(ScopeId(4))
+Bindings mismatch:
+after transform: ScopeId(3): ["_ref", "a", "b"]
+rebuilt : ScopeId(8): ["a", "b"]
+Scope parent mismatch:
+after transform: ScopeId(3): Some(ScopeId(0))
+rebuilt : ScopeId(8): Some(ScopeId(7))
+Scope children mismatch:
+after transform: ScopeId(3): [ScopeId(5)]
+rebuilt : ScopeId(8): []
+Scope parent mismatch:
+after transform: ScopeId(5): Some(ScopeId(3))
+rebuilt : ScopeId(9): Some(ScopeId(7))
+Symbol scope ID mismatch for "foo":
+after transform: SymbolId(0): ScopeId(0)
+rebuilt : SymbolId(0): ScopeId(0)
+Symbol scope ID mismatch for "_foo":
+after transform: SymbolId(8): ScopeId(0)
+rebuilt : SymbolId(2): ScopeId(0)
+Symbol scope ID mismatch for "a":
+after transform: SymbolId(1): ScopeId(1)
+rebuilt : SymbolId(3): ScopeId(3)
+Symbol scope ID mismatch for "b":
+after transform: SymbolId(2): ScopeId(1)
+rebuilt : SymbolId(4): ScopeId(3)
+Symbol scope ID mismatch for "_name":
+after transform: SymbolId(10): ScopeId(2)
+rebuilt : SymbolId(5): ScopeId(4)
+Symbol flags mismatch for "name":
+after transform: SymbolId(11): SymbolFlags(FunctionScopedVariable | Function)
+rebuilt : SymbolId(8): SymbolFlags(FunctionScopedVariable)
+Symbol scope ID mismatch for "name":
+after transform: SymbolId(11): ScopeId(4)
+rebuilt : SymbolId(8): ScopeId(4)
+Symbol scope ID mismatch for "_ref":
+after transform: SymbolId(13): ScopeId(3)
+rebuilt : SymbolId(10): ScopeId(7)
* async-to-generator/object-method-with-super/input.js
x Output mismatch
* async-to-generator/shadowed-promise/input.js
-x Output mismatch
+Bindings mismatch:
+after transform: ScopeId(0): ["Promise", "_foo", "foo"]
+rebuilt : ScopeId(3): []
+Scope flags mismatch:
+after transform: ScopeId(0): ScopeFlags(Top)
+rebuilt : ScopeId(3): ScopeFlags(Function)
+Scope parent mismatch:
+after transform: ScopeId(0): None
+rebuilt : ScopeId(3): Some(ScopeId(2))
+Scope children mismatch:
+after transform: ScopeId(0): [ScopeId(1)]
+rebuilt : ScopeId(3): [ScopeId(4)]
+Scope parent mismatch:
+after transform: ScopeId(1): Some(ScopeId(0))
+rebuilt : ScopeId(1): Some(ScopeId(0))
+Scope children mismatch:
+after transform: ScopeId(1): [ScopeId(2)]
+rebuilt : ScopeId(1): []
+Scope parent mismatch:
+after transform: ScopeId(2): Some(ScopeId(1))
+rebuilt : ScopeId(4): Some(ScopeId(3))
+Symbol scope ID mismatch for "Promise":
+after transform: SymbolId(0): ScopeId(0)
+rebuilt : SymbolId(0): ScopeId(0)
+Symbol scope ID mismatch for "foo":
+after transform: SymbolId(1): ScopeId(0)
+rebuilt : SymbolId(1): ScopeId(0)
+Symbol scope ID mismatch for "_foo":
+after transform: SymbolId(3): ScopeId(0)
+rebuilt : SymbolId(2): ScopeId(0)
* async-to-generator/shadowed-promise-import/input.mjs
-x Output mismatch
+Bindings mismatch:
+after transform: ScopeId(0): ["Promise", "_foo", "foo"]
+rebuilt : ScopeId(3): []
+Scope flags mismatch:
+after transform: ScopeId(0): ScopeFlags(Top)
+rebuilt : ScopeId(3): ScopeFlags(Function)
+Scope parent mismatch:
+after transform: ScopeId(0): None
+rebuilt : ScopeId(3): Some(ScopeId(2))
+Scope children mismatch:
+after transform: ScopeId(0): [ScopeId(1)]
+rebuilt : ScopeId(3): []
+Scope parent mismatch:
+after transform: ScopeId(1): Some(ScopeId(0))
+rebuilt : ScopeId(1): Some(ScopeId(0))
+Symbol scope ID mismatch for "Promise":
+after transform: SymbolId(0): ScopeId(0)
+rebuilt : SymbolId(0): ScopeId(0)
+Symbol scope ID mismatch for "foo":
+after transform: SymbolId(1): ScopeId(0)
+rebuilt : SymbolId(1): ScopeId(0)
+Symbol scope ID mismatch for "_foo":
+after transform: SymbolId(2): ScopeId(0)
+rebuilt : SymbolId(2): ScopeId(0)
* async-to-generator/shadowed-promise-nested/input.js
-x Output mismatch
+Bindings mismatch:
+after transform: ScopeId(0): ["Promise", "_foo", "foo"]
+rebuilt : ScopeId(3): ["Promise", "_bar", "bar"]
+Scope flags mismatch:
+after transform: ScopeId(0): ScopeFlags(Top)
+rebuilt : ScopeId(3): ScopeFlags(Function)
+Scope parent mismatch:
+after transform: ScopeId(0): None
+rebuilt : ScopeId(3): Some(ScopeId(2))
+Scope children mismatch:
+after transform: ScopeId(0): [ScopeId(1)]
+rebuilt : ScopeId(3): [ScopeId(4), ScopeId(5)]
+Bindings mismatch:
+after transform: ScopeId(1): ["Promise", "_bar", "bar"]
+rebuilt : ScopeId(6): []
+Scope parent mismatch:
+after transform: ScopeId(1): Some(ScopeId(0))
+rebuilt : ScopeId(6): Some(ScopeId(5))
+Scope children mismatch:
+after transform: ScopeId(1): [ScopeId(2)]
+rebuilt : ScopeId(6): []
+Scope parent mismatch:
+after transform: ScopeId(2): Some(ScopeId(1))
+rebuilt : ScopeId(4): Some(ScopeId(3))
+Symbol scope ID mismatch for "Promise":
+after transform: SymbolId(0): ScopeId(0)
+rebuilt : SymbolId(0): ScopeId(0)
+Symbol scope ID mismatch for "foo":
+after transform: SymbolId(1): ScopeId(0)
+rebuilt : SymbolId(1): ScopeId(0)
+Symbol scope ID mismatch for "_foo":
+after transform: SymbolId(5): ScopeId(0)
+rebuilt : SymbolId(2): ScopeId(0)
+Symbol scope ID mismatch for "Promise":
+after transform: SymbolId(2): ScopeId(1)
+rebuilt : SymbolId(3): ScopeId(3)
+Symbol scope ID mismatch for "bar":
+after transform: SymbolId(3): ScopeId(1)
+rebuilt : SymbolId(4): ScopeId(3)
+Symbol scope ID mismatch for "_bar":
+after transform: SymbolId(4): ScopeId(1)
+rebuilt : SymbolId(5): ScopeId(3)
* bluebird-coroutines/arrow-function/input.js
x Output mismatch
@@ -1682,14 +1840,40 @@ x Output mismatch
x Output mismatch
* regression/8783/input.js
-x Output mismatch
+Scope children mismatch:
+after transform: ScopeId(0): [ScopeId(1)]
+rebuilt : ScopeId(0): [ScopeId(1)]
+Bindings mismatch:
+after transform: ScopeId(1): ["_poll", "poll"]
+rebuilt : ScopeId(2): []
+Scope parent mismatch:
+after transform: ScopeId(1): Some(ScopeId(0))
+rebuilt : ScopeId(2): Some(ScopeId(1))
+Scope children mismatch:
+after transform: ScopeId(1): [ScopeId(2)]
+rebuilt : ScopeId(2): []
+Scope parent mismatch:
+after transform: ScopeId(2): Some(ScopeId(1))
+rebuilt : ScopeId(3): Some(ScopeId(1))
+Symbol scope ID mismatch for "_poll":
+after transform: SymbolId(1): ScopeId(1)
+rebuilt : SymbolId(0): ScopeId(1)
+Symbol flags mismatch for "poll":
+after transform: SymbolId(2): SymbolFlags(FunctionScopedVariable | Function)
+rebuilt : SymbolId(1): SymbolFlags(FunctionScopedVariable)
+Symbol scope ID mismatch for "poll":
+after transform: SymbolId(2): ScopeId(2)
+rebuilt : SymbolId(1): ScopeId(1)
+Symbol reference IDs mismatch for "poll":
+after transform: SymbolId(2): [ReferenceId(7)]
+rebuilt : SymbolId(1): [ReferenceId(4), ReferenceId(7)]
+Reference symbol mismatch for "poll":
+after transform: SymbolId(0) "poll"
+rebuilt : SymbolId(1) "poll"
* regression/T7108/input.js
x Output mismatch
-* regression/T7194/input.js
-x Output mismatch
-
* regression/gh-6923/input.js
x Output mismatch