enhance `conditionals` (#3643)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sun, 22 Dec 2019 04:29:32 +0000 (04:29 +0000)
committerGitHub <noreply@github.com>
Sun, 22 Dec 2019 04:29:32 +0000 (04:29 +0000)
lib/compress.js
test/compress/comparisons.js
test/compress/conditionals.js
test/compress/issue-1034.js
test/compress/issue-640.js

index c5b6756..c00b9f0 100644 (file)
@@ -7005,25 +7005,42 @@ merge(Compressor.prototype, {
                 });
             }
         }
-        // x ? y(a) : y(b) --> y(x ? a : b)
-        var arg_index;
+        // x ? y : y --> x, y
+        if (consequent.equivalent_to(alternative)) return make_sequence(self, [
+            condition,
+            consequent
+        ]).optimize(compressor);
         if (consequent instanceof AST_Call
             && alternative.TYPE === consequent.TYPE
-            && consequent.args.length > 0
-            && consequent.args.length == alternative.args.length
-            && consequent.expression.equivalent_to(alternative.expression)
-            && !condition.has_side_effects(compressor)
-            && !consequent.expression.has_side_effects(compressor)
-            && typeof (arg_index = single_arg_diff()) == "number") {
-            var node = consequent.clone();
-            node.args[arg_index] = make_node(AST_Conditional, self, {
-                condition: condition,
-                consequent: consequent.args[arg_index],
-                alternative: alternative.args[arg_index]
-            });
-            return node;
+            && consequent.args.length == alternative.args.length) {
+            var arg_index = arg_diff();
+            // x ? y(a) : z(a) --> (x ? y : z)(a)
+            if (arg_index == -1
+                && !(consequent.expression instanceof AST_PropAccess)
+                && !(alternative.expression instanceof AST_PropAccess)) {
+                var node = consequent.clone();
+                node.expression = make_node(AST_Conditional, self, {
+                    condition: condition,
+                    consequent: consequent.expression,
+                    alternative: alternative.expression
+                });
+                return node;
+            }
+            // x ? y(a) : y(b) --> y(x ? a : b)
+            if (arg_index >= 0
+                && consequent.expression.equivalent_to(alternative.expression)
+                && !condition.has_side_effects(compressor)
+                && !consequent.expression.has_side_effects(compressor)) {
+                var node = consequent.clone();
+                node.args[arg_index] = make_node(AST_Conditional, self, {
+                    condition: condition,
+                    consequent: consequent.args[arg_index],
+                    alternative: alternative.args[arg_index]
+                });
+                return node;
+            }
         }
