fix corner case in `reduce_vars` (#3959)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sat, 6 Jun 2020 02:04:37 +0000 (10:04 +0800)
committerGitHub <noreply@github.com>
Sat, 6 Jun 2020 02:04:37 +0000 (10:04 +0800)
fixes #3958

lib/compress.js
test/compress/reduce_vars.js

index db445bb..f71d956 100644 (file)
@@ -352,6 +352,23 @@ merge(Compressor.prototype, {
         return orig.length == 1 && orig[0] instanceof AST_SymbolFunarg;
     }
 
+    function is_content_constant(ref, depth) {
+        var escaped = ref.definition().escaped;
+        switch (escaped.length) {
+          case 0:
+            return true;
+          case 1:
+            var found = false;
+            escaped[0].walk(new TreeWalker(function(node) {
+                if (found) return true;
+                if (node === ref) return found = true;
+            }));
+            return found;
+          default:
+            return depth <= escaped.depth;
+        }
+    }
+
     (function(def) {
         def(AST_Node, noop);
 
@@ -496,9 +513,15 @@ merge(Compressor.prototype, {
         }
 
         function to_value(def, sym, fixed) {
-            if (fixed instanceof AST_Node) return fixed;
-            if (typeof fixed == "function") return fixed();
-            return make_node(AST_Undefined, sym);
+            if (fixed == null) {
+                fixed = make_node(AST_Undefined, sym);
+            } else if (typeof fixed == "function") {
+                fixed = fixed();
+            }
+            if (fixed instanceof AST_Array || fixed instanceof AST_Object) {
+                if (!is_content_constant(sym)) return false;
+            }
+            return fixed;
         }
 
         function ref_once(compressor, def) {
@@ -3515,27 +3538,8 @@ merge(Compressor.prototype, {
                 };
                 cached.push(fixed);
             }
-            if (value && typeof value == "object") {
-                var escaped = this.definition().escaped;
-                switch (escaped.length) {
-                  case 0:
-                    break;
-                  case 1:
-                    if (contains_ref(escaped[0], this)) break;
-                  default:
-                    if (depth > escaped.depth) return this;
-                }
-            }
+            if (value && typeof value == "object" && !is_content_constant(this, depth)) return this;
             return value;
-
-            function contains_ref(expr, ref) {
-                var found = false;
-                expr.walk(new TreeWalker(function(node) {
-                    if (found) return true;
-                    if (node === ref) return found = true;
-                }));
-                return found;
-            }
         });
         var global_objs = {
             Array: Array,
index 1a782b4..41eb009 100644 (file)
@@ -7323,3 +7323,38 @@ issue_3957_2: {
         "0",
     ]
 }
+
+issue_3958: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        side_effects: true,
+        toplevel: true,
+        unsafe: true,
+        unused: true,
+    }
+    input: {
+        var a;
+        (function(b) {
+            (function(c) {
+                console.log(c[0] = 1);
+            })(a = b);
+            --a;
+        })([]);
+        console.log(a);
+    }
+    expect: {
+        var a;
+        (function(b) {
+            (function(c) {
+                console.log(c[0] = 1);
+            })(a = []);
+            --a;
+        })();
+        console.log(a);
+    }
+    expect_stdout: [
+        "1",
+        "0",
+    ]
+}