diff --git a/crates/swc/tests/exec/next/40399/1/exec.js b/crates/swc/tests/exec/next/40399/1/exec.js new file mode 100644 index 000000000000..1a894eee941a --- /dev/null +++ b/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"); +})(); diff --git a/crates/swc/tests/exec/next/40399/2/exec.js b/crates/swc/tests/exec/next/40399/2/exec.js new file mode 100644 index 000000000000..0006d905abd4 --- /dev/null +++ b/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); +})(); diff --git a/crates/swc/tests/exec/next/40399/3/exec.js b/crates/swc/tests/exec/next/40399/3/exec.js new file mode 100644 index 000000000000..c082a6986304 --- /dev/null +++ b/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(); +})(); diff --git a/crates/swc/tests/fixture/next.js/40399/1/input/index.js b/crates/swc/tests/fixture/next.js/40399/1/input/index.js new file mode 100644 index 000000000000..56c071d50411 --- /dev/null +++ b/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"); +})(); diff --git a/crates/swc/tests/fixture/next.js/40399/1/output/index.js b/crates/swc/tests/fixture/next.js/40399/1/output/index.js new file mode 100644 index 000000000000..e6261e8b6378 --- /dev/null +++ b/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 + ]; + } + }); +})(); diff --git a/crates/swc/tests/fixture/next.js/40399/2/input/index.js b/crates/swc/tests/fixture/next.js/40399/2/input/index.js new file mode 100644 index 000000000000..0006d905abd4 --- /dev/null +++ b/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); +})(); diff --git a/crates/swc/tests/fixture/next.js/40399/2/output/index.js b/crates/swc/tests/fixture/next.js/40399/2/output/index.js new file mode 100644 index 000000000000..6b360d2ca044 --- /dev/null +++ b/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 + ]; + } + }); +})(); diff --git a/crates/swc/tests/fixture/next.js/40399/3/input/index.js b/crates/swc/tests/fixture/next.js/40399/3/input/index.js new file mode 100644 index 000000000000..370a488b432f --- /dev/null +++ b/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(); +})(); diff --git a/crates/swc/tests/fixture/next.js/40399/3/output/index.js b/crates/swc/tests/fixture/next.js/40399/3/output/index.js new file mode 100644 index 000000000000..e15f20da405e --- /dev/null +++ b/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 + ]; + } + }); +})(); diff --git a/crates/swc/tests/tsc-references/awaitCallExpression6_es5.1.normal.js b/crates/swc/tests/tsc-references/awaitCallExpression6_es5.1.normal.js index 9b1fba7ad670..022161205b37 100644 --- a/crates/swc/tests/tsc-references/awaitCallExpression6_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/awaitCallExpression6_es5.1.normal.js @@ -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 diff --git a/crates/swc/tests/tsc-references/awaitCallExpression7_es5.1.normal.js b/crates/swc/tests/tsc-references/awaitCallExpression7_es5.1.normal.js index 44e800e9b511..79115d0c9b58 100644 --- a/crates/swc/tests/tsc-references/awaitCallExpression7_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/awaitCallExpression7_es5.1.normal.js @@ -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 diff --git a/crates/swc/tests/tsc-references/awaitClassExpression_es5.1.normal.js b/crates/swc/tests/tsc-references/awaitClassExpression_es5.1.normal.js index b58d5c22a743..23f1eb185266 100644 --- a/crates/swc/tests/tsc-references/awaitClassExpression_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/awaitClassExpression_es5.1.normal.js @@ -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: diff --git a/crates/swc_ecma_transforms_compat/src/es2015/generator.rs b/crates/swc_ecma_transforms_compat/src/es2015/generator.rs index 5157b3b4f8ec..742ff6cae81a 100644 --- a/crates/swc_ecma_transforms_compat/src/es2015/generator.rs +++ b/crates/swc_ecma_transforms_compat/src/es2015/generator.rs @@ -338,7 +338,6 @@ struct Generator { /// Index to `blocks` with_block_stack: Option>>, - temp_vars: Vec, hoisted_vars: Vec, hoisted_fns: Vec, } @@ -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::>(); @@ -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::>(); @@ -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, - _cache_identifier: bool, + is_new_call: bool, ) -> (Box, Box) { - 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))) + } + } } } }