fix corner case in `loops` (#4183)
authorAlex Lam S.L <alexlamsl@gmail.com>
Mon, 5 Oct 2020 09:28:46 +0000 (10:28 +0100)
committerGitHub <noreply@github.com>
Mon, 5 Oct 2020 09:28:46 +0000 (17:28 +0800)
fixes #4182

lib/compress.js
test/compress/loops.js

index 74c0feb..fbd0774 100644 (file)
@@ -700,7 +700,7 @@ merge(Compressor.prototype, {
             tw.in_loop = this;
             push(tw);
             this.body.walk(tw);
-            if (has_break_or_continue(this, tw.parent())) {
+            if (has_loop_control(this, tw.parent())) {
                 pop(tw);
                 push(tw);
             }
@@ -717,7 +717,7 @@ merge(Compressor.prototype, {
             if (this.condition) this.condition.walk(tw);
             this.body.walk(tw);
             if (this.step) {
-                if (has_break_or_continue(this, tw.parent())) {
+                if (has_loop_control(this, tw.parent())) {
                     pop(tw);
                     push(tw);
                 }
@@ -5812,11 +5812,12 @@ merge(Compressor.prototype, {
         return compressor.option("loops") ? make_node(AST_For, self, self).optimize(compressor) : self;
     });
 
-    function has_break_or_continue(loop, parent) {
+    function has_loop_control(loop, parent, type) {
+        if (!type) type = AST_LoopControl;
         var found = false;
         var tw = new TreeWalker(function(node) {
             if (found || node instanceof AST_Scope) return true;
-            if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === loop) {
+            if (node instanceof type && tw.loopcontrol_target(node) === loop) {
                 return found = true;
             }
         });
@@ -5840,7 +5841,7 @@ merge(Compressor.prototype, {
                     ]
                 })
             }).optimize(compressor);
-            if (!has_break_or_continue(self, compressor.parent())) {
+            if (!has_loop_control(self, compressor.parent())) {
                 return make_node(AST_BlockStatement, self.body, {
                     body: [
                         self.body,
@@ -5851,14 +5852,14 @@ merge(Compressor.prototype, {
                 }).optimize(compressor);
             }
         }
-        if (self.body instanceof AST_BlockStatement) {
+        if (self.body instanceof AST_BlockStatement && !has_loop_control(self, compressor.parent(), AST_Continue)) {
             var body = self.body.body;
             for (var i = body.length; --i >= 0;) {
                 var stat = body[i];
                 if (stat instanceof AST_If
                     && !stat.alternative
                     && stat.body instanceof AST_Break
-                    && compressor.loopcontrol_target(stat.body) === compressor.self()) {
+                    && compressor.loopcontrol_target(stat.body) === self) {
                     self.condition = make_node(AST_Binary, self, {
                         operator: "&&",
                         left: stat.condition.negate(compressor),
index b8d351a..1fa3d00 100644 (file)
@@ -1126,3 +1126,74 @@ issue_4091_2: {
     }
     expect_stdout: "undefined"
 }
+
+issue_4182_1: {
+    options = {
+        loops: true,
+    }
+    input: {
+        (function() {
+            do {
+                try {
+                    return;
+                } finally {
+                    continue;
+                }
+                console.log("FAIL");
+            } while (0);
+            console.log("PASS");
+        })();
+    }
+    expect: {
+        (function() {
+            do {
+                try {
+                    return;
+                } finally {
+                    continue;
+                }
+                console.log("FAIL");
+            } while (0);
+            console.log("PASS");
+        })();
+    }
+    expect_stdout: "PASS"
+}
+
+issue_4182_2: {
+    options = {
+        loops: true,
+    }
+    input: {
+        (function() {
+            L: do {
+                do {
+                    try {
+                        return;
+                    } finally {
+                        continue L;
+                    }
+                    console.log("FAIL");
+                } while (0);
+                console.log("FAIL");
+            } while (0);
+            console.log("PASS");
+        })();
+    }
+    expect: {
+        (function() {
+            L: do {
+                do {
+                    try {
+                        return;
+                    } finally {
+                        continue L;
+                    }
+                } while (console.log("FAIL"), 0);
+                console.log("FAIL");
+            } while (0);
+            console.log("PASS");
+        })();
+    }
+    expect_stdout: "PASS"
+}