fix `collapse_vars` within loops (#2915)
authorAlex Lam S.L <alexlamsl@gmail.com>
Tue, 13 Feb 2018 21:15:52 +0000 (05:15 +0800)
committerGitHub <noreply@github.com>
Tue, 13 Feb 2018 21:15:52 +0000 (05:15 +0800)
fixes #2914

lib/compress.js
test/compress/collapse_vars.js

index a161b45..50843f6 100644 (file)
@@ -914,6 +914,7 @@ merge(Compressor.prototype, {
 
     function tighten_body(statements, compressor) {
         var scope = compressor.find_parent(AST_Scope);
+        var in_loop = is_in_loop();
         var CHANGED, max_iter = 10;
         do {
             CHANGED = false;
@@ -936,6 +937,14 @@ merge(Compressor.prototype, {
             }
         } while (CHANGED && max_iter-- > 0);
 
+        function is_in_loop() {
+            for (var node, level = 0; node = compressor.parent(level); level++) {
+                if (node instanceof AST_IterationStatement) return true;
+                if (node instanceof AST_Scope) break;
+            }
+            return false;
+        }
+
         // Search from right to left for assignment-like expressions:
         // - `var a = x;`
         // - `a = x;`
@@ -1096,9 +1105,9 @@ merge(Compressor.prototype, {
                     var stop_if_hit = null;
                     var lhs = get_lhs(candidate);
                     if (!lhs || is_lhs_read_only(lhs) || lhs.has_side_effects(compressor)) continue;
-                    var lhs_local = is_lhs_local(lhs);
                     // Locate symbols which may execute code outside of scanning range
                     var lvalues = get_lvalues(candidate);
+                    var lhs_local = is_lhs_local(lhs);
                     if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
                     var side_effects = value_has_side_effects(candidate);
                     var replace_all = replace_all_symbols();
@@ -1393,7 +1402,12 @@ merge(Compressor.prototype, {
 
             function is_lhs_local(lhs) {
                 while (lhs instanceof AST_PropAccess) lhs = lhs.expression;
-                return lhs instanceof AST_SymbolRef && lhs.definition().scope === scope;
+                return lhs instanceof AST_SymbolRef
+                    && lhs.definition().scope === scope
+                    && !(in_loop
+                        && (lhs.name in lvalues
+                            || candidate instanceof AST_Unary
+                            || candidate instanceof AST_Assign && candidate.operator != "="));
             }
 
             function value_has_side_effects(expr) {
index 2c7bbde..bcb9cb9 100644 (file)
@@ -4546,3 +4546,76 @@ issue_2908: {
     }
     expect_stdout: "2"
 }
+
+issue_2914_1: {
+    options = {
+        collapse_vars: true,
+    }
+    input: {
+        function read(input) {
+            var i = 0;
+            var e = 0;
+            var t = 0;
+            while (e < 32) {
+                var n = input[i++];
+                t |= (127 & n) << e;
+                if (0 === (128 & n))
+                    return t;
+                e += 7;
+            }
+        }
+        console.log(read([129]));
+    }
+    expect: {
+        function read(input) {
+            var i = 0;
+            var e = 0;
+            var t = 0;
+            while (e < 32) {
+                var n = input[i++];
+                t |= (127 & n) << e;
+                if (0 === (128 & n))
+                    return t;
+                e += 7;
+            }
+        }
+        console.log(read([129]));
+    }
+    expect_stdout: "1"
+}
+
+issue_2914_2: {
+    options = {
+        collapse_vars: true,
+    }
+    input: {
+        function read(input) {
+            var i = 0;
+            var e = 0;
+            var t = 0;
+            while (e < 32) {
+                var n = input[i++];
+                t = (127 & n) << e;
+                if (0 === (128 & n))
+                    return t;
+                e += 7;
+            }
+        }
+        console.log(read([129]));
+    }
+    expect: {
+        function read(input) {
+            var i = 0;
+            var e = 0;
+            var t = 0;
+            while (e < 32) {
+                var n = input[i++];
+                if (0 === (128 & n))
+                    return t = (127 & n) << e;
+                e += 7;
+            }
+        }
+        console.log(read([129]));
+    }
+    expect_stdout: "0"
+}