aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/compress.js81
-rw-r--r--test/compress/numbers.js52
2 files changed, 113 insertions, 20 deletions
diff --git a/lib/compress.js b/lib/compress.js
index e645bd4e..ffa5a644 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -2485,6 +2485,60 @@ merge(Compressor.prototype, {
node.DEFMETHOD("is_truthy", func);
});
+ // is_negative_zero()
+ // return true if the node may represent -0
+ (function(def) {
+ def(AST_Node, return_true);
+ def(AST_Array, return_false);
+ function binary(op, left, right) {
+ switch (op) {
+ case "-":
+ return left.is_negative_zero()
+ && (!(right instanceof AST_Constant) || right.value == 0);
+ case "&&":
+ case "||":
+ case "*":
+ return left.is_negative_zero() || right.is_negative_zero();
+ case "/":
+ case "%":
+ return left.is_negative_zero();
+ default:
+ return false;
+ }
+ }
+ def(AST_Assign, function() {
+ var op = this.operator;
+ if (op == "=") return this.right.is_negative_zero();
+ return binary(op.slice(0, -1), this.left, this.right);
+ });
+ def(AST_Binary, function() {
+ return binary(this.operator, this.left, this.right);
+ });
+ def(AST_Constant, function() {
+ return this.value == 0 && 1 / this.value < 0;
+ });
+ def(AST_Lambda, return_false);
+ def(AST_Object, return_false);
+ def(AST_RegExp, return_false);
+ def(AST_Sequence, function() {
+ return this.tail_node().is_negative_zero();
+ });
+ def(AST_SymbolRef, function() {
+ var fixed = this.fixed_value();
+ if (!fixed) return true;
+ this.is_negative_zero = return_true;
+ var result = fixed.is_negative_zero();
+ delete this.is_negative_zero;
+ return result;
+ });
+ def(AST_UnaryPrefix, function() {
+ return this.operator == "+" && this.expression.is_negative_zero()
+ || this.operator == "-";
+ });
+ })(function(node, func) {
+ node.DEFMETHOD("is_negative_zero", func);
+ });
+
// may_throw_on_access()
// returns true if this node may be null, undefined or contain `AST_Accessor`
(function(def) {
@@ -6111,7 +6165,6 @@ 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
@@ -6533,6 +6586,7 @@ merge(Compressor.prototype, {
&& (self.operator != "+"
|| self.right.left.is_boolean(compressor)
|| self.right.left.is_number(compressor))
+ && (self.operator != "-" || !self.left.is_negative_zero())
&& (self.right.left.is_constant_expression()
|| !self.right.right.has_side_effects(compressor))) {
self = make_node(AST_Binary, self, {
@@ -6567,7 +6621,12 @@ merge(Compressor.prototype, {
self = make_binary(self, self.left.operator, lhs, self.left.right);
} else if (self.left.right instanceof AST_Constant) {
var rhs = make_binary(self.left, align(self.left.operator, self.operator), self.left.right, self.right, self.left.right.start, self.right.end);
- self = make_binary(self, self.left.operator, self.left.left, rhs);
+ if (self.left.operator != "-"
+ || !self.right.value
+ || rhs.evaluate(compressor)
+ || !self.left.left.is_negative_zero()) {
+ self = make_binary(self, self.left.operator, self.left.left, rhs);
+ }
}
}
break;
@@ -6580,7 +6639,7 @@ merge(Compressor.prototype, {
operator: "+",
expression: self.right
}).optimize(compressor);
- if (self.right.is_number(compressor) && !may_be_minus_zero(self.right)) return self.right;
+ if (self.right.is_number(compressor) && !self.right.is_negative_zero()) return self.right;
}
break;
// 1 * n => n
@@ -6601,7 +6660,7 @@ merge(Compressor.prototype, {
operator: "+",
expression: self.left
}).optimize(compressor);
- if (self.left.is_number(compressor) && !may_be_minus_zero(self.left)) return self.left;
+ if (self.left.is_number(compressor) && !self.left.is_negative_zero()) return self.left;
}
break;
// n - 0 => n
@@ -6756,20 +6815,6 @@ 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) {
diff --git a/test/compress/numbers.js b/test/compress/numbers.js
index c40ca09d..fdfb6c2f 100644
--- a/test/compress/numbers.js
+++ b/test/compress/numbers.js
@@ -1075,11 +1075,11 @@ issue_3653: {
}
expect: {
console.log(0 - (console && 0));
- console.log(0 - (console && 0) + 0);
+ console.log(0 - (console && 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));
@@ -1167,3 +1167,51 @@ issue_3676_2: {
}
expect_stdout: "NaN"
}
+
+issue_3682_1: {
+ options = {
+ evaluate: true,
+ unsafe_math: true,
+ }
+ input: {
+ var a = -0;
+ console.log(1 / (a - 1 + 1));
+ }
+ expect: {
+ var a = -0;
+ console.log(1 / (a - 1 + 1));
+ }
+ expect_stdout: "Infinity"
+}
+
+issue_3682_2: {
+ options = {
+ evaluate: true,
+ unsafe_math: true,
+ }
+ input: {
+ var a = -0, b = 1;
+ console.log(1 / (a - (b - b)));
+ }
+ expect: {
+ var a = -0, b = 1;
+ console.log(1 / (a - (b - b)));
+ }
+ expect_stdout: "-Infinity"
+}
+
+issue_3682_3: {
+ options = {
+ evaluate: true,
+ unsafe_math: true,
+ }
+ input: {
+ var a = -0, b = 1, c = -1;
+ console.log(1 / (a - (+b + +c)));
+ }
+ expect: {
+ var a = -0, b = 1, c = -1;
+ console.log(1 / (a - (+b + +c)));
+ }
+ expect_stdout: "-Infinity"
+}