Skip to content

Commit

Permalink
fix(es/compat): Fix generator (#5796)
Browse files Browse the repository at this point in the history
**Description:**

- Merge `temp_vars` into `hoisted_vars`.
- Fix the context of the function call and new call.

**Related issue (if exists):**

 - vercel/next.js#40399
  • Loading branch information
magic-akari committed Sep 10, 2022
1 parent c8bb70f commit aa8672e
Show file tree
Hide file tree
Showing 13 changed files with 268 additions and 29 deletions.
7 changes: 7 additions & 0 deletions crates/swc/tests/exec/next/40399/1/exec.js
@@ -0,0 +1,7 @@
(async () => {
// Blob is not defined
// const blob = new Blob();

new Uint8Array(await Promise.resolve(10));
console.log("Success");
})();
6 changes: 6 additions & 0 deletions crates/swc/tests/exec/next/40399/2/exec.js
@@ -0,0 +1,6 @@
(async () => {
const a = await 1;
expect(a).toBe(1);
const b = ((x) => x + x)(await 2);
expect(b).toBe(4);
})();
25 changes: 25 additions & 0 deletions crates/swc/tests/exec/next/40399/3/exec.js
@@ -0,0 +1,25 @@
class Foo {
constructor(v) {
this.value = v;
}

static klass = class {
constructor(v) {
this.value = v;
}
};
}

(async () => {
class Bar extends Foo {
async bar() {
const foo = new Foo(await Promise.resolve(1));
const foo2 = new Foo.klass(await Promise.resolve(2));

console.log(foo.value);
console.log(foo2.value);
}
}

await new Bar().bar();
})();
5 changes: 5 additions & 0 deletions crates/swc/tests/fixture/next.js/40399/1/input/index.js
@@ -0,0 +1,5 @@
(async () => {
const blob = new Blob();
new Uint8Array(await blob.arrayBuffer());
console.log("Success");
})();
25 changes: 25 additions & 0 deletions crates/swc/tests/fixture/next.js/40399/1/output/index.js
@@ -0,0 +1,25 @@
import _async_to_generator from "@swc/helpers/src/_async_to_generator.mjs";
import _ts_generator from "@swc/helpers/src/_ts_generator.mjs";
_async_to_generator(function() {
var blob, _;
return _ts_generator(this, function(_state) {
switch(_state.label){
case 0:
blob = new Blob();
_ = Uint8Array.bind;
return [
4,
blob.arrayBuffer()
];
case 1:
new (_.apply(Uint8Array, [
void 0,
_state.sent()
]));
console.log("Success");
return [
2
];
}
});
})();
6 changes: 6 additions & 0 deletions crates/swc/tests/fixture/next.js/40399/2/input/index.js
@@ -0,0 +1,6 @@
(async () => {
const a = await 1;
expect(a).toBe(1);
const b = ((x) => x + x)(await 2);
expect(b).toBe(4);
})();
32 changes: 32 additions & 0 deletions crates/swc/tests/fixture/next.js/40399/2/output/index.js
@@ -0,0 +1,32 @@
import _async_to_generator from "@swc/helpers/src/_async_to_generator.mjs";
import _ts_generator from "@swc/helpers/src/_ts_generator.mjs";
_async_to_generator(function() {
var a, b, _;
return _ts_generator(this, function(_state) {
switch(_state.label){
case 0:
return [
4,
1
];
case 1:
a = _state.sent();
expect(a).toBe(1);
_ = function(x) {
return x + x;
};
return [
4,
2
];
case 2:
b = _.apply(void 0, [
_state.sent()
]);
expect(b).toBe(4);
return [
2
];
}
});
})();
25 changes: 25 additions & 0 deletions crates/swc/tests/fixture/next.js/40399/3/input/index.js
@@ -0,0 +1,25 @@
class Foo {
constructor(v) {
this.value = v;
}

static klass = class {
constructor(v) {
this.value = v;
}
};
}

(async () => {
class Bar extends Foo {
async bar() {
const foo = new Foo(await Promise.resolve(1));
const foo2 = new Foo.klass(await Promise.resolve(2));

expect(foo.value).toBe(1);
expect(foo2.value).toBe(2);
}
}

await new Bar().bar();
})();
84 changes: 84 additions & 0 deletions crates/swc/tests/fixture/next.js/40399/3/output/index.js
@@ -0,0 +1,84 @@
import _async_to_generator from "@swc/helpers/src/_async_to_generator.mjs";
import _class_call_check from "@swc/helpers/src/_class_call_check.mjs";
import _create_class from "@swc/helpers/src/_create_class.mjs";
import _define_property from "@swc/helpers/src/_define_property.mjs";
import _inherits from "@swc/helpers/src/_inherits.mjs";
import _create_super from "@swc/helpers/src/_create_super.mjs";
import _ts_generator from "@swc/helpers/src/_ts_generator.mjs";
var Foo = function Foo(v) {
"use strict";
_class_call_check(this, Foo);
this.value = v;
};
_define_property(Foo, "klass", function _class(v) {
"use strict";
_class_call_check(this, _class);
this.value = v;
});
_async_to_generator(function() {
var Bar;
return _ts_generator(this, function(_state) {
switch(_state.label){
case 0:
Bar = /*#__PURE__*/ function(Foo1) {
"use strict";
_inherits(Bar, Foo1);
var _super = _create_super(Bar);
function Bar() {
_class_call_check(this, Bar);
return _super.apply(this, arguments);
}
_create_class(Bar, [
{
key: "bar",
value: function bar() {
return _async_to_generator(function() {
var foo, _, foo2, _1, _2;
return _ts_generator(this, function(_state) {
switch(_state.label){
case 0:
_ = Foo.bind;
return [
4,
Promise.resolve(1)
];
case 1:
foo = new (_.apply(Foo, [
void 0,
_state.sent()
]));
_2 = (_1 = Foo.klass).bind;
return [
4,
Promise.resolve(2)
];
case 2:
foo2 = new (_2.apply(_1, [
void 0,
_state.sent()
]));
expect(foo.value).toBe(1);
expect(foo2.value).toBe(2);
return [
2
];
}
});
})();
}
}
]);
return Bar;
}(Foo);
return [
4,
new Bar().bar()
];
case 1:
_state.sent();
return [
2
];
}
});
})();
Expand Up @@ -6,7 +6,7 @@ function func() {
}
function _func() {
_func = _async_to_generator(function() {
var b;
var b, _;
return _ts_generator(this, function(_state) {
switch(_state.label){
case 0:
Expand All @@ -17,7 +17,7 @@ function _func() {
p
];
case 1:
b = _.apply(void 0, [
b = _.apply(o, [
_state.sent(),
a,
a
Expand Down
Expand Up @@ -6,7 +6,7 @@ function func() {
}
function _func() {
_func = _async_to_generator(function() {
var b, _tmp;
var b, _, _tmp;
return _ts_generator(this, function(_state) {
switch(_state.label){
case 0:
Expand All @@ -20,7 +20,7 @@ function _func() {
p
];
case 1:
b = _.apply(void 0, _tmp.concat(_state.sent(), a));
b = _.apply(o, _tmp.concat(_state.sent(), a));
after();
return [
2
Expand Down
Expand Up @@ -9,7 +9,7 @@ function func() {
}
function _func() {
_func = _async_to_generator(function() {
var D;
var D, _;
return _ts_generator(this, function(_state) {
switch(_state.label){
case 0:
Expand Down
72 changes: 48 additions & 24 deletions crates/swc_ecma_transforms_compat/src/es2015/generator.rs
Expand Up @@ -338,7 +338,6 @@ struct Generator {
/// Index to `blocks`
with_block_stack: Option<Vec<Ptr<CodeBlock>>>,

temp_vars: Vec<VarDeclarator>,
hoisted_vars: Vec<VarDeclarator>,
hoisted_fns: Vec<FnDecl>,
}
Expand Down Expand Up @@ -370,7 +369,6 @@ impl Default for Generator {
exception_block_stack: Default::default(),
current_exception_block: Default::default(),
with_block_stack: Default::default(),
temp_vars: Default::default(),
hoisted_vars: Default::default(),
hoisted_fns: Default::default(),
}
Expand Down Expand Up @@ -751,10 +749,11 @@ impl VisitMut for Generator {
// .mark resumeLabel
// _b.apply(_a, _c.concat([%sent%, 2]));

let (mut target, this_arg) =
self.create_call_binding(node.callee.take().expect_expr(), true);
node.callee.visit_mut_with(self);

let (target, this_arg) =
self.create_call_binding(node.callee.take().expect_expr(), false);

target.visit_mut_with(self);
let callee = self.cache_expression(target);

let mut args = node.args.take().into_iter().map(Some).collect::<Vec<_>>();
Expand Down Expand Up @@ -787,13 +786,11 @@ impl VisitMut for Generator {
// .mark resumeLabel
// new (_b.apply(_a, _c.concat([%sent%, 2])));

let (mut target, this_arg) = self.create_call_binding(
Box::new(node.callee.take().make_member(quote_ident!("bind"))),
true,
);
node.callee.visit_mut_with(self);

target.visit_mut_with(self);
let callee = self.cache_expression(target);
let (target, this_arg) = self.create_call_binding(node.callee.take(), true);

let callee = self.cache_expression(Box::new(target.make_member(quote_ident!("bind"))));

let mut arg = if let Some(args) = node.args.take() {
let mut args = args.into_iter().map(Some).collect::<Vec<_>>();
Expand All @@ -809,16 +806,16 @@ impl VisitMut for Generator {
None
};

let apply = callee.make_member(Ident::new(js_word!("apply"), node.span));
let apply = Expr::Ident(callee).apply(
node.span,
this_arg,
arg.take().map(|v| v.as_arg()).into_iter().collect(),
);

*node = NewExpr {
span: node.span,
callee: Box::new(apply),
args: Some(
once(this_arg.as_arg())
.chain(arg.take().map(|v| v.as_arg()).into_iter())
.collect(),
),
args: None,
type_args: None,
};
return;
Expand Down Expand Up @@ -3392,7 +3389,7 @@ impl Generator {
fn create_temp_variable(&mut self) -> Ident {
let i = private_ident!("_");

self.temp_vars.push(VarDeclarator {
self.hoisted_vars.push(VarDeclarator {
span: DUMMY_SP,
name: i.clone().into(),
init: None,
Expand All @@ -3404,16 +3401,43 @@ impl Generator {

/// Returns `(target, this_arg)`
fn create_call_binding(
&self,
&mut self,
expr: Box<Expr>,
_cache_identifier: bool,
is_new_call: bool,
) -> (Box<Expr>, Box<Expr>) {
let callee = expr;
let mut callee = expr;

match &*callee {
Expr::SuperProp(..) => (callee, Box::new(Expr::This(ThisExpr { span: DUMMY_SP }))),
match &mut *callee {
Expr::Ident(..) => (
callee.clone(),
if is_new_call {
callee
} else {
undefined(DUMMY_SP)
},
),

Expr::Member(MemberExpr { obj, .. }) if !is_new_call => {
if obj.is_ident() {
let this_arg = obj.clone();
return (callee, this_arg);
}

let this_arg = self.create_temp_variable();
*obj = Box::new(obj.take().make_assign_to(op!("="), this_arg.clone().into()));

(callee, Box::new(Expr::Ident(this_arg)))
}

_ => (callee, undefined(DUMMY_SP)),
_ => {
if !is_new_call {
(callee, undefined(DUMMY_SP))
} else {
let this_arg = self.create_temp_variable();
let target = callee.make_assign_to(op!("="), this_arg.clone().into());
(Box::new(target), Box::new(Expr::Ident(this_arg)))
}
}
}
}
}
Expand Down

1 comment on commit aa8672e

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: aa8672e Previous: 49942ca Ratio
es/full/minify/libraries/antd 2483931405 ns/iter (± 157654513) 2451081491 ns/iter (± 66638631) 1.01
es/full/minify/libraries/d3 487250631 ns/iter (± 27364123) 463061858 ns/iter (± 23657832) 1.05
es/full/minify/libraries/echarts 1883726164 ns/iter (± 53251890) 1831571956 ns/iter (± 43276570) 1.03
es/full/minify/libraries/jquery 118029072 ns/iter (± 2969446) 103139586 ns/iter (± 5137713) 1.14
es/full/minify/libraries/lodash 154897953 ns/iter (± 11763110) 136018657 ns/iter (± 6582291) 1.14
es/full/minify/libraries/moment 75523714 ns/iter (± 8230160) 62368120 ns/iter (± 3117080) 1.21
es/full/minify/libraries/react 27255331 ns/iter (± 792407) 24750153 ns/iter (± 1093337) 1.10
es/full/minify/libraries/terser 392120388 ns/iter (± 15654044) 367368892 ns/iter (± 12571036) 1.07
es/full/minify/libraries/three 656575004 ns/iter (± 63485380) 626658818 ns/iter (± 63256020) 1.05
es/full/minify/libraries/typescript 5372070303 ns/iter (± 599608851) 5003824947 ns/iter (± 144677011) 1.07
es/full/minify/libraries/victory 1033323963 ns/iter (± 81262484) 966298737 ns/iter (± 44314749) 1.07
es/full/minify/libraries/vue 199605573 ns/iter (± 25980939) 171574133 ns/iter (± 13849459) 1.16
es/full/codegen/es3 34582 ns/iter (± 2214) 32870 ns/iter (± 1053) 1.05
es/full/codegen/es5 34354 ns/iter (± 2815) 32739 ns/iter (± 372) 1.05
es/full/codegen/es2015 34130 ns/iter (± 3320) 33456 ns/iter (± 1106) 1.02
es/full/codegen/es2016 34374 ns/iter (± 2106) 33483 ns/iter (± 1256) 1.03
es/full/codegen/es2017 34404 ns/iter (± 3091) 33739 ns/iter (± 2221) 1.02
es/full/codegen/es2018 35077 ns/iter (± 5465) 33706 ns/iter (± 932) 1.04
es/full/codegen/es2019 34325 ns/iter (± 5554) 33601 ns/iter (± 750) 1.02
es/full/codegen/es2020 34247 ns/iter (± 1448) 33408 ns/iter (± 615) 1.03
es/full/all/es3 253959950 ns/iter (± 20309131) 216477751 ns/iter (± 20790712) 1.17
es/full/all/es5 238679872 ns/iter (± 17778750) 202383072 ns/iter (± 17491871) 1.18
es/full/all/es2015 192713613 ns/iter (± 12401036) 162308693 ns/iter (± 13528183) 1.19
es/full/all/es2016 188759830 ns/iter (± 15150143) 161907729 ns/iter (± 11981314) 1.17
es/full/all/es2017 189358897 ns/iter (± 18192947) 160210722 ns/iter (± 11956221) 1.18
es/full/all/es2018 187239811 ns/iter (± 14442055) 156997709 ns/iter (± 12021424) 1.19
es/full/all/es2019 184566302 ns/iter (± 13214796) 158452089 ns/iter (± 13566768) 1.16
es/full/all/es2020 178238302 ns/iter (± 15891160) 151838842 ns/iter (± 12578687) 1.17
es/full/parser 837340 ns/iter (± 83085) 843524 ns/iter (± 51749) 0.99
es/full/base/fixer 32413 ns/iter (± 3317) 31601 ns/iter (± 2474) 1.03
es/full/base/resolver_and_hygiene 105683 ns/iter (± 25986) 103869 ns/iter (± 9525) 1.02
serialization of ast node 226 ns/iter (± 7) 227 ns/iter (± 13) 1.00
serialization of serde 233 ns/iter (± 9) 236 ns/iter (± 23) 0.99

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.