fix corner cases with logical assignment operators (#4816)
authorAlex Lam S.L <alexlamsl@gmail.com>
Tue, 23 Mar 2021 05:02:45 +0000 (05:02 +0000)
committerGitHub <noreply@github.com>
Tue, 23 Mar 2021 05:02:45 +0000 (13:02 +0800)
fixes #4815

lib/compress.js
test/compress/assignments.js

index 95cccb5..673426b 100644 (file)
@@ -814,26 +814,39 @@ merge(Compressor.prototype, {
         def(AST_Assign, function(tw, descend, compressor) {
             var node = this;
             var left = node.left;
-            if (node.operator == "=" && left.equivalent_to(node.right) && !left.has_side_effects(compressor)) {
-                node.right.walk(tw);
-                walk_prop(left);
-                node.__drop = true;
-            } else if (!(left instanceof AST_Destructured || left instanceof AST_SymbolRef)) {
+            var scan = left instanceof AST_Destructured || left instanceof AST_SymbolRef;
+            switch (node.operator) {
+              case "=":
+                if (left.equivalent_to(node.right) && !left.has_side_effects(compressor)) {
+                    node.right.walk(tw);
+                    walk_prop(left);
+                    node.__drop = true;
+                    return true;
+                }
+                if (scan) {
+                    walk_assign();
+                    return true;
+                }
                 mark_assignment_to_arguments(left);
                 return;
-            } else switch (node.operator) {
-              case "=":
-                walk_assign();
-                break;
               case "&&=":
               case "||=":
               case "??=":
                 left.walk(tw);
                 push(tw);
-                walk_assign();
+                if (scan) {
+                    walk_assign();
+                } else {
+                    mark_assignment_to_arguments(left);
+                    node.right.walk(tw);
+                }
                 pop(tw);
-                break;
+                return true;
               default:
+                if (!scan) {
+                    mark_assignment_to_arguments(left);
+                    return;
+                }
                 var d = left.definition();
                 d.assignments++;
                 var fixed = d.fixed;
@@ -860,8 +873,8 @@ merge(Compressor.prototype, {
                     left.walk(tw);
                     d.fixed = false;
                 }
+                return true;
             }
-            return true;
 
             function walk_prop(lhs) {
                 if (lhs instanceof AST_Dot) {
@@ -7229,9 +7242,15 @@ merge(Compressor.prototype, {
             }
             if (left.has_side_effects(compressor)) return this;
             var right = this.right;
-            this.write_only = !(lazy_op[this.operator.slice(0, -1)] && right.has_side_effects(compressor));
-            if (!root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) return this;
-            return right.drop_side_effect_free(compressor);
+            if (lazy_op[this.operator.slice(0, -1)]) {
+                this.write_only = !right.has_side_effects(compressor);
+            } else {
+                this.write_only = true;
+                if (root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) {
+                    return right.drop_side_effect_free(compressor);
+                }
+            }
+            return this;
         });
         def(AST_Await, function(compressor) {
             if (!compressor.option("awaits")) return this;
index 274a0d6..db56229 100644 (file)
@@ -549,3 +549,43 @@ logical_side_effects: {
     expect_stdout: "PASS"
     node_version: ">=15"
 }
+
+issue_4815_1: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var a = "PASS";
+        42..p &&= a = "FAIL";
+        console.log(a);
+    }
+    expect: {
+        var a = "PASS";
+        42..p &&= a = "FAIL";
+        console.log(a);
+    }
+    expect_stdout: "PASS"
+    node_version: ">=15"
+}
+
+issue_4815_2: {
+    options = {
+        pure_getters: "strict",
+        side_effects: true,
+    }
+    input: {
+        var a = "PASS";
+        42..p &&= a = "FAIL";
+        console.log(a);
+    }
+    expect: {
+        var a = "PASS";
+        42..p &&= a = "FAIL";
+        console.log(a);
+    }
+    expect_stdout: "PASS"
+    node_version: ">=15"
+}