fix corner case in `collapse_vars` (#2909)
authorAlex Lam S.L <alexlamsl@gmail.com>
Mon, 12 Feb 2018 17:41:22 +0000 (01:41 +0800)
committerGitHub <noreply@github.com>
Mon, 12 Feb 2018 17:41:22 +0000 (01:41 +0800)
fixes #2908

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

index 2b796dc..ad691f7 100644 (file)
@@ -972,13 +972,13 @@ merge(Compressor.prototype, {
                     || node instanceof AST_Try
                     || node instanceof AST_With
                     || parent instanceof AST_For && node !== parent.init
-                    || (side_effects || !replace_all)
+                    || !replace_all
                         && (node instanceof AST_SymbolRef && !node.is_declared(compressor))) {
                     abort = true;
                     return node;
                 }
                 // Stop only if candidate is found within conditional branches
-                if (!stop_if_hit && (side_effects || !replace_all)
+                if (!stop_if_hit && (!lhs_local || !replace_all)
                     && (parent instanceof AST_Binary && lazy_op(parent.operator) && parent.left !== node
                         || parent instanceof AST_Conditional && parent.condition !== node
                         || parent instanceof AST_If && parent.condition !== node)) {
@@ -1096,17 +1096,12 @@ 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);
                     if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
-                    var replace_all = value_def;
-                    if (!replace_all && lhs instanceof AST_SymbolRef) {
-                        var def = lhs.definition();
-                        if (def.references.length - def.replaced == (candidate instanceof AST_VarDef ? 1 : 2)) {
-                            replace_all = true;
-                        }
-                    }
                     var side_effects = value_has_side_effects(candidate);
+                    var replace_all = replace_all_symbols();
                     var may_throw = candidate.may_throw(compressor);
                     var funarg = candidate.name instanceof AST_SymbolFunarg;
                     var hit = funarg;
@@ -1151,7 +1146,7 @@ merge(Compressor.prototype, {
                                 hit_index++;
                             }
                             branch.expression = branch.expression.transform(scanner);
-                            if (side_effects || !replace_all) break;
+                            if (!replace_all) break;
                         }
                     }
                     abort = true;
@@ -1393,11 +1388,28 @@ 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;
+            }
+
             function value_has_side_effects(expr) {
                 if (expr instanceof AST_Unary) return false;
                 return get_rvalue(expr).has_side_effects(compressor);
             }
 
+            function replace_all_symbols() {
+                if (side_effects) return false;
+                if (value_def) return true;
+                if (lhs instanceof AST_SymbolRef) {
+                    var def = lhs.definition();
+                    if (def.references.length - def.replaced == (candidate instanceof AST_VarDef ? 1 : 2)) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
             function may_modify(sym) {
                 var def = sym.definition();
                 if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun) return false;
index ed1d8d9..2c7bbde 100644 (file)
@@ -4517,3 +4517,32 @@ issue_2891_2: {
     }
     expect_stdout: true
 }
+
+issue_2908: {
+    options = {
+        collapse_vars: true,
+    }
+    input: {
+        var a = 0, b = 0;
+        function f(c) {
+            if (1 == c) return;
+            a++;
+            if (2 == c) b = a;
+        }
+        f(0);
+        f(2);
+        console.log(b);
+    }
+    expect: {
+        var a = 0, b = 0;
+        function f(c) {
+            if (1 == c) return;
+            a++;
+            if (2 == c) b = a;
+        }
+        f(0);
+        f(2);
+        console.log(b);
+    }
+    expect_stdout: "2"
+}