mirror of
https://github.com/swc-project/swc.git
synced 2024-12-24 22:22:34 +03:00
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:
parent
c8bb70f97e
commit
aa8672e739
7
crates/swc/tests/exec/next/40399/1/exec.js
Normal file
7
crates/swc/tests/exec/next/40399/1/exec.js
Normal file
@ -0,0 +1,7 @@
|
||||
(async () => {
|
||||
// Blob is not defined
|
||||
// const blob = new Blob();
|
||||
|
||||
new Uint8Array(await Promise.resolve(10));
|
||||
console.log("Success");
|
||||
})();
|
6
crates/swc/tests/exec/next/40399/2/exec.js
Normal file
6
crates/swc/tests/exec/next/40399/2/exec.js
Normal 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);
|
||||
})();
|
25
crates/swc/tests/exec/next/40399/3/exec.js
Normal file
25
crates/swc/tests/exec/next/40399/3/exec.js
Normal 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();
|
||||
})();
|
5
crates/swc/tests/fixture/next.js/40399/1/input/index.js
Normal file
5
crates/swc/tests/fixture/next.js/40399/1/input/index.js
Normal file
@ -0,0 +1,5 @@
|
||||
(async () => {
|
||||
const blob = new Blob();
|
||||
new Uint8Array(await blob.arrayBuffer());
|
||||
console.log("Success");
|
||||
})();
|
25
crates/swc/tests/fixture/next.js/40399/1/output/index.js
Normal file
25
crates/swc/tests/fixture/next.js/40399/1/output/index.js
Normal 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
|
||||
];
|
||||
}
|
||||
});
|
||||
})();
|
6
crates/swc/tests/fixture/next.js/40399/2/input/index.js
Normal file
6
crates/swc/tests/fixture/next.js/40399/2/input/index.js
Normal 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);
|
||||
})();
|
32
crates/swc/tests/fixture/next.js/40399/2/output/index.js
Normal file
32
crates/swc/tests/fixture/next.js/40399/2/output/index.js
Normal 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
|
||||
];
|
||||
}
|
||||
});
|
||||
})();
|
25
crates/swc/tests/fixture/next.js/40399/3/input/index.js
Normal file
25
crates/swc/tests/fixture/next.js/40399/3/input/index.js
Normal 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();
|
||||
})();
|
84
crates/swc/tests/fixture/next.js/40399/3/output/index.js
Normal file
84
crates/swc/tests/fixture/next.js/40399/3/output/index.js
Normal 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
|
||||
];
|
||||
}
|
||||
});
|
||||
})();
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user