-        // x?y?z:a:a --> x&&y?z:a
+        // x ? (y ? a : b) : b --> x && y ? a : b
         if (consequent instanceof AST_Conditional
             && consequent.alternative.equivalent_to(alternative)) {
             return make_node(AST_Conditional, self, {
@@ -7036,12 +7053,18 @@ merge(Compressor.prototype, {
                 alternative: alternative
             });
         }
-        // x ? y : y --> x, y
-        if (consequent.equivalent_to(alternative)) {
-            return make_sequence(self, [
-                condition,
-                consequent
-            ]).optimize(compressor);
+        // x ? a : (y ? a : b)--> x || y ? a : b
+        if (alternative instanceof AST_Conditional
+            && consequent.equivalent_to(alternative.consequent)) {
+            return make_node(AST_Conditional, self, {
+                condition: make_node(AST_Binary, self, {
+                    left: condition,
+                    operator: "||",
+                    right: alternative.condition
+                }),
+                consequent: consequent,
+                alternative: alternative.alternative
+            });
         }
         // x ? (y, w) : (z, w) --> x ? y : z, w
         if ((consequent instanceof AST_Sequence || alternative instanceof AST_Sequence)
@@ -7145,17 +7168,18 @@ merge(Compressor.prototype, {
                     && node.expression.getValue());
         }
 
-        function single_arg_diff() {
+        function arg_diff() {
             var a = consequent.args;
             var b = alternative.args;
             for (var i = 0, len = a.length; i < len; i++) {
                 if (!a[i].equivalent_to(b[i])) {
                     for (var j = i + 1; j < len; j++) {
-                        if (!a[j].equivalent_to(b[j])) return;
+                        if (!a[j].equivalent_to(b[j])) return -2;
                     }
                     return i;
                 }
             }
+            return -1;
         }
 
         function can_shift_lhs_of_tail(node) {
index bb140fd..a4e0acc 100644 (file)
@@ -33,10 +33,10 @@ unsafe_comps: {
     }
     expect: {
         var obj1, obj2;
-        obj2 <  obj1 ? g1() : f1();
-        obj1 <  obj2 ? f2() : g2();
-        obj1 <  obj2 ? g3() : f3();
-        obj2 <  obj1 ? f4() : g4();
+        (obj2 <  obj1 ? g1 : f1)();
+        (obj1 <  obj2 ? f2 : g2)();
+        (obj1 <  obj2 ? g3 : f3)();
+        (obj2 <  obj1 ? f4 : g4)();
     }
 }
 
index 3e7a092..3f3df72 100644 (file)
@@ -41,7 +41,7 @@ ifs_2: {
     }
     expect: {
         foo ? x() : bar ? y() : baz && z();
-        foo ? x() : bar ? y() : baz ? z() : t();
+        (foo ? x : bar ? y : baz ? z : t)();
     }
 }
 
@@ -289,7 +289,7 @@ cond_5: {
         }
     }
     expect: {
-        some_condition() && some_other_condition() ? do_something() : alternate();
+        (some_condition() && some_other_condition() ? do_something : alternate)();
         some_condition() && some_other_condition() && do_something();
     }
 }
@@ -663,6 +663,69 @@ cond_9: {
     }
 }
 
+cond_10: {
+    options = {
+        conditionals: true,
+        if_return: true,
+    }
+    input: {
+        function f(a) {
+            if (1 == a) return "foo";
+            if (2 == a) return "foo";
+            if (3 == a) return "foo";
+            if (4 == a) return 42;
+            if (5 == a) return "foo";
+            if (6 == a) return "foo";
+            return "bar";
+        }
+        console.log(f(1), f(2), f(3), f(4), f(5), f(6), f(7));
+    }
+    expect: {
+        function f(a) {
+            return 1 == a || 2 == a || 3 == a ? "foo" : 4 == a ? 42 : 5 == a || 6 == a ? "foo" : "bar";
+        }
+        console.log(f(1), f(2), f(3), f(4), f(5), f(6), f(7));
+    }
+    expect_stdout: "foo foo foo 42 foo foo bar"
+}
+
+cond_11: {
+    options = {
+        conditionals: true,
+    }
+    input: {
+        var o = {
+            p: "foo",
+            q: function() {
+                return this.p;
+            }
+        };
+        function f() {
+            return "bar";
+        }
+        function g(a) {
+            return a ? f() : o.q();
+        }
+        console.log(g(0), g(1));
+    }
+    expect: {
+        var o = {
+            p: "foo",
+            q: function() {
+                return this.p;
+            }
+        };
+        function f() {
+            return "bar";
+        }
+        function g(a) {
+            return a ? f() : o.q();
+        }
+        console.log(g(0), g(1));
+    }
+    expect_stdout: "foo bar"
+}
+
 ternary_boolean_consequent: {
     options = {
         booleans: true,
index e8b6918..316d6a7 100644 (file)
@@ -30,7 +30,7 @@ non_hoisted_function_after_return: {
     }
     expect: {
         function foo(x) {
-            return x ? bar() : baz();
+            return (x ? bar : baz)();
             function bar() { return 7 }
             function baz() { return 8 }
         }
@@ -181,7 +181,7 @@ non_hoisted_function_after_return_strict: {
     expect: {
         "use strict";
         function foo(x) {
-            return x ? bar() : baz();
+            return (x ? bar : baz)();
             function bar() { return 7 }
             function baz() { return 8 }
         }
index 88b63ab..394d6ba 100644 (file)
@@ -21,7 +21,7 @@ cond_5: {
         }
     }
     expect: {
-        some_condition() && some_other_condition() ? do_something() : alternate();
+        (some_condition() && some_other_condition() ? do_something : alternate)();
         if (some_condition() && some_other_condition()) do_something();
     }
 }