Skip to content

Commit a3dea9c

Browse files
committed
feat(transformer/async-to-generator): handle arrow-function correctly (#6640)
1 parent 390abca commit a3dea9c

File tree

5 files changed

+57
-64
lines changed

5 files changed

+57
-64
lines changed

crates/oxc_transformer/src/es2017/async_to_generator.rs

Lines changed: 49 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ use oxc_ast::{
4949
},
5050
NONE,
5151
};
52-
use oxc_span::SPAN;
52+
use oxc_semantic::ScopeFlags;
53+
use oxc_span::{GetSpan, SPAN};
5354
use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
5455

5556
use crate::{common::helper_loader::Helper, context::TransformCtx};
@@ -102,6 +103,11 @@ impl<'a, 'ctx> Traverse<'a> for AsyncToGenerator<'a, 'ctx> {
102103
}
103104
let new_function = self.transform_function(func, ctx);
104105
*expr = ctx.ast.expression_from_function(new_function);
106+
} else if let Expression::ArrowFunctionExpression(arrow) = expr {
107+
if !arrow.r#async {
108+
return;
109+
}
110+
*expr = self.transform_arrow_function(arrow, ctx);
105111
}
106112
}
107113

@@ -134,50 +140,6 @@ impl<'a, 'ctx> Traverse<'a> for AsyncToGenerator<'a, 'ctx> {
134140
}
135141
}
136142
}
137-
138-
fn exit_arrow_function_expression(
139-
&mut self,
140-
arrow: &mut ArrowFunctionExpression<'a>,
141-
ctx: &mut TraverseCtx<'a>,
142-
) {
143-
if !arrow.r#async {
144-
return;
145-
}
146-
let body = ctx.ast.function_body(
147-
SPAN,
148-
ctx.ast.move_vec(&mut arrow.body.directives),
149-
ctx.ast.move_vec(&mut arrow.body.statements),
150-
);
151-
let target = ctx.ast.function(
152-
FunctionType::FunctionExpression,
153-
SPAN,
154-
None,
155-
true,
156-
false,
157-
false,
158-
arrow.type_parameters.take(),
159-
NONE,
160-
ctx.ast.alloc(ctx.ast.formal_parameters(
161-
SPAN,
162-
arrow.params.kind,
163-
ctx.ast.move_vec(&mut arrow.params.items),
164-
arrow.params.rest.take(),
165-
)),
166-
arrow.return_type.take(),
167-
Some(body),
168-
);
169-
let parameters =
170-
ctx.ast.vec1(ctx.ast.argument_expression(ctx.ast.expression_from_function(target)));
171-
let call = self.ctx.helper_call_expr(Helper::AsyncToGenerator, parameters, ctx);
172-
let body = ctx.ast.function_body(
173-
SPAN,
174-
ctx.ast.vec(),
175-
ctx.ast.vec1(ctx.ast.statement_expression(SPAN, call)),
176-
);
177-
arrow.body = ctx.ast.alloc(body);
178-
arrow.r#async = false;
179-
arrow.expression = true;
180-
}
181143
}
182144

