handle `pure_funcs` under `inline` & `reduce_vars` correctly (#3066)
authorAlex Lam S.L <alexlamsl@gmail.com>
Mon, 9 Apr 2018 18:46:38 +0000 (02:46 +0800)
committerGitHub <noreply@github.com>
Mon, 9 Apr 2018 18:46:38 +0000 (02:46 +0800)
fixes #3065

README.md
lib/compress.js
test/compress/pure_funcs.js

index 3585911..9244361 100644 (file)
--- a/README.md
+++ b/README.md
@@ -685,7 +685,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
   pass `pure_funcs: [ 'Math.floor' ]` to let it know that this
   function won't produce any side effect, in which case the whole
   statement would get discarded.  The current implementation adds some
-  overhead (compression will be slower).
+  overhead (compression will be slower). Make sure symbols under `pure_funcs`
+  are also under `mangle.reserved` to avoid mangling.
 
 - `pure_getters` (default: `"strict"`) -- If you pass `true` for
   this, UglifyJS will assume that object property access
index ddba624..73f4632 100644 (file)
@@ -4573,7 +4573,8 @@ merge(Compressor.prototype, {
             }
         }
         var stat = is_func && fn.body[0];
-        if (compressor.option("inline") && stat instanceof AST_Return) {
+        var can_inline = compressor.option("inline") && !self.is_expr_pure(compressor);
+        if (can_inline && stat instanceof AST_Return) {
             var value = stat.value;
             if (!value || value.is_constant_expression()) {
                 if (value) {
@@ -4587,7 +4588,7 @@ merge(Compressor.prototype, {
         }
         if (is_func) {
             var def, value, scope, in_loop, level = -1;
-            if (compressor.option("inline")
+            if (can_inline
                 && !fn.uses_arguments
                 && !fn.uses_eval
                 && !(fn.name && fn instanceof AST_Function)
@@ -5460,11 +5461,12 @@ merge(Compressor.prototype, {
                 return make_node(AST_Infinity, self).optimize(compressor);
             }
         }
-        if (compressor.option("reduce_vars")
-            && is_lhs(self, compressor.parent()) !== self) {
+        var parent = compressor.parent();
+        if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
             var d = self.definition();
             var fixed = self.fixed_value();
-            var single_use = d.single_use;
+            var single_use = d.single_use
+                && !(parent instanceof AST_Call && parent.is_expr_pure(compressor));
             if (single_use && fixed instanceof AST_Lambda) {
                 if (d.scope !== self.scope
                     && (!compressor.option("reduce_funcs")
index 0df51e5..56c36dd 100644 (file)
@@ -535,3 +535,110 @@ issue_2705_6: {
         "/* */new(/* */a()||b())(c(),d());",
     ]
 }
+
+issue_3065_1: {
+    options = {
+        inline: true,
+        pure_funcs: [ "pureFunc" ],
+        reduce_vars: true,
+        side_effects: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        function modifyWrapper(a, f, wrapper) {
+            wrapper.a = a;
+            wrapper.f = f;
+            return wrapper;
+        }
+        function pureFunc(fun) {
+            return modifyWrapper(1, fun, function(a) {
+                return fun(a);
+            });
+        }
+        var unused = pureFunc(function(x) {
+            return x;
+        });
+    }
+    expect: {}
+}
+
+issue_3065_2: {
+    rename = true
+    options = {
+        inline: true,
+        pure_funcs: [ "pureFunc" ],
+        reduce_vars: true,
+        side_effects: true,
+        toplevel: true,
+        unused: true,
+    }
+    mangle = {
+        reserved: [ "pureFunc" ],
+        toplevel: true,
+    }
+    input: {
+        function modifyWrapper(a, f, wrapper) {
+            wrapper.a = a;
+            wrapper.f = f;
+            return wrapper;
+        }
+        function pureFunc(fun) {
+            return modifyWrapper(1, fun, function(a) {
+                return fun(a);
+            });
+        }
+        var unused = pureFunc(function(x) {
+            return x;
+        });
+    }
+    expect: {}
+}
+
+issue_3065_3: {
+    options = {
+        pure_funcs: [ "debug" ],
+        reduce_vars: true,
+        side_effects: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        function debug(msg) {
+            console.log(msg);
+        }
+        debug(function() {
+            console.log("PASS");
+            return "FAIL";
+        }());
+    }
+    expect: {
+        (function() {
+            console.log("PASS");
+        })();
+    }
+}
+
+issue_3065_4: {
+    options = {
+        pure_funcs: [ "debug" ],
+        reduce_vars: true,
+        side_effects: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var debug = function(msg) {
+            console.log(msg);
+        };
+        debug(function() {
+            console.log("PASS");
+            return "FAIL";
+        }());
+    }
+    expect: {
+        (function() {
+            console.log("PASS");
+        })();
+    }
+}