diff --git a/internal/bundler_tests/bundler_dce_test.go b/internal/bundler_tests/bundler_dce_test.go index 97014265458..ea09225d434 100644 --- a/internal/bundler_tests/bundler_dce_test.go +++ b/internal/bundler_tests/bundler_dce_test.go @@ -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{ diff --git a/internal/bundler_tests/snapshots/snapshots_dce.txt b/internal/bundler_tests/snapshots/snapshots_dce.txt index 3c2ad0dc08c..80d5435f26e 100644 --- a/internal/bundler_tests/snapshots/snapshots_dce.txt +++ b/internal/bundler_tests/snapshots/snapshots_dce.txt @@ -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 diff --git a/internal/js_parser/js_parser.go b/internal/js_parser/js_parser.go index aff81bc3641..e6e40e0a949 100644 --- a/internal/js_parser/js_parser.go +++ b/internal/js_parser/js_parser.go @@ -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 } } diff --git a/internal/js_parser/js_parser_test.go b/internal/js_parser/js_parser_test.go index 72b7b61cc67..79c75cb850c 100644 --- a/internal/js_parser/js_parser_test.go +++ b/internal/js_parser/js_parser_test.go @@ -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)", ": ERROR: Expected \";\" but found \"(\"\n") expectParseError(t, "y = x => {}(0)", ": ERROR: Expected \";\" but found \"(\"\n") @@ -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))", ": ERROR: Expected \")\" but found \"(\"\n") expectParseError(t, "(x => {}(0))", ": ERROR: Expected \")\" but found \"(\"\n") @@ -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))", ": ERROR: Expected \")\" but found \"(\"\n") expectParseError(t, "y = (x => {}(0))", ": ERROR: Expected \")\" but found \"(\"\n") @@ -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) { @@ -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") diff --git a/internal/js_printer/js_printer.go b/internal/js_printer/js_printer.go index 4011815bc94..dc74f791f03 100644 --- a/internal/js_printer/js_printer.go +++ b/internal/js_printer/js_printer.go @@ -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"