enhance if_return (#5594)
This commit is contained in:
parent
672cdfa57a
commit
64e3ceec3b
139
lib/compress.js
139
lib/compress.js
|
|
@ -3451,7 +3451,7 @@ Compressor.prototype.compress = function(node) {
|
||||||
var changed = false;
|
var changed = false;
|
||||||
var parent = compressor.parent();
|
var parent = compressor.parent();
|
||||||
var self = compressor.self();
|
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 in_iife = in_lambda && parent && parent.TYPE == "Call" && parent.expression === self;
|
||||||
var chain_if_returns = in_lambda && compressor.option("conditionals") && compressor.option("sequences");
|
var chain_if_returns = in_lambda && compressor.option("conditionals") && compressor.option("sequences");
|
||||||
var multiple_if_returns = has_multiple_if_returns(statements);
|
var multiple_if_returns = has_multiple_if_returns(statements);
|
||||||
|
|
@ -3460,7 +3460,7 @@ Compressor.prototype.compress = function(node) {
|
||||||
var j = next_index(i);
|
var j = next_index(i);
|
||||||
var next = statements[j];
|
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)
|
&& !(self instanceof AST_SwitchBranch)
|
||||||
&& !(in_try && in_try.bfinally && in_async_generator(in_lambda))) {
|
&& !(in_try && in_try.bfinally && in_async_generator(in_lambda))) {
|
||||||
var body = stat.value;
|
var body = stat.value;
|
||||||
|
|
@ -3493,7 +3493,7 @@ Compressor.prototype.compress = function(node) {
|
||||||
body: as_statement_array_with_return(stat.body, ab),
|
body: as_statement_array_with_return(stat.body, ab),
|
||||||
});
|
});
|
||||||
stat.alternative = make_node(AST_BlockStatement, stat, {
|
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;
|
||||||
statements[i] = stat.transform(compressor);
|
statements[i] = stat.transform(compressor);
|
||||||
|
|
@ -3502,15 +3502,17 @@ Compressor.prototype.compress = function(node) {
|
||||||
|
|
||||||
if (ab && !stat.alternative && next instanceof AST_Jump) {
|
if (ab && !stat.alternative && next instanceof AST_Jump) {
|
||||||
var cond = stat.condition;
|
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) {
|
if (cond !== stat.condition) {
|
||||||
changed = true;
|
changed = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.condition = cond;
|
stat.condition = cond;
|
||||||
statements[j] = stat.body;
|
var body = stat.body;
|
||||||
stat.body = next;
|
stat.body = make_node(AST_BlockStatement, next, {
|
||||||
if (next === jump) jump = null;
|
body: extract_functions(true, null, j + 1),
|
||||||
statements[i] = stat;
|
});
|
||||||
|
statements.splice(i, 1, stat, body);
|
||||||
statements[i] = stat.transform(compressor);
|
statements[i] = stat.transform(compressor);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -3522,7 +3524,7 @@ Compressor.prototype.compress = function(node) {
|
||||||
changed = true;
|
changed = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.body = make_node(AST_BlockStatement, stat.body, {
|
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, {
|
stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
|
||||||
body: as_statement_array_with_return(stat.alternative, alt),
|
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) {
|
if (!stat.alternative && next instanceof AST_Return) {
|
||||||
changed = true;
|
changed = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.alternative = next;
|
stat.alternative = make_node(AST_BlockStatement, next, {
|
||||||
if (next === jump) jump = null;
|
body: extract_functions(true, null, j + 1),
|
||||||
statements.splice(i, 1, stat.transform(compressor));
|
});
|
||||||
statements.splice(j, 1);
|
statements[i] = stat;
|
||||||
|
statements[i] = stat.transform(compressor);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!stat.alternative && !next && in_lambda) {
|
// if (foo()) return x; [ return ; ] ---> return foo() ? x : undefined;
|
||||||
// if (foo()) return x; [ return ; ] ---> return foo() ? x : undefined;
|
// if (foo()) return bar() ? x : void 0; ---> return foo() && bar() ? x : void 0;
|
||||||
if (in_bool || value && multiple_if_returns) {
|
// if (foo()) return bar() ? void 0 : x; ---> return !foo() || bar() ? void 0 : x;
|
||||||
changed = true;
|
if (in_lambda && declare_only && !next && !stat.alternative && (in_bool
|
||||||
stat = stat.clone();
|
|| value && multiple_if_returns
|
||||||
stat.alternative = make_node(AST_Return, stat, { value: null });
|
|| value instanceof AST_Conditional && (is_undefined(value.consequent, compressor)
|
||||||
statements.splice(i, 1, stat.transform(compressor));
|
|| is_undefined(value.alternative, compressor)))) {
|
||||||
continue;
|
changed = true;
|
||||||
}
|
stat = stat.clone();
|
||||||
// if (foo()) return bar() ? x : void 0; ---> return foo() && bar() ? x : void 0;
|
stat.alternative = make_node(AST_Return, stat, { value: null });
|
||||||
// if (foo()) return bar() ? void 0 : x; ---> return !foo() || bar() ? void 0 : x;
|
statements[i] = stat;
|
||||||
var or;
|
statements[i] = stat.transform(compressor);
|
||||||
if (value instanceof AST_Conditional
|
continue;
|
||||||
&& ((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 (a) return b; if (c) return d; e; ---> return a ? b : c ? d : void e;
|
// 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
|
if (chain_if_returns && !stat.alternative
|
||||||
&& (!(prev_stat = statements[prev = prev_index(i)]) && in_iife
|
&& (!(prev_stat = statements[prev = prev_index(i)]) && in_iife
|
||||||
|| prev_stat instanceof AST_If && prev_stat.body instanceof AST_Return)
|
|| 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;
|
changed = true;
|
||||||
var exprs = [];
|
var exprs = [];
|
||||||
var args = prev_stat ? trim_defns(prev, exprs) : [ i, 1 ];
|
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
exprs.push(stat.condition);
|
exprs.push(stat.condition);
|
||||||
stat.condition = make_sequence(stat, exprs);
|
stat.condition = make_sequence(stat, exprs);
|
||||||
stat.alternative = make_node(AST_BlockStatement, next, {
|
stat.alternative = make_node(AST_BlockStatement, next, {
|
||||||
body: [
|
body: extract_functions().concat(make_node(AST_Return, next, { value: null })),
|
||||||
next,
|
|
||||||
make_node(AST_Return, next, { value: null }),
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
args.push(stat.transform(compressor));
|
statements[i] = stat.transform(compressor);
|
||||||
statements.splice(j, 1);
|
|
||||||
[].splice.apply(statements, args);
|
|
||||||
i = prev + 1;
|
i = prev + 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -3703,17 +3688,18 @@ Compressor.prototype.compress = function(node) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function extract_functions() {
|
function extract_functions(mode, stop, end) {
|
||||||
var defuns = [];
|
var defuns = [];
|
||||||
var lexical = false;
|
var lexical = false;
|
||||||
var start = i + 1;
|
var start = i + 1;
|
||||||
var end;
|
if (!mode) {
|
||||||
if (merge_jump) {
|
|
||||||
end = statements.lastIndexOf(jump);
|
|
||||||
if (end < 0) end = statements.length;
|
|
||||||
} else {
|
|
||||||
end = statements.length;
|
end = statements.length;
|
||||||
jump = null;
|
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) {
|
var tail = statements.splice(start, end - start).filter(function(stat) {
|
||||||
if (stat instanceof AST_LambdaDefinition) {
|
if (stat instanceof AST_LambdaDefinition) {
|
||||||
|
|
@ -3723,11 +3709,11 @@ Compressor.prototype.compress = function(node) {
|
||||||
if (is_lexical_definition(stat)) lexical = true;
|
if (is_lexical_definition(stat)) lexical = true;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
if (merge_jump === 3) {
|
if (mode === 3) {
|
||||||
tail.push(make_node(AST_SimpleStatement, jump.value, {
|
tail.push(make_node(AST_SimpleStatement, stop.value, {
|
||||||
body: make_sequence(jump.value, jump.value.expressions.slice(0, -1)),
|
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);
|
[].push.apply(lexical ? tail : statements, defuns);
|
||||||
return tail;
|
return tail;
|
||||||
|
|
@ -3758,38 +3744,29 @@ Compressor.prototype.compress = function(node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function next_index(i) {
|
function next_index(i) {
|
||||||
for (var j = i + 1; j < statements.length; j++) {
|
declare_only = true;
|
||||||
if (!is_declaration(statements[j])) break;
|
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;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prev_index(i) {
|
function prev_index(i) {
|
||||||
for (var j = i; --j >= 0;) {
|
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;
|
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) {
|
function eliminate_returns(stat, in_block) {
|
||||||
if (stat instanceof AST_Exit) {
|
if (stat instanceof AST_Exit) {
|
||||||
var mode = match_return(stat, true);
|
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 (var_defs.length > 0) body.push(make_node(AST_Var, self, { definitions: var_defs }));
|
||||||
if (body.length > 0) {
|
if (body.length > 0) {
|
||||||
body.push(self);
|
body.push(self.transform(compressor));
|
||||||
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
||||||
}
|
}
|
||||||
} else if (body_exprs && alt_exprs) {
|
} else if (body_exprs && alt_exprs) {
|
||||||
|
|
|
||||||
|
|
@ -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: {
|
if_return_cond_void_1: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
if_return: true,
|
if_return: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
|
@ -242,6 +298,7 @@ if_return_cond_void_1: {
|
||||||
|
|
||||||
if_return_cond_void_2: {
|
if_return_cond_void_2: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
if_return: true,
|
if_return: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
|
@ -504,14 +561,88 @@ if_var_return_4: {
|
||||||
return v();
|
return v();
|
||||||
var a = w();
|
var a = w();
|
||||||
if (x())
|
if (x())
|
||||||
return y();
|
return y(a);
|
||||||
z();
|
z();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f() {
|
function f() {
|
||||||
return u() ? v() : (a = w(), x() ? y() : (z(), void 0));
|
|
||||||
var a;
|
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) {
|
function f(a) {
|
||||||
switch (a) {
|
switch (a) {
|
||||||
case 42:
|
case 42:
|
||||||
return console.log("PASS") ? FAIL : void 0;
|
if (console.log("PASS"))
|
||||||
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f(42);
|
f(42);
|
||||||
|
|
@ -1899,6 +2031,7 @@ issue_5586: {
|
||||||
|
|
||||||
issue_5587_1: {
|
issue_5587_1: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
if_return: true,
|
if_return: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
|
@ -1921,6 +2054,7 @@ issue_5587_1: {
|
||||||
|
|
||||||
issue_5587_2: {
|
issue_5587_2: {
|
||||||
options = {
|
options = {
|
||||||
|
conditionals: true,
|
||||||
if_return: true,
|
if_return: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user