enhance `conditionals` (#4106)
authorAlex Lam S.L <alexlamsl@gmail.com>
Tue, 15 Sep 2020 21:51:42 +0000 (22:51 +0100)
committerGitHub <noreply@github.com>
Tue, 15 Sep 2020 21:51:42 +0000 (05:51 +0800)
lib/compress.js
test/compress/conditionals.js

index 52ed0e6..dbf4e09 100644 (file)
@@ -8456,35 +8456,26 @@ merge(Compressor.prototype, {
             condition,
             consequent
         ]).optimize(compressor);
+        // x ? y.p : z.p => (x ? y : z).p
+        // x ? y(a) : z(a) => (x ? y : z)(a)
+        // x ? y.f(a) : z.f(a) => (x ? y : z).f(a)
+        var combined = combine_tail(consequent, alternative, true);
+        if (combined) return combined;
+        // x ? y(a) : y(b) => y(x ? a : b)
+        var arg_index;
         if (consequent instanceof AST_Call
-            && alternative.TYPE === consequent.TYPE
-            && 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;
-            }
+            && alternative.TYPE == consequent.TYPE
+            && (arg_index = arg_diff(consequent, alternative)) >= 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 ? a : b) : b => x && y ? a : b
         if (consequent instanceof AST_Conditional
@@ -8685,10 +8676,12 @@ merge(Compressor.prototype, {
                     && node.expression.value);
         }
 
-        function arg_diff() {
+        function arg_diff(consequent, alternative) {
             var a = consequent.args;
             var b = alternative.args;
-            for (var i = 0, len = a.length; i < len; i++) {
+            var len = a.length;
+            if (len != b.length) return -2;
+            for (var i = 0; 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 -2;
@@ -8699,6 +8692,32 @@ merge(Compressor.prototype, {
             return -1;
         }
 
+        function is_tail_equivalent(consequent, alternative) {
+            if (consequent.TYPE != alternative.TYPE) return;
+            if (consequent instanceof AST_Call) {
+                if (arg_diff(consequent, alternative) != -1) return;
+                return consequent.TYPE != "Call"
+                    || !(consequent.expression instanceof AST_PropAccess
+                        || alternative.expression instanceof AST_PropAccess)
+                    || is_tail_equivalent(consequent.expression, alternative.expression);
+            }
+            if (consequent instanceof AST_Dot) return consequent.property == alternative.property;
+            if (consequent instanceof AST_Sub) return consequent.property.equivalent_to(alternative.property);
+        }
+
+        function combine_tail(consequent, alternative, top) {
+            if (!is_tail_equivalent(consequent, alternative)) return !top && make_node(AST_Conditional, self, {
+                condition: condition,
+                consequent: consequent,
+                alternative: alternative
+            });
+            var exp = combine_tail(consequent.expression, alternative.expression);
+            if (!exp) return;
+            var node = consequent.clone();
+            node.expression = exp;
+            return node;
+        }
+
         function can_shift_lhs_of_tail(node) {
             return node === node.tail_node() || all(node.expressions.slice(0, -1), function(expr) {
                 return !expr.has_side_effects(compressor);
index ab9c410..4d54b83 100644 (file)
@@ -783,6 +783,28 @@ cond_12: {
     }
 }
 
+cond_13: {
+    options = {
+        conditionals: true,
+    }
+    input: {
+        x ? y(a) : z(a);
+        x ? y.f(a) : z.f(a);
+        x ? y.f(a) : z.g(a);
+        x ? y.f()(a) : z.g()(a);
+        x ? y.f.u(a) : z.g.u(a);
+        x ? y.f().u(a) : z.g().u(a);
+    }
+    expect: {
+        (x ? y : z)(a);
+        (x ? y : z).f(a);
+        x ? y.f(a) : z.g(a);
+        (x ? y.f() : z.g())(a);
+        (x ? y.f : z.g).u(a);
+        (x ? y.f() : z.g()).u(a);
+    }
+}
+
 ternary_boolean_consequent: {
     options = {
         booleans: true,