enhance `side_effects` (#4727)
authorAlex Lam S.L <alexlamsl@gmail.com>
Wed, 3 Mar 2021 10:47:17 +0000 (10:47 +0000)
committerGitHub <noreply@github.com>
Wed, 3 Mar 2021 10:47:17 +0000 (18:47 +0800)
lib/compress.js
test/compress/collapse_vars.js
test/compress/issue-281.js
test/compress/merge_vars.js
test/compress/reduce_vars.js
test/compress/sequences.js

index 1b22d86..99e67b9 100644 (file)
@@ -4797,9 +4797,15 @@ merge(Compressor.prototype, {
                 || this.right.has_side_effects(compressor);
         });
         def(AST_Binary, function(compressor) {
-            return this.left.has_side_effects(compressor)
-                || this.right.has_side_effects(compressor)
-                || this.operator == "in" && !is_object(this.right);
+            var lhs = this.left;
+            if (lhs.has_side_effects(compressor)) return true;
+            var rhs = this.right;
+            var op = this.operator;
+            if (!rhs.has_side_effects(compressor)) return op == "in" && !is_object(rhs);
+            if (op == "&&" && rhs instanceof AST_PropAccess && lhs.equivalent_to(rhs.expression)) {
+                return rhs instanceof AST_Sub && rhs.property.has_side_effects(compressor);
+            }
+            return true;
         });
         def(AST_Block, function(compressor) {
             return any(this.body, compressor);
@@ -7208,33 +7214,42 @@ merge(Compressor.prototype, {
             return node;
         });
         def(AST_Binary, function(compressor, first_in_statement) {
-            if (this.operator == "in" && !is_object(this.right)) {
-                var left = this.left.drop_side_effect_free(compressor, first_in_statement);
-                if (left === this.left) return this;
+            var left = this.left;
+            var right = this.right;
+            var op = this.operator;
+            if (op == "in" && !is_object(right)) {
+                var lhs = left.drop_side_effect_free(compressor, first_in_statement);
+                if (lhs === left) return this;
                 var node = this.clone();
-                node.left = left || make_node(AST_Number, this.left, {
-                    value: 0
-                });
+                node.left = lhs || make_node(AST_Number, left, { value: 0 });
                 return node;
             }
-            var right = this.right.drop_side_effect_free(compressor, first_in_statement);
-            if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement);
-            if (lazy_op[this.operator] && !(right instanceof AST_Function)) {
+            var rhs = right.drop_side_effect_free(compressor, first_in_statement);
+            if (!rhs) return left.drop_side_effect_free(compressor, first_in_statement);
+            if (lazy_op[op] && !(rhs instanceof AST_Function)) {
                 var node = this;
-                if (right !== node.right) {
-                    node = this.clone();
-                    node.right = right.drop_side_effect_free(compressor);
-                }
-                if (this.operator == "??") return node;
+                 if (op == "&&"
+                    && rhs instanceof AST_PropAccess
+                    && left.equivalent_to(rhs.expression)
+                    && !left.has_side_effects(compressor)) {
+                    var prop = rhs instanceof AST_Sub && rhs.property.drop_side_effect_free(compressor);
+                    if (!prop) return left.drop_side_effect_free(compressor, first_in_statement);
+                    node = node.clone();
+                    node.right = prop;
+                } else if (rhs !== right) {
+                    node = node.clone();
+                    node.right = rhs.drop_side_effect_free(compressor);
+                }
+                if (op == "??") return node;
                 return (first_in_statement ? best_of_statement : best_of_expression)(node, make_node(AST_Binary, this, {
-                    operator: node.operator == "&&" ? "||" : "&&",
-                    left: node.left.negate(compressor, first_in_statement),
-                    right: node.right
+                    operator: op == "&&" ? "||" : "&&",
+                    left: left.negate(compressor, first_in_statement),
+                    right: node.right,
                 }));
             } else {
-                var left = this.left.drop_side_effect_free(compressor, first_in_statement);
-                if (!left) return right;
-                return make_sequence(this, [ left, right.drop_side_effect_free(compressor) ]);
+                var lhs = left.drop_side_effect_free(compressor, first_in_statement);
+                if (!lhs) return rhs;
+                return make_sequence(this, [ lhs, rhs.drop_side_effect_free(compressor) ]);
             }
         });
         def(AST_Call, function(compressor, first_in_statement) {
index fe963b4..c0a545c 100644 (file)
@@ -2863,7 +2863,7 @@ lvalues_def: {
     expect: {
         var a = 0, b = 1;
         a = b++, b = +void 0;
-        a && a[a++];
+        a && a++;
         console.log(a, b);
     }
     expect_stdout: true
@@ -5098,7 +5098,7 @@ issue_2878: {
             }
             b = f2();
             a = 1;
-            b && b.b;
+            b && b[console];
             f2();
         })();
         console.log(c);
@@ -5111,7 +5111,7 @@ issue_2878: {
             }
             b = f2(),
             a = 1,
-            b && b.b,
+            b && console,
             f2();
         })(),
         console.log(c);
@@ -6546,7 +6546,7 @@ issue_3520: {
                 (function f() {
                     c = 0;
                     var i = void 0;
-                    var f = f && f[i];
+                    var f = f && f[console && i];
                 })();
                 a += b;
                 c && b++;
@@ -6560,7 +6560,7 @@ issue_3520: {
             for (var i = 2; --i >= 0;) {
                 (function() {
                     c = 0;
-                    var f = f && f[void 0];
+                    var f = f && f[console && void 0];
                 })();
                 a += b;
                 c && b++;
index 1c339bc..797f7d9 100644 (file)
@@ -463,15 +463,19 @@ drop_fargs: {
         var a = 1;
         !function(a_1) {
             a++;
-        }(a++ + (a && a.var));
+        }(a++ + (a && console.log(a)));
         console.log(a);
     }
     expect: {
         var a = 1;
-        ++a && a.var, a++;
+        ++a && console.log(a),
+        a++;
         console.log(a);
     }
-    expect_stdout: "3"
+    expect_stdout: [
+        "2",
+        "3",
+    ]
 }
 
 keep_fargs: {
@@ -486,13 +490,17 @@ keep_fargs: {
         var a = 1;
         !function(a_1) {
             a++;
-        }(a++ + (a && a.var));
+        }(a++ + (a && console.log(a)));
         console.log(a);
     }
     expect: {
         var a = 1;
-        ++a && a.var, a++;
+        ++a && console.log(a),
+        a++;
         console.log(a);
     }
-    expect_stdout: "3"
+    expect_stdout: [
+        "2",
+        "3",
+    ]
 }
index c45f835..667cacf 100644 (file)
@@ -2723,7 +2723,7 @@ issue_4135: {
             var c = function() {
                 var d = 0;
                 function f() {
-                    d && d.p;
+                    d && d[console];
                 }
                 f();
                 this;
@@ -2735,7 +2735,7 @@ issue_4135: {
         0;
         a++;
         if (!a)
-            c = (a++, c = 0, void (c && c.p));
+            c = (a++, c = 0, void (c && console));
         var c;
         console.log(a, -1, c);
     }
index 5ae0884..110f046 100644 (file)
@@ -2554,7 +2554,7 @@ side_effects_assign: {
         console.log(a);
     }
     expect: {
-        var a = typeof void (a && a.in);
+        var a = "undefined";
         console.log(a);
     }
     expect_stdout: "undefined"
@@ -2595,9 +2595,7 @@ pure_getters_2: {
         var a;
         var a = a && a.b;
     }
-    expect: {
-        var a = a && a.b;
-    }
+    expect: {}
 }
 
 pure_getters_3: {
index b819036..a9dbc70 100644 (file)
@@ -745,12 +745,12 @@ issue_2062: {
     }
     input: {
         var a = 1;
-        if ([ a || a++ + a--, a++ + a--, a && a.var ]);
+        if ([ a || a++ + a--, a++ + a--, a && a[console] ]);
         console.log(a);
     }
     expect: {
         var a = 1;
-        a || (a++, a--), a++, --a && a.var;
+        a || (a++, a--), a++, --a && console;
         console.log(a);
     }
     expect_stdout: "1"
@@ -1088,7 +1088,7 @@ issue_3490_1: {
         if ({
             3: function() {
                 var a;
-                return (a && a.p) < this;
+                return (a && a[console]) < this;
             }(),
         }) c = "PASS";
         if (b) while ("" == typeof d);
@@ -1098,7 +1098,7 @@ issue_3490_1: {
         var b = 42, c = "FAIL";
         if (function() {
             var a;
-            a && a.p;
+            a && console;
         }(), c = "PASS", b) while ("" == typeof d);
         console.log(c, b);
     }