fix corner case in `reduce_vars` (#4189)
authorAlex Lam S.L <alexlamsl@gmail.com>
Wed, 7 Oct 2020 14:01:39 +0000 (15:01 +0100)
committerGitHub <noreply@github.com>
Wed, 7 Oct 2020 14:01:39 +0000 (22:01 +0800)
fixes #4188

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

index 29cc82a..fa1cc38 100644 (file)
@@ -354,6 +354,13 @@ merge(Compressor.prototype, {
         return orig.length == 1 && orig[0] instanceof AST_SymbolFunarg;
     }
 
+    function cross_scope(def, sym) {
+        do {
+            if (def === sym) return false;
+            if (sym instanceof AST_Scope) return true;
+        } while (sym = sym.parent_scope);
+    }
+
     (function(def) {
         def(AST_Node, noop);
 
@@ -506,6 +513,7 @@ merge(Compressor.prototype, {
         function ref_once(compressor, def) {
             return compressor.option("unused")
                 && !def.scope.pinned()
+                && def.single_use !== false
                 && def.references.length - def.recursive_refs == 1;
         }
 
@@ -840,11 +848,13 @@ merge(Compressor.prototype, {
                 && d.orig[0] instanceof AST_SymbolDefun) {
                 tw.loop_ids[d.id] = tw.in_loop;
             }
-            var value;
-            if (d.fixed === undefined || !safe_to_read(tw, d)) {
+            if (d.fixed === false) {
+                var redef = d.redefined();
+                if (redef && cross_scope(d.scope, this.scope)) redef.single_use = false;
+            } else if (d.fixed === undefined || !safe_to_read(tw, d)) {
                 d.fixed = false;
             } else if (d.fixed) {
-                value = this.fixed_value();
+                var value = this.fixed_value();
                 var recursive = recursive_ref(tw, d);
                 if (recursive) {
                     d.recursive_refs++;
@@ -5140,13 +5150,6 @@ merge(Compressor.prototype, {
             return rhs.right;
         }
 
-        function cross_scope(def, sym) {
-            do {
-                if (def === sym) return false;
-                if (sym instanceof AST_Scope) return true;
-            } while (sym = sym.parent_scope);
-        }
-
         function scan_ref_scoped(node, descend, init) {
             if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef) {
                 var def = node.left.definition();
@@ -8310,13 +8313,6 @@ merge(Compressor.prototype, {
         return lhs instanceof AST_SymbolRef || lhs.TYPE === self.TYPE;
     }
 
-    function find_variable(compressor, name) {
-        var level = 0, node;
-        while (node = compressor.parent(level++)) {
-            if (node.variables) return node.find_variable(name);
-        }
-    }
-
     OPT(AST_Undefined, function(self, compressor) {
         if (compressor.option("unsafe_undefined")) {
             var undef = find_scope(compressor).find_variable("undefined");
index 209ac23..ec2c1f6 100644 (file)
@@ -196,7 +196,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
             var sym = node.scope.find_variable(name);
             if (!sym) {
                 sym = self.def_global(node);
-            } else if (sym.scope instanceof AST_Lambda && name == "arguments") {
+            } else if (name == "arguments" && sym.scope instanceof AST_Lambda) {
                 sym.scope.uses_arguments = true;
             }
             if (name == "eval") {
index 414d664..ea3703c 100644 (file)
@@ -7535,3 +7535,69 @@ global_assign: {
     }
     expect_stdout: "PASS"
 }
+
+issue_4188_1: {
+    options = {
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        (function() {
+            try {
+                while (A)
+                    var a = function() {}, b = a;
+            } catch (a) {
+                console.log(function() {
+                    return typeof a;
+                }(), typeof b);
+            }
+        })();
+    }
+    expect: {
+        (function() {
+            try {
+                while (A)
+                    var a = function() {}, b = a;
+            } catch (a) {
+                console.log(function() {
+                    return typeof a;
+                }(), typeof b);
+            }
+        })();
+    }
+    expect_stdout: "object undefined"
+}
+
+issue_4188_2: {
+    options = {
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        (function() {
+            try {
+                throw 42;
+            } catch (a) {
+                console.log(function() {
+                    return typeof a;
+                }(), typeof b);
+            }
+            while (!console)
+                var a = function() {}, b = a;
+        })();
+    }
+    expect: {
+        (function() {
+            try {
+                throw 42;
+            } catch (a) {
+                console.log(function() {
+                    return typeof a;
+                }(), typeof b);
+            }
+            while (!console)
+                var a = function() {}, b = a;
+        })();
+    }
+    expect_stdout: "number undefined"
+}