diff --git a/lib/compress.js b/lib/compress.js index 5a05ac8b..f1557848 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -3391,6 +3391,7 @@ Compressor.prototype.compress = function(node) { var changed = false; var parent = compressor.parent(); var self = compressor.self(); + var exit, exit_defs, merge_exit; var in_iife = in_lambda && parent && parent.TYPE == "Call" && parent.expression === self; var chain_if_returns = in_lambda && compressor.option("conditionals") && compressor.option("sequences"); var multiple_if_returns = has_multiple_if_returns(statements); @@ -3446,6 +3447,7 @@ Compressor.prototype.compress = function(node) { stat.condition = cond; statements[j] = stat.body; stat.body = next; + if (next === exit) exit = null; statements[i] = stat; statements[i] = stat.transform(compressor); continue; @@ -3489,6 +3491,7 @@ Compressor.prototype.compress = function(node) { changed = true; stat = stat.clone(); stat.alternative = next; + if (next === exit) exit = null; statements.splice(i, 1, stat.transform(compressor)); statements.splice(j, 1); continue; @@ -3532,6 +3535,11 @@ Compressor.prototype.compress = function(node) { continue; } } + + if (stat instanceof AST_Exit) { + exit = stat; + exit_defs = null; + } } return changed; @@ -3553,7 +3561,25 @@ Compressor.prototype.compress = function(node) { } function can_drop_abort(ab) { - if (ab instanceof AST_Return) return in_lambda && is_undefined(ab.value); + if (ab instanceof AST_Exit) { + if (exit && exit.equivalent_to(ab)) { + if (!exit_defs) { + exit_defs = new Dictionary(); + exit.walk(new TreeWalker(function(node) { + if (node instanceof AST_SymbolRef) exit_defs.set(node.name, node.definition()); + })); + } + var abort = false; + ab.walk(new TreeWalker(function(node) { + if (abort) return true; + if (node instanceof AST_SymbolRef && exit_defs.get(node.name) !== node.definition()) { + return abort = true; + } + })); + if (!abort) return merge_exit = true; + } + return in_lambda && ab instanceof AST_Return && is_undefined(ab.value); + } if (!(ab instanceof AST_LoopControl)) return false; var lct = compressor.loopcontrol_target(ab); if (ab instanceof AST_Continue) return match_target(loop_body(lct)); @@ -3562,6 +3588,7 @@ Compressor.prototype.compress = function(node) { } function can_merge_flow(ab) { + merge_exit = false; if (!can_drop_abort(ab)) return false; for (var j = statements.length; --j > i;) { var stat = statements[j]; @@ -3581,7 +3608,16 @@ Compressor.prototype.compress = function(node) { function extract_functions() { var defuns = []; var lexical = false; - var tail = statements.splice(i + 1).filter(function(stat) { + var start = i + 1; + var end; + if (merge_exit) { + end = statements.lastIndexOf(exit); + if (end < 0) end = statements.length; + } else { + end = statements.length; + exit = null; + } + var tail = statements.splice(start, end - start).filter(function(stat) { if (stat instanceof AST_LambdaDefinition) { defuns.push(stat); return false; @@ -3600,7 +3636,7 @@ Compressor.prototype.compress = function(node) { block = last.body; } block.pop(); - if (ab.value) block.push(make_node(AST_SimpleStatement, ab.value, { body: ab.value })); + if (!merge_exit && ab.value) block.push(make_node(AST_SimpleStatement, ab.value, { body: ab.value })); return body; } diff --git a/test/compress/if_return.js b/test/compress/if_return.js index 155d912e..2ea62f76 100644 --- a/test/compress/if_return.js +++ b/test/compress/if_return.js @@ -850,3 +850,116 @@ issue_866_2: { })(); } } + +identical_returns_1: { + options = { + conditionals: true, + if_return: true, + } + input: { + console.log(function() { + if (console.log("foo")) + return 42; + else + while (console.log("bar")); + return 42; + }()); + } + expect: { + console.log(function() { + if (!console.log("foo")) + while (console.log("bar")); + return 42; + }()); + } + expect_stdout: [ + "foo", + "bar", + "42", + ] +} + +identical_returns_2: { + options = { + conditionals: true, + if_return: true, + } + input: { + console.log(function() { + if (console.log("foo")) + while (console.log("FAIL")); + else + return "bar"; + return "bar"; + }()); + } + expect: { + console.log(function() { + if (console.log("foo")) + while (console.log("FAIL")); + return "bar"; + }()); + } + expect_stdout: [ + "foo", + "bar", + ] +} + +identical_returns_3: { + options = { + if_return: true, + } + input: { + function f(a) { + if (a) + return 42; + if (a) + return; + return 42; + } + if (f(console)) + console.log("PASS"); + } + expect: { + function f(a) { + if (a) + return 42; + if (a) + ; + else + return 42; + } + if (f(console)) + console.log("PASS"); + } + expect_stdout: "PASS" +} + +issue_4374: { + options = { + booleans: true, + conditionals: true, + if_return: true, + reduce_vars: true, + unused: true, + } + input: { + (function() { + console.log(f(console)); + function f(a) { + if (console) return 0; + if (a) return 1; + return 0; + } + })(); + } + expect: { + (function() { + console.log(function(a) { + return !console && a ? 1 : 0; + }(console)); + })(); + } + expect_stdout: "0" +} diff --git a/test/compress/let.js b/test/compress/let.js index 43306b9c..83e69e85 100644 --- a/test/compress/let.js +++ b/test/compress/let.js @@ -892,6 +892,40 @@ if_return_2: { node_version: ">=4" } +if_return_3: { + options = { + if_return: true, + } + input: { + "use strict"; + var a = "PASS"; + function f(b) { + if (console) { + let b = a; + return b; + } else + while (console.log("FAIL 1")); + return b; + } + console.log(f("FAIL 2")); + } + expect: { + "use strict"; + var a = "PASS"; + function f(b) { + if (console) { + let b = a; + return b; + } else + while (console.log("FAIL 1")); + return b; + } + console.log(f("FAIL 2")); + } + expect_stdout: "PASS" + node_version: ">=4" +} + do_if_continue_1: { options = { if_return: true, diff --git a/test/compress/transform.js b/test/compress/transform.js index 1bee8da9..a06d08a9 100644 --- a/test/compress/transform.js +++ b/test/compress/transform.js @@ -127,7 +127,7 @@ if_return: { if (w) { if (y) return; } else if (z) return; - return x == y || (x && w(), y && z()), !0; + return x != y && (x && w(), y && z()), !0; } } }