From b244b4ec21fdb65870068879f02e5471ab371d1d Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Tue, 16 Mar 2021 21:38:33 +0000 Subject: [PATCH] enhance "functions" (#4791) --- lib/compress.js | 29 +++++++++-------- test/compress/awaits.js | 64 +++++++++++++++++++++++++++++++++----- test/compress/functions.js | 36 +++++++++++++++++---- test/compress/yields.js | 64 +++++++++++++++++++++++++++++++++----- 4 files changed, 156 insertions(+), 37 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 7264153de7..f8b9c8c319 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -6203,8 +6203,8 @@ merge(Compressor.prototype, { && value instanceof AST_LambdaExpression && !is_arrow(value) && assigned_once(value, sym.references) - && can_declare_defun() - && can_rename(value, def.name.name)) { + && can_declare_defun(value) + && (old_def = rename_def(value, def.name.name)) !== false) { AST_Node.warn("Declaring {name} as function [{file}:{line},{col}]", template(def.name)); var ctor; switch (value.CTOR) { @@ -6269,27 +6269,26 @@ merge(Compressor.prototype, { }); } - function can_declare_defun() { - if (compressor.has_directive("use strict")) return parent instanceof AST_Scope; + function can_declare_defun(fn) { + if (compressor.has_directive("use strict") || !(fn instanceof AST_Function)) { + return parent instanceof AST_Scope; + } return parent instanceof AST_Block || parent instanceof AST_For && parent.init === node || parent instanceof AST_If; } - function can_rename(fn, name) { - if (!fn.name) return !fn.variables.get(name); - old_def = fn.name.definition(); - if (old_def.orig.length > 1) { - old_def = null; - } else { - if (old_def.assignments > 0) return false; - if (old_def.name == name) return true; - } + function rename_def(fn, name) { + if (!fn.name) return null; + var def = fn.name.definition(); + if (def.orig.length > 1) return null; + if (def.assignments > 0) return false; + if (def.name == name) return def; if (name == "await" && is_async(fn)) return false; if (name == "yield" && is_generator(fn)) return false; - return !old_def || all(old_def.references, function(ref) { + return all(def.references, function(ref) { return ref.scope.find_variable(name) === sym; - }); + }) && def; } function is_catch(node) { diff --git a/test/compress/awaits.js b/test/compress/awaits.js index be3cc5a06d..8882f1e7ad 100644 --- a/test/compress/awaits.js +++ b/test/compress/awaits.js @@ -614,14 +614,14 @@ functions: { async function b() { return !!b; } - var c = async function(c) { + async function c(c) { return c; - }; + } if (await c(await b(await a()))) { - async function d() {} - async function e() { - return typeof e; - } + var d = async function() {}; + var e = async function y() { + return typeof y; + }; var f = async function(f) { return f; }; @@ -672,9 +672,9 @@ functions_use_strict: { async function b() { return !!b; } - var c = async function(c) { + async function c(c) { return c; - }; + } if (await c(await b(await a()))) { var d = async function() {}; var e = async function y() { @@ -691,6 +691,54 @@ functions_use_strict: { node_version: ">=8" } +functions_anonymous: { + options = { + functions: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var await = async function() { + console.log("PASS"); + }; + await(await); + } + expect: { + async function await() { + console.log("PASS"); + } + await(); + } + expect_stdout: "PASS" + node_version: ">=8" +} + +functions_inner_var: { + options = { + functions: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var await = function a() { + var a; + console.log(a, a); + }; + await(await); + } + expect: { + function await() { + var a; + console.log(a, a); + } + await(); + } + expect_stdout: "undefined undefined" + node_version: ">=8" +} + issue_4335_1: { options = { inline: true, diff --git a/test/compress/functions.js b/test/compress/functions.js index e43efceab7..2c529f0fdb 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -2751,17 +2751,17 @@ functions: { function b() { return !!b; } - var c = function(c) { + function c(c) { return c; - }; + } if (c(b(a()))) { function d() {} function e() { return typeof e; } - var f = function(f) { + function f(f) { return f; - }; + } console.log(a(d()), b(e()), c(f(42)), typeof d, e(), typeof f); } }(); @@ -2808,9 +2808,9 @@ functions_use_strict: { function b() { return !!b; } - var c = function(c) { + function c(c) { return c; - }; + } if (c(b(a()))) { var d = function() {}; var e = function y() { @@ -2826,6 +2826,30 @@ functions_use_strict: { expect_stdout: "a true 42 function function function" } +functions_inner_var: { + options = { + functions: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var a = function() { + var a; + console.log(a, a); + }; + a(a); + } + expect: { + function a() { + var a; + console.log(a, a); + } + a(); + } + expect_stdout: "undefined undefined" +} + issue_2437: { options = { collapse_vars: true, diff --git a/test/compress/yields.js b/test/compress/yields.js index 06f46c9d4a..05972e53ab 100644 --- a/test/compress/yields.js +++ b/test/compress/yields.js @@ -388,14 +388,14 @@ functions: { function* b() { return !!b; } - var c = function*(c) { + function* c(c) { return c; - }; + } if (yield* c(yield* b(yield* a()))) { - function* d() {} - function* e() { - return typeof e; - } + var d = function*() {}; + var e = function* y() { + return typeof y; + }; var f = function*(f) { return f; }; @@ -446,9 +446,9 @@ functions_use_strict: { function* b() { return !!b; } - var c = function*(c) { + function* c(c) { return c; - }; + } if (yield* c(yield* b(yield* a()))) { var d = function*() {}; var e = function* y() { @@ -465,6 +465,54 @@ functions_use_strict: { node_version: ">=4" } +functions_anonymous: { + options = { + functions: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var yield = function*() { + return "PASS"; + }; + console.log(yield().next(yield).value); + } + expect: { + function* yield() { + return "PASS"; + } + console.log(yield().next(yield).value); + } + expect_stdout: "PASS" + node_version: ">=4" +} + +functions_inner_var: { + options = { + functions: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var yield = function* a() { + var a; + console.log(a, a); + }; + yield().next(yield); + } + expect: { + function* yield() { + var a; + console.log(a, a); + } + yield().next(yield); + } + expect_stdout: "undefined undefined" + node_version: ">=4" +} + negate_iife: { options = { negate_iife: true,