support rest parameters (#4515)

This commit is contained in:
Alex Lam S.L
2021-01-07 02:04:09 +00:00
committed by GitHub
parent 68497d0258
commit c3d358a5b8
12 changed files with 819 additions and 135 deletions

View File

@@ -81,13 +81,14 @@ function Compressor(options, false_by_default) {
objects : !false_by_default,
passes : 1,
properties : !false_by_default,
pure_getters : !false_by_default && "strict",
pure_funcs : null,
pure_getters : !false_by_default && "strict",
reduce_funcs : !false_by_default,
reduce_vars : !false_by_default,
rests : !false_by_default,
sequences : !false_by_default,
side_effects : !false_by_default,
spread : !false_by_default,
spreads : !false_by_default,
strings : !false_by_default,
switches : !false_by_default,
top_retain : null,
@@ -609,7 +610,7 @@ merge(Compressor.prototype, {
});
}
function scan_declaration(tw, lhs, fixed, visit) {
function scan_declaration(tw, compressor, lhs, fixed, visit) {
var scanner = new TreeWalker(function(node) {
if (node instanceof AST_DefaultValue) {
reset_flags(node);
@@ -640,6 +641,15 @@ merge(Compressor.prototype, {
};
node.walk(scanner);
});
if (node.rest) {
fixed = compressor.option("rests") && function() {
var value = save();
return value instanceof AST_Array ? make_node(AST_Array, node, {
elements: value.elements.slice(node.elements.length),
}) : node.rest;
};
node.rest.walk(scanner);
}
fixed = save;
return true;
}
@@ -670,6 +680,10 @@ merge(Compressor.prototype, {
};
node.value.walk(scanner);
});
if (node.rest) {
fixed = false;
node.rest.walk(scanner);
}
fixed = save;
return true;
}
@@ -719,12 +733,12 @@ merge(Compressor.prototype, {
var safe = !fn.uses_arguments || tw.has_directive("use strict");
fn.argnames.forEach(function(arg, i) {
var value = iife.args[i];
scan_declaration(tw, arg, function() {
scan_declaration(tw, compressor, arg, function() {
var j = fn.argnames.indexOf(arg);
return (j < 0 ? value : iife.args[j]) || make_node(AST_Undefined, iife);
}, function(node, fixed) {
var d = node.definition();
if (safe && d.fixed === undefined) {
if (fixed && safe && d.fixed === undefined) {
mark(tw, d);
tw.loop_ids[d.id] = tw.in_loop;
var value = iife.args[i];
@@ -759,7 +773,7 @@ merge(Compressor.prototype, {
return;
} else if (node.operator == "=") {
node.right.walk(tw);
scan_declaration(tw, left, function() {
scan_declaration(tw, compressor, left, function() {
return node.right;
}, function(sym, fixed, walk) {
if (!(sym instanceof AST_SymbolRef)) {
@@ -769,7 +783,7 @@ merge(Compressor.prototype, {
}
var d = sym.definition();
d.assignments++;
if (!is_modified(compressor, tw, node, node.right, 0) && safe_to_assign(tw, d)) {
if (fixed && !is_modified(compressor, tw, node, node.right, 0) && safe_to_assign(tw, d)) {
push_ref(d, sym);
mark(tw, d);
if (d.single_use && left instanceof AST_Destructured) d.single_use = false;
@@ -1135,15 +1149,15 @@ merge(Compressor.prototype, {
}
return true;
});
def(AST_VarDef, function(tw) {
def(AST_VarDef, function(tw, descend, compressor) {
var node = this;
if (!node.value) return;
node.value.walk(tw);
scan_declaration(tw, node.name, function() {
scan_declaration(tw, compressor, node.name, function() {
return node.value;
}, function(name, fixed) {
var d = name.definition();
if (safe_to_assign(tw, d, true)) {
if (fixed && safe_to_assign(tw, d, true)) {
mark(tw, d);
tw.loop_ids[d.id] = tw.in_loop;
d.fixed = fixed;
@@ -5097,6 +5111,7 @@ merge(Compressor.prototype, {
node.argnames.forEach(function(argname) {
argname.mark_symbol(marker, scanner);
});
if (node.rest) node.rest.mark_symbol(marker, scanner);
}
if (node instanceof AST_Arrow && node.value) {
node.value.walk(tw);
@@ -5513,8 +5528,9 @@ merge(Compressor.prototype, {
var fns_with_marked_args = [];
var trimmer = new TreeTransformer(function(node) {
if (node instanceof AST_DefaultValue) return trim_default(trimmer, node);
if (node instanceof AST_Destructured && node.rest) node.rest = node.rest.transform(trimmer);
if (node instanceof AST_DestructuredArray) {
var trim = true;
var trim = !node.rest;
for (var i = node.elements.length; --i >= 0;) {
var element = node.elements[i].transform(trimmer);
if (element) {
@@ -5528,19 +5544,33 @@ merge(Compressor.prototype, {
}
return node;
}
if (node instanceof AST_DestructuredKeyVal) {
var retain = false;
if (node.key instanceof AST_Node) {
node.key = node.key.transform(tt);
retain = node.key.has_side_effects(compressor);
}
if (retain && is_decl(node.value)) {
node.value = node.value.transform(tt);
} else {
var value = node.value.transform(trimmer);
if (!value) return List.skip;
node.value = value;
}
if (node instanceof AST_DestructuredObject) {
var properties = [];
node.properties.forEach(function(prop) {
var retain = false;
if (prop.key instanceof AST_Node) {
prop.key = prop.key.transform(tt);
retain = prop.key.has_side_effects(compressor);
}
if ((retain || node.rest) && is_decl(prop.value)) {
prop.value = prop.value.transform(tt);
properties.push(prop);
} else {
var value = prop.value.transform(trimmer);
if (!value && node.rest) {
if (prop.value instanceof AST_DestructuredArray) {
value = make_node(AST_DestructuredArray, prop.value, { elements: [] });
} else {
value = make_node(AST_DestructuredObject, prop.value, { properties: [] });
}
}
if (value) {
prop.value = value;
properties.push(prop);
}
}
});
node.properties = properties;
return node;
}
if (node instanceof AST_SymbolDeclaration) return node.definition().id in in_use_ids ? node : null;
@@ -5607,7 +5637,7 @@ merge(Compressor.prototype, {
unused_fn_names.push(node);
}
if (!(node instanceof AST_Accessor)) {
var trim = compressor.drop_fargs(node, parent);
var trim = compressor.drop_fargs(node, parent) && !node.rest;
for (var a = node.argnames, i = a.length; --i >= 0;) {
var sym = a[i];
if (!(sym instanceof AST_SymbolFunarg)) {
@@ -5634,6 +5664,13 @@ merge(Compressor.prototype, {
sym.__unused = true;
}
}
if (node.rest) {
node.rest = node.rest.transform(trimmer);
if (node.rest instanceof AST_DestructuredArray && node.rest.elements.length == 0
|| node.rest instanceof AST_DestructuredObject && node.rest.properties.length == 0) {
node.rest = null;
}
}
fns_with_marked_args.push(node);
}
}
@@ -6149,8 +6186,22 @@ merge(Compressor.prototype, {
element = element.transform(trimmer);
if (element) elements[index] = element;
});
if (node.rest) {
if (compressor.option("rests")) {
value = values && make_node(AST_Array, save, {
elements: values.slice(node.elements.length),
});
node.rest = node.rest.transform(trimmer);
} else {
node.rest = node.rest.transform(tt);
}
}
value = save;
if (values && elements.length == 0) return null;
if (node.rest) {
elements.length = node.elements.length;
} else if (values && elements.length == 0) {
return null;
}
fill_holes(node, elements);
node.elements = elements;
return node;
@@ -6181,19 +6232,36 @@ merge(Compressor.prototype, {
value = values && values[prop.key];
retain = false;
}
if (retain && is_decl(prop.value)) {
if ((retain || node.rest) && is_decl(prop.value)) {
prop.value = prop.value.transform(tt);
properties.push(prop);
} else {
var newValue = prop.value.transform(trimmer);
if (!newValue && node.rest) {
if (prop.value instanceof AST_DestructuredArray) {
newValue = make_node(AST_DestructuredArray, prop.value, { elements: [] });
} else {
newValue = make_node(AST_DestructuredObject, prop.value, { properties: [] });
}
}
if (newValue) {
prop.value = newValue;
properties.push(prop);
}
}
});
if (node.rest) {
if (compressor.option("rests")) {
value = values && make_node(AST_Object, save, {
properties: [],
});
node.rest = node.rest.transform(trimmer);
} else {
node.rest = node.rest.transform(tt);
}
}
value = save;
if (properties.length == 0 && value && !value.may_throw_on_access(compressor)) {
if (properties.length == 0 && !node.rest && value && !value.may_throw_on_access(compressor)) {
return null;
}
node.properties = properties;
@@ -7704,16 +7772,26 @@ merge(Compressor.prototype, {
if (!all(args, function(arg) {
return !(arg instanceof AST_Spread);
})) return;
if (fn.rest) {
if (!compressor.option("rests")) return;
var insert = fn.argnames.length;
for (var i = args.length; i < insert; i++) {
args[i] = make_node(AST_Undefined, call).optimize(compressor);
}
args[insert] = make_node(AST_Array, call, { elements: args.splice(insert) });
fn.argnames.push(fn.rest);
fn.rest = null;
}
var pos = 0, last = 0;
var is_iife = fn === exp && !fn.name;
var drop_defaults = is_iife && compressor.option("default_values");
var drop_fargs = is_iife && compressor.drop_fargs(fn, call) ? function(argname, arg) {
if (!argname) return true;
if (argname instanceof AST_DestructuredArray) {
return argname.elements.length == 0 && arg instanceof AST_Array;
return argname.elements.length == 0 && !argname.rest && arg instanceof AST_Array;
}
if (argname instanceof AST_DestructuredObject) {
return argname.properties.length == 0 && arg && !arg.may_throw_on_access(compressor);
return argname.properties.length == 0 && !argname.rest && arg && !arg.may_throw_on_access(compressor);
}
return argname.__unused;
} : return_false;
@@ -8311,7 +8389,7 @@ merge(Compressor.prototype, {
}
function can_substitute_directly() {
if (has_default || has_destructured || var_assigned) return;
if (has_default || has_destructured || var_assigned || fn.rest) return;
if (compressor.option("inline") < 2 && fn.argnames.length) return;
if (!fn.variables.all(function(def) {
return def.references.length - def.replaced < 2 && def.orig[0] instanceof AST_SymbolFunarg;
@@ -8526,15 +8604,18 @@ merge(Compressor.prototype, {
operator: "=",
left: make_node(AST_DestructuredArray, self, {
elements: fn.argnames.map(function(argname) {
return argname.convert_symbol(AST_SymbolRef, function(ref, name) {
var symbol = make_node(AST_SymbolVar, name, name);
name.definition().orig.push(symbol);
append_var(decls, expressions, symbol);
});
return argname.convert_symbol(AST_SymbolRef, process);
}),
rest: fn.rest && fn.rest.convert_symbol(AST_SymbolRef, process),
}),
right: make_node(AST_Array, self, { elements: self.args.slice() }),
}));
function process(ref, name) {
var symbol = make_node(AST_SymbolVar, name, name);
name.definition().orig.push(symbol);
append_var(decls, expressions, symbol);
}
}
function flatten_vars(decls, expressions) {
@@ -8568,7 +8649,7 @@ merge(Compressor.prototype, {
function flatten_fn() {
var decls = [];
var expressions = [];
if (has_default > 1 || has_destructured) {
if (has_default > 1 || has_destructured || fn.rest) {
flatten_destructured(decls, expressions);
} else {
flatten_args(decls, expressions);
@@ -10308,7 +10389,7 @@ merge(Compressor.prototype, {
OPT(AST_Spread, function(self, compressor) {
var exp = self.expression;
if (compressor.option("spread") && exp instanceof AST_Array && !(compressor.parent() instanceof AST_Object)) {
if (compressor.option("spreads") && exp instanceof AST_Array && !(compressor.parent() instanceof AST_Object)) {
return List.splice(exp.elements.map(function(node) {
return node instanceof AST_Hole ? make_node(AST_Undefined, node).optimize(compressor) : node;
}));
@@ -10392,7 +10473,7 @@ merge(Compressor.prototype, {
argname = null;
}
}
} else if (index < fn.argnames.length + 5 && compressor.drop_fargs(fn, fn_parent)) {
} else if (index < fn.argnames.length + 5 && compressor.drop_fargs(fn, fn_parent) && !fn.rest) {
while (index >= fn.argnames.length) {
argname = fn.make_var(AST_SymbolFunarg, fn, "argument_" + fn.argnames.length);
fn.argnames.push(argname);
@@ -10603,7 +10684,7 @@ merge(Compressor.prototype, {
if (!(prop instanceof AST_Spread)) return process(prop);
found = true;
var exp = prop.expression;
if (compressor.option("spread") && exp instanceof AST_Object && all(exp.properties, function(prop) {
if (compressor.option("spreads") && exp instanceof AST_Object && all(exp.properties, function(prop) {
return !(prop instanceof AST_ObjectGetter || prop instanceof AST_Spread);
})) {
changed = true;