fix corner case in `inline` (#4754)
authorAlex Lam S.L <alexlamsl@gmail.com>
Mon, 8 Mar 2021 04:38:53 +0000 (04:38 +0000)
committerGitHub <noreply@github.com>
Mon, 8 Mar 2021 04:38:53 +0000 (12:38 +0800)
fixes #4753

lib/ast.js
lib/compress.js
lib/parse.js
test/compress/functions.js

index 1a1e045..e77ec09 100644 (file)
@@ -139,7 +139,7 @@ var AST_Node = DEFNODE("Node", "start end", {
 }, null);
 
 (AST_Node.log_function = function(fn, verbose) {
-    if (!fn) {
+    if (typeof fn != "function") {
         AST_Node.info = AST_Node.warn = noop;
         return;
     }
index 3551655..f63c186 100644 (file)
@@ -9046,6 +9046,7 @@ merge(Compressor.prototype, {
                     if (!all(stat.enclosed, function(def) {
                         return def.scope === stat || !defined[def.name];
                     })) return false;
+                    if (in_loop) in_loop.push(stat.name.definition());
                     continue;
                 }
                 if (!(stat instanceof AST_Var)) continue;
@@ -9189,32 +9190,56 @@ merge(Compressor.prototype, {
             }
         }
 
+        function flatten_var(name) {
+            var redef = name.definition().redefined();
+            if (redef) {
+                name = name.clone();
+                name.thedef = redef;
+            }
+            return name;
+        }
+
         function flatten_vars(decls, expressions) {
-            var pos = expressions.length;
+            var args = [ insert, 0 ];
+            var decl_var = [], expr_var = [], expr_loop = [];
             for (var i = 0; i < fn.body.length; i++) {
                 var stat = fn.body[i];
+                if (stat instanceof AST_LambdaDefinition) {
+                    if (in_loop) {
+                        var name = make_node(AST_SymbolVar, stat.name, flatten_var(stat.name));
+                        name.definition().orig.push(name);
+                        append_var(decls, expressions, name, to_func_expr(stat, true));
+                    } else {
+                        var def = stat.name.definition();
+                        scope.functions.set(def.name, def);
+                        scope.variables.set(def.name, def);
+                        scope.enclosed.push(def);
+                        scope.var_names()[def.name] = true;
+                        args.push(stat);
+                    }
+                    continue;
+                }
                 if (!(stat instanceof AST_Var)) continue;
                 for (var j = 0; j < stat.definitions.length; j++) {
                     var var_def = stat.definitions[j];
-                    var name = var_def.name;
-                    var redef = name.definition().redefined();
-                    if (redef) {
-                        name = name.clone();
-                        name.thedef = redef;
-                    }
-                    append_var(decls, expressions, name, var_def.value);
+                    var name = flatten_var(var_def.name);
+                    append_var(decl_var, expr_var, name, var_def.value);
                     if (in_loop && !HOP(arg_used, name.name)) {
                         var def = fn.variables.get(name.name);
                         var sym = make_node(AST_SymbolRef, name, name);
                         def.references.push(sym);
-                        expressions.splice(pos++, 0, make_node(AST_Assign, var_def, {
+                        expr_loop.push(make_node(AST_Assign, var_def, {
                             operator: "=",
                             left: sym,
-                            right: make_node(AST_Undefined, name)
+                            right: make_node(AST_Undefined, name),
                         }));
                     }
                 }
             }
+            [].push.apply(decls, decl_var);
+            [].push.apply(expressions, expr_loop);
+            [].push.apply(expressions, expr_var);
+            return args;
         }
 
         function flatten_fn() {
@@ -9225,19 +9250,8 @@ merge(Compressor.prototype, {
             } else {
                 flatten_args(decls, expressions);
             }
-            flatten_vars(decls, expressions);
+            var args = flatten_vars(decls, expressions);
             expressions.push(value);
-            var args = fn.body.filter(function(stat) {
-                if (stat instanceof AST_LambdaDefinition) {
-                    var def = stat.name.definition();
-                    scope.functions.set(def.name, def);
-                    scope.variables.set(def.name, def);
-                    scope.enclosed.push(def);
-                    scope.var_names()[def.name] = true;
-                    return true;
-                }
-            });
-            args.unshift(insert, 0);
             if (decls.length) args.push(make_node(AST_Var, fn, {
                 definitions: decls
             }));
index 835ac21..5a4d981 100644 (file)
@@ -1743,7 +1743,7 @@ function parse($TEXT, options) {
                 name: "new.target",
                 start: start,
                 end: prev(),
-            })
+            });
         }
         var newexp = expr_atom(false), args;
         if (is("punc", "(")) {
index 856dbce..682b584 100644 (file)
@@ -5771,3 +5771,64 @@ new_target: {
     expect_stdout: "function undefined"
     node_version: ">=6"
 }
+
+issue_4753_1: {
+    options = {
+        inline: true,
+        toplevel: true,
+    }
+    input: {
+        for (var i in [ 1, 2 ])
+            (function() {
+                function f() {}
+                f && console.log(f.p ^= 42);
+            })();
+    }
+    expect: {
+        for (var i in [ 1, 2 ])
+            f = function() {},
+            void (f && console.log(f.p ^= 42));
+        var f;
+    }
+    expect_stdout: [
+        "42",
+        "42",
+    ]
+}
+
+issue_4753_2: {
+    options = {
+        inline: true,
+        reduce_vars: true,
+        side_effects: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        do {
+            (function() {
+                var a = f();
+                function f() {
+                    return "PASS";
+                }
+                f;
+                function g() {
+                    console.log(a);
+                }
+                g();
+            })();
+        } while (0);
+    }
+    expect: {
+        do {
+            f = function() {
+                return "PASS";
+            },
+            a = void 0,
+            a = f(),
+            console.log(a);
+        } while (0);
+        var f, a;
+    }
+    expect_stdout: "PASS"
+}