From c1ab1004f3a6eaeb8f36f1a7f9a8517bbbd255db Mon Sep 17 00:00:00 2001 From: Michael Hensler Date: Fri, 15 Nov 2019 14:56:07 -0800 Subject: [PATCH 1/3] fix #510: inline identity functions --- lib/compress/index.js | 13 ++++++++ test/compress/async.js | 5 ++- test/compress/functions.js | 9 ++---- test/compress/identity.js | 61 ++++++++++++++++++++++++++++++++++++ test/compress/reduce_vars.js | 6 ++-- 5 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 test/compress/identity.js diff --git a/lib/compress/index.js b/lib/compress/index.js index a5ca5b229..34da24762 100644 --- a/lib/compress/index.js +++ b/lib/compress/index.js @@ -5214,6 +5214,19 @@ def_optimize(AST_Call, function(self, compressor) { var args = self.args.concat(value); return make_sequence(self, args).optimize(compressor); } + + // optimize identity function + if ( + fn.argnames.length === 1 + && value.start.type === "name" + && value.name === fn.argnames[0].name + ) { + // replace call with first argument or undefined if none passed + return make_sequence( + self, + [self.args[0] || make_node(AST_Undefined)] + ).optimize(compressor); + } } if (can_inline) { var scope, in_loop, level = -1; diff --git a/test/compress/async.js b/test/compress/async.js index 69b00de36..892cb420e 100644 --- a/test/compress/async.js +++ b/test/compress/async.js @@ -165,9 +165,8 @@ async_inline: { !async function(){await 3}(); !async function(x){await console.log(4)}(); - function echo(x){return x} - echo(async function(){return await 1}()); - echo(async function(x){await console.log(2)}()); + !async function(){await 1}(); + !async function(x){await console.log(2)}(); console.log("top"); diff --git a/test/compress/functions.js b/test/compress/functions.js index 47840fd22..0b4cba63d 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -409,11 +409,7 @@ inner_ref: { }(2)); } expect: { - console.log(function(a) { - return a; - }(1), function(a) { - return a; - }()); + console.log(1, void 0); } expect_stdout: "1 undefined" } @@ -2107,8 +2103,7 @@ duplicate_arg_var: { }("PASS")); } expect: { - console.log((b = "PASS", b)); - var b; + console.log("PASS"); } expect_stdout: "PASS" } diff --git a/test/compress/identity.js b/test/compress/identity.js new file mode 100644 index 000000000..6b3989402 --- /dev/null +++ b/test/compress/identity.js @@ -0,0 +1,61 @@ +inline_identity: { + options = { + defaults: true, + toplevel: true + } + input: { + const id = x => x; + console.log(id(1), id(2)); + } + expect: { + console.log(1, 2); + } + expect_stdout: "1 2" +} + +inline_identity_no_params: { + options = { + defaults: true, + toplevel: true + } + input: { + const id = x => x; + console.log(id(), id()); + } + expect: { + console.log(void 0, void 0); + } + expect_stdout: "undefined undefined" +} + +inline_identity_extra_params: { + options = { + defaults: true, + toplevel: true + } + input: { + const id = x => x; + console.log(id(1, 2), id(3, 4)); + } + expect: { + console.log(1, 3); + } + expect_stdout: "1 3" +} + +inline_identity_higher_order: { + options = { + defaults: true, + toplevel: true + } + input: { + const id = x => x; + const inc = x => x + 1; + console.log(id(inc)(1), id(inc)(2)); + } + expect: { + const inc = x => x + 1; + console.log(inc(1), inc(2)); + } + expect_stdout: "2 3" +} diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index e6a9203e2..c9e94843a 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -1429,6 +1429,7 @@ defun_inline_3: { defun_call: { options = { + evaluate: true, inline: true, reduce_funcs: true, reduce_vars: true, @@ -1447,10 +1448,7 @@ defun_call: { } expect: { function f() { - return 4 + h(1) - h(4); - function h(a) { - return a; - } + return 1; } } } From a75af08ca4830a44f6cd9ce99242a4ddb79bbd5e Mon Sep 17 00:00:00 2001 From: Michael Hensler Date: Fri, 15 Nov 2019 17:57:46 -0800 Subject: [PATCH 2/3] bringing back test semantics hidden by identity. simplifying identity optimization --- lib/compress/index.js | 5 +- test/compress/async.js | 11 +++-- test/compress/functions.js | 19 +++++--- test/compress/identity.js | 95 +++++++++++++++++++++++++++++++++++--- 4 files changed, 108 insertions(+), 22 deletions(-) diff --git a/lib/compress/index.js b/lib/compress/index.js index 34da24762..c02cb8cae 100644 --- a/lib/compress/index.js +++ b/lib/compress/index.js @@ -5222,10 +5222,7 @@ def_optimize(AST_Call, function(self, compressor) { && value.name === fn.argnames[0].name ) { // replace call with first argument or undefined if none passed - return make_sequence( - self, - [self.args[0] || make_node(AST_Undefined)] - ).optimize(compressor); + return (self.args[0] || make_node(AST_Undefined)).optimize(compressor); } } if (can_inline) { diff --git a/test/compress/async.js b/test/compress/async.js index 892cb420e..5c97de30c 100644 --- a/test/compress/async.js +++ b/test/compress/async.js @@ -151,9 +151,9 @@ async_inline: { (async function(){ return await 3; })(); (async function(x){ await console.log(x); })(4); - function echo(x) { return x; } - echo( async function(){ return await 1; }() ); - echo( async function(x){ await console.log(x); }(2) ); + function invoke(x, y) { return x(y); } + invoke( async function(){ return await 1; } ); + invoke( async function(x){ await console.log(x); }, 2); function top() { console.log("top"); } top(); @@ -165,8 +165,9 @@ async_inline: { !async function(){await 3}(); !async function(x){await console.log(4)}(); - !async function(){await 1}(); - !async function(x){await console.log(2)}(); + function invoke(x, y){return x(y)} + invoke(async function(){return await 1}); + invoke(async function(x){await console.log(x)}, 2); console.log("top"); diff --git a/test/compress/functions.js b/test/compress/functions.js index 0b4cba63d..2051be3aa 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -400,18 +400,22 @@ inner_ref: { input: { console.log(function(a) { return function() { - return a; + return a + 1; }(); }(1), function(a) { return function(a) { - return a; + return typeof a; }(); }(2)); } expect: { - console.log(1, void 0); + console.log(function (a) { + return a + 1; + }(1), function (a) { + return typeof a; + }()); } - expect_stdout: "1 undefined" + expect_stdout: "2 'undefined'" } issue_2107: { @@ -2098,14 +2102,15 @@ duplicate_arg_var: { } input: { console.log(function(b) { - return b; + return b + "ING"; var b; }("PASS")); } expect: { - console.log("PASS"); + console.log((b = "PASS", b + "ING")); + var b; } - expect_stdout: "PASS" + expect_stdout: "PASSING" } issue_2737_1: { diff --git a/test/compress/identity.js b/test/compress/identity.js index 6b3989402..58c3eda31 100644 --- a/test/compress/identity.js +++ b/test/compress/identity.js @@ -1,6 +1,8 @@ inline_identity: { options = { - defaults: true, + inline: true, + reduce_vars: true, + unused: true, toplevel: true } input: { @@ -13,14 +15,33 @@ inline_identity: { expect_stdout: "1 2" } -inline_identity_no_params: { +inline_identity_function: { options = { - defaults: true, + inline: true, + reduce_vars: true, + unused: true, + toplevel: true + } + input: { + function id(x) { return x }; + console.log(id(1), id(2)); + } + expect: { + console.log(1, 2); + } + expect_stdout: "1 2" +} + +inline_identity_undefined: { + options = { + inline: true, + reduce_vars: true, + unused: true, toplevel: true } input: { const id = x => x; - console.log(id(), id()); + console.log(id(), id(undefined)); } expect: { console.log(void 0, void 0); @@ -30,7 +51,9 @@ inline_identity_no_params: { inline_identity_extra_params: { options = { - defaults: true, + inline: true, + reduce_vars: true, + unused: true, toplevel: true } input: { @@ -45,7 +68,9 @@ inline_identity_extra_params: { inline_identity_higher_order: { options = { - defaults: true, + inline: true, + reduce_vars: true, + unused: true, toplevel: true } input: { @@ -59,3 +84,61 @@ inline_identity_higher_order: { } expect_stdout: "2 3" } + +inline_identity_duplicate_arg_var: { + options = { + inline: true, + reduce_vars: true, + unused: true, + toplevel: true + } + input: { + const id = x => { + return x; + var x; + } + console.log(id(1), id(2)); + } + expect: { + console.log(1, 2); + } + expect_stdout: "1 2" +} + +inline_identity_inner_ref: { + options = { + inline: true, + reduce_vars: true, + unused: true, + toplevel: true + } + input: { + const id = a => (function () { return a })(); + const undef = a => (a => a)(); + console.log(id(1), id(2), undef(3), undef(4)); + } + expect: { + console.log(1, 2, void 0, void 0); + } + expect_stdout: "1 2 undefined undefined" +} + +inline_identity_async: { + options = { + inline: true, + reduce_vars: true, + unused: true, + toplevel: true + } + input: { + const id = x => x; + id(async () => await 1)(); + id(async x => await console.log(2))(); + } + expect: { + (async () => await 1)(); + (async x => await console.log(2))(); + } + expect_stdout: "2" + node_version: ">=8" +} \ No newline at end of file From 826398c2fe39ec1d5586f4fde709027d3f789960 Mon Sep 17 00:00:00 2001 From: Michael Hensler Date: Fri, 15 Nov 2019 21:48:55 -0800 Subject: [PATCH 3/3] fix node 12 issue and don't drop extra args with side effects --- lib/compress/index.js | 1 + test/compress/functions.js | 6 +++--- test/compress/identity.js | 34 +++++++++++++++++++++++++++------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/lib/compress/index.js b/lib/compress/index.js index c02cb8cae..180487b01 100644 --- a/lib/compress/index.js +++ b/lib/compress/index.js @@ -5218,6 +5218,7 @@ def_optimize(AST_Call, function(self, compressor) { // optimize identity function if ( fn.argnames.length === 1 + && self.args.length < 2 && value.start.type === "name" && value.name === fn.argnames[0].name ) { diff --git a/test/compress/functions.js b/test/compress/functions.js index 2051be3aa..86f86dd42 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -404,7 +404,7 @@ inner_ref: { }(); }(1), function(a) { return function(a) { - return typeof a; + return a === undefined; }(); }(2)); } @@ -412,10 +412,10 @@ inner_ref: { console.log(function (a) { return a + 1; }(1), function (a) { - return typeof a; + return void 0 === a; }()); } - expect_stdout: "2 'undefined'" + expect_stdout: "2 true" } issue_2107: { diff --git a/test/compress/identity.js b/test/compress/identity.js index 58c3eda31..3234b44f2 100644 --- a/test/compress/identity.js +++ b/test/compress/identity.js @@ -58,12 +58,13 @@ inline_identity_extra_params: { } input: { const id = x => x; - console.log(id(1, 2), id(3, 4)); + console.log(id(1, console.log(2)), id(3, 4)); } expect: { - console.log(1, 3); + const id = x => x; + console.log(id(1, console.log(2)), 3); } - expect_stdout: "1 3" + expect_stdout: ["2", "1 3"] } inline_identity_higher_order: { @@ -76,7 +77,7 @@ inline_identity_higher_order: { input: { const id = x => x; const inc = x => x + 1; - console.log(id(inc)(1), id(inc)(2)); + console.log(id(inc(1)), id(inc)(2)); } expect: { const inc = x => x + 1; @@ -85,6 +86,25 @@ inline_identity_higher_order: { expect_stdout: "2 3" } +inline_identity_inline_function: { + options = { + evaluate: true, + inline: true, + passes: 2, + reduce_vars: true, + unused: true, + toplevel: true + } + input: { + const id = x => x; + console.log(id(x => x + 1)(1), id((x => x + 1)(2))); + } + expect: { + console.log(2, 3); + } + expect_stdout: "2 3" +} + inline_identity_duplicate_arg_var: { options = { inline: true, @@ -96,7 +116,7 @@ inline_identity_duplicate_arg_var: { const id = x => { return x; var x; - } + }; console.log(id(1), id(2)); } expect: { @@ -113,7 +133,7 @@ inline_identity_inner_ref: { toplevel: true } input: { - const id = a => (function () { return a })(); + const id = a => (function() { return a; })(); const undef = a => (a => a)(); console.log(id(1), id(2), undef(3), undef(4)); } @@ -141,4 +161,4 @@ inline_identity_async: { } expect_stdout: "2" node_version: ">=8" -} \ No newline at end of file +}