improve collapsible value detection (#1638)
authorAlex Lam S.L <alexlamsl@gmail.com>
Thu, 23 Mar 2017 18:55:32 +0000 (02:55 +0800)
committerGitHub <noreply@github.com>
Thu, 23 Mar 2017 18:55:32 +0000 (02:55 +0800)
- #1634 bars variables with cross-scope references in between to collapse
- but if assigned value is side-effect-free, no states can be modified, so it is safe to move

lib/compress.js
test/compress/collapse_vars.js
test/mocha/glob.js

index cfa8f23..e75d7c9 100644 (file)
@@ -592,9 +592,10 @@ merge(Compressor.prototype, {
                     // Restrict var replacement to constants if side effects encountered.
                     if (side_effects_encountered |= lvalues_encountered) continue;
 
+                    var value_has_side_effects = var_decl.value.has_side_effects(compressor);
                     // Non-constant single use vars can only be replaced in same scope.
                     if (ref.scope !== self) {
-                        side_effects_encountered |= var_decl.value.has_side_effects(compressor);
+                        side_effects_encountered |= value_has_side_effects;
                         continue;
                     }
 
@@ -620,6 +621,7 @@ merge(Compressor.prototype, {
                                 || (parent instanceof AST_If          && node !== parent.condition)
                                 || (parent instanceof AST_Conditional && node !== parent.condition)
                                 || (node instanceof AST_SymbolRef
+                                    && value_has_side_effects
                                     && !are_references_in_scope(node.definition(), self))
                                 || (parent instanceof AST_Binary
                                     && (parent.operator == "&&" || parent.operator == "||")
index 6f273b9..2437ca5 100644 (file)
@@ -1522,3 +1522,71 @@ issue_1631_3: {
     }
     expect_stdout: "6"
 }
+
+var_side_effects_1: {
+    options = {
+        collapse_vars: true,
+    }
+    input: {
+        var print = console.log.bind(console);
+        function foo(x) {
+            var twice = x * 2;
+            print('Foo:', twice);
+        }
+        foo(10);
+    }
+    expect: {
+        var print = console.log.bind(console);
+        function foo(x) {
+            print('Foo:', 2 * x);
+        }
+        foo(10);
+    }
+    expect_stdout: true
+}
+
+var_side_effects_2: {
+    options = {
+        collapse_vars: true,
+    }
+    input: {
+        var print = console.log.bind(console);
+        function foo(x) {
+            var twice = x.y * 2;
+            print('Foo:', twice);
+        }
+        foo({ y: 10 });
+    }
+    expect: {
+        var print = console.log.bind(console);
+        function foo(x) {
+            var twice = 2 * x.y;
+            print('Foo:', twice);
+        }
+        foo({ y: 10 });
+    }
+    expect_stdout: true
+}
+
+var_side_effects_3: {
+    options = {
+        collapse_vars: true,
+        pure_getters: true,
+    }
+    input: {
+        var print = console.log.bind(console);
+        function foo(x) {
+            var twice = x.y * 2;
+            print('Foo:', twice);
+        }
+        foo({ y: 10 });
+    }
+    expect: {
+        var print = console.log.bind(console);
+        function foo(x) {
+            print('Foo:', 2 * x.y);
+        }
+        foo({ y: 10 });
+    }
+    expect_stdout: true
+}
index e291efc..e9555a5 100644 (file)
@@ -5,7 +5,7 @@ var path = require("path");
 describe("minify() with input file globs", function() {
     it("minify() with one input file glob string.", function() {
         var result = Uglify.minify("test/input/issue-1242/foo.*");
-        assert.strictEqual(result.code, 'function foo(o){var n=2*o;print("Foo:",n)}var print=console.log.bind(console);');
+        assert.strictEqual(result.code, 'function foo(o){print("Foo:",2*o)}var print=console.log.bind(console);');
     });
     it("minify() with an array of one input file glob.", function() {
         var result = Uglify.minify([
@@ -20,7 +20,7 @@ describe("minify() with input file globs", function() {
         ], {
             compress: { toplevel: true }
         });
-        assert.strictEqual(result.code, 'var print=console.log.bind(console),a=function(n){return 3*n}(3),b=function(n){return n/2}(12);print("qux",a,b),function(n){var o=2*n;print("Foo:",o)}(11);');
+        assert.strictEqual(result.code, 'var print=console.log.bind(console),a=function(n){return 3*n}(3),b=function(n){return n/2}(12);print("qux",a,b),function(n){print("Foo:",2*n)}(11);');
     });
     it("should throw with non-matching glob string", function() {
         var glob = "test/input/issue-1242/blah.*";