fix(es/compat): Fix generator (#5796)

**Description:**

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

**Related issue (if exists):**

 - https://github.com/vercel/next.js/issues/40399
This commit is contained in:
magic-akari 2022-09-10 14:01:43 +08:00 committed by GitHub
parent c8bb70f97e
commit aa8672e739
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 268 additions and 29 deletions

View File

@ -0,0 +1,7 @@
(async () => {
// Blob is not defined
// const blob = new Blob();
new Uint8Array(await Promise.resolve(10));
console.log("Success");
})();

View File

@ -0,0 +1,6 @@
(async () => {
const a = await 1;
expect(a).toBe(1);
const b = ((x) => x + x)(await 2);
expect(b).toBe(4);
})();

View File

@ -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();
})();

View File

@ -0,0 +1,5 @@
(async () => {
const blob = new Blob();
new Uint8Array(await blob.arrayBuffer());
console.log("Success");
})();

View File

@ -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
];
}
});
})();

View File

@ -0,0 +1,6 @@
(async () => {
const a = await 1;
expect(a).toBe(1);
const b = ((x) => x + x)(await 2);
expect(b).toBe(4);
})();

View File

@ -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
];
}
});
})();

View File

@ -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();
})();

View File

@ -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
];
}
});
})();

View File

@ -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:
@ -17,7 +17,7 @@ function _func() {
p
];
case 1:
b = _.apply(void 0, [
b = _.apply(o, [
_state.sent(),
a,
a

View File

@ -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:
@ -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

View File

@ -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:

View File

@ -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>,
}
@ -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(),
}
@ -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<_>>();
@ -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<_>>();
@ -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;
@ -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,
@ -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)
},
),
_ => (callee, 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)))
}
_ => {
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)))
}
}
}
}
}