Skip to content

Commit b633706

Browse files
authored
fix & improve function argument compression (#1584)
- one-use function call => IIFE should take `eval()` & `arguments` into account - if unused parameter cannot be eliminated, replace it with `0` fixes #1583
1 parent e9920f7 commit b633706

File tree

3 files changed

+171
-13
lines changed

3 files changed

+171
-13
lines changed

lib/compress.js

+33-13
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,9 @@ merge(Compressor.prototype, {
281281
if (node instanceof AST_Function
282282
&& (iife = tw.parent()) instanceof AST_Call
283283
&& iife.expression === node) {
284+
// Virtually turn IIFE parameters into variable definitions:
285+
// (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
286+
// So existing transformation rules can work on them.
284287
node.argnames.forEach(function(arg, i) {
285288
var d = arg.definition();
286289
d.fixed = iife.args[i] || make_node(AST_Undefined, iife);
@@ -1810,10 +1813,12 @@ merge(Compressor.prototype, {
18101813
node.name = null;
18111814
}
18121815
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
1813-
if (!compressor.option("keep_fargs")) {
1814-
for (var a = node.argnames, i = a.length; --i >= 0;) {
1815-
var sym = a[i];
1816-
if (!(sym.definition().id in in_use_ids)) {
1816+
var trim = !compressor.option("keep_fargs");
1817+
for (var a = node.argnames, i = a.length; --i >= 0;) {
1818+
var sym = a[i];
1819+
if (!(sym.definition().id in in_use_ids)) {
1820+
sym.__unused = true;
1821+
if (trim) {
18171822
a.pop();
18181823
compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", {
18191824
name : sym.name,
@@ -1822,7 +1827,9 @@ merge(Compressor.prototype, {
18221827
col : sym.start.col
18231828
});
18241829
}
1825-
else break;
1830+
}
1831+
else {
1832+
trim = false;
18261833
}
18271834
}
18281835
}
@@ -2609,6 +2616,9 @@ merge(Compressor.prototype, {
26092616
exp = def.fixed;
26102617
if (compressor.option("unused")
26112618
&& def.references.length == 1
2619+
&& !(def.scope.uses_arguments
2620+
&& def.orig[0] instanceof AST_SymbolFunarg)
2621+
&& !def.scope.uses_eval
26122622
&& compressor.find_parent(AST_Scope) === def.scope) {
26132623
self.expression = exp;
26142624
}
@@ -2617,16 +2627,26 @@ merge(Compressor.prototype, {
26172627
if (compressor.option("unused")
26182628
&& exp instanceof AST_Function
26192629
&& !exp.uses_arguments
2620-
&& !exp.uses_eval
2621-
&& self.args.length > exp.argnames.length) {
2622-
var end = exp.argnames.length;
2623-
for (var i = end, len = self.args.length; i < len; i++) {
2624-
var node = self.args[i].drop_side_effect_free(compressor);
2625-
if (node) {
2626-
self.args[end++] = node;
2630+
&& !exp.uses_eval) {
2631+
var pos = 0, last = 0;
2632+
for (var i = 0, len = self.args.length; i < len; i++) {
2633+
var trim = i >= exp.argnames.length;
2634+
if (trim || exp.argnames[i].__unused) {
2635+
var node = self.args[i].drop_side_effect_free(compressor);
2636+
if (node) {
2637+
self.args[pos++] = node;
2638+
} else if (!trim) {
2639+
self.args[pos++] = make_node(AST_Number, self.args[i], {
2640+
value: 0
2641+
});
2642+
continue;
2643+
}
2644+
} else {
2645+
self.args[pos++] = self.args[i];
26272646
}
2647+
last = pos;
26282648
}
2629-
self.args.length = end;
2649+
self.args.length = last;
26302650
}
26312651
if (compressor.option("unsafe")) {
26322652
if (exp instanceof AST_SymbolRef && exp.undeclared()) {

test/compress/drop-unused.js

+30
Original file line numberDiff line numberDiff line change
@@ -761,3 +761,33 @@ assign_chain: {
761761
}
762762
}
763763
}
764+
765+
issue_1583: {
766+
options = {
767+
keep_fargs: true,
768+
reduce_vars: true,
769+
unused: true,
770+
}
771+
input: {
772+
function m(t) {
773+
(function(e) {
774+
t = e();
775+
})(function() {
776+
return (function(a) {
777+
return a;
778+
})(function(a) {});
779+
});
780+
}
781+
}
782+
expect: {
783+
function m(t) {
784+
(function(e) {
785+
t = (function() {
786+
return (function(a) {
787+
return a;
788+
})(function(a) {});
789+
})();
790+
})();
791+
}
792+
}
793+
}

test/compress/reduce_vars.js

+108
Original file line numberDiff line numberDiff line change
@@ -1144,3 +1144,111 @@ double_reference: {
11441144
}
11451145
}
11461146
}
1147+
1148+
iife_arguments_1: {
1149+
options = {
1150+
reduce_vars: true,
1151+
unused: true,
1152+
}
1153+
input: {
1154+
(function(x) {
1155+
console.log(x() === arguments[0]);
1156+
})(function f() {
1157+
return f;
1158+
});
1159+
}
1160+
expect: {
1161+
(function(x) {
1162+
console.log(x() === arguments[0]);
1163+
})(function f() {
1164+
return f;
1165+
});
1166+
}
1167+
}
1168+
1169+
iife_arguments_2: {
1170+
options = {
1171+
reduce_vars: true,
1172+
unused: true,
1173+
}
1174+
input: {
1175+
(function() {
1176+
var x = function f() {
1177+
return f;
1178+
};
1179+
console.log(x() === arguments[0]);
1180+
})();
1181+
}
1182+
expect: {
1183+
(function() {
1184+
console.log(function f() {
1185+
return f;
1186+
}() === arguments[0]);
1187+
})();
1188+
}
1189+
}
1190+
1191+
iife_eval_1: {
1192+
options = {
1193+
reduce_vars: true,
1194+
unused: true,
1195+
}
1196+
input: {
1197+
(function(x) {
1198+
console.log(x() === eval("x"));
1199+
})(function f() {
1200+
return f;
1201+
});
1202+
}
1203+
expect: {
1204+
(function(x) {
1205+
console.log(x() === eval("x"));
1206+
})(function f() {
1207+
return f;
1208+
});
1209+
}
1210+
}
1211+
1212+
iife_eval_2: {
1213+
options = {
1214+
reduce_vars: true,
1215+
unused: true,
1216+
}
1217+
input: {
1218+
(function() {
1219+
var x = function f() {
1220+
return f;
1221+
};
1222+
console.log(x() === eval("x"));
1223+
})();
1224+
}
1225+
expect: {
1226+
(function() {
1227+
var x = function f() {
1228+
return f;
1229+
};
1230+
console.log(x() === eval("x"));
1231+
})();
1232+
}
1233+
}
1234+
1235+
iife_func_side_effects: {
1236+
options = {
1237+
reduce_vars: true,
1238+
unused: true,
1239+
}
1240+
input: {
1241+
(function(a, b, c) {
1242+
return b();
1243+
})(x(), function() {
1244+
return y();
1245+
}, z());
1246+
}
1247+
expect: {
1248+
(function(a, b, c) {
1249+
return function() {
1250+
return y();
1251+
}();
1252+
})(x(), 0, z());
1253+
}
1254+
}

0 commit comments

Comments
 (0)