Skip to content

Commit

Permalink
async arrow functions are not IIFEs
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Nov 19, 2023
1 parent 9fa4e79 commit 19ff9d3
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 18 deletions.
2 changes: 2 additions & 0 deletions internal/bundler_tests/bundler_dce_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4319,6 +4319,8 @@ func TestDCEOfIIFE(t *testing.T) {
use(isPure);
var isNotPure = ((x = foo, y = bar) => 123)();
use(isNotPure);
(async () => ({ get then() { notPure() } }))();
(async function() { return { get then() { notPure() } }; })();
`,
},
entryPaths: []string{
Expand Down
8 changes: 8 additions & 0 deletions internal/bundler_tests/snapshots/snapshots_dce.txt
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,14 @@ var isPure = /* @__PURE__ */ ((x, y) => 123)();
use(isPure);
var isNotPure = ((x = foo, y = bar) => 123)();
use(isNotPure);
(async () => ({ get then() {
notPure();
} }))();
(async function() {
return { get then() {
notPure();
} };
})();

================================================================================
TestDCEOfUsingDeclarations
Expand Down
4 changes: 2 additions & 2 deletions internal/js_parser/js_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -14335,11 +14335,11 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
if !e.CanBeUnwrappedIfUnused {
switch target := e.Target.Data.(type) {
case *js_ast.EArrow:
if p.iifeCanBeRemovedIfUnused(target.Args, target.Body) {
if !target.IsAsync && p.iifeCanBeRemovedIfUnused(target.Args, target.Body) {
e.CanBeUnwrappedIfUnused = true
}
case *js_ast.EFunction:
if p.iifeCanBeRemovedIfUnused(target.Fn.Args, target.Fn.Body) {
if !target.Fn.IsAsync && !target.Fn.IsGenerator && p.iifeCanBeRemovedIfUnused(target.Fn.Args, target.Fn.Body) {
e.CanBeUnwrappedIfUnused = true
}
}
Expand Down
30 changes: 15 additions & 15 deletions internal/js_parser/js_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2415,9 +2415,9 @@ func TestArrow(t *testing.T) {

expectPrinted(t, "(() => {})\n(0)", "/* @__PURE__ */ (() => {\n})(0);\n")
expectPrinted(t, "(x => {})\n(0)", "/* @__PURE__ */ ((x) => {\n})(0);\n")
expectPrinted(t, "(async () => {})\n(0)", "/* @__PURE__ */ (async () => {\n})(0);\n")
expectPrinted(t, "(async x => {})\n(0)", "/* @__PURE__ */ (async (x) => {\n})(0);\n")
expectPrinted(t, "(async (x) => {})\n(0)", "/* @__PURE__ */ (async (x) => {\n})(0);\n")
expectPrinted(t, "(async () => {})\n(0)", "(async () => {\n})(0);\n")
expectPrinted(t, "(async x => {})\n(0)", "(async (x) => {\n})(0);\n")
expectPrinted(t, "(async (x) => {})\n(0)", "(async (x) => {\n})(0);\n")

expectParseError(t, "y = () => {}(0)", "<stdin>: ERROR: Expected \";\" but found \"(\"\n")
expectParseError(t, "y = x => {}(0)", "<stdin>: ERROR: Expected \";\" but found \"(\"\n")
Expand All @@ -2439,9 +2439,9 @@ func TestArrow(t *testing.T) {

expectPrinted(t, "y = (() => {})\n(0)", "y = /* @__PURE__ */ (() => {\n})(0);\n")
expectPrinted(t, "y = (x => {})\n(0)", "y = /* @__PURE__ */ ((x) => {\n})(0);\n")
expectPrinted(t, "y = (async () => {})\n(0)", "y = /* @__PURE__ */ (async () => {\n})(0);\n")
expectPrinted(t, "y = (async x => {})\n(0)", "y = /* @__PURE__ */ (async (x) => {\n})(0);\n")
expectPrinted(t, "y = (async (x) => {})\n(0)", "y = /* @__PURE__ */ (async (x) => {\n})(0);\n")
expectPrinted(t, "y = (async () => {})\n(0)", "y = (async () => {\n})(0);\n")
expectPrinted(t, "y = (async x => {})\n(0)", "y = (async (x) => {\n})(0);\n")
expectPrinted(t, "y = (async (x) => {})\n(0)", "y = (async (x) => {\n})(0);\n")

expectParseError(t, "(() => {}(0))", "<stdin>: ERROR: Expected \")\" but found \"(\"\n")
expectParseError(t, "(x => {}(0))", "<stdin>: ERROR: Expected \")\" but found \"(\"\n")
Expand All @@ -2463,9 +2463,9 @@ func TestArrow(t *testing.T) {

expectPrinted(t, "((() => {})\n(0))", "/* @__PURE__ */ (() => {\n})(0);\n")
expectPrinted(t, "((x => {})\n(0))", "/* @__PURE__ */ ((x) => {\n})(0);\n")
expectPrinted(t, "((async () => {})\n(0))", "/* @__PURE__ */ (async () => {\n})(0);\n")
expectPrinted(t, "((async x => {})\n(0))", "/* @__PURE__ */ (async (x) => {\n})(0);\n")
expectPrinted(t, "((async (x) => {})\n(0))", "/* @__PURE__ */ (async (x) => {\n})(0);\n")
expectPrinted(t, "((async () => {})\n(0))", "(async () => {\n})(0);\n")
expectPrinted(t, "((async x => {})\n(0))", "(async (x) => {\n})(0);\n")
expectPrinted(t, "((async (x) => {})\n(0))", "(async (x) => {\n})(0);\n")

expectParseError(t, "y = (() => {}(0))", "<stdin>: ERROR: Expected \")\" but found \"(\"\n")
expectParseError(t, "y = (x => {}(0))", "<stdin>: ERROR: Expected \")\" but found \"(\"\n")
Expand All @@ -2487,9 +2487,9 @@ func TestArrow(t *testing.T) {

expectPrinted(t, "y = ((() => {})\n(0))", "y = /* @__PURE__ */ (() => {\n})(0);\n")
expectPrinted(t, "y = ((x => {})\n(0))", "y = /* @__PURE__ */ ((x) => {\n})(0);\n")
expectPrinted(t, "y = ((async () => {})\n(0))", "y = /* @__PURE__ */ (async () => {\n})(0);\n")
expectPrinted(t, "y = ((async x => {})\n(0))", "y = /* @__PURE__ */ (async (x) => {\n})(0);\n")
expectPrinted(t, "y = ((async (x) => {})\n(0))", "y = /* @__PURE__ */ (async (x) => {\n})(0);\n")
expectPrinted(t, "y = ((async () => {})\n(0))", "y = (async () => {\n})(0);\n")
expectPrinted(t, "y = ((async x => {})\n(0))", "y = (async (x) => {\n})(0);\n")
expectPrinted(t, "y = ((async (x) => {})\n(0))", "y = (async (x) => {\n})(0);\n")
}

func TestTemplate(t *testing.T) {
Expand Down Expand Up @@ -4412,14 +4412,14 @@ func TestMangleIIFE(t *testing.T) {
expectPrintedNormalAndMangle(t, "(() => { return a() })()", "(() => {\n return a();\n})();\n", "a();\n")
expectPrintedNormalAndMangle(t, "(() => { let b = a; b() })()", "(() => {\n let b = a;\n b();\n})();\n", "a();\n")
expectPrintedNormalAndMangle(t, "(() => { let b = a; return b() })()", "(() => {\n let b = a;\n return b();\n})();\n", "a();\n")
expectPrintedNormalAndMangle(t, "(async () => {})()", "/* @__PURE__ */ (async () => {\n})();\n", "")
expectPrintedNormalAndMangle(t, "(async () => {})()", "(async () => {\n})();\n", "")
expectPrintedNormalAndMangle(t, "(async () => { a() })()", "(async () => {\n a();\n})();\n", "(async () => a())();\n")
expectPrintedNormalAndMangle(t, "(async () => { let b = a; b() })()", "(async () => {\n let b = a;\n b();\n})();\n", "(async () => a())();\n")

expectPrintedNormalAndMangle(t, "var a = (function() {})()", "var a = /* @__PURE__ */ function() {\n}();\n", "var a = /* @__PURE__ */ function() {\n}();\n")
expectPrintedNormalAndMangle(t, "(function() {})()", "/* @__PURE__ */ (function() {\n})();\n", "")
expectPrintedNormalAndMangle(t, "(function*() {})()", "/* @__PURE__ */ (function* () {\n})();\n", "")
expectPrintedNormalAndMangle(t, "(async function() {})()", "/* @__PURE__ */ (async function() {\n})();\n", "")
expectPrintedNormalAndMangle(t, "(function*() {})()", "(function* () {\n})();\n", "")
expectPrintedNormalAndMangle(t, "(async function() {})()", "(async function() {\n})();\n", "")
expectPrintedNormalAndMangle(t, "(function() { a() })()", "(function() {\n a();\n})();\n", "(function() {\n a();\n})();\n")
expectPrintedNormalAndMangle(t, "(function*() { a() })()", "(function* () {\n a();\n})();\n", "(function* () {\n a();\n})();\n")
expectPrintedNormalAndMangle(t, "(async function() { a() })()", "(async function() {\n a();\n})();\n", "(async function() {\n a();\n})();\n")
Expand Down
6 changes: 5 additions & 1 deletion internal/js_printer/js_printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2358,7 +2358,11 @@ func (p *printer) printExpr(expr js_ast.Expr, level js_ast.L, flags printExprFla

// Inline IIFEs that return expressions at print time
if len(e.Args) == 0 {
if arrow, ok := e.Target.Data.(*js_ast.EArrow); ok && len(arrow.Args) == 0 {
// Note: Do not inline async arrow functions as they are not IIFEs. In
// particular, they are not necessarily invoked immediately, and any
// exceptions involved in their evaluation will be swallowed without
// bubbling up to the surrounding context.
if arrow, ok := e.Target.Data.(*js_ast.EArrow); ok && len(arrow.Args) == 0 && !arrow.IsAsync {
stmts := arrow.Body.Block.Stmts

// "(() => {})()" => "void 0"
Expand Down

0 comments on commit 19ff9d3

Please sign in to comment.