diff --git a/lib/compress.js b/lib/compress.js index 8e446209..f6d6a9fb 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -3451,7 +3451,7 @@ Compressor.prototype.compress = function(node) { var changed = false; var parent = compressor.parent(); var self = compressor.self(); - var jump, merge_jump; + var declare_only, jump, merge_jump; 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); @@ -3460,7 +3460,7 @@ Compressor.prototype.compress = function(node) { var j = next_index(i); var next = statements[j]; - if (in_lambda && !next && stat instanceof AST_Return + if (in_lambda && declare_only && !next && stat instanceof AST_Return && !(self instanceof AST_SwitchBranch) && !(in_try && in_try.bfinally && in_async_generator(in_lambda))) { var body = stat.value; @@ -3493,7 +3493,7 @@ Compressor.prototype.compress = function(node) { body: as_statement_array_with_return(stat.body, ab), }); stat.alternative = make_node(AST_BlockStatement, stat, { - body: as_statement_array(stat.alternative).concat(extract_functions()), + body: as_statement_array(stat.alternative).concat(extract_functions(merge_jump, jump)), }); statements[i] = stat; statements[i] = stat.transform(compressor); @@ -3502,15 +3502,17 @@ Compressor.prototype.compress = function(node) { if (ab && !stat.alternative && next instanceof AST_Jump) { var cond = stat.condition; - cond = best_of_expression(cond, cond.negate(compressor), stat.body instanceof AST_BlockStatement); + var preference = i + 1 == j && stat.body instanceof AST_BlockStatement; + cond = best_of_expression(cond, cond.negate(compressor), preference); if (cond !== stat.condition) { changed = true; stat = stat.clone(); stat.condition = cond; - statements[j] = stat.body; - stat.body = next; - if (next === jump) jump = null; - statements[i] = stat; + var body = stat.body; + stat.body = make_node(AST_BlockStatement, next, { + body: extract_functions(true, null, j + 1), + }); + statements.splice(i, 1, stat, body); statements[i] = stat.transform(compressor); continue; } @@ -3522,7 +3524,7 @@ Compressor.prototype.compress = function(node) { changed = true; stat = stat.clone(); stat.body = make_node(AST_BlockStatement, stat.body, { - body: as_statement_array(stat.body).concat(extract_functions()), + body: as_statement_array(stat.body).concat(extract_functions(merge_jump, jump)), }); stat.alternative = make_node(AST_BlockStatement, stat.alternative, { body: as_statement_array_with_return(stat.alternative, alt), @@ -3551,38 +3553,26 @@ Compressor.prototype.compress = function(node) { if (!stat.alternative && next instanceof AST_Return) { changed = true; stat = stat.clone(); - stat.alternative = next; - if (next === jump) jump = null; - statements.splice(i, 1, stat.transform(compressor)); - statements.splice(j, 1); + stat.alternative = make_node(AST_BlockStatement, next, { + body: extract_functions(true, null, j + 1), + }); + statements[i] = stat; + statements[i] = stat.transform(compressor); continue; } - if (!stat.alternative && !next && in_lambda) { - // if (foo()) return x; [ return ; ] ---> return foo() ? x : undefined; - if (in_bool || value && multiple_if_returns) { - changed = true; - stat = stat.clone(); - stat.alternative = make_node(AST_Return, stat, { value: null }); - statements.splice(i, 1, stat.transform(compressor)); - continue; - } - // if (foo()) return bar() ? x : void 0; ---> return foo() && bar() ? x : void 0; - // if (foo()) return bar() ? void 0 : x; ---> return !foo() || bar() ? void 0 : x; - var or; - if (value instanceof AST_Conditional - && ((or = is_undefined(value.consequent, compressor)) - || is_undefined(value.alternative, compressor))) { - changed = true; - var ret = stat.body.clone(); - ret.value = value.clone(); - ret.value.condition = make_node(AST_Binary, stat, { - operator: or ? "||" : "&&", - left: or ? stat.condition.negate(compressor) : stat.condition, - right: value.condition, - }); - statements.splice(i, 1, ret.transform(compressor)); - continue; - } + // if (foo()) return x; [ return ; ] ---> return foo() ? x : undefined; + // if (foo()) return bar() ? x : void 0; ---> return foo() && bar() ? x : void 0; + // if (foo()) return bar() ? void 0 : x; ---> return !foo() || bar() ? void 0 : x; + if (in_lambda && declare_only && !next && !stat.alternative && (in_bool + || value && multiple_if_returns + || value instanceof AST_Conditional && (is_undefined(value.consequent, compressor) + || is_undefined(value.alternative, compressor)))) { + changed = true; + stat = stat.clone(); + stat.alternative = make_node(AST_Return, stat, { value: null }); + statements[i] = stat; + statements[i] = stat.transform(compressor); + continue; } // if (a) return b; if (c) return d; e; ---> return a ? b : c ? d : void e; // @@ -3593,22 +3583,17 @@ Compressor.prototype.compress = function(node) { if (chain_if_returns && !stat.alternative && (!(prev_stat = statements[prev = prev_index(i)]) && in_iife || prev_stat instanceof AST_If && prev_stat.body instanceof AST_Return) - && next_index(j) == statements.length && next instanceof AST_SimpleStatement) { + && (!next ? !declare_only + : next instanceof AST_SimpleStatement && next_index(j) == statements.length)) { changed = true; var exprs = []; - var args = prev_stat ? trim_defns(prev, exprs) : [ i, 1 ]; stat = stat.clone(); exprs.push(stat.condition); stat.condition = make_sequence(stat, exprs); stat.alternative = make_node(AST_BlockStatement, next, { - body: [ - next, - make_node(AST_Return, next, { value: null }), - ], + body: extract_functions().concat(make_node(AST_Return, next, { value: null })), }); - args.push(stat.transform(compressor)); - statements.splice(j, 1); - [].splice.apply(statements, args); + statements[i] = stat.transform(compressor); i = prev + 1; continue; } @@ -3703,17 +3688,18 @@ Compressor.prototype.compress = function(node) { return true; } - function extract_functions() { + function extract_functions(mode, stop, end) { var defuns = []; var lexical = false; var start = i + 1; - var end; - if (merge_jump) { - end = statements.lastIndexOf(jump); - if (end < 0) end = statements.length; - } else { + if (!mode) { end = statements.length; jump = null; + } else if (stop) { + end = statements.lastIndexOf(stop); + } else { + stop = statements[end]; + if (stop !== jump) jump = null; } var tail = statements.splice(start, end - start).filter(function(stat) { if (stat instanceof AST_LambdaDefinition) { @@ -3723,11 +3709,11 @@ Compressor.prototype.compress = function(node) { if (is_lexical_definition(stat)) lexical = true; return true; }); - if (merge_jump === 3) { - tail.push(make_node(AST_SimpleStatement, jump.value, { - body: make_sequence(jump.value, jump.value.expressions.slice(0, -1)), + if (mode === 3) { + tail.push(make_node(AST_SimpleStatement, stop.value, { + body: make_sequence(stop.value, stop.value.expressions.slice(0, -1)), })); - jump.value = jump.value.tail_node(); + stop.value = stop.value.tail_node(); } [].push.apply(lexical ? tail : statements, defuns); return tail; @@ -3758,38 +3744,29 @@ Compressor.prototype.compress = function(node) { } function next_index(i) { - for (var j = i + 1; j < statements.length; j++) { - if (!is_declaration(statements[j])) break; + declare_only = true; + for (var j = i; ++j < statements.length;) { + var stat = statements[j]; + if (is_declaration(stat)) continue; + if (stat instanceof AST_Var) { + declare_only = false; + continue; + } + break; } return j; } function prev_index(i) { for (var j = i; --j >= 0;) { - if (!(statements[j] instanceof AST_Var)) break; + var stat = statements[j]; + if (stat instanceof AST_Var) continue; + if (is_declaration(stat)) continue; + break; } return j; } - function trim_defns(j, exprs) { - var args = [ j + 1, i - j ]; - var var_defs = []; - while (++j < i) { - var stat = statements[j]; - stat.remove_initializers(compressor, var_defs); - stat.definitions.forEach(function(var_def) { - if (!var_def.value) return; - exprs.push(make_node(AST_Assign, var_def, { - operator: "=", - left: var_def.name.convert_symbol(AST_SymbolRef, process_to_assign), - right: var_def.value, - })); - }); - } - if (var_defs.length > 0) args.push(make_node(AST_Var, stat, { definitions: var_defs })); - return args; - } - function eliminate_returns(stat, in_block) { if (stat instanceof AST_Exit) { var mode = match_return(stat, true); @@ -9618,7 +9595,7 @@ Compressor.prototype.compress = function(node) { } if (var_defs.length > 0) body.push(make_node(AST_Var, self, { definitions: var_defs })); if (body.length > 0) { - body.push(self); + body.push(self.transform(compressor)); return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); } } else if (body_exprs && alt_exprs) { diff --git a/test/compress/if_return.js b/test/compress/if_return.js index 477e4367..7b6c6977 100644 --- a/test/compress/if_return.js +++ b/test/compress/if_return.js @@ -218,8 +218,64 @@ if_return_8: { } } +if_return_9: { + options = { + booleans: true, + conditionals: true, + if_return: true, + sequences: true, + } + input: { + !function() { + if (console.log("foo")) + return 42; + var a = console.log("bar"); + }(); + } + expect: { + !function() { + var a; + return console.log("foo") || (a = console.log("bar"), void 0); + }(); + } + expect_stdout: [ + "foo", + "bar", + ] +} + +if_return_10: { + options = { + booleans: true, + conditionals: true, + if_return: true, + sequences: true, + } + input: { + !function() { + if (console.log("foo")) + return 42; + if (console.log("bar")) + return null; + var a = console.log("baz"); + }(); + } + expect: { + !function() { + var a; + return console.log("foo") || !console.log("bar") && (a = console.log("baz"), void 0); + }(); + } + expect_stdout: [ + "foo", + "bar", + "baz", + ] +} + if_return_cond_void_1: { options = { + conditionals: true, if_return: true, } input: { @@ -242,6 +298,7 @@ if_return_cond_void_1: { if_return_cond_void_2: { options = { + conditionals: true, if_return: true, } input: { @@ -504,14 +561,88 @@ if_var_return_4: { return v(); var a = w(); if (x()) - return y(); + return y(a); z(); } } expect: { function f() { - return u() ? v() : (a = w(), x() ? y() : (z(), void 0)); var a; + return u() ? v() : (a = w(), x() ? y(a) : (z(), void 0)); + } + } +} + +if_var_return_5: { + options = { + conditionals: true, + if_return: true, + } + input: { + function f() { + if (w()) + return x(); + var a = y(); + return z(a); + } + } + expect: { + function f() { + var a; + return w() ? x() : (a = y(), z(a)); + } + } +} + +if_defns_return_1: { + options = { + conditionals: true, + if_return: true, + sequences: true, + side_effects: true, + } + input: { + function f() { + if (u()) + return v(); + function g() {} + if (w()) + return x(g); + var a = y(); + z(a); + } + } + expect: { + function f() { + var a; + return u() ? v() : w() ? x(g) : (a = y(), void z(a)); + function g() {} + } + } +} + +if_defns_return_2: { + options = { + conditionals: true, + if_return: true, + } + input: { + function f(a, b, c) { + if (v()) + return a(); + if (w()) + return b(); + if (x()) { + var d = c(); + return y(d); + } + return z(); + } + } + expect: { + function f(a, b, c) { + var d; + return v() ? a() : w() ? b() : x() ? (d = c(), y(d)) : z(); } } } @@ -1759,7 +1890,8 @@ issue_5584_1: { function f(a) { switch (a) { case 42: - return console.log("PASS") ? FAIL : void 0; + if (console.log("PASS")) + return FAIL; } } f(42); @@ -1899,6 +2031,7 @@ issue_5586: { issue_5587_1: { options = { + conditionals: true, if_return: true, } input: { @@ -1921,6 +2054,7 @@ issue_5587_1: { issue_5587_2: { options = { + conditionals: true, if_return: true, } input: {