183145
impl<'a, 'ctx> AsyncToGenerator<'a, 'ctx> {
@@ -226,4 +188,46 @@ impl<'a, 'ctx> AsyncToGenerator<'a, 'ctx> {
226188
Some(body),
227189
)
228190
}
191+
192+
fn transform_arrow_function(
193+
&self,
194+
arrow: &mut ArrowFunctionExpression<'a>,
195+
ctx: &mut TraverseCtx<'a>,
196+
) -> Expression<'a> {
197+
let mut body = ctx.ast.function_body(
198+
SPAN,
199+
ctx.ast.move_vec(&mut arrow.body.directives),
200+
ctx.ast.move_vec(&mut arrow.body.statements),
201+
);
202+
203+
// If the arrow's expression is true, we need to wrap the only one expression with return statement.
204+
if arrow.expression {
205+
let statement = body.statements.first_mut().unwrap();
206+
let expression = match statement {
207+
Statement::ExpressionStatement(es) => ctx.ast.move_expression(&mut es.expression),
208+
_ => unreachable!(),
209+
};
210+
*statement = ctx.ast.statement_return(expression.span(), Some(expression));
211+
}
212+
213+
let r#type = FunctionType::FunctionExpression;
214+
let parameters = ctx.ast.alloc(ctx.ast.formal_parameters(
215+
SPAN,
216+
arrow.params.kind,
217+
ctx.ast.move_vec(&mut arrow.params.items),
218+
arrow.params.rest.take(),
219+
));
220+
let body = Some(body);
221+
let mut function = ctx
222+
.ast
223+
.function(r#type, SPAN, None, true, false, false, NONE, NONE, parameters, NONE, body);
224+
function.scope_id = arrow.scope_id.clone();
225+
if let Some(scope_id) = function.scope_id.get() {
226+
ctx.scopes_mut().get_flags_mut(scope_id).remove(ScopeFlags::Arrow);
227+
}
228+
229+
let arguments =
230+
ctx.ast.vec1(ctx.ast.argument_expression(ctx.ast.expression_from_function(function)));
231+
self.ctx.helper_call_expr(Helper::AsyncToGenerator, arguments, ctx)
232+
}
229233
}

crates/oxc_transformer/src/es2017/mod.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use oxc_ast::ast::{ArrowFunctionExpression, Expression, Statement};
1+
use oxc_ast::ast::{Expression, Statement};
22
use oxc_traverse::{Traverse, TraverseCtx};
33

44
use crate::context::TransformCtx;
@@ -34,14 +34,4 @@ impl<'a, 'ctx> Traverse<'a> for ES2017<'a, 'ctx> {
3434
self.async_to_generator.exit_statement(stmt, ctx);
3535
}
3636
}
37-
38-
fn exit_arrow_function_expression(
39-
&mut self,
40-
node: &mut ArrowFunctionExpression<'a>,
41-
ctx: &mut TraverseCtx<'a>,
42-
) {
43-
if self.options.async_to_generator {
44-
self.async_to_generator.exit_arrow_function_expression(node, ctx);
45-
}
46-
}
4737
}

crates/oxc_transformer/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,6 @@ impl<'a, 'ctx> Traverse<'a> for TransformerImpl<'a, 'ctx> {
333333
.push(ctx.ast.statement_return(SPAN, Some(statement.unbox().expression)));
334334
arrow.expression = false;
335335
}
336-
self.x2_es2017.exit_arrow_function_expression(arrow, ctx);
337336
}
338337

339338
fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {

tasks/transform_conformance/snapshots/babel.snap.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
commit: 3bcfee23
22

3-
Passed: 341/1051
3+
Passed: 342/1051
44

55
# All Passed:
66
* babel-plugin-transform-logical-assignment-operators
@@ -1628,7 +1628,7 @@ x Output mismatch
16281628
x Output mismatch
16291629

16301630

1631-
# babel-plugin-transform-async-to-generator (1/24)
1631+
# babel-plugin-transform-async-to-generator (2/24)
16321632
* assumption-ignoreFunctionLength-true/basic/input.mjs
16331633
x Output mismatch
16341634

@@ -1677,9 +1677,6 @@ x Output mismatch
16771677
* regression/15978/input.js
16781678
x Output mismatch
16791679

1680-
* regression/4599/input.js
1681-
x Output mismatch
1682-
16831680
* regression/8783/input.js
16841681
x Output mismatch
16851682

tasks/transform_conformance/snapshots/babel_exec.snap.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
commit: 3bcfee23
22

3-
Passed: 35/62
3+
Passed: 34/62
44

55
# All Passed:
66
* babel-plugin-transform-logical-assignment-operators
@@ -73,7 +73,7 @@ exec failed
7373
exec failed
7474

7575

76-
# babel-plugin-transform-async-to-generator (2/6)
76+
# babel-plugin-transform-async-to-generator (1/6)
7777
* regression/15978/exec.js
7878
exec failed
7979

@@ -83,6 +83,9 @@ exec failed
8383
* regression/T6882/exec.js
8484
exec failed
8585

86+
* regression/fn-name/exec.js
87+
exec failed
88+
8689
* regression/test262-fn-length/exec.js
8790
exec failed
8891

0 commit comments

Comments
 (0)