fix corner cases with logical assignment operators (#4828)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sat, 27 Mar 2021 19:44:45 +0000 (19:44 +0000)
committerGitHub <noreply@github.com>
Sat, 27 Mar 2021 19:44:45 +0000 (03:44 +0800)
fixes #4827

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

index 6286741..24446b2 100644 (file)
@@ -2391,21 +2391,36 @@ merge(Compressor.prototype, {
                 return null;
             }
 
+            function find_stop_logical(parent, op, level) {
+                var node;
+                do {
+                    node = parent;
+                    parent = scanner.parent(++level);
+                } while (parent instanceof AST_Assign && parent.operator.slice(0, -1) == op
+                    || parent instanceof AST_Binary && parent.operator == op);
+                return node;
+            }
+
             function find_stop_value(node, level) {
                 var parent = scanner.parent(level);
                 if (parent instanceof AST_Array) return find_stop_value(parent, level + 1);
-                if (parent instanceof AST_Assign) return may_throw(parent) || parent.left.match_symbol(function(ref) {
-                    return ref instanceof AST_SymbolRef && (lhs.name == ref.name || value_def.name == ref.name);
-                }) ? node : find_stop_value(parent, level + 1);
+                if (parent instanceof AST_Assign) {
+                    if (may_throw(parent)) return node;
+                    if (parent.left.match_symbol(function(ref) {
+                        return ref instanceof AST_SymbolRef && (lhs.name == ref.name || value_def.name == ref.name);
+                    })) return node;
+                    var op;
+                    if (parent.left === node || !lazy_op[op = parent.operator.slice(0, -1)]) {
+                        return find_stop_value(parent, level + 1);
+                    }
+                    return find_stop_logical(parent, op, level);
+                }
                 if (parent instanceof AST_Binary) {
-                    if (lazy_op[parent.operator] && parent.left !== node) {
-                        do {
-                            node = parent;
-                            parent = scanner.parent(++level);
-                        } while (parent instanceof AST_Binary && parent.operator == node.operator);
-                        return node;
+                    var op;
+                    if (parent.left === node || !lazy_op[op = parent.operator]) {
+                        return find_stop_value(parent, level + 1);
                     }
-                    return find_stop_value(parent, level + 1);
+                    return find_stop_logical(parent, op, level);
                 }
                 if (parent instanceof AST_Call) return parent;
                 if (parent instanceof AST_Case) {
@@ -5325,8 +5340,9 @@ merge(Compressor.prototype, {
         var tw = new TreeWalker(function(node, descend) {
             if (node instanceof AST_Assign) {
                 var lhs = node.left;
+                var rhs = node.right;
                 if (lhs instanceof AST_Destructured) {
-                    node.right.walk(tw);
+                    rhs.walk(tw);
                     var marker = new TreeWalker(function(node) {
                         if (node instanceof AST_Destructured) return;
                         if (node instanceof AST_DefaultValue) {
@@ -5354,9 +5370,17 @@ merge(Compressor.prototype, {
                     lhs.walk(marker);
                     return true;
                 }
+                if (lazy_op[node.operator.slice(0, -1)]) {
+                    lhs.walk(tw);
+                    push();
+                    rhs.walk(tw);
+                    if (lhs instanceof AST_SymbolRef) mark(lhs);
+                    pop();
+                    return true;
+                }
                 if (lhs instanceof AST_SymbolRef) {
                     if (node.operator != "=") mark(lhs, true);
-                    node.right.walk(tw);
+                    rhs.walk(tw);
                     mark(lhs);
                     return true;
                 }
index 80538bd..3973e2f 100644 (file)
@@ -603,3 +603,72 @@ issue_4819: {
     expect_stdout: "true"
     node_version: ">=15"
 }
+
+issue_4827_1: {
+    options = {
+        collapse_vars: true,
+        toplevel: true,
+    }
+    input: {
+        A = "FAIL";
+        var a = A, b = "PASS", c;
+        c &&= b = a, console.log(b);
+    }
+    expect: {
+        A = "FAIL";
+        var a = A, b = "PASS", c;
+        c &&= b = a, console.log(b);
+    }
+    expect_stdout: "PASS"
+    node_version: ">=15"
+}
+
+issue_4827_2: {
+    options = {
+        collapse_vars: true,
+        inline: true,
+        reduce_vars: true,
+        side_effects: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var a = 0, b = "PASS";
+        function f(c) {
+            a++,
+            c &&= b = a;
+        }
+        f();
+        console.log(b);
+    }
+    expect: {
+        var a = 0, b = "PASS";
+        a++,
+        c &&= b = a;
+        var c;
+        console.log(b);
+    }
+    expect_stdout: "PASS"
+    node_version: ">=15"
+}
+
+issue_4827_3: {
+    options = {
+        merge_vars: true,
+        toplevel: true,
+    }
+    input: {
+        var a = 0, b, c;
+        a++;
+        c &&= b = a;
+        console.log(b);
+    }
+    expect: {
+        var a = 0, b, c;
+        a++;
+        c &&= b = a;
+        console.log(b);
+    }
+    expect_stdout: "undefined"
+    node_version: ">=15"
+}