fix corner case in unused (#3716)

This commit is contained in:
Alex Lam S.L
2020-02-12 23:46:16 +00:00
committed by GitHub
parent 2557148bba
commit 83a42716c3
4 changed files with 116 additions and 69 deletions

View File

@@ -4001,6 +4001,8 @@ merge(Compressor.prototype, {
}; };
// pass 3: we should drop declarations not in_use // pass 3: we should drop declarations not in_use
var unused_fn_names = []; var unused_fn_names = [];
var calls_to_drop_args = [];
var fns_with_marked_args = [];
var tt = new TreeTransformer(function(node, descend, in_list) { var tt = new TreeTransformer(function(node, descend, in_list) {
var parent = tt.parent(); var parent = tt.parent();
if (drop_vars) { if (drop_vars) {
@@ -4041,6 +4043,7 @@ merge(Compressor.prototype, {
} }
} }
} }
if (node instanceof AST_Call) calls_to_drop_args.push(node);
if (scope !== self) return; if (scope !== self) return;
if (node instanceof AST_Function && node.name && drop_fn_name(node.name.definition())) { if (node instanceof AST_Function && node.name && drop_fn_name(node.name.definition())) {
unused_fn_names.push(node); unused_fn_names.push(node);
@@ -4059,6 +4062,7 @@ merge(Compressor.prototype, {
trim = false; trim = false;
} }
} }
fns_with_marked_args.push(node);
} }
if (drop_funcs && node instanceof AST_Defun && node !== self) { if (drop_funcs && node instanceof AST_Defun && node !== self) {
var def = node.name.definition(); var def = node.name.definition();
@@ -4252,6 +4256,9 @@ merge(Compressor.prototype, {
unused_fn_names.forEach(function(fn) { unused_fn_names.forEach(function(fn) {
fn.name = null; fn.name = null;
}); });
calls_to_drop_args.forEach(function(call) {
drop_unused_call_args(call, compressor, fns_with_marked_args);
});
function log(sym, text, props) { function log(sym, text, props) {
AST_Node[sym.unreferenced() ? "warn" : "info"](text, props); AST_Node[sym.unreferenced() ? "warn" : "info"](text, props);
@@ -5448,6 +5455,62 @@ merge(Compressor.prototype, {
return make_sequence(node, x); return make_sequence(node, x);
} }
function drop_unused_call_args(call, compressor, fns_with_marked_args) {
var exp = call.expression;
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
if (!(fn instanceof AST_Lambda)) return;
if (fn.uses_arguments) return;
if (fn.pinned()) return;
if (fns_with_marked_args && fns_with_marked_args.indexOf(fn) < 0) return;
var args = call.args;
var pos = 0, last = 0;
var drop_fargs = fn === exp && !fn.name && compressor.drop_fargs(fn, call);
var side_effects = [];
for (var i = 0; i < args.length; i++) {
var trim = i >= fn.argnames.length;
if (trim || fn.argnames[i].__unused) {
var node = args[i].drop_side_effect_free(compressor);
if (drop_fargs) {
fn.argnames.splice(i, 1);
args.splice(i, 1);
if (node) side_effects.push(node);
i--;
continue;
} else if (node) {
side_effects.push(node);
args[pos++] = make_sequence(call, side_effects);
side_effects = [];
} else if (!trim) {
if (side_effects.length) {
node = make_sequence(call, side_effects);
side_effects = [];
} else {
node = make_node(AST_Number, args[i], {
value: 0
});
}
args[pos++] = node;
continue;
}
} else {
side_effects.push(args[i]);
args[pos++] = make_sequence(call, side_effects);
side_effects = [];
}
last = pos;
}
if (drop_fargs) for (; i < fn.argnames.length; i++) {
if (fn.argnames[i].__unused) fn.argnames.splice(i--, 1);
}
args.length = last;
if (!side_effects.length) return;
var arg = make_sequence(call, side_effects);
args.push(args.length < fn.argnames.length ? make_node(AST_UnaryPrefix, call, {
operator: "void",
expression: arg
}) : arg);
}
OPT(AST_Call, function(self, compressor) { OPT(AST_Call, function(self, compressor) {
var exp = self.expression; var exp = self.expression;
if (compressor.option("sequences")) { if (compressor.option("sequences")) {
@@ -5464,63 +5527,7 @@ merge(Compressor.prototype, {
if (seq !== self) return seq.optimize(compressor); if (seq !== self) return seq.optimize(compressor);
} }
} }
var fn = exp; if (compressor.option("unused")) drop_unused_call_args(self, compressor);
if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) {
fn = fn.fixed_value();
}
var is_func = fn instanceof AST_Lambda;
if (compressor.option("unused")
&& is_func
&& !fn.uses_arguments
&& !fn.pinned()) {
var pos = 0, last = 0;
var drop_fargs = exp === fn && !fn.name && compressor.drop_fargs(fn, self);
var side_effects = [];
for (var i = 0; i < self.args.length; i++) {
var trim = i >= fn.argnames.length;
if (trim || fn.argnames[i].__unused) {
var node = self.args[i].drop_side_effect_free(compressor);
if (drop_fargs) {
fn.argnames.splice(i, 1);
self.args.splice(i, 1);
if (node) side_effects.push(node);
i--;
continue;
} else if (node) {
side_effects.push(node);
self.args[pos++] = make_sequence(self, side_effects);
side_effects = [];
} else if (!trim) {
if (side_effects.length) {
node = make_sequence(self, side_effects);
side_effects = [];
} else {
node = make_node(AST_Number, self.args[i], {
value: 0
});
}
self.args[pos++] = node;
continue;
}
} else {
side_effects.push(self.args[i]);
self.args[pos++] = make_sequence(self, side_effects);
side_effects = [];
}
last = pos;
}
if (drop_fargs) for (; i < fn.argnames.length; i++) {
if (fn.argnames[i].__unused) fn.argnames.splice(i--, 1);
}
self.args.length = last;
if (side_effects.length) {
var arg = make_sequence(self, side_effects);
self.args.push(self.args.length < fn.argnames.length ? make_node(AST_UnaryPrefix, self, {
operator: "void",
expression: arg
}) : arg);
}
}
if (compressor.option("unsafe")) { if (compressor.option("unsafe")) {
if (is_undeclared_ref(exp)) switch (exp.name) { if (is_undeclared_ref(exp)) switch (exp.name) {
case "Array": case "Array":
@@ -5786,6 +5793,8 @@ merge(Compressor.prototype, {
} }
} }
} }
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
var is_func = fn instanceof AST_Lambda;
var stat = is_func && fn.first_statement(); var stat = is_func && fn.first_statement();
var can_inline = compressor.option("inline") && !self.is_expr_pure(compressor); var can_inline = compressor.option("inline") && !self.is_expr_pure(compressor);
if (exp === fn && can_inline && stat instanceof AST_Return) { if (exp === fn && can_inline && stat instanceof AST_Return) {

View File

@@ -1191,10 +1191,10 @@ issue_2105_1: {
input: { input: {
!function(factory) { !function(factory) {
factory(); factory();
}( function() { }(function() {
return function(fn) { return function(fn) {
fn()().prop(); fn()().prop();
}( function() { }(function() {
function bar() { function bar() {
var quux = function() { var quux = function() {
console.log("PASS"); console.log("PASS");
@@ -1205,7 +1205,7 @@ issue_2105_1: {
return { prop: foo }; return { prop: foo };
} }
return bar; return bar;
} ); });
}); });
} }
expect: { expect: {
@@ -1235,10 +1235,10 @@ issue_2105_2: {
input: { input: {
!function(factory) { !function(factory) {
factory(); factory();
}( function() { }(function() {
return function(fn) { return function(fn) {
fn()().prop(); fn()().prop();
}( function() { }(function() {
function bar() { function bar() {
var quux = function() { var quux = function() {
console.log("PASS"); console.log("PASS");
@@ -1249,7 +1249,7 @@ issue_2105_2: {
return { prop: foo }; return { prop: foo };
} }
return bar; return bar;
} ); });
}); });
} }
expect: { expect: {
@@ -1258,6 +1258,44 @@ issue_2105_2: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_2105_3: {
options = {
inline: true,
passes: 2,
reduce_vars: true,
unused: true,
}
input: {
!function(factory) {
factory();
}(function() {
return function(fn) {
fn()().prop();
}(function() {
function bar() {
var quux = function() {
console.log("PASS");
}, foo = function() {
console.log;
quux();
};
return { prop: foo };
}
return bar;
});
});
}
expect: {
!void void {
prop: function() {
console.log;
void console.log("PASS");
}
}.prop();
}
expect_stdout: "PASS"
}
issue_2226_1: { issue_2226_1: {
options = { options = {
side_effects: true, side_effects: true,
@@ -2330,7 +2368,7 @@ function_parameter_ie8: {
(function() { (function() {
(function f() { (function f() {
console.log("PASS"); console.log("PASS");
})(0); })();
})(); })();
} }
expect_stdout: "PASS" expect_stdout: "PASS"

View File

@@ -1276,7 +1276,7 @@ issue_2630_3: {
(function() { (function() {
(function f1(a) { (function f1(a) {
f2(); f2();
--x >= 0 && f1({}); --x >= 0 && f1();
})(a++); })(a++);
function f2() { function f2() {
a++; a++;

View File

@@ -728,7 +728,7 @@ issue_2630_3: {
(function() { (function() {
(function f1() { (function f1() {
f2(); f2();
--x >= 0 && f1({}); --x >= 0 && f1();
})(a++); })(a++);
function f2() { function f2() {
a++; a++;
@@ -1369,7 +1369,7 @@ recursive_iife_1: {
} }
expect: { expect: {
console.log(function f(a, b) { console.log(function f(a, b) {
return b || f("FAIL", "PASS"); return b || f(0, "PASS");
}()); }());
} }
expect_stdout: "PASS" expect_stdout: "PASS"
@@ -1388,7 +1388,7 @@ recursive_iife_2: {
} }
expect: { expect: {
console.log(function f(a, b) { console.log(function f(a, b) {
return b || f("FAIL", "PASS"); return b || f(0, "PASS");
}(0, 0)); }(0, 0));
} }
expect_stdout: "PASS" expect_stdout: "PASS"
@@ -1416,7 +1416,7 @@ recursive_iife_3: {
var a = 1, c = "PASS"; var a = 1, c = "PASS";
(function() { (function() {
(function f(b, d, e) { (function f(b, d, e) {
a-- && f(null, 42, 0); a-- && f(0, 42, 0);
e && (c = "FAIL"); e && (c = "FAIL");
d && d.p; d && d.p;
})(); })();