fix cross-scope inlining of `AST_Function`s (#2486)
authorAlex Lam S.L <alexlamsl@gmail.com>
Thu, 16 Nov 2017 02:04:30 +0000 (10:04 +0800)
committerGitHub <noreply@github.com>
Thu, 16 Nov 2017 02:04:30 +0000 (10:04 +0800)
fixes #2485

bin/uglifyjs
lib/ast.js
lib/compress.js
test/compress/reduce_vars.js

index 8cbb3ca..04c402d 100755 (executable)
@@ -15,7 +15,7 @@ var path = require("path");
 var program = require("commander");
 var UglifyJS = require("../tools/node");
 
-var skip_keys = [ "cname", "enclosed", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ];
+var skip_keys = [ "cname", "enclosed", "inlined", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ];
 var files = {};
 var options = {
     compress: false,
index 9b243f1..a2aa2b4 100644 (file)
@@ -352,11 +352,11 @@ var AST_Accessor = DEFNODE("Accessor", null, {
     $documentation: "A setter/getter function.  The `name` property is always null."
 }, AST_Lambda);
 
-var AST_Function = DEFNODE("Function", null, {
+var AST_Function = DEFNODE("Function", "inlined", {
     $documentation: "A function expression"
 }, AST_Lambda);
 
-var AST_Defun = DEFNODE("Defun", null, {
+var AST_Defun = DEFNODE("Defun", "inlined", {
     $documentation: "A function definition"
 }, AST_Lambda);
 
index 0f72404..2577643 100644 (file)
@@ -373,6 +373,7 @@ merge(Compressor.prototype, {
                     }
                 }
                 if (node instanceof AST_Defun) {
+                    node.inlined = false;
                     var d = node.name.definition();
                     if (compressor.exposed(d) || safe_to_read(d)) {
                         d.fixed = false;
@@ -389,6 +390,7 @@ merge(Compressor.prototype, {
                     return true;
                 }
                 if (node instanceof AST_Function) {
+                    node.inlined = false;
                     push();
                     var iife;
                     if (!node.name
@@ -4329,16 +4331,21 @@ merge(Compressor.prototype, {
                 d.fixed = fixed = make_node(AST_Function, fixed, fixed);
             }
             if (d.single_use && fixed instanceof AST_Function) {
-                if (!compressor.option("reduce_funcs") && d.scope !== self.scope) {
+                if (d.scope !== self.scope
+                    && (!compressor.option("reduce_funcs")
+                        || d.escaped
+                        || fixed.inlined)) {
                     d.single_use = false;
-                } else if (d.escaped && d.scope !== self.scope || recursive_ref(compressor, d)) {
+                } else if (recursive_ref(compressor, d)) {
                     d.single_use = false;
                 } else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) {
                     d.single_use = fixed.is_constant_expression(self.scope);
                     if (d.single_use == "f") {
                         var scope = self.scope;
                         do {
-                            if (scope.name) scope.name.definition().single_use = false;
+                            if (scope instanceof AST_Defun || scope instanceof AST_Function) {
+                                scope.inlined = true;
+                            }
                         } while (scope = scope.parent_scope);
                     }
                 }
index e718949..02ff5e4 100644 (file)
@@ -4477,3 +4477,51 @@ perf_8: {
     }
     expect_stdout: "348150"
 }
+
+issue_2485: {
+    options = {
+        reduce_funcs: true,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        var foo = function(bar) {
+            var n = function(a, b) {
+                return a + b;
+            };
+            var sumAll = function(arg) {
+                return arg.reduce(n, 0);
+            };
+            var runSumAll = function(arg) {
+                return sumAll(arg);
+            };
+            bar.baz = function(arg) {
+                var n = runSumAll(arg);
+                return (n.get = 1), n;
+            };
+            return bar;
+        };
+        var bar = foo({});
+        console.log(bar.baz([1, 2, 3]));
+    }
+    expect: {
+        var foo = function(bar) {
+            var n = function(a, b) {
+                return a + b;
+            };
+            var runSumAll = function(arg) {
+                return function(arg) {
+                    return arg.reduce(n, 0);
+                }(arg);
+            };
+            bar.baz = function(arg) {
+                var n = runSumAll(arg);
+                return (n.get = 1), n;
+            };
+            return bar;
+        };
+        var bar = foo({});
+        console.log(bar.baz([1, 2, 3]));
+    }
+    expect_stdout: "6"
+}