diff --git a/lib/compress.js b/lib/compress.js index c123242058..274ab60441 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -4242,8 +4242,19 @@ merge(Compressor.prototype, { d.fixed = fixed = make_node(AST_Function, fixed, fixed); } if (fixed && d.single_use) { - var value = fixed.optimize(compressor); - return value === fixed ? fixed.clone(true) : value; + var recurse; + if (fixed instanceof AST_Function) { + for (var i = 0; recurse = compressor.parent(i); i++) { + if (recurse instanceof AST_Lambda) { + var name = recurse.name; + if (name && name.definition() === d) break; + } + } + } + if (!recurse) { + var value = fixed.optimize(compressor); + return value === fixed ? fixed.clone(true) : value; + } } if (fixed && d.should_replace === undefined) { var init; diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index 25f95ff8bf..f1a27ff9a7 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -3654,3 +3654,194 @@ issue_2440_with_2: { } } } + +issue_2442: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function foo() { + foo(); + } + } + expect: {} +} + +recursive_inlining_1: { + options = { + reduce_vars: true, + unused: true, + } + input: { + !function() { + function foo() { bar(); } + function bar() { foo(); } + console.log("PASS"); + }(); + } + expect: { + !function() { + console.log("PASS"); + }(); + } + expect_stdout: "PASS" +} + +recursive_inlining_2: { + options = { + reduce_vars: true, + unused: true, + } + input: { + !function() { + function foo() { qux(); } + function bar() { foo(); } + function qux() { bar(); } + console.log("PASS"); + }(); + } + expect: { + !function() { + console.log("PASS"); + }(); + } + expect_stdout: "PASS" +} + +recursive_inlining_3: { + options = { + reduce_vars: true, + unused: true, + } + input: { + !function() { + function foo(x) { console.log("foo", x); if (x) bar(x-1); } + function bar(x) { console.log("bar", x); if (x) qux(x-1); } + function qux(x) { console.log("qux", x); if (x) foo(x-1); } + qux(4); + }(); + } + expect: { + !function() { + function qux(x) { + console.log("qux", x); + if (x) (function(x) { + console.log("foo", x); + if (x) (function(x) { + console.log("bar", x); + if (x) qux(x - 1); + })(x - 1); + })(x - 1); + } + qux(4); + }(); + } + expect_stdout: [ + "qux 4", + "foo 3", + "bar 2", + "qux 1", + "foo 0", + ] +} + +recursive_inlining_4: { + options = { + reduce_vars: true, + unused: true, + } + input: { + !function() { + function foo(x) { console.log("foo", x); if (x) bar(x-1); } + function bar(x) { console.log("bar", x); if (x) qux(x-1); } + function qux(x) { console.log("qux", x); if (x) foo(x-1); } + qux(4); + bar(5); + }(); + } + expect: { + !function() { + function bar(x) { + console.log("bar", x); + if (x) qux(x - 1); + } + function qux(x) { + console.log("qux", x); + if (x) (function(x) { + console.log("foo", x); + if (x) bar(x - 1); + })(x - 1); + } + qux(4); + bar(5); + }(); + } + expect_stdout: [ + "qux 4", + "foo 3", + "bar 2", + "qux 1", + "foo 0", + "bar 5", + "qux 4", + "foo 3", + "bar 2", + "qux 1", + "foo 0", + ] +} + +recursive_inlining_5: { + options = { + reduce_vars: true, + unused: true, + } + input: { + !function() { + function foo(x) { console.log("foo", x); if (x) bar(x-1); } + function bar(x) { console.log("bar", x); if (x) qux(x-1); } + function qux(x) { console.log("qux", x); if (x) foo(x-1); } + qux(4); + bar(5); + foo(3); + }(); + } + expect: { + !function() { + function foo(x) { + console.log("foo", x); + if (x) bar(x - 1); + } + function bar(x) { + console.log("bar", x); + if (x) qux(x - 1); + } + function qux(x) { + console.log("qux", x); + if (x) foo(x - 1); + } + qux(4); + bar(5); + foo(3); + }(); + } + expect_stdout: [ + "qux 4", + "foo 3", + "bar 2", + "qux 1", + "foo 0", + "bar 5", + "qux 4", + "foo 3", + "bar 2", + "qux 1", + "foo 0", + "foo 3", + "bar 2", + "qux 1", + "foo 0", + ] +}