fix corner case in `evaluate` (#3656)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sun, 29 Dec 2019 13:16:53 +0000 (21:16 +0800)
committerGitHub <noreply@github.com>
Sun, 29 Dec 2019 13:16:53 +0000 (21:16 +0800)
fixes #3655

lib/compress.js
test/compress/numbers.js

index 9045a8d..9c60d0a 100644 (file)
@@ -5998,6 +5998,7 @@ merge(Compressor.prototype, {
     });
 
     var indexFns = makePredicate("indexOf lastIndexOf");
+    var minus_zero_op = makePredicate("- * / %");
     var commutativeOperators = makePredicate("== === != !== * & | ^");
     function is_object(node) {
         return node instanceof AST_Array
@@ -6459,11 +6460,11 @@ merge(Compressor.prototype, {
               // 0 + n => n
               case "+":
                 if (self.left.value == 0) {
-                    if (self.right.is_number(compressor)) return self.right;
                     if (self.right.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
                         operator: "+",
                         expression: self.right
                     }).optimize(compressor);
+                    if (self.right.is_number(compressor) && !may_be_minus_zero(self.right)) return self.right;
                 }
                 break;
               // 1 * n => n
@@ -6479,8 +6480,12 @@ merge(Compressor.prototype, {
             if (self.right instanceof AST_Number && !self.left.is_constant()) switch (self.operator) {
               // n + 0 => n
               case "+":
-                if (self.right.value == 0 && (self.left.is_boolean(compressor) || self.left.is_number(compressor))) {
-                    return self.left;
+                if (self.right.value == 0) {
+                    if (self.left.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
+                        operator: "+",
+                        expression: self.left
+                    }).optimize(compressor);
+                    if (self.left.is_number(compressor) && !may_be_minus_zero(self.left)) return self.left;
                 }
                 break;
               // n - 0 => n
@@ -6635,6 +6640,20 @@ merge(Compressor.prototype, {
                         && self.left.expression instanceof AST_Number && self.left.expression.value == 1;
             }
         }
+
+        function may_be_minus_zero(node) {
+            var ev = node.evaluate(compressor);
+            if (ev instanceof AST_Node) {
+                var op = ev.operator;
+                if (!op) return true;
+                if (ev instanceof AST_Assign) {
+                    if (op == "=") return may_be_minus_zero(ev.right);
+                    op = op.slice(0, -1);
+                }
+                if (minus_zero_op[op]) return true;
+                if (ev instanceof AST_UnaryPrefix && op == "+") return true;
+            } else if (ev == 0 && 1 / ev < 0) return true;
+        }
     });
 
     function recursive_ref(compressor, def) {
index 07e93f6..f49996a 100644 (file)
@@ -1075,14 +1075,53 @@ issue_3653: {
     }
     expect: {
         console.log(0 - (console && 0));
-        console.log(0 - (console && 0));
+        console.log(0 - (console && 0) + 0);
         console.log(0 - (0 - (console && 0)));
         console.log(0 - (console && 0));
         console.log(1 / (0 - (console && 0)));
+        console.log(0 - (console && 0) + 0);
         console.log(0 - (console && 0));
         console.log(0 - (console && 0));
         console.log(0 - (console && 0));
-        console.log(0 - (console && 0));
+    }
+    expect_stdout: [
+        "0",
+        "0",
+        "0",
+        "0",
+        "Infinity",
+        "0",
+        "0",
+        "0",
+        "0",
+    ]
+}
+
+issue_3655: {
+    options = {
+        evaluate: true,
+    }
+    input: {
+        console.log(0 + 0 * -[].length);
+        console.log(0 + (0 + 0 * -[].length));
+        console.log(0 - (0 + 0 * -[].length));
+        console.log(1 * (0 + 0 * -[].length));
+        console.log(1 / (0 + 0 * -[].length));
+        console.log((0 + 0 * -[].length) + 0);
+        console.log((0 + 0 * -[].length) - 0);
+        console.log((0 + 0 * -[].length) * 1);
+        console.log((0 + 0 * -[].length) / 1);
+    }
+    expect: {
+        console.log(0 + 0 * -[].length);
+        console.log(0 + 0 * -[].length);
+        console.log(0 - (0 + 0 * -[].length));
+        console.log(0 + 0 * -[].length);
+        console.log(1 / (0 + 0 * -[].length));
+        console.log(0 + 0 * -[].length);
+        console.log(0 + 0 * -[].length);
+        console.log(0 + 0 * -[].length);
+        console.log(0 + 0 * -[].length);
     }
     expect_stdout: [
         "0",