enhance if_return (#5582)
This commit is contained in:
@@ -1965,6 +1965,12 @@ Compressor.prototype.compress = function(node) {
|
|||||||
block = compressor.parent(level++);
|
block = compressor.parent(level++);
|
||||||
} else if (block instanceof AST_LabeledStatement) {
|
} else if (block instanceof AST_LabeledStatement) {
|
||||||
block = block.body;
|
block = block.body;
|
||||||
|
} else if (block instanceof AST_SwitchBranch) {
|
||||||
|
var branches = compressor.parent(level);
|
||||||
|
if (branches.body[branches.body.length - 1] === block || has_break(block.body)) {
|
||||||
|
level++;
|
||||||
|
block = branches;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
stat = block;
|
stat = block;
|
||||||
@@ -1975,8 +1981,16 @@ Compressor.prototype.compress = function(node) {
|
|||||||
&& (block instanceof AST_BlockStatement
|
&& (block instanceof AST_BlockStatement
|
||||||
|| block instanceof AST_Catch
|
|| block instanceof AST_Catch
|
||||||
|| block instanceof AST_Scope
|
|| block instanceof AST_Scope
|
||||||
|
|| block instanceof AST_SwitchBranch
|
||||||
|| block instanceof AST_Try)
|
|| block instanceof AST_Try)
|
||||||
&& is_last_statement(block.body, stat));
|
&& is_last_statement(block.body, stat));
|
||||||
|
|
||||||
|
function has_break(stats) {
|
||||||
|
for (var i = stats.length; --i >= 0;) {
|
||||||
|
if (stats[i] instanceof AST_Break) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function find_loop_scope_try() {
|
function find_loop_scope_try() {
|
||||||
@@ -3437,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 exit, merge_exit;
|
var 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);
|
||||||
@@ -3447,6 +3461,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var next = statements[j];
|
var next = statements[j];
|
||||||
|
|
||||||
if (in_lambda && !next && stat instanceof AST_Return
|
if (in_lambda && !next && stat instanceof AST_Return
|
||||||
|
&& !(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;
|
||||||
if (!body) {
|
if (!body) {
|
||||||
@@ -3494,7 +3509,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
stat.condition = cond;
|
stat.condition = cond;
|
||||||
statements[j] = stat.body;
|
statements[j] = stat.body;
|
||||||
stat.body = next;
|
stat.body = next;
|
||||||
if (next === exit) exit = null;
|
if (next === jump) jump = null;
|
||||||
statements[i] = stat;
|
statements[i] = stat;
|
||||||
statements[i] = stat.transform(compressor);
|
statements[i] = stat.transform(compressor);
|
||||||
continue;
|
continue;
|
||||||
@@ -3538,7 +3553,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
changed = true;
|
changed = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.alternative = next;
|
stat.alternative = next;
|
||||||
if (next === exit) exit = null;
|
if (next === jump) jump = null;
|
||||||
statements.splice(i, 1, stat.transform(compressor));
|
statements.splice(i, 1, stat.transform(compressor));
|
||||||
statements.splice(j, 1);
|
statements.splice(j, 1);
|
||||||
continue;
|
continue;
|
||||||
@@ -3583,12 +3598,12 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stat instanceof AST_Exit) {
|
if (stat instanceof AST_Break || stat instanceof AST_Exit) {
|
||||||
exit = stat;
|
jump = stat;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exit && exit === next) eliminate_returns(stat);
|
if (jump && jump === next) eliminate_returns(stat);
|
||||||
}
|
}
|
||||||
return changed;
|
return changed;
|
||||||
|
|
||||||
@@ -3610,38 +3625,41 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function match_return(ab, exact) {
|
function match_return(ab, exact) {
|
||||||
if (!exit) return false;
|
if (!jump) return false;
|
||||||
if (exit.TYPE != ab.TYPE) return false;
|
if (jump.TYPE != ab.TYPE) return false;
|
||||||
var value = ab.value;
|
var value = ab.value;
|
||||||
if (!value) return false;
|
if (!value) return false;
|
||||||
var equals = exit.equals(ab);
|
var equals = jump.equals(ab);
|
||||||
if (!equals && value instanceof AST_Sequence) {
|
if (!equals && value instanceof AST_Sequence) {
|
||||||
value = value.tail_node();
|
value = value.tail_node();
|
||||||
if (exit.value && exit.value.equals(value)) equals = 2;
|
if (jump.value && jump.value.equals(value)) equals = 2;
|
||||||
}
|
}
|
||||||
if (!equals && !exact && exit.value instanceof AST_Sequence) {
|
if (!equals && !exact && jump.value instanceof AST_Sequence) {
|
||||||
if (exit.value.tail_node().equals(value)) equals = 3;
|
if (jump.value.tail_node().equals(value)) equals = 3;
|
||||||
}
|
}
|
||||||
return equals;
|
return equals;
|
||||||
}
|
}
|
||||||
|
|
||||||
function can_drop_abort(ab) {
|
function can_drop_abort(ab) {
|
||||||
if (ab instanceof AST_Exit) {
|
if (ab instanceof AST_Exit) {
|
||||||
if (merge_exit = match_return(ab)) return true;
|
if (merge_jump = match_return(ab)) return true;
|
||||||
if (!in_lambda) return false;
|
if (!in_lambda) return false;
|
||||||
if (!(ab instanceof AST_Return)) return false;
|
if (!(ab instanceof AST_Return)) return false;
|
||||||
if (is_undefined(ab.value)) return true;
|
var value = ab.value;
|
||||||
return ab.value instanceof AST_Sequence && is_undefined(ab.value.tail_node());
|
if (value && !is_undefined(value.tail_node())) return false;
|
||||||
|
if (self instanceof AST_SwitchBranch) merge_jump = 4;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (!(ab instanceof AST_LoopControl)) return false;
|
if (!(ab instanceof AST_LoopControl)) return false;
|
||||||
var lct = compressor.loopcontrol_target(ab);
|
var lct = compressor.loopcontrol_target(ab);
|
||||||
if (ab instanceof AST_Continue) return match_target(loop_body(lct));
|
if (ab instanceof AST_Continue) return match_target(loop_body(lct));
|
||||||
if (lct instanceof AST_IterationStatement) return false;
|
if (lct instanceof AST_IterationStatement) return false;
|
||||||
|
if (jump) merge_jump = jump.equals(ab);
|
||||||
return match_target(lct);
|
return match_target(lct);
|
||||||
}
|
}
|
||||||
|
|
||||||
function can_merge_flow(ab) {
|
function can_merge_flow(ab) {
|
||||||
merge_exit = false;
|
merge_jump = false;
|
||||||
if (!can_drop_abort(ab)) return false;
|
if (!can_drop_abort(ab)) return false;
|
||||||
for (var j = statements.length; --j > i;) {
|
for (var j = statements.length; --j > i;) {
|
||||||
var stat = statements[j];
|
var stat = statements[j];
|
||||||
@@ -3663,12 +3681,12 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var lexical = false;
|
var lexical = false;
|
||||||
var start = i + 1;
|
var start = i + 1;
|
||||||
var end;
|
var end;
|
||||||
if (merge_exit) {
|
if (merge_jump) {
|
||||||
end = statements.lastIndexOf(exit);
|
end = statements.lastIndexOf(jump);
|
||||||
if (end < 0) end = statements.length;
|
if (end < 0) end = statements.length;
|
||||||
} else {
|
} else {
|
||||||
end = statements.length;
|
end = statements.length;
|
||||||
exit = null;
|
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) {
|
||||||
@@ -3678,11 +3696,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_exit === 3) {
|
if (merge_jump === 3) {
|
||||||
tail.push(make_node(AST_SimpleStatement, exit.value, {
|
tail.push(make_node(AST_SimpleStatement, jump.value, {
|
||||||
body: make_sequence(exit.value, exit.value.expressions.slice(0, -1)),
|
body: make_sequence(jump.value, jump.value.expressions.slice(0, -1)),
|
||||||
}));
|
}));
|
||||||
exit.value = exit.value.tail_node();
|
jump.value = jump.value.tail_node();
|
||||||
}
|
}
|
||||||
[].push.apply(lexical ? tail : statements, defuns);
|
[].push.apply(lexical ? tail : statements, defuns);
|
||||||
return tail;
|
return tail;
|
||||||
@@ -3690,6 +3708,8 @@ Compressor.prototype.compress = function(node) {
|
|||||||
|
|
||||||
function trim_return(value, mode) {
|
function trim_return(value, mode) {
|
||||||
if (value) switch (mode) {
|
if (value) switch (mode) {
|
||||||
|
case 4:
|
||||||
|
return value;
|
||||||
case 3:
|
case 3:
|
||||||
if (!(value instanceof AST_Sequence)) break;
|
if (!(value instanceof AST_Sequence)) break;
|
||||||
case 2:
|
case 2:
|
||||||
@@ -3705,7 +3725,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
block.pop();
|
block.pop();
|
||||||
var value = ab.value;
|
var value = ab.value;
|
||||||
if (merge_exit) value = trim_return(value, merge_exit);
|
if (merge_jump) value = trim_return(value, merge_jump);
|
||||||
if (value) block.push(make_node(AST_SimpleStatement, value, { body: value }));
|
if (value) block.push(make_node(AST_SimpleStatement, value, { body: value }));
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
@@ -3757,7 +3777,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
} else if (stat instanceof AST_LabeledStatement) {
|
} else if (stat instanceof AST_LabeledStatement) {
|
||||||
stat.body = eliminate_returns(stat.body);
|
stat.body = eliminate_returns(stat.body);
|
||||||
} else if (stat instanceof AST_Try) {
|
} else if (stat instanceof AST_Try) {
|
||||||
if (!stat.bfinally || !exit.value || exit.value.is_constant()) {
|
if (!stat.bfinally || !jump.value || jump.value.is_constant()) {
|
||||||
if (stat.bcatch) eliminate_returns(stat.bcatch);
|
if (stat.bcatch) eliminate_returns(stat.bcatch);
|
||||||
var trimmed = eliminate_returns(stat.body.pop(), true);
|
var trimmed = eliminate_returns(stat.body.pop(), true);
|
||||||
if (trimmed) stat.body.push(trimmed);
|
if (trimmed) stat.body.push(trimmed);
|
||||||
|
|||||||
@@ -1393,3 +1393,198 @@ void_match: {
|
|||||||
"foo",
|
"foo",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch_break: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
switch (a) {
|
||||||
|
default:
|
||||||
|
if (console.log("foo"))
|
||||||
|
break;
|
||||||
|
while (console.log("bar"));
|
||||||
|
case 42:
|
||||||
|
if (console.log("baz"))
|
||||||
|
break;
|
||||||
|
while (console.log("moo"));
|
||||||
|
break;
|
||||||
|
case null:
|
||||||
|
if (console.log("moz"))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
f(42);
|
||||||
|
f(null);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
switch (a) {
|
||||||
|
default:
|
||||||
|
if (console.log("foo"))
|
||||||
|
break;
|
||||||
|
while (console.log("bar"));
|
||||||
|
case 42:
|
||||||
|
if (!console.log("baz"))
|
||||||
|
while (console.log("moo"));
|
||||||
|
break;
|
||||||
|
case null:
|
||||||
|
console.log("moz");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
f(42);
|
||||||
|
f(null);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
"baz",
|
||||||
|
"moo",
|
||||||
|
"baz",
|
||||||
|
"moo",
|
||||||
|
"moz",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_return_1: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
switch (a) {
|
||||||
|
case console.log("PASS"):
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case 42:
|
||||||
|
FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
switch (a) {
|
||||||
|
case console.log("PASS"):
|
||||||
|
return;
|
||||||
|
case 42:
|
||||||
|
FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_return_2: {
|
||||||
|
options = {
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
switch (a) {
|
||||||
|
case console.log("PASS"):
|
||||||
|
if (console)
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case 42:
|
||||||
|
FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
switch (a) {
|
||||||
|
case console.log("PASS"):
|
||||||
|
if (console);
|
||||||
|
break;
|
||||||
|
case 42:
|
||||||
|
FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_return_3: {
|
||||||
|
options = {
|
||||||
|
if_return: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
switch (a) {
|
||||||
|
case console.log("foo"):
|
||||||
|
if (console)
|
||||||
|
return void console.log("bar");
|
||||||
|
break;
|
||||||
|
case 42:
|
||||||
|
FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
switch (a) {
|
||||||
|
case console.log("foo"):
|
||||||
|
if (console)
|
||||||
|
console.log("bar");
|
||||||
|
break;
|
||||||
|
case 42:
|
||||||
|
FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_return_4: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
if_return: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
switch (a) {
|
||||||
|
case console.log("foo"):
|
||||||
|
if (console) {
|
||||||
|
console.log("bar");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 42:
|
||||||
|
FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
switch (a) {
|
||||||
|
case console.log("foo"):
|
||||||
|
console && console.log("bar");
|
||||||
|
break;
|
||||||
|
case 42:
|
||||||
|
FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user