fix corner cases in `inline` (#5255)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sun, 2 Jan 2022 13:24:41 +0000 (13:24 +0000)
committerGitHub <noreply@github.com>
Sun, 2 Jan 2022 13:24:41 +0000 (21:24 +0800)
fixes #5254

lib/compress.js
test/compress/const.js
test/compress/functions.js
test/compress/let.js

index 2e38368..5997a4b 100644 (file)
@@ -10317,7 +10317,7 @@ Compressor.prototype.compress = function(node) {
 
         function flatten_vars(decls, expressions) {
             var args = [ insert, 0 ];
-            var decl_var = [], expr_var = [], expr_loop = [], exprs = [];
+            var decl_var = [], expr_fn = [], expr_var = [], expr_loop = [], exprs = [];
             fn.body.filter(in_loop ? function(stat) {
                 if (!(stat instanceof AST_LambdaDefinition)) return true;
                 var name = make_node(AST_SymbolVar, stat.name, flatten_var(stat.name));
@@ -10325,7 +10325,7 @@ Compressor.prototype.compress = function(node) {
                 def.fixed = false;
                 def.orig.push(name);
                 def.eliminated++;
-                append_var(decls, expressions, name, to_func_expr(stat, true));
+                append_var(decls, expr_fn, name, to_func_expr(stat, true));
                 return false;
             } : function(stat) {
                 if (!(stat instanceof AST_LambdaDefinition)) return true;
@@ -10351,20 +10351,23 @@ Compressor.prototype.compress = function(node) {
                         exprs = [];
                     }
                     append_var(decl_var, expr_var, name, value);
-                    if (in_loop && !arg_used.has(name.name) && !fn.functions.has(name.name)) {
-                        var def = fn.variables.get(name.name);
-                        var sym = make_node(AST_SymbolRef, name, name);
-                        def.references.push(sym);
-                        expr_loop.push(make_node(AST_Assign, var_def, {
-                            operator: "=",
-                            left: sym,
-                            right: make_node(AST_Undefined, name),
-                        }));
-                    }
+                    if (!in_loop) continue;
+                    if (arg_used.has(name.name)) continue;
+                    var def = fn.variables.get(name.name);
+                    if (fn.functions.has(name.name) && def.orig.length == 1) continue;
+                    var def = fn.variables.get(name.name);
+                    var sym = make_node(AST_SymbolRef, name, name);
+                    def.references.push(sym);
+                    expr_loop.push(make_node(AST_Assign, var_def, {
+                        operator: "=",
+                        left: sym,
+                        right: make_node(AST_Undefined, name),
+                    }));
                 }
             });
             [].push.apply(decls, decl_var);
             [].push.apply(expressions, expr_loop);
+            [].push.apply(expressions, expr_fn);
             [].push.apply(expressions, expr_var);
             return args;
         }
@@ -12986,12 +12989,17 @@ Compressor.prototype.compress = function(node) {
                 scope.enclosed.push(def);
                 scope.variables.set(name, def);
                 def.single_use = false;
-                if (!in_loop || fn.functions.has(name)) return;
+                if (!in_loop) return;
+                if (fn.functions.has(name) && def.orig.length == 1) return;
                 if (def.references.length == def.replaced) return;
-                var sym = flatten_var(def.orig[0]);
-                if (sym.TYPE != "SymbolVar") return;
-                var ref = make_node(AST_SymbolRef, sym, sym);
-                sym.definition().references.push(ref);
+                if (!all(def.orig, function(sym) {
+                    return !(sym instanceof AST_SymbolConst
+                        || sym instanceof AST_SymbolFunarg
+                        || sym instanceof AST_SymbolLet);
+                })) return;
+                var sym = def.orig[0];
+                var ref = make_node(AST_SymbolRef, sym, flatten_var(sym));
+                ref.definition().references.push(ref);
                 body.push(make_node(AST_SimpleStatement, sym, {
                     body: make_node(AST_Assign, sym, {
                         operator: "=",
index 60c686c..96210a5 100644 (file)
@@ -1727,3 +1727,28 @@ issue_4965_2: {
     expect_stdout: "undefined"
     node_version: ">=4"
 }
+
+issue_5254: {
+    options = {
+        inline: true,
+        toplevel: true,
+    }
+    input: {
+        do {
+            (function() {
+                const a = console.log;
+                a && a("foo");
+            })();
+        } while (console.log("bar"));
+    }
+    expect: {
+        do {
+            const a = console.log;
+            a && a("foo");
+        } while (console.log("bar"));
+    }
+    expect_stdout: [
+        "foo",
+        "bar",
+    ]
+}
index bb951d2..a56e107 100644 (file)
@@ -944,6 +944,7 @@ inline_loop_5: {
     }
     expect: {
         for (var a in "foo")
+            f = void 0,
             f = function() {},
             void console.log(typeof f, a - f);
         var f;
@@ -971,6 +972,7 @@ inline_loop_6: {
     }
     expect: {
         for (var a in "foo")
+            f = void 0,
             f = function() {},
             void console.log(typeof f, a - f);
         var f;
@@ -983,6 +985,64 @@ inline_loop_6: {
 }
 
 inline_loop_7: {
+    options = {
+        inline: true,
+        toplevel: true,
+    }
+    input: {
+        for (var a in "foo") {
+            (function() {
+                function f() {}
+                var f;
+                while (console.log(typeof f, a - f));
+            })();
+        }
+    }
+    expect: {
+        for (var a in "foo") {
+            f = void 0;
+            var f = function() {};
+            var f;
+            while (console.log(typeof f, a - f));
+        }
+    }
+    expect_stdout: [
+        "function NaN",
+        "function NaN",
+        "function NaN",
+    ]
+}
+
+inline_loop_8: {
+    options = {
+        inline: true,
+        toplevel: true,
+    }
+    input: {
+        for (var a in "foo") {
+            (function() {
+                var f;
+                function f() {}
+                while (console.log(typeof f, a - f));
+            })();
+        }
+    }
+    expect: {
+        for (var a in "foo") {
+            f = void 0;
+            var f = function() {};
+            var f;
+            while (console.log(typeof f, a - f));
+        }
+    }
+    expect_stdout: [
+        "function NaN",
+        "function NaN",
+        "function NaN",
+    ]
+}
+
+inline_loop_9: {
     options = {
         inline: true,
         toplevel: true,
@@ -6797,10 +6857,10 @@ issue_4753_2: {
     }
     expect: {
         do {
+            a = void 0,
             f = function() {
                 return "PASS";
             },
-            a = void 0,
             a = f(),
             console.log(a);
         } while (0);
@@ -7750,3 +7810,68 @@ issue_5249_2: {
     }
     expect_stdout: "undefined"
 }
+
+issue_5254_1: {
+    options = {
+        inline: 3,
+        unused: true,
+    }
+    input: {
+        (function(a) {
+            while (a--)
+                (function f() {
+                    var f = new function() {
+                        console.log(f);
+                    }();
+                })();
+        })(2);
+    }
+    expect: {
+        (function(a) {
+            while (a--)
+                f = void 0,
+                f = new function() {
+                    console.log(f);
+                }(),
+                void 0;
+            var f;
+        })(2);
+    }
+    expect_stdout: [
+        "undefined",
+        "undefined",
+    ]
+}
+
+issue_5254_2: {
+    options = {
+        inline: true,
+        unused: true,
+    }
+    input: {
+        (function(a) {
+            while (a--)
+                (function f() {
+                    var f = new function() {
+                        console.log(f);
+                    }();
+                    while (!console);
+                })();
+        })(2);
+    }
+    expect: {
+        (function(a) {
+            while (a--) {
+                f = void 0;
+                var f = new function() {
+                    console.log(f);
+                }();
+                while (!console);
+            }
+        })(2);
+    }
+    expect_stdout: [
+        "undefined",
+        "undefined",
+    ]
+}
index 5ecef2e..a689fd5 100644 (file)
@@ -1878,3 +1878,31 @@ issue_5240: {
     ]
     node_version: ">=4"
 }
+
+issue_5254: {
+    options = {
+        inline: true,
+        toplevel: true,
+    }
+    input: {
+        "use strict";
+        do {
+            (function() {
+                let a = console.log;
+                a && a("foo");
+            })();
+        } while (console.log("bar"));
+    }
+    expect: {
+        "use strict";
+        do {
+            let a = console.log;
+            a && a("foo");
+        } while (console.log("bar"));
+    }
+    expect_stdout: [
+        "foo",
+        "bar",
+    ]
+    node_version: ">=4"
+}