From f9806b43c33400b73e19d5bd216a2b5653dfcfbd Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sun, 10 May 2020 11:38:32 +0100 Subject: [PATCH] enhance `evaluate` & `reduce_vars` (#3870) --- lib/compress.js | 24 ++++++++++++++++-------- test/compress/join_vars.js | 22 +++++++++++----------- test/compress/reduce_vars.js | 21 +++++++++++++++++++++ 3 files changed, 48 insertions(+), 19 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 904295ee..4f5e9253 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -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 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); } } diff --git a/test/compress/join_vars.js b/test/compress/join_vars.js index 3e4334cf..67d7fd05 100644 --- a/test/compress/join_vars.js +++ b/test/compress/join_vars.js @@ -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: { diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index ec75e911..ee1e4711 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -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", + ] +} -- 2.34.1