From: Alex Lam S.L Date: Mon, 21 Sep 2020 22:49:32 +0000 (+0100) Subject: fix corner case in `evaluate` (#4138) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=13cdc167a24fc49f5275b17810525f6879986304;p=UglifyJS.git fix corner case in `evaluate` (#4138) fixes #4137 --- diff --git a/lib/compress.js b/lib/compress.js index 82bbbf1b..adc894f2 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -3106,7 +3106,12 @@ merge(Compressor.prototype, { (function(def) { def(AST_Node, return_false); def(AST_Assign, function(compressor) { - return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor); + switch (this.operator) { + case "+=": + if (this.left.is_string(compressor)) return true; + case "=": + return this.right.is_string(compressor); + } }); def(AST_Binary, function(compressor) { return this.operator == "+" && @@ -7365,10 +7370,9 @@ merge(Compressor.prototype, { var indexFns = makePredicate("indexOf lastIndexOf"); var commutativeOperators = makePredicate("== === != !== * & | ^"); function is_object(node) { - while ((node = node.tail_node()) instanceof AST_SymbolRef) { - node = node.fixed_value(); - if (!node) return false; - } + if (node instanceof AST_Assign) return node.operator == "=" && is_object(node.right); + if (node instanceof AST_Sequence) return is_object(node.tail_node()); + if (node instanceof AST_SymbolRef) return is_object(node.fixed_value()); return node instanceof AST_Array || node instanceof AST_Lambda || node instanceof AST_New @@ -7760,14 +7764,16 @@ merge(Compressor.prototype, { associative = compressor.option("unsafe_math"); // +a - b => a - b // a - +b => a - b - if (self.operator != "+") { - if (self.left instanceof AST_UnaryPrefix && self.left.operator == "+") { - self.left = self.left.expression; - } - if (self.right instanceof AST_UnaryPrefix && self.right.operator == "+") { - self.right = self.right.expression; + [ "left", "right" ].forEach(function(operand) { + var node = self[operand]; + if (node instanceof AST_UnaryPrefix && node.operator == "+") { + var exp = node.expression; + if (exp.is_boolean(compressor) || exp.is_number(compressor) + || self.operator != "+" && exp.is_string(compressor)) { + self[operand] = exp; + } } - } + }); case "&": case "|": case "^": diff --git a/test/compress/asm.js b/test/compress/asm.js index 54cf90f4..65d20b9c 100644 --- a/test/compress/asm.js +++ b/test/compress/asm.js @@ -95,7 +95,7 @@ asm_mixed: { return +sum; } function geometricMean(start, end) { - return start |= 0, end |= 0, +exp(logSum(start, end) / (end - start | 0)); + return start |= 0, end |= 0, +exp(+logSum(start, end) / (end - start | 0)); } var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer); return { geometricMean: geometricMean }; diff --git a/test/compress/numbers.js b/test/compress/numbers.js index 32987a6b..7f355a12 100644 --- a/test/compress/numbers.js +++ b/test/compress/numbers.js @@ -91,7 +91,7 @@ evaluate_1: { expect: { console.log( x + 1 + 2, - 2 * x, + 2 * +x, +x + 1 + 2, 1 + x + 2 + 3, 3 | x, @@ -130,7 +130,7 @@ evaluate_1_unsafe_math: { expect: { console.log( x + 1 + 2, - 2 * x, + 2 * +x, +x + 3, 1 + x + 2 + 3, 3 | x, @@ -148,45 +148,52 @@ evaluate_1_unsafe_math: { evaluate_2: { options = { evaluate: true, + reduce_vars: true, unsafe_math: false, } input: { - var x = "42", y = null; - [ - x + 1 + 2, - x * 1 * 2, - +x + 1 + 2, - 1 + x + 2 + 3, - 1 | x | 2 | 3, - 1 + x-- + 2 + 3, - 1 + (x*y + 2) + 3, - 1 + (2 + x + 3), - 1 + (2 + ~x + 3), - -y + (2 + ~x + 3), - 1 & (2 & x & 3), - 1 + (2 + (x |= 0) + 3), - ].forEach(function(n) { - console.log(typeof n, n); - }); + function f(num) { + var x = "" + num, y = null; + [ + x + 1 + 2, + x * 1 * 2, + +x + 1 + 2, + 1 + x + 2 + 3, + 1 | x | 2 | 3, + 1 + x-- + 2 + 3, + 1 + (x*y + 2) + 3, + 1 + (2 + x + 3), + 1 + (2 + ~x + 3), + -y + (2 + ~x + 3), + 1 & (2 & x & 3), + 1 + (2 + (x |= 0) + 3), + ].forEach(function(n) { + console.log(typeof n, n); + }); + } + f(42); } expect: { - var x = "42", y = null; - [ - x + 1 + 2, - 2 * x, - +x + 1 + 2, - 1 + x + 2 + 3, - 3 | x, - 1 + x-- + 2 + 3, - x*y + 2 + 1 + 3, - 1 + (2 + x + 3), - 2 + ~x + 3 + 1, - 2 + ~x + 3 - y, - 0 & x, - 2 + (x |= 0) + 3 + 1, - ].forEach(function(n) { - console.log(typeof n, n); - }); + function f(num) { + var x = "" + num, y = null; + [ + x + "12", + 2 * x, + +x + 1 + 2, + 1 + x + "23", + 3 | x, + 1 + x-- + 2 + 3, + x*y + 2 + 1 + 3, + 2 + x + 3 + 1, + 2 + ~x + 3 + 1, + 2 + ~x + 3, + 0 & x, + 2 + (x |= 0) + 3 + 1, + ].forEach(function(n) { + console.log(typeof n, n); + }); + } + f(42); } expect_stdout: [ "string 4212", @@ -207,45 +214,52 @@ evaluate_2: { evaluate_2_unsafe_math: { options = { evaluate: true, + reduce_vars: true, unsafe_math: true, } input: { - var x = "42", y = null; - [ - x + 1 + 2, - x * 1 * 2, - +x + 1 + 2, - 1 + x + 2 + 3, - 1 | x | 2 | 3, - 1 + x-- + 2 + 3, - 1 + (x*y + 2) + 3, - 1 + (2 + x + 3), - 1 + (2 + ~x + 3), - -y + (2 + ~x + 3), - 1 & (2 & x & 3), - 1 + (2 + (x |= 0) + 3), - ].forEach(function(n) { - console.log(typeof n, n); - }); + function f(num) { + var x = "" + num, y = null; + [ + x + 1 + 2, + x * 1 * 2, + +x + 1 + 2, + 1 + x + 2 + 3, + 1 | x | 2 | 3, + 1 + x-- + 2 + 3, + 1 + (x*y + 2) + 3, + 1 + (2 + x + 3), + 1 + (2 + ~x + 3), + -y + (2 + ~x + 3), + 1 & (2 & x & 3), + 1 + (2 + (x |= 0) + 3), + ].forEach(function(n) { + console.log(typeof n, n); + }); + } + f(42); } expect: { - var x = "42", y = null; - [ - x + 1 + 2, - 2 * x, - +x + 3, - 1 + x + 2 + 3, - 3 | x, - 6 + x--, - x*y + 6, - 1 + (2 + x + 3), - 6 + ~x, - 5 + ~x - y, - 0 & x, - 6 + (x |= 0), - ].forEach(function(n) { - console.log(typeof n, n); - }); + function f(num) { + var x = "" + num, y = null; + [ + x + "12", + 2 * x, + +x + 3, + 1 + x + "23", + 3 | x, + 6 + x--, + x*y + 6, + 6 + x, + 6 + ~x, + 5 + ~x, + 0 & x, + 6 + (x |= 0), + ].forEach(function(n) { + console.log(typeof n, n); + }); + } + f(42); } expect_stdout: [ "string 4212", @@ -310,45 +324,52 @@ evaluate_4: { evaluate_5: { options = { evaluate: true, + reduce_vars: true, unsafe_math: false, } input: { - var a = "1"; - [ - +a + 2 + 3, - +a + 2 - 3, - +a - 2 + 3, - +a - 2 - 3, - 2 + +a + 3, - 2 + +a - 3, - 2 - +a + 3, - 2 - +a - 3, - 2 + 3 + +a, - 2 + 3 - +a, - 2 - 3 + +a, - 2 - 3 - +a, - ].forEach(function(n) { - console.log(typeof n, n); - }); + function f(num) { + var a = "" + num; + [ + +a + 2 + 3, + +a + 2 - 3, + +a - 2 + 3, + +a - 2 - 3, + 2 + +a + 3, + 2 + +a - 3, + 2 - +a + 3, + 2 - +a - 3, + 2 + 3 + +a, + 2 + 3 - +a, + 2 - 3 + +a, + 2 - 3 - +a, + ].forEach(function(n) { + console.log(typeof n, n); + }); + } + f(1); } expect: { - var a = "1"; - [ - +a + 2 + 3, - +a + 2 - 3, - a - 2 + 3, - a - 2 - 3, - +a + 2 + 3, - +a + 2 - 3, - 2 - a + 3, - 2 - a - 3, - +a + 5, - 5 - a, - +a - 1, - -1 - a, - ].forEach(function(n) { - console.log(typeof n, n); - }); + function f(num) { + var a = "" + num; + [ + +a + 2 + 3, + +a + 2 - 3, + a - 2 + 3, + a - 2 - 3, + +a + 2 + 3, + +a + 2 - 3, + 2 - a + 3, + 2 - a - 3, + +a + 5, + 5 - a, + +a - 1, + -1 - a, + ].forEach(function(n) { + console.log(typeof n, n); + }); + } + f(1); } expect_stdout: [ "number 6", @@ -369,45 +390,52 @@ evaluate_5: { evaluate_5_unsafe_math: { options = { evaluate: true, + reduce_vars: true, unsafe_math: true, } input: { - var a = "1"; - [ - +a + 2 + 3, - +a + 2 - 3, - +a - 2 + 3, - +a - 2 - 3, - 2 + +a + 3, - 2 + +a - 3, - 2 - +a + 3, - 2 - +a - 3, - 2 + 3 + +a, - 2 + 3 - +a, - 2 - 3 + +a, - 2 - 3 - +a, - ].forEach(function(n) { - console.log(typeof n, n); - }); + function f(num) { + var a = "" + num; + [ + +a + 2 + 3, + +a + 2 - 3, + +a - 2 + 3, + +a - 2 - 3, + 2 + +a + 3, + 2 + +a - 3, + 2 - +a + 3, + 2 - +a - 3, + 2 + 3 + +a, + 2 + 3 - +a, + 2 - 3 + +a, + 2 - 3 - +a, + ].forEach(function(n) { + console.log(typeof n, n); + }); + } + f(1); } expect: { - var a = "1"; - [ - +a + 5, - +a + -1, - a - -1, - a - 5, - +a + 5, - +a + -1, - 5 - a, - -1 - a, - +a + 5, - 5 - a, - +a - 1, - -1 - a, - ].forEach(function(n) { - console.log(typeof n, n); - }); + function f(num) { + var a = "" + num; + [ + +a + 5, + +a + -1, + a - -1, + a - 5, + +a + 5, + +a + -1, + 5 - a, + -1 - a, + +a + 5, + 5 - a, + +a - 1, + -1 - a, + ].forEach(function(n) { + console.log(typeof n, n); + }); + } + f(1); } expect_stdout: [ "number 6", @@ -546,37 +574,44 @@ evaluate_6_unsafe_math: { evaluate_7: { options = { evaluate: true, + reduce_vars: true, unsafe_math: false, } input: { - var x = "42", y; - [ - +x + 2 + (3 + !y), - +x + 2 + (3 - !y), - +x + 2 - (3 + !y), - +x + 2 - (3 - !y), - +x - 2 + (3 + !y), - +x - 2 + (3 - !y), - +x - 2 - (3 + !y), - +x - 2 - (3 - !y), - ].forEach(function(n) { - console.log(typeof n, n); - }); + function f(num, y) { + var x = "" + num; + [ + +x + 2 + (3 + !y), + +x + 2 + (3 - !y), + +x + 2 - (3 + !y), + +x + 2 - (3 - !y), + +x - 2 + (3 + !y), + +x - 2 + (3 - !y), + +x - 2 - (3 + !y), + +x - 2 - (3 - !y), + ].forEach(function(n) { + console.log(typeof n, n); + }); + } + f(42); } expect: { - var x = "42", y; - [ - +x + 2 + (3 + !y), - +x + 2 + (3 - !y), - +x + 2 - (3 + !y), - +x + 2 - (3 - !y), - x - 2 + (3 + !y), - x - 2 + (3 - !y), - x - 2 - (3 + !y), - x - 2 - (3 - !y), - ].forEach(function(n) { - console.log(typeof n, n); - }); + function f(num, y) { + var x = "" + num; + [ + +x + 2 + (3 + !y), + +x + 2 + (3 - !y), + +x + 2 - (3 + !y), + +x + 2 - (3 - !y), + x - 2 + (3 + !y), + x - 2 + (3 - !y), + x - 2 - (3 + !y), + x - 2 - (3 - !y), + ].forEach(function(n) { + console.log(typeof n, n); + }); + } + f(42); } expect_stdout: [ "number 48", @@ -593,37 +628,44 @@ evaluate_7: { evaluate_7_unsafe_math: { options = { evaluate: true, + reduce_vars: true, unsafe_math: true, } input: { - var x = "42", y; - [ - +x + 2 + (3 + !y), - +x + 2 + (3 - !y), - +x + 2 - (3 + !y), - +x + 2 - (3 - !y), - +x - 2 + (3 + !y), - +x - 2 + (3 - !y), - +x - 2 - (3 + !y), - +x - 2 - (3 - !y), - ].forEach(function(n) { - console.log(typeof n, n); - }); + function f(num, y) { + var x = "" + num; + [ + +x + 2 + (3 + !y), + +x + 2 + (3 - !y), + +x + 2 - (3 + !y), + +x + 2 - (3 - !y), + +x - 2 + (3 + !y), + +x - 2 + (3 - !y), + +x - 2 - (3 + !y), + +x - 2 - (3 - !y), + ].forEach(function(n) { + console.log(typeof n, n); + }); + } + f(42); } expect: { - var x = "42", y; - [ - +x + 5 + !y, - +x + 5 - !y, - +x + -1 - !y, - +x + -1 + !y, - x - -1 + !y, - x - -1 - !y, - x - 5 - !y, - x - 5 + !y, - ].forEach(function(n) { - console.log(typeof n, n); - }); + function f(num, y) { + var x = "" + num; + [ + +x + 5 + !y, + +x + 5 - !y, + +x + -1 - !y, + +x + -1 + !y, + x - -1 + !y, + x - -1 - !y, + x - 5 - !y, + x - 5 + !y, + ].forEach(function(n) { + console.log(typeof n, n); + }); + } + f(42); } expect_stdout: [ "number 48", @@ -1267,3 +1309,16 @@ issue_3695: { } expect_stdout: "NaN" } + +issue_4137: { + options = { + evaluate: true, + } + input: { + console.log(+(A = []) * (A[0] = 1)); + } + expect: { + console.log(+(A = []) * (A[0] = 1)); + } + expect_stdout: "0" +}