fix corner case in `inline` (#4418)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sat, 19 Dec 2020 17:24:29 +0000 (17:24 +0000)
committerGitHub <noreply@github.com>
Sat, 19 Dec 2020 17:24:29 +0000 (01:24 +0800)
fixes #4417

lib/ast.js
lib/compress.js
test/compress/async.js

index e966cef..f319a42 100644 (file)
@@ -578,6 +578,10 @@ var AST_Arrow = DEFNODE("Arrow", "inlined value", {
     },
 }, AST_Lambda);
 
+function is_async(node) {
+    return node instanceof AST_AsyncDefun || node instanceof AST_AsyncFunction;
+}
+
 var AST_AsyncFunction = DEFNODE("AsyncFunction", "inlined name", {
     $documentation: "An asynchronous function expression",
     $propdoc: {
index 5081120..d99310e 100644 (file)
@@ -7772,7 +7772,7 @@ merge(Compressor.prototype, {
             });
         if (can_inline && stat instanceof AST_Return) {
             var value = stat.value;
-            if (exp === fn && (!value || value.is_constant_expression())) {
+            if (exp === fn && (!value || value.is_constant_expression() && safe_from_await(value))) {
                 var args = self.args.concat(value || make_node(AST_Undefined, self));
                 return make_sequence(self, args).optimize(compressor);
             }
@@ -7861,6 +7861,26 @@ merge(Compressor.prototype, {
         }
         return try_evaluate(compressor, self);
 
+        function safe_from_await(node) {
+            if (!is_async(scope || compressor.find_parent(AST_Scope))) return true;
+            var safe = true;
+            var tw = new TreeWalker(function(node) {
+                if (!safe) return true;
+                if (node instanceof AST_Scope) {
+                    if (node === fn) return;
+                    if (node instanceof AST_Arrow) {
+                        for (var i = 0; safe && i < node.argnames.length; i++) node.argnames[i].walk(tw);
+                    } else if (is_defun(node) && node.name.name == "await") {
+                        safe = false;
+                    }
+                    return true;
+                }
+                if (node instanceof AST_Symbol && node.name == "await" && node !== fn.name) safe = false;
+            });
+            node.walk(tw);
+            return safe;
+        }
+
         function return_value(stat) {
             if (!stat) return make_node(AST_Undefined, self);
             if (stat instanceof AST_Return) return stat.value || make_node(AST_Undefined, self);
@@ -7927,8 +7947,7 @@ merge(Compressor.prototype, {
                 }
                 if (node instanceof AST_Scope) return abort = true;
                 if (verify_await && node instanceof AST_Symbol && node.name == "await") {
-                    var scope = compressor.find_parent(AST_Scope);
-                    if (scope instanceof AST_AsyncDefun || scope instanceof AST_AsyncFunction) return abort = true;
+                    if (is_async(compressor.find_parent(AST_Scope))) return abort = true;
                     verify_await = false;
                 }
                 if (node instanceof AST_SymbolRef) {
@@ -8031,18 +8050,7 @@ merge(Compressor.prototype, {
             } while (!(scope instanceof AST_Scope));
             insert = scope.body.indexOf(child) + 1;
             if (!insert) return false;
-            if (scope instanceof AST_AsyncDefun || scope instanceof AST_AsyncFunction) {
-                var found = false;
-                fn.walk(new TreeWalker(function(node) {
-                    if (found) return true;
-                    if (node instanceof AST_Scope && node !== fn) {
-                        if (is_defun(node) && node.name.name == "await") found = true;
-                        return true;
-                    }
-                    if (node instanceof AST_Symbol && node.name == "await" && node !== fn.name) return found = true;
-                }));
-                if (found) return false;
-            }
+            if (!safe_from_await(fn)) return false;
             var safe_to_inject = exp !== fn || fn.parent_scope.resolve() === scope;
             if (scope instanceof AST_Toplevel) {
                 if (compressor.toplevel.vars) {
index 4fd16ef..d73bba4 100644 (file)
@@ -597,3 +597,25 @@ issue_4406: {
     expect_stdout: "PASS"
     node_version: ">=8"
 }
+
+issue_4417: {
+    options = {
+        inline: true,
+    }
+    input: {
+        (async function() {
+            console.log(function() {
+                return await => 0;
+            }().prototype);
+        })();
+    }
+    expect: {
+        (async function() {
+            console.log(function() {
+                return await => 0;
+            }().prototype);
+        })();
+    }
+    expect_stdout: "undefined"
+    node_version: ">=8"
+}