enhance `evaluate` & `reduce_vars` (#3870)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sun, 10 May 2020 10:38:32 +0000 (11:38 +0100)
committerGitHub <noreply@github.com>
Sun, 10 May 2020 10:38:32 +0000 (18:38 +0800)
lib/compress.js
test/compress/join_vars.js
test/compress/reduce_vars.js

index 904295e..4f5e925 100644 (file)
@@ -3302,19 +3302,23 @@ merge(Compressor.prototype, {
         var non_converting_unary = makePredicate("! typeof void");
         def(AST_UnaryPrefix, function(compressor, ignore_side_effects, cached, depth) {
             var e = this.expression;
+            var op = this.operator;
             // Function would be evaluated to an array and so typeof would
             // incorrectly return 'object'. Hence making is a special case.
             if (compressor.option("typeofs")
-                && this.operator == "typeof"
+                && op == "typeof"
                 && (e instanceof AST_Lambda
                     || e instanceof AST_SymbolRef
                         && e.fixed_value() instanceof AST_Lambda)) {
                 return typeof function(){};
             }
-            if (!non_converting_unary[this.operator]) depth++;
+            if (!non_converting_unary[op]) depth++;
             var v = e._eval(compressor, ignore_side_effects, cached, depth);
-            if (v === this.expression) return this;
-            switch (this.operator) {
+            if (v === e) {
+                if (ignore_side_effects && op == "void") return void 0;
+                return this;
+            }
+            switch (op) {
               case "!": return !v;
               case "typeof":
                 // typeof <RegExp> returns "object" or "function" on different platforms
@@ -3330,7 +3334,7 @@ merge(Compressor.prototype, {
                 if (!(e instanceof AST_SymbolRef)) return this;
                 var refs = e.definition().references;
                 if (refs[refs.length - 1] !== e) return this;
-                return HOP(e, "_eval") ? +(this.operator[0] + 1) + +v : v;
+                return HOP(e, "_eval") ? +(op[0] + 1) + +v : v;
             }
             return this;
         });
@@ -7500,9 +7504,13 @@ merge(Compressor.prototype, {
                         init = fixed;
                     }
                 } else {
-                    var ev = fixed.evaluate(compressor);
-                    if (ev !== fixed && (!(ev instanceof RegExp)
-                        || compressor.option("unsafe_regexp") && !def.cross_loop && same_scope(def))) {
+                    var ev = fixed.evaluate(compressor, true);
+                    if (ev !== fixed
+                        && typeof ev != "function"
+                        && (typeof ev != "object"
+                            || ev instanceof RegExp
+                                && compressor.option("unsafe_regexp")
+                                && !def.cross_loop && same_scope(def))) {
                         init = make_node_from_constant(ev, fixed);
                     }
                 }
index 3e4334c..67d7fd0 100644 (file)
@@ -785,11 +785,12 @@ issue_3791_2: {
 
 issue_3795: {
     options = {
+        booleans: true,
         collapse_vars: true,
-        conditionals: true,
         dead_code: true,
         evaluate: true,
         join_vars: true,
+        keep_fargs: "strict",
         loops: true,
         passes: 2,
         reduce_vars: true,
@@ -798,22 +799,21 @@ issue_3795: {
     }
     input: {
         var a = "FAIL";
-        function f(b) {
-            for (var i = 1; b && i; --i) return 0;
+        function f(b, c) {
+            for (var i = 5; c && i; --i) return -1;
             a = "PASS";
         }
-        var c = f(a = "");
-        console.log(a);
+        var d = f(a = 42, d);
+        console.log(a, d);
     }
     expect: {
-        var a = "FAIL";
-        (function(b) {
-            a = "";
+        var a = "FAIL", d = function() {
+            if (a = 42, d) return -1;
             a = "PASS";
-        })();
-        console.log(a);
+        }();
+        console.log(a, d);
     }
-    expect_stdout: "PASS"
+    expect_stdout: "PASS undefined"
 }
 
 if_body: {
index ec75e91..ee1e471 100644 (file)
@@ -7054,3 +7054,24 @@ issue_3866: {
     }
     expect_stdout: "PASS"
 }
+
+void_side_effects: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var a = void console.log("PASS");
+        console.log(a);
+    }
+    expect: {
+        console.log("PASS");
+        console.log(void 0);
+    }
+    expect_stdout: [
+        "PASS",
+        "undefined",
+    ]
+}