Skip to content

Commit 9f57920

Browse files
authored
enhance if_return (#5518)
1 parent 933ca9d commit 9f57920

File tree

4 files changed

+187
-4
lines changed

4 files changed

+187
-4
lines changed

lib/compress.js

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3391,6 +3391,7 @@ Compressor.prototype.compress = function(node) {
33913391
var changed = false;
33923392
var parent = compressor.parent();
33933393
var self = compressor.self();
3394+
var exit, exit_defs, merge_exit;
33943395
var in_iife = in_lambda && parent && parent.TYPE == "Call" && parent.expression === self;
33953396
var chain_if_returns = in_lambda && compressor.option("conditionals") && compressor.option("sequences");
33963397
var multiple_if_returns = has_multiple_if_returns(statements);
@@ -3446,6 +3447,7 @@ Compressor.prototype.compress = function(node) {
34463447
stat.condition = cond;
34473448
statements[j] = stat.body;
34483449
stat.body = next;
3450+
if (next === exit) exit = null;
34493451
statements[i] = stat;
34503452
statements[i] = stat.transform(compressor);
34513453
continue;
@@ -3489,6 +3491,7 @@ Compressor.prototype.compress = function(node) {
34893491
changed = true;
34903492
stat = stat.clone();
34913493
stat.alternative = next;
3494+
if (next === exit) exit = null;
34923495
statements.splice(i, 1, stat.transform(compressor));
34933496
statements.splice(j, 1);
34943497
continue;
@@ -3532,6 +3535,11 @@ Compressor.prototype.compress = function(node) {
35323535
continue;
35333536
}
35343537
}
3538+
3539+
if (stat instanceof AST_Exit) {
3540+
exit = stat;
3541+
exit_defs = null;
3542+
}
35353543
}
35363544
return changed;
35373545

@@ -3553,7 +3561,25 @@ Compressor.prototype.compress = function(node) {
35533561
}
35543562

35553563
function can_drop_abort(ab) {
3556-
if (ab instanceof AST_Return) return in_lambda && is_undefined(ab.value);
3564+
if (ab instanceof AST_Exit) {
3565+
if (exit && exit.equivalent_to(ab)) {
3566+
if (!exit_defs) {
3567+
exit_defs = new Dictionary();
3568+
exit.walk(new TreeWalker(function(node) {
3569+
if (node instanceof AST_SymbolRef) exit_defs.set(node.name, node.definition());
3570+
}));
3571+
}
3572+
var abort = false;
3573+
ab.walk(new TreeWalker(function(node) {
3574+
if (abort) return true;
3575+
if (node instanceof AST_SymbolRef && exit_defs.get(node.name) !== node.definition()) {
3576+
return abort = true;
3577+
}
3578+
}));
3579+
if (!abort) return merge_exit = true;
3580+
}
3581+
return in_lambda && ab instanceof AST_Return && is_undefined(ab.value);
3582+
}
35573583
if (!(ab instanceof AST_LoopControl)) return false;
35583584
var lct = compressor.loopcontrol_target(ab);
35593585
if (ab instanceof AST_Continue) return match_target(loop_body(lct));
@@ -3562,6 +3588,7 @@ Compressor.prototype.compress = function(node) {
35623588
}
35633589

35643590
function can_merge_flow(ab) {
3591+
merge_exit = false;
35653592
if (!can_drop_abort(ab)) return false;
35663593
for (var j = statements.length; --j > i;) {
35673594
var stat = statements[j];
@@ -3581,7 +3608,16 @@ Compressor.prototype.compress = function(node) {
35813608
function extract_functions() {
35823609
var defuns = [];
35833610
var lexical = false;
3584-
var tail = statements.splice(i + 1).filter(function(stat) {
3611+
var start = i + 1;
3612+
var end;
3613+
if (merge_exit) {
3614+
end = statements.lastIndexOf(exit);
3615+
if (end < 0) end = statements.length;
3616+
} else {
3617+
end = statements.length;
3618+
exit = null;
3619+
}
3620+
var tail = statements.splice(start, end - start).filter(function(stat) {
35853621
if (stat instanceof AST_LambdaDefinition) {
35863622
defuns.push(stat);
35873623
return false;
@@ -3600,7 +3636,7 @@ Compressor.prototype.compress = function(node) {
36003636
block = last.body;
36013637
}
36023638
block.pop();
3603-
if (ab.value) block.push(make_node(AST_SimpleStatement, ab.value, { body: ab.value }));
3639+
if (!merge_exit && ab.value) block.push(make_node(AST_SimpleStatement, ab.value, { body: ab.value }));
36043640
return body;
36053641
}
36063642

test/compress/if_return.js

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,3 +850,116 @@ issue_866_2: {
850850
})();
851851
}
852852
}
853+
854+
identical_returns_1: {
855+
options = {
856+
conditionals: true,
857+
if_return: true,
858+
}
859+
input: {
860+
console.log(function() {
861+
if (console.log("foo"))
862+
return 42;
863+
else
864+
while (console.log("bar"));
865+
return 42;
866+
}());
867+
}
868+
expect: {
869+
console.log(function() {
870+
if (!console.log("foo"))
871+
while (console.log("bar"));
872+
return 42;
873+
}());
874+
}
875+
expect_stdout: [
876+
"foo",
877+
"bar",
878+
"42",
879+
]
880+
}
881+
882+
identical_returns_2: {
883+
options = {
884+
conditionals: true,
885+
if_return: true,
886+
}
887+
input: {
888+
console.log(function() {
889+
if (console.log("foo"))
890+
while (console.log("FAIL"));
891+
else
892+
return "bar";
893+
return "bar";
894+
}());
895+
}
896+
expect: {
897+
console.log(function() {
898+
if (console.log("foo"))
899+
while (console.log("FAIL"));
900+
return "bar";
901+
}());
902+
}
903+
expect_stdout: [
904+
"foo",
905+
"bar",
906+
]
907+
}
908+
909+
identical_returns_3: {
910+
options = {
911+
if_return: true,
912+
}
913+
input: {
914+
function f(a) {
915+
if (a)
916+
return 42;
917+
if (a)
918+
return;
919+
return 42;
920+
}
921+
if (f(console))
922+
console.log("PASS");
923+
}
924+
expect: {
925+
function f(a) {
926+
if (a)
927+
return 42;
928+
if (a)
929+
;
930+
else
931+
return 42;
932+
}
933+
if (f(console))
934+
console.log("PASS");
935+
}
936+
expect_stdout: "PASS"
937+
}
938+
939+
issue_4374: {
940+
options = {
941+
booleans: true,
942+
conditionals: true,
943+
if_return: true,
944+
reduce_vars: true,
945+
unused: true,
946+
}
947+
input: {
948+
(function() {
949+
console.log(f(console));
950+
function f(a) {
951+
if (console) return 0;
952+
if (a) return 1;
953+
return 0;
954+
}
955+
})();
956+
}
957+
expect: {
958+
(function() {
959+
console.log(function(a) {
960+
return !console && a ? 1 : 0;
961+
}(console));
962+
})();
963+
}
964+
expect_stdout: "0"
965+
}

test/compress/let.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,40 @@ if_return_2: {
892892
node_version: ">=4"
893893
}
894894

895+
if_return_3: {
896+
options = {
897+
if_return: true,
898+
}
899+
input: {
900+
"use strict";
901+
var a = "PASS";
902+
function f(b) {
903+
if (console) {
904+
let b = a;
905+
return b;
906+
} else
907+
while (console.log("FAIL 1"));
908+
return b;
909+
}
910+
console.log(f("FAIL 2"));
911+
}
912+
expect: {
913+
"use strict";
914+
var a = "PASS";
915+
function f(b) {
916+
if (console) {
917+
let b = a;
918+
return b;
919+
} else
920+
while (console.log("FAIL 1"));
921+
return b;
922+
}
923+
console.log(f("FAIL 2"));
924+
}
925+
expect_stdout: "PASS"
926+
node_version: ">=4"
927+
}
928+
895929
do_if_continue_1: {
896930
options = {
897931
if_return: true,

test/compress/transform.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ if_return: {
127127
if (w) {
128128
if (y) return;
129129
} else if (z) return;
130-
return x == y || (x && w(), y && z()), !0;
130+
return x != y && (x && w(), y && z()), !0;
131131
}
132132
}
133133
}

0 commit comments

Comments
 (0)