fix corner case in `reduce_vars` (#3129)
authorAlex Lam S.L <alexlamsl@gmail.com>
Thu, 10 May 2018 10:45:20 +0000 (18:45 +0800)
committerGitHub <noreply@github.com>
Thu, 10 May 2018 10:45:20 +0000 (18:45 +0800)
lib/compress.js
test/compress/reduce_vars.js

index d3c2452..5f35b98 100644 (file)
@@ -361,7 +361,7 @@ merge(Compressor.prototype, {
                     if (def.scope === scope) return true;
                 } while (scope instanceof AST_Function && (scope = scope.parent_scope));
             })) {
-                tw.defun_ids[def.id] = undefined;
+                tw.defun_ids[def.id] = false;
             }
             def.recursive_refs = 0;
             def.references = [];
@@ -386,23 +386,29 @@ merge(Compressor.prototype, {
             if (def.id in tw.defun_ids) {
                 var marker = tw.defun_ids[def.id];
                 if (!marker) return;
-                if (marker !== tw.safe_ids) {
-                    tw.defun_ids[def.id] = undefined;
-                    return;
+                var visited = tw.defun_visited[def.id];
+                if (marker === tw.safe_ids) {
+                    if (!visited) return def.fixed;
+                } else if (visited) {
+                    def.init.enclosed.forEach(function(d) {
+                        if (def.init.variables.get(d.name) === d) return;
+                        if (!safe_to_read(tw, d)) d.fixed = false;
+                    });
+                } else {
+                    tw.defun_ids[def.id] = false;
                 }
-                return def.fixed;
-            }
-            if (!tw.in_loop) {
-                tw.defun_ids[def.id] = tw.safe_ids;
-                return def.fixed;
-            } else if (tw.defun_ids[def.id] !== false) {
-                tw.defun_ids[def.id] = undefined;
+            } else {
+                if (!tw.in_loop) {
+                    tw.defun_ids[def.id] = tw.safe_ids;
+                    return def.fixed;
+                }
+                tw.defun_ids[def.id] = false;
             }
         }
 
         function walk_defuns(tw, scope) {
             scope.functions.each(function(def) {
-                if (def.init instanceof AST_Defun && tw.defun_ids[def.id] === undefined) {
+                if (def.init instanceof AST_Defun && !tw.defun_visited[def.id]) {
                     tw.defun_ids[def.id] = tw.safe_ids;
                     def.init.walk(tw);
                 }
@@ -587,8 +593,9 @@ merge(Compressor.prototype, {
         });
         def(AST_Defun, function(tw, descend, compressor) {
             var id = this.name.definition().id;
+            if (tw.defun_visited[id]) return true;
             if (tw.defun_ids[id] !== tw.safe_ids) return true;
-            tw.defun_ids[id] = false;
+            tw.defun_visited[id] = true;
             this.inlined = false;
             push(tw);
             reset_variables(tw, compressor, this);
@@ -820,6 +827,7 @@ merge(Compressor.prototype, {
         });
         // Flow control for visiting `AST_Defun`s
         tw.defun_ids = Object.create(null);
+        tw.defun_visited = Object.create(null);
         // Record the loop body in which `AST_SymbolDeclaration` is first encountered
         tw.in_loop = null;
         tw.loop_ids = Object.create(null);
index bc5fcf1..ac55f81 100644 (file)
@@ -6059,6 +6059,38 @@ conditional_nested_2: {
     expect_stdout: "1"
 }
 
+conditional_nested_3: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+    }
+    input: {
+        var n = 2, c = 0;
+        (function f(a) {
+            0 < n-- && g(a = 1);
+            function g() {
+                a && c++;
+            }
+            g();
+            0 < n-- && f();
+        })();
+        console.log(c);
+    }
+    expect: {
+        var n = 2, c = 0;
+        (function f(a) {
+            0 < n-- && g(a = 1);
+            function g() {
+                a && c++;
+            }
+            g();
+            0 < n-- && f();
+        })();
+        console.log(c);
+    }
+    expect_stdout: "2"
+}
+
 issue_2436: {
     options = {
         evaluate: true,