enhance `reduce_vars` (#5164)
authorAlex Lam S.L <alexlamsl@gmail.com>
Thu, 4 Nov 2021 10:36:39 +0000 (18:36 +0800)
committerGitHub <noreply@github.com>
Thu, 4 Nov 2021 10:36:39 +0000 (18:36 +0800)
- fix corner case in `join_vars`

lib/compress.js
test/compress/join_vars.js
test/compress/reduce_vars.js

index a442f94..d8823d6 100644 (file)
@@ -389,7 +389,18 @@ merge(Compressor.prototype, {
         }
         var lhs = is_lhs(node, parent);
         if (lhs) return lhs;
+        if (level == 0 && value && value.is_constant()) return;
         if (parent instanceof AST_Array) return is_modified(compressor, tw, parent, parent, level + 1);
+        if (parent instanceof AST_Assign) switch (parent.operator) {
+          case "=":
+            return is_modified(compressor, tw, parent, value, level + 1, immutable, recursive);
+          case "&&=":
+          case "||=":
+          case "??=":
+            return is_modified(compressor, tw, parent, parent, level + 1);
+          default:
+            return;
+        }
         if (parent instanceof AST_Binary) {
             if (!lazy_op[parent.operator]) return;
             return is_modified(compressor, tw, parent, parent, level + 1);
@@ -625,7 +636,7 @@ merge(Compressor.prototype, {
             if (def.fixed === undefined) return declare || all(def.orig, function(sym) {
                 return !(sym instanceof AST_SymbolLet);
             });
-            if (def.fixed === false) return false;
+            if (def.fixed === false || def.fixed === 0) return false;
             var safe = tw.safe_ids[def.id];
             if (def.safe_ids) {
                 def.safe_ids[def.id] = false;
@@ -973,7 +984,13 @@ merge(Compressor.prototype, {
                     }
                     var d = sym.definition();
                     d.assignments++;
-                    if (fixed && !modified && !sym.in_arg && safe_to_assign(tw, d)) {
+                    if (!fixed || sym.in_arg || !safe_to_assign(tw, d)) {
+                        walk();
+                        d.fixed = false;
+                    } else if (modified) {
+                        walk();
+                        d.fixed = 0;
+                    } else {
                         push_ref(d, sym);
                         mark(tw, d);
                         if (left instanceof AST_Destructured
@@ -984,9 +1001,6 @@ merge(Compressor.prototype, {
                         mark_escaped(tw, d, sym.scope, node, right, 0, 1);
                         sym.fixed = d.fixed = fixed;
                         sym.fixed.assigns = [ node ];
-                    } else {
-                        walk();
-                        d.fixed = false;
                     }
                 });
             }
@@ -1265,7 +1279,7 @@ merge(Compressor.prototype, {
                 if (!safe) return;
                 safe.assign = true;
             });
-            if (d.fixed === false) {
+            if (d.fixed === false || d.fixed === 0) {
                 var redef = d.redefined();
                 if (redef && cross_scope(d.scope, this.scope)) redef.single_use = false;
             } else if (d.fixed === undefined || !safe_to_read(tw, d)) {
@@ -1290,7 +1304,7 @@ merge(Compressor.prototype, {
                     if (d.single_use) {
                         d.single_use = "m";
                     } else {
-                        d.fixed = false;
+                        d.fixed = 0;
                     }
                 }
                 if (d.fixed && tw.loop_ids[d.id] !== tw.in_loop) d.cross_loop = true;
@@ -1475,9 +1489,14 @@ merge(Compressor.prototype, {
 
     AST_Symbol.DEFMETHOD("fixed_value", function() {
         var fixed = this.definition().fixed;
+        if (fixed) {
+            if (this.fixed) fixed = this.fixed;
+            return fixed instanceof AST_Node ? fixed : fixed();
+        }
+        fixed = fixed === 0 && this.fixed;
         if (!fixed) return fixed;
-        if (this.fixed) fixed = this.fixed;
-        return fixed instanceof AST_Node ? fixed : fixed();
+        var value = fixed instanceof AST_Node ? fixed : fixed();
+        return value.is_constant() && value;
     });
 
     AST_SymbolRef.DEFMETHOD("is_immutable", function() {
@@ -3593,11 +3612,11 @@ merge(Compressor.prototype, {
                 if (!(node.left instanceof AST_PropAccess)) return;
                 var sym = node.left.expression;
                 if (!(sym instanceof AST_SymbolRef)) return;
-                if (!names[sym.name]) return;
+                if (!(sym.name in names)) return;
                 if (!node.right.is_constant_expression(scope)) return;
                 var prop = node.left.property;
                 if (prop instanceof AST_Node) {
-                    if (try_join(prop)) prop = node.left.property = prop.right;
+                    if (try_join(prop)) prop = node.left.property = prop.right.clone();
                     prop = prop.evaluate(compressor);
                 }
                 if (prop instanceof AST_Node) return;
@@ -3615,7 +3634,7 @@ merge(Compressor.prototype, {
                 if (!all(value.properties, diff)) return;
                 value.properties.push(make_node(AST_ObjectKeyVal, node, {
                     key: prop,
-                    value: node.right
+                    value: node.right,
                 }));
                 return true;
             }
index f7dd4ae..94612c4 100644 (file)
@@ -507,7 +507,7 @@ chained_assignments: {
     expect_stdout: "PASS"
 }
 
-folded_assignments: {
+folded_assignments_1: {
     options = {
         evaluate: true,
         join_vars: true,
@@ -527,6 +527,30 @@ folded_assignments: {
     expect_stdout: "PASS 42"
 }
 
+folded_assignments_2: {
+    options = {
+        evaluate: true,
+        join_vars: true,
+    }
+    input: {
+        "use strict";
+        var a = {};
+        a[42] = "FAIL";
+        a[a.PASS = 42] = "PASS";
+        console.log(a[42], a.PASS);
+    }
+    expect: {
+        "use strict";
+        var a = {
+            42: "FAIL",
+            PASS: 42,
+        };
+        a[42] = "PASS";
+        console.log(a[42], a.PASS);
+    }
+    expect_stdout: "PASS 42"
+}
+
 inlined_assignments: {
     options = {
         join_vars: true,
@@ -550,6 +574,7 @@ typescript_enum: {
     rename = true
     options = {
         assignments: true,
+        collapse_vars: true,
         evaluate: true,
         hoist_props: true,
         inline: true,
index ebb6229..43e1ff1 100644 (file)
@@ -7320,6 +7320,46 @@ local_assignment_loop: {
     expect_stdout: "PASS"
 }
 
+local_assignment_modified: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        side_effects: true,
+        toplevel: true,
+    }
+    input: {
+        var a;
+        (a = a || {}).p = 42;
+        console.log(a.p);
+    }
+    expect: {
+        var a;
+        (a = {}).p = 42;
+        console.log(a.p);
+    }
+    expect_stdout: "42"
+}
+
+local_definition_modified: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        side_effects: true,
+        toplevel: true,
+    }
+    input: {
+        var a = a || {};
+        a.p = 42;
+        console.log(a.p);
+    }
+    expect: {
+        var a = {};
+        a.p = 42;
+        console.log(a.p);
+    }
+    expect_stdout: "42"
+}
+
 issue_3957_1: {
     options = {
         evaluate: true,
@@ -7435,6 +7475,7 @@ issue_4030: {
         collapse_vars: true,
         evaluate: true,
         reduce_vars: true,
+        side_effects: true,
         toplevel: true,
         unused: true,
     }