From c8d98f4787f402c283cb1b3a31d7ce325d209281 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Wed, 6 Jul 2022 21:28:00 +0100 Subject: [PATCH] enhance `if_return` (#5541) --- lib/compress.js | 62 +++++++++++++++++----------- test/compress/if_return.js | 83 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 118 insertions(+), 27 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index b1554863..395c3618 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -3411,20 +3411,20 @@ Compressor.prototype.compress = function(node) { if (in_lambda && !next && stat instanceof AST_Return && !(in_try && in_try.bfinally && in_async_generator(in_lambda))) { - if (!stat.value) { + var body = stat.value; + if (!body) { changed = true; statements.splice(i, 1); continue; } - var tail = stat.value.tail_node(); - if (tail instanceof AST_UnaryPrefix && tail.operator == "void") { + var tail = body.tail_node(); + if (is_undefined(tail)) { changed = true; - var body; - if (tail === stat.value) { - body = tail.expression; - } else { - body = stat.value.clone(); - body.expressions[body.length - 1] = tail.expression; + if (body instanceof AST_UnaryPrefix) { + body = body.expression; + } else if (tail instanceof AST_UnaryPrefix) { + body = body.clone(); + body.expressions[body.expressions.length - 1] = tail.expression; } statements[i] = make_node(AST_SimpleStatement, stat, { body: body }); continue; @@ -3573,14 +3573,18 @@ Compressor.prototype.compress = function(node) { }); } - function match_return(ab) { + function match_return(ab, exact) { if (!exit) return false; if (exit.TYPE != ab.TYPE) return false; var value = ab.value; + if (!value) return false; var equals = exit.equivalent_to(ab); if (!equals && value instanceof AST_Sequence) { value = value.tail_node(); - equals = exit.value ? exit.value.equivalent_to(value) : is_undefined(value); + if (exit.value && exit.value.equivalent_to(value)) equals = 2; + } + if (!equals && !exact && exit.value instanceof AST_Sequence) { + if (exit.value.tail_node().equivalent_to(value)) equals = 3; } if (!equals) return false; if (exit_defs == null) { @@ -3591,19 +3595,22 @@ Compressor.prototype.compress = function(node) { if (!exit_defs.size()) exit_defs = false; } var abort = false; - if (value && exit_defs) value.walk(new TreeWalker(function(node) { + if (exit_defs) value.walk(new TreeWalker(function(node) { if (abort) return true; if (node instanceof AST_SymbolRef && exit_defs.get(node.name) !== node.definition()) { return abort = true; } })); - return !abort; + return !abort && equals; } function can_drop_abort(ab) { if (ab instanceof AST_Exit) { - if (match_return(ab)) return merge_exit = true; - return in_lambda && ab instanceof AST_Return && is_undefined(ab.value); + if (merge_exit = match_return(ab)) return true; + if (!in_lambda) return false; + if (!(ab instanceof AST_Return)) return false; + if (is_undefined(ab.value)) return true; + return ab.value instanceof AST_Sequence && is_undefined(ab.value.tail_node()); } if (!(ab instanceof AST_LoopControl)) return false; var lct = compressor.loopcontrol_target(ab); @@ -3650,17 +3657,23 @@ Compressor.prototype.compress = function(node) { if (is_lexical_definition(stat)) lexical = true; return true; }); + if (merge_exit === 3) { + tail.push(make_node(AST_SimpleStatement, exit.value, { + body: make_sequence(exit.value, exit.value.expressions.slice(0, -1)), + })); + exit.value = exit.value.tail_node(); + } [].push.apply(lexical ? tail : statements, defuns); return tail; } - function trim_return(value) { - if (!value) return; - if (exit.value) { - if (exit.value.TYPE == value.TYPE) return; - if (value instanceof AST_Sequence) return make_sequence(value, value.expressions.slice(0, -1)); + function trim_return(value, mode) { + if (value) switch (mode) { + case 3: + if (!(value instanceof AST_Sequence)) break; + case 2: + return make_sequence(value, value.expressions.slice(0, -1)); } - return value; } function as_statement_array_with_return(node, ab) { @@ -3671,7 +3684,7 @@ Compressor.prototype.compress = function(node) { } block.pop(); var value = ab.value; - if (merge_exit) value = trim_return(value); + if (merge_exit) value = trim_return(value, merge_exit); if (value) block.push(make_node(AST_SimpleStatement, value, { body: value })); return body; } @@ -3711,8 +3724,9 @@ Compressor.prototype.compress = function(node) { function eliminate_returns(stat, in_block) { if (stat instanceof AST_Exit) { - if (match_return(stat)) { - var value = trim_return(stat.value); + var mode = match_return(stat, true); + if (mode) { + var value = trim_return(stat.value, mode); if (value) return make_node(AST_SimpleStatement, value, { body: value }); return in_block ? null : make_node(AST_EmptyStatement, stat); } diff --git a/test/compress/if_return.js b/test/compress/if_return.js index e4e32f1c..c56c61d4 100644 --- a/test/compress/if_return.js +++ b/test/compress/if_return.js @@ -1283,7 +1283,7 @@ sequence_void_1: { expect: { function f() { if (console) - return console, void console.log("PASS"); + console, void console.log("PASS"); } f(); } @@ -1309,10 +1309,87 @@ sequence_void_2: { function f() { if (console) console, void console.log("PASS"); - return; - FAIL; + else { + return; + FAIL; + } } f(); } expect_stdout: "PASS" } + +tail_match: { + options = { + if_return: true, + } + input: { + function f(a) { + if (a) { + console.log("foo"); + return console.log("bar"); + } + while (console.log("baz")); + return console.log("moo"), console.log("bar"); + } + f(); + f(42); + } + expect: { + function f(a) { + if (a) + console.log("foo"); + else { + while (console.log("baz")); + console.log("moo"); + } + return console.log("bar"); + } + f(); + f(42); + } + expect_stdout: [ + "baz", + "moo", + "bar", + "foo", + "bar", + ] +} + +void_match: { + options = { + if_return: true, + } + input: { + function f(a) { + if (a) { + console.log("foo"); + return; + } + while (console.log("bar")); + return console.log("baz"), void console.log("moo"); + } + f(); + f(42); + } + expect: { + function f(a) { + if (a) + console.log("foo"); + else { + while (console.log("bar")); + console.log("baz"), + console.log("moo"); + } + } + f(); + f(42); + } + expect_stdout: [ + "bar", + "baz", + "moo", + "foo", + ] +}