From f52b0e7c318ad5742bbe65f28d20334defdd68b4 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sun, 7 Mar 2021 20:19:51 +0000 Subject: [PATCH] fix corner case in `side_effects` (#4752) fixes #4751 --- lib/compress.js | 34 ++--- test/compress/collapse_vars.js | 10 +- test/compress/evaluate.js | 4 +- test/compress/ie8.js | 5 +- test/compress/merge_vars.js | 4 +- test/compress/pure_getters.js | 220 +++++++++++++++++++++++++++++++++ test/compress/reduce_vars.js | 6 +- test/compress/sequences.js | 8 +- test/compress/side_effects.js | 31 ++++- 9 files changed, 277 insertions(+), 45 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 349dad90..3551655a 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -4797,15 +4797,9 @@ merge(Compressor.prototype, { || this.right.has_side_effects(compressor); }); def(AST_Binary, function(compressor) { - var lhs = this.left; - if (lhs.has_side_effects(compressor)) return true; - var rhs = this.right; - var op = this.operator; - if (!rhs.has_side_effects(compressor)) return op == "in" && !is_object(rhs); - if (op == "&&" && rhs instanceof AST_PropAccess && lhs.equivalent_to(rhs.expression)) { - return rhs instanceof AST_Sub && rhs.property.has_side_effects(compressor); - } - return true; + return this.left.has_side_effects(compressor) + || this.right.has_side_effects(compressor) + || this.operator == "in" && !is_object(this.right); }); def(AST_Block, function(compressor) { return any(this.body, compressor); @@ -7220,17 +7214,6 @@ merge(Compressor.prototype, { if (!rhs) return left.drop_side_effect_free(compressor, first_in_statement); if (lazy_op[op] && rhs.has_side_effects(compressor)) { var node = this; - if (op == "&&" - && rhs instanceof AST_PropAccess - && left.equivalent_to(rhs.expression) - && !left.has_side_effects(compressor)) { - var prop = rhs instanceof AST_Sub - && rhs.property.drop_side_effect_free(compressor, first_in_statement); - if (!prop) return left.drop_side_effect_free(compressor, first_in_statement); - node = node.clone(); - node.right = prop; - return node.drop_side_effect_free(compressor, first_in_statement); - } if (rhs !== right) { node = node.clone(); node.right = rhs.drop_side_effect_free(compressor); @@ -7242,13 +7225,12 @@ merge(Compressor.prototype, { right: node.right, }); return first_in_statement ? best_of_statement(node, negated) : best_of_expression(node, negated); - } else { - var lhs = left.drop_side_effect_free(compressor, first_in_statement); - if (!lhs) return rhs; - rhs = rhs.drop_side_effect_free(compressor); - if (!rhs) return lhs; - return make_sequence(this, [ lhs, rhs ]); } + var lhs = left.drop_side_effect_free(compressor, first_in_statement); + if (!lhs) return rhs; + rhs = rhs.drop_side_effect_free(compressor); + if (!rhs) return lhs; + return make_sequence(this, [ lhs, rhs ]); }); def(AST_Call, function(compressor, first_in_statement) { var self = this; diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index dcc87397..9719860c 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -2862,7 +2862,7 @@ lvalues_def: { expect: { var a = 0, b = 1; a = b++, b = +void 0; - a && a++; + a && a[a++]; console.log(a, b); } expect_stdout: true @@ -5096,7 +5096,7 @@ issue_2878: { } b = f2(); a = 1; - b && b[console]; + b && b.b; f2(); })(); console.log(c); @@ -5109,7 +5109,7 @@ issue_2878: { } b = f2(), a = 1, - b && console, + b && b.b, f2(); })(), console.log(c); @@ -6544,7 +6544,7 @@ issue_3520: { (function f() { c = 0; var i = void 0; - var f = f && f[console && i]; + var f = f && f[i]; })(); a += b; c && b++; @@ -6558,7 +6558,7 @@ issue_3520: { for (var i = 2; --i >= 0;) { (function() { c = 0; - var f = f && f[console && void 0]; + var f = f && f[void 0]; })(); a += b; c && b++; diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js index 2c978fff..597c7c87 100644 --- a/test/compress/evaluate.js +++ b/test/compress/evaluate.js @@ -2726,8 +2726,8 @@ issue_3944: { } expect: { void function f() { - while (b = void 0, b = console.log(0 == (b && b.p)), void 0); - var b; + while (a = 0 == (a = void 0), console.log(a), void 0); + var a; f; }(); } diff --git a/test/compress/ie8.js b/test/compress/ie8.js index 7e49672f..a1daa59c 100644 --- a/test/compress/ie8.js +++ b/test/compress/ie8.js @@ -2923,13 +2923,14 @@ issue_4568: { issue_4729: { options = { ie8: true, + pure_getters: true, toplevel: true, unused: true, } input: { try { f; - } catch(e) { + } catch (e) { var a = a && a[function f() {}]; console.log("PASS"); } @@ -2937,7 +2938,7 @@ issue_4729: { expect: { try { f; - } catch(e) { + } catch (e) { (function f() {}); console.log("PASS"); } diff --git a/test/compress/merge_vars.js b/test/compress/merge_vars.js index 667cacf8..c45f8353 100644 --- a/test/compress/merge_vars.js +++ b/test/compress/merge_vars.js @@ -2723,7 +2723,7 @@ issue_4135: { var c = function() { var d = 0; function f() { - d && d[console]; + d && d.p; } f(); this; @@ -2735,7 +2735,7 @@ issue_4135: { 0; a++; if (!a) - c = (a++, c = 0, void (c && console)); + c = (a++, c = 0, void (c && c.p)); var c; console.log(a, -1, c); } diff --git a/test/compress/pure_getters.js b/test/compress/pure_getters.js index 6adc6168..13f9d4fe 100644 --- a/test/compress/pure_getters.js +++ b/test/compress/pure_getters.js @@ -1220,6 +1220,104 @@ drop_arguments: { expect_stdout: "PASS" } +lvalues_def: { + options = { + collapse_vars: true, + pure_getters: true, + side_effects: true, + unused: true, + } + input: { + var a = 0, b = 1; + var a = b++, b = +function() {}(); + a && a[a++]; + console.log(a, b); + } + expect: { + var a = 0, b = 1; + a = b++, b = +void 0; + a && a++; + console.log(a, b); + } + expect_stdout: true +} + +side_effects_assign: { + options = { + evaluate: true, + pure_getters: true, + reduce_funcs: true, + reduce_vars: true, + sequences: true, + side_effects: true, + toplevel: true, + } + input: { + var a = typeof void (a && a.in == 1, 0); + console.log(a); + } + expect: { + var a = "undefined"; + console.log(a); + } + expect_stdout: "undefined" +} + +issue_2062: { + options = { + booleans: true, + collapse_vars: true, + conditionals: true, + pure_getters: true, + side_effects: true, + } + input: { + var a = 1; + if ([ a || a++ + a--, a++ + a--, a && a.var ]); + console.log(a); + } + expect: { + var a = 1; + a || (a++, a--), a++, a--; + console.log(a); + } + expect_stdout: "1" +} + +issue_2878: { + options = { + collapse_vars: true, + pure_getters: true, + sequences: true, + } + input: { + var c = 0; + (function(a, b) { + function f2() { + if (a) c++; + } + b = f2(); + a = 1; + b && b.b; + f2(); + })(); + console.log(c); + } + expect: { + var c = 0; + (function(a, b) { + function f2() { + if (a) c++; + } + b = f2(), + a = 1, + f2(); + })(), + console.log(c); + } + expect_stdout: "1" +} + issue_3427: { options = { assignments: true, @@ -1242,6 +1340,74 @@ issue_3427: { expect_stdout: true } +issue_3490_1: { + options = { + conditionals: true, + dead_code: true, + inline: true, + pure_getters: true, + sequences: true, + side_effects: true, + toplevel: true, + } + input: { + var b = 42, c = "FAIL"; + if ({ + 3: function() { + var a; + return (a && a.p) < this; + }(), + }) c = "PASS"; + if (b) while ("" == typeof d); + console.log(c, b); + } + expect: { + var b = 42, c = "FAIL"; + if (function() { + var a; + }(), c = "PASS", b) while ("" == typeof d); + console.log(c, b); + } + expect_stdout: "PASS 42" +} + +issue_4135: { + options = { + evaluate: true, + inline: true, + merge_vars: true, + pure_getters: true, + reduce_vars: true, + side_effects: true, + toplevel: true, + unused: true, + } + input: { + var a = 0, b = 0; + --b; + a++; + if (!a) + var c = function() { + var d = 0; + function f() { + d && d.p; + } + f(); + this; + }(a++); + console.log(a, b, c); + } + expect: { + var a = 0; + 0; + a++; + if (!a) + var c = void a++; + console.log(a, -1, c); + } + expect_stdout: "1 -1 undefined" +} + issue_4440: { options = { pure_getters: "strict", @@ -1270,3 +1436,57 @@ issue_4440: { } expect_stdout: "PASS" } + +issue_4730_1: { + options = { + pure_getters: true, + side_effects: true, + } + input: { + var a; + console.log("PASS") + (a && a[a.p]); + } + expect: { + var a; + console.log("PASS"); + } + expect_stdout: "PASS" +} + +issue_4730_2: { + options = { + pure_getters: true, + side_effects: true, + } + input: { + var a; + !console.log("PASS") || a && a[a.p]; + } + expect: { + var a; + console.log("PASS"); + } + expect_stdout: "PASS" +} + +issue_4751: { + options = { + pure_getters: true, + side_effects: true, + } + input: { + var o = { + get p() { + console.log("PASS"); + }, + }; + o && o.p; + } + expect: { + var o = { + get p() { + console.log("PASS"); + }, + }; + } +} diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index 110f046a..5ae0884b 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -2554,7 +2554,7 @@ side_effects_assign: { console.log(a); } expect: { - var a = "undefined"; + var a = typeof void (a && a.in); console.log(a); } expect_stdout: "undefined" @@ -2595,7 +2595,9 @@ pure_getters_2: { var a; var a = a && a.b; } - expect: {} + expect: { + var a = a && a.b; + } } pure_getters_3: { diff --git a/test/compress/sequences.js b/test/compress/sequences.js index 79b308b5..90de1974 100644 --- a/test/compress/sequences.js +++ b/test/compress/sequences.js @@ -754,12 +754,12 @@ issue_2062: { } input: { var a = 1; - if ([ a || a++ + a--, a++ + a--, a && a[console] ]); + if ([ a || a++ + a--, a++ + a--, a && a.var ]); console.log(a); } expect: { var a = 1; - a || (a++, a--), a++, --a && console; + a || (a++, a--), a++, --a && a.var; console.log(a); } expect_stdout: "1" @@ -1097,7 +1097,7 @@ issue_3490_1: { if ({ 3: function() { var a; - return (a && a[console]) < this; + return (a && a.p) < this; }(), }) c = "PASS"; if (b) while ("" == typeof d); @@ -1107,7 +1107,7 @@ issue_3490_1: { var b = 42, c = "FAIL"; if (function() { var a; - a && console; + a && a.p; }(), c = "PASS", b) while ("" == typeof d); console.log(c, b); } diff --git a/test/compress/side_effects.js b/test/compress/side_effects.js index 03298274..0e6a7442 100644 --- a/test/compress/side_effects.js +++ b/test/compress/side_effects.js @@ -561,6 +561,7 @@ drop_side_effect_free_call: { issue_4730_1: { options = { + pure_getters: "strict", side_effects: true, } input: { @@ -569,13 +570,15 @@ issue_4730_1: { } expect: { var a; - console.log("PASS"); + console.log("PASS"), + a && a[a.p]; } expect_stdout: "PASS" } issue_4730_2: { options = { + pure_getters: "strict", side_effects: true, } input: { @@ -584,7 +587,31 @@ issue_4730_2: { } expect: { var a; - console.log("PASS"); + !console.log("PASS") || a && a[a.p]; + } + expect_stdout: "PASS" +} + +issue_4751: { + options = { + pure_getters: "strict", + side_effects: true, + } + input: { + var o = { + get p() { + console.log("PASS"); + }, + }; + o && o.p; + } + expect: { + var o = { + get p() { + console.log("PASS"); + }, + }; + o && o.p; } expect_stdout: "PASS" } -- 2.34.1