enhance functions & reduce_vars (#5045)

This commit is contained in:
Alex Lam S.L
2021-07-03 23:19:08 +01:00
committed by GitHub
parent 668f96623c
commit 972b9f0bef
9 changed files with 288 additions and 162 deletions

View File

@@ -484,9 +484,21 @@ merge(Compressor.prototype, {
def.single_use = undefined; def.single_use = undefined;
} }
function reset_variables(tw, compressor, scope) { function reset_block_variables(tw, compressor, scope) {
scope.variables.each(function(def) { scope.variables.each(function(def) {
reset_def(tw, compressor, def); reset_def(tw, compressor, def);
});
}
function reset_variables(tw, compressor, scope) {
scope.fn_defs = [];
scope.variables.each(function(def) {
reset_def(tw, compressor, def);
var init = def.init;
if (init instanceof AST_LambdaDefinition) {
scope.fn_defs.push(init);
init.safe_ids = null;
}
if (def.fixed === null) { if (def.fixed === null) {
def.safe_ids = tw.safe_ids; def.safe_ids = tw.safe_ids;
mark(tw, def); mark(tw, def);
@@ -496,13 +508,7 @@ merge(Compressor.prototype, {
} }
}); });
scope.may_call_this = function() { scope.may_call_this = function() {
scope.may_call_this = noop; scope.may_call_this = scope.contains_this() ? return_true : return_false;
if (!scope.contains_this()) return;
scope.functions.each(function(def) {
if (def.init instanceof AST_LambdaDefinition && !(def.id in tw.defun_ids)) {
tw.defun_ids[def.id] = false;
}
});
}; };
if (scope.uses_arguments) scope.each_argname(function(node) { if (scope.uses_arguments) scope.each_argname(function(node) {
node.definition().last_ref = false; node.definition().last_ref = false;
@@ -513,39 +519,56 @@ merge(Compressor.prototype, {
}); });
} }
function mark_defun(tw, def) { function mark_fn_def(tw, def, fn) {
if (def.id in tw.defun_ids) { if (!HOP(fn, "safe_ids")) return;
var marker = tw.defun_ids[def.id]; var marker = fn.safe_ids;
if (!marker) return; if (marker === false) return;
var visited = tw.defun_visited[def.id]; if (fn.parent_scope.resolve().may_call_this === return_true) return;
if (marker === tw.safe_ids) return !visited && def.fixed; if (marker) {
var visited = member(fn, tw.fn_visited);
if (marker === tw.safe_ids) return !visited && fn;
if (visited) { if (visited) {
def.init.enclosed.forEach(function(d) { fn.enclosed.forEach(function(d) {
if (def.init.variables.get(d.name) === d) return; if (fn.variables.get(d.name) === d) return;
if (!safe_to_read(tw, d)) d.fixed = false; if (safe_to_read(tw, d)) return;
d.single_use = false;
if (d.fixed instanceof AST_LambdaDefinition) return;
d.fixed = false;
}); });
return; return;
} }
} else if (!tw.in_loop) { } else if (!tw.in_loop && !(tw.fn_scanning && tw.fn_scanning !== def.scope.resolve())) {
var scope = def.scope; fn.safe_ids = tw.safe_ids;
var s = tw.find_parent(AST_Scope); return fn;
do {
if (s === scope) {
tw.defun_ids[def.id] = tw.safe_ids;
return def.fixed;
} }
} while (s instanceof AST_LambdaExpression && (s = s.parent_scope.resolve())); fn.safe_ids = false;
}
tw.defun_ids[def.id] = false;
} }
function walk_defuns(tw, scope) { function walk_fn_def(tw, fn) {
scope.functions.each(function(def) { var was_scanning = tw.fn_scanning;
if (def.init instanceof AST_LambdaDefinition && !tw.defun_visited[def.id]) { tw.fn_scanning = fn;
tw.defun_ids[def.id] = tw.safe_ids; fn.walk(tw);
def.init.walk(tw); tw.fn_scanning = was_scanning;
} }
function pop_scope(tw, scope) {
var fn_defs = scope.fn_defs;
var tangled = scope.may_call_this === return_true ? fn_defs : fn_defs.filter(function(fn) {
if (fn.safe_ids === false) return true;
fn.safe_ids = tw.safe_ids;
walk_fn_def(tw, fn);
return false;
}); });
pop(tw);
tangled.forEach(function(fn) {
fn.safe_ids = tw.safe_ids;
walk_fn_def(tw, fn);
});
fn_defs.forEach(function(fn) {
delete fn.safe_ids;
});
delete scope.fn_defs;
delete scope.may_call_this;
} }
function push(tw) { function push(tw) {
@@ -592,13 +615,13 @@ merge(Compressor.prototype, {
if (def.fixed === undefined) return declare || all(def.orig, function(sym) { if (def.fixed === undefined) return declare || all(def.orig, function(sym) {
return !(sym instanceof AST_SymbolLet); return !(sym instanceof AST_SymbolLet);
}); });
if (def.fixed === null && def.safe_ids) {
def.safe_ids[def.id] = false;
delete def.safe_ids;
return true;
}
if (def.fixed === false) return false; if (def.fixed === false) return false;
var safe = tw.safe_ids[def.id]; var safe = tw.safe_ids[def.id];
if (def.safe_ids) {
def.safe_ids[def.id] = false;
delete def.safe_ids;
return def.fixed === null || HOP(tw.safe_ids, def.id) && !safe.read;
}
if (!HOP(tw.safe_ids, def.id)) { if (!HOP(tw.safe_ids, def.id)) {
if (!safe) return false; if (!safe) return false;
if (safe.read) { if (safe.read) {
@@ -813,8 +836,7 @@ merge(Compressor.prototype, {
}, visit); }, visit);
walk_lambda(fn, tw); walk_lambda(fn, tw);
var safe_ids = tw.safe_ids; var safe_ids = tw.safe_ids;
pop(tw); pop_scope(tw, fn);
walk_defuns(tw, fn);
if (!aborts) tw.safe_ids = safe_ids; if (!aborts) tw.safe_ids = safe_ids;
return true; return true;
@@ -835,7 +857,8 @@ merge(Compressor.prototype, {
var node = this; var node = this;
var left = node.left; var left = node.left;
var right = node.right; var right = node.right;
var scan = left instanceof AST_Destructured || left instanceof AST_SymbolRef; var ld = left instanceof AST_SymbolRef && left.definition();
var scan = ld || left instanceof AST_Destructured;
switch (node.operator) { switch (node.operator) {
case "=": case "=":
if (left.equivalent_to(right) && !left.has_side_effects(compressor)) { if (left.equivalent_to(right) && !left.has_side_effects(compressor)) {
@@ -844,7 +867,17 @@ merge(Compressor.prototype, {
node.__drop = true; node.__drop = true;
return true; return true;
} }
if (scan) { if (ld && right instanceof AST_LambdaExpression) {
walk_assign();
if (ld.escaped.length) {
right.walk(tw);
} else {
right.parent_scope.resolve().fn_defs.push(right);
right.safe_ids = null;
}
return true;
} else if (scan) {
right.walk(tw);
walk_assign(); walk_assign();
return true; return true;
} }
@@ -856,6 +889,7 @@ merge(Compressor.prototype, {
left.walk(tw); left.walk(tw);
push(tw); push(tw);
if (scan) { if (scan) {
right.walk(tw);
walk_assign(); walk_assign();
} else { } else {
mark_assignment_to_arguments(left); mark_assignment_to_arguments(left);
@@ -868,20 +902,19 @@ merge(Compressor.prototype, {
mark_assignment_to_arguments(left); mark_assignment_to_arguments(left);
return; return;
} }
var d = left.definition(); ld.assignments++;
d.assignments++; var fixed = ld.fixed;
var fixed = d.fixed;
if (is_modified(compressor, tw, node, node, 0)) { if (is_modified(compressor, tw, node, node, 0)) {
d.fixed = false; ld.fixed = false;
return; return;
} }
var safe = safe_to_read(tw, d); var safe = safe_to_read(tw, ld);
right.walk(tw); right.walk(tw);
if (safe && !left.in_arg && safe_to_assign(tw, d)) { if (safe && !left.in_arg && safe_to_assign(tw, ld)) {
push_ref(d, left); push_ref(ld, left);
mark(tw, d); mark(tw, ld);
if (d.single_use) d.single_use = false; if (ld.single_use) ld.single_use = false;
left.fixed = d.fixed = function() { left.fixed = ld.fixed = function() {
return make_node(AST_Binary, node, { return make_node(AST_Binary, node, {
operator: node.operator.slice(0, -1), operator: node.operator.slice(0, -1),
left: make_ref(left, fixed), left: make_ref(left, fixed),
@@ -892,7 +925,7 @@ merge(Compressor.prototype, {
left.fixed.assigns.push(node); left.fixed.assigns.push(node);
} else { } else {
left.walk(tw); left.walk(tw);
d.fixed = false; ld.fixed = false;
} }
return true; return true;
} }
@@ -920,8 +953,8 @@ merge(Compressor.prototype, {
} }
function walk_assign() { function walk_assign() {
right.walk(tw); var recursive = ld && recursive_ref(tw, ld);
var modified = is_modified(compressor, tw, node, right, 0, is_immutable(right), recursive_ref(tw, d)); var modified = is_modified(compressor, tw, node, right, 0, is_immutable(right), recursive);
scan_declaration(tw, compressor, left, function() { scan_declaration(tw, compressor, left, function() {
return node.right; return node.right;
}, function(sym, fixed, walk) { }, function(sym, fixed, walk) {
@@ -956,9 +989,7 @@ merge(Compressor.prototype, {
return true; return true;
}); });
def(AST_BlockScope, function(tw, descend, compressor) { def(AST_BlockScope, function(tw, descend, compressor) {
this.variables.each(function(def) { reset_block_variables(tw, compressor, this);
reset_def(tw, compressor, def);
});
}); });
def(AST_Call, function(tw, descend) { def(AST_Call, function(tw, descend) {
var node = this; var node = this;
@@ -969,43 +1000,43 @@ merge(Compressor.prototype, {
arg.walk(tw); arg.walk(tw);
if (arg instanceof AST_Spread) iife = false; if (arg instanceof AST_Spread) iife = false;
}); });
if (iife) exp.reduce_vars = reduce_iife; if (iife) {
exp.reduce_vars = reduce_iife;
} else {
exp.safe_ids = tw.safe_ids;
}
exp.walk(tw); exp.walk(tw);
if (iife) delete exp.reduce_vars; if (iife) delete exp.reduce_vars;
return true; return true;
} }
var def = exp instanceof AST_SymbolRef && exp.definition();
if (node.TYPE == "Call" && tw.in_boolean_context()) { if (node.TYPE == "Call" && tw.in_boolean_context()) {
if (def) { if (exp instanceof AST_SymbolRef) {
def.bool_fn++; exp.definition().bool_fn++;
} else if (exp instanceof AST_Assign && exp.operator == "=" && exp.left instanceof AST_SymbolRef) { } else if (exp instanceof AST_Assign && exp.operator == "=" && exp.left instanceof AST_SymbolRef) {
exp.left.definition().bool_fn++; exp.left.definition().bool_fn++;
} }
} }
if (def && def.fixed instanceof AST_LambdaDefinition) { exp.walk(tw);
var defun = mark_defun(tw, def); var fixed = exp instanceof AST_SymbolRef && exp.fixed_value();
if (defun) { var optional = node.optional;
descend(); var fn;
defun.walk(tw); if (fixed instanceof AST_Lambda) {
return true; fn = mark_fn_def(tw, exp.definition(), fixed);
} optional = false;
} else { } else {
tw.find_parent(AST_Scope).may_call_this(); tw.find_parent(AST_Scope).may_call_this();
} }
if (!node.optional) return; if (optional) push(tw);
exp.walk(tw);
push(tw);
node.args.forEach(function(arg) { node.args.forEach(function(arg) {
arg.walk(tw); arg.walk(tw);
}); });
pop(tw); if (optional) pop(tw);
if (fn) walk_fn_def(tw, fn);
return true; return true;
}); });
def(AST_Class, function(tw, descend, compressor) { def(AST_Class, function(tw, descend, compressor) {
var node = this; var node = this;
node.variables.each(function(def) { reset_block_variables(tw, compressor, node);
reset_def(tw, compressor, def);
});
if (node.extends) node.extends.walk(tw); if (node.extends) node.extends.walk(tw);
var props = node.properties.filter(function(prop) { var props = node.properties.filter(function(prop) {
reset_flags(prop); reset_flags(prop);
@@ -1057,7 +1088,7 @@ merge(Compressor.prototype, {
return true; return true;
}); });
def(AST_Do, function(tw) { def(AST_Do, function(tw) {
var saved_loop = tw.in_loop; var save_loop = tw.in_loop;
tw.in_loop = this; tw.in_loop = this;
push(tw); push(tw);
this.body.walk(tw); this.body.walk(tw);
@@ -1067,39 +1098,37 @@ merge(Compressor.prototype, {
} }
this.condition.walk(tw); this.condition.walk(tw);
pop(tw); pop(tw);
tw.in_loop = saved_loop; tw.in_loop = save_loop;
return true; return true;
}); });
def(AST_For, function(tw, descend, compressor) { def(AST_For, function(tw, descend, compressor) {
this.variables.each(function(def) { var node = this;
reset_def(tw, compressor, def); reset_block_variables(tw, compressor, node);
}); if (node.init) node.init.walk(tw);
if (this.init) this.init.walk(tw); var save_loop = tw.in_loop;
var saved_loop = tw.in_loop; tw.in_loop = node;
tw.in_loop = this;
push(tw); push(tw);
if (this.condition) this.condition.walk(tw); if (node.condition) node.condition.walk(tw);
this.body.walk(tw); node.body.walk(tw);
if (this.step) { if (node.step) {
if (has_loop_control(this, tw.parent())) { if (has_loop_control(node, tw.parent())) {
pop(tw); pop(tw);
push(tw); push(tw);
} }
this.step.walk(tw); node.step.walk(tw);
} }
pop(tw); pop(tw);
tw.in_loop = saved_loop; tw.in_loop = save_loop;
return true; return true;
}); });
def(AST_ForEnumeration, function(tw, descend, compressor) { def(AST_ForEnumeration, function(tw, descend, compressor) {
this.variables.each(function(def) { var node = this;
reset_def(tw, compressor, def); reset_block_variables(tw, compressor, node);
}); node.object.walk(tw);
this.object.walk(tw); var save_loop = tw.in_loop;
var saved_loop = tw.in_loop; tw.in_loop = node;
tw.in_loop = this;
push(tw); push(tw);
var init = this.init; var init = node.init;
if (init instanceof AST_Definitions) { if (init instanceof AST_Definitions) {
init.definitions[0].name.mark_symbol(function(node) { init.definitions[0].name.mark_symbol(function(node) {
if (node instanceof AST_SymbolDeclaration) { if (node instanceof AST_SymbolDeclaration) {
@@ -1120,9 +1149,9 @@ merge(Compressor.prototype, {
} else { } else {
init.walk(tw); init.walk(tw);
} }
this.body.walk(tw); node.body.walk(tw);
pop(tw); pop(tw);
tw.in_loop = saved_loop; tw.in_loop = save_loop;
return true; return true;
}); });
def(AST_If, function(tw) { def(AST_If, function(tw) {
@@ -1145,13 +1174,14 @@ merge(Compressor.prototype, {
}); });
def(AST_Lambda, function(tw, descend, compressor) { def(AST_Lambda, function(tw, descend, compressor) {
var fn = this; var fn = this;
if (HOP(fn, "safe_ids") && fn.safe_ids !== tw.safe_ids) return true;
if (!push_uniq(tw.fn_visited, fn)) return true;
fn.inlined = false; fn.inlined = false;
push(tw); push(tw);
reset_variables(tw, compressor, fn); reset_variables(tw, compressor, fn);
descend(); descend();
pop(tw); pop_scope(tw, fn);
if (fn.name) mark_escaped(tw, fn.name.definition(), fn, fn.name, fn, 0, 1); if (fn.name) mark_escaped(tw, fn.name.definition(), fn, fn.name, fn, 0, 1);
walk_defuns(tw, fn);
return true; return true;
}); });
def(AST_LambdaDefinition, function(tw, descend, compressor) { def(AST_LambdaDefinition, function(tw, descend, compressor) {
@@ -1159,15 +1189,13 @@ merge(Compressor.prototype, {
var def = fn.name.definition(); var def = fn.name.definition();
var parent = tw.parent(); var parent = tw.parent();
if (parent instanceof AST_ExportDeclaration || parent instanceof AST_ExportDefault) def.single_use = false; if (parent instanceof AST_ExportDeclaration || parent instanceof AST_ExportDefault) def.single_use = false;
if (tw.defun_visited[def.id]) return true; if (HOP(fn, "safe_ids") && fn.safe_ids !== tw.safe_ids) return true;
if (def.init === fn && tw.defun_ids[def.id] !== tw.safe_ids) return true; if (!push_uniq(tw.fn_visited, fn)) return true;
tw.defun_visited[def.id] = true;
fn.inlined = false; fn.inlined = false;
push(tw); push(tw);
reset_variables(tw, compressor, fn); reset_variables(tw, compressor, fn);
descend(); descend();
pop(tw); pop_scope(tw, fn);
walk_defuns(tw, fn);
return true; return true;
}); });
def(AST_Sub, function(tw) { def(AST_Sub, function(tw) {
@@ -1179,12 +1207,11 @@ merge(Compressor.prototype, {
return true; return true;
}); });
def(AST_Switch, function(tw, descend, compressor) { def(AST_Switch, function(tw, descend, compressor) {
this.variables.each(function(def) { var node = this;
reset_def(tw, compressor, def); reset_block_variables(tw, compressor, node);
}); node.expression.walk(tw);
this.expression.walk(tw);
var first = true; var first = true;
this.body.forEach(function(branch) { node.body.forEach(function(branch) {
if (branch instanceof AST_Default) return; if (branch instanceof AST_Default) return;
branch.expression.walk(tw); branch.expression.walk(tw);
if (first) { if (first) {
@@ -1193,7 +1220,7 @@ merge(Compressor.prototype, {
} }
}) })
if (!first) pop(tw); if (!first) pop(tw);
walk_body(this, tw); walk_body(node, tw);
return true; return true;
}); });
def(AST_SwitchBranch, function(tw) { def(AST_SwitchBranch, function(tw) {
@@ -1258,36 +1285,62 @@ merge(Compressor.prototype, {
} }
if (!this.fixed) this.fixed = d.fixed; if (!this.fixed) this.fixed = d.fixed;
var parent; var parent;
if (d.fixed instanceof AST_LambdaDefinition if (value instanceof AST_Lambda
&& !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) { && !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) {
var defun = mark_defun(tw, d); var fn = mark_fn_def(tw, d, value);
if (defun) defun.walk(tw); if (fn) walk_fn_def(tw, fn);
} }
}); });
def(AST_Template, function(tw, descend) {
var node = this;
var tag = node.tag;
if (!tag) return;
if (tag instanceof AST_LambdaExpression) {
node.expressions.forEach(function(exp) {
exp.walk(tw);
});
tag.safe_ids = tw.safe_ids;
tag.walk(tw);
delete tag.reduce_vars;
return true;
}
tag.walk(tw);
var fixed = tag instanceof AST_SymbolRef && tag.fixed_value();
var fn;
if (fixed instanceof AST_Lambda) {
fn = mark_fn_def(tw, tag.definition(), fixed);
} else {
tw.find_parent(AST_Scope).may_call_this();
}
node.expressions.forEach(function(exp) {
exp.walk(tw);
});
if (fn) walk_fn_def(tw, fn);
return true;
});
def(AST_Toplevel, function(tw, descend, compressor) { def(AST_Toplevel, function(tw, descend, compressor) {
this.globals.each(function(def) { var node = this;
node.globals.each(function(def) {
reset_def(tw, compressor, def); reset_def(tw, compressor, def);
}); });
push(tw); push(tw);
reset_variables(tw, compressor, this); reset_variables(tw, compressor, node);
descend(); descend();
pop(tw); pop_scope(tw, node);
walk_defuns(tw, this);
return true; return true;
}); });
def(AST_Try, function(tw, descend, compressor) { def(AST_Try, function(tw, descend, compressor) {
this.variables.each(function(def) { var node = this;
reset_def(tw, compressor, def); reset_block_variables(tw, compressor, node);
});
push(tw); push(tw);
walk_body(this, tw); walk_body(node, tw);
pop(tw); pop(tw);
if (this.bcatch) { if (node.bcatch) {
push(tw); push(tw);
this.bcatch.walk(tw); node.bcatch.walk(tw);
pop(tw); pop(tw);
} }
if (this.bfinally) this.bfinally.walk(tw); if (node.bfinally) node.bfinally.walk(tw);
return true; return true;
}); });
def(AST_Unary, function(tw, descend) { def(AST_Unary, function(tw, descend) {
@@ -1338,8 +1391,12 @@ merge(Compressor.prototype, {
}); });
def(AST_VarDef, function(tw, descend, compressor) { def(AST_VarDef, function(tw, descend, compressor) {
var node = this; var node = this;
if (node.value) { var value = node.value;
node.value.walk(tw); if (value instanceof AST_LambdaExpression && node.name instanceof AST_SymbolDeclaration) {
value.parent_scope.resolve().fn_defs.push(value);
value.safe_ids = null;
} else if (value) {
value.walk(tw);
} else if (!(tw.parent() instanceof AST_Let)) { } else if (!(tw.parent() instanceof AST_Let)) {
return; return;
} }
@@ -1363,12 +1420,12 @@ merge(Compressor.prototype, {
return true; return true;
}); });
def(AST_While, function(tw, descend) { def(AST_While, function(tw, descend) {
var saved_loop = tw.in_loop; var save_loop = tw.in_loop;
tw.in_loop = this; tw.in_loop = this;
push(tw); push(tw);
descend(); descend();
pop(tw); pop(tw);
tw.in_loop = saved_loop; tw.in_loop = save_loop;
return true; return true;
}); });
})(function(node, func) { })(function(node, func) {
@@ -1387,9 +1444,9 @@ merge(Compressor.prototype, {
reset_flags(node); reset_flags(node);
return node.reduce_vars(tw, descend, compressor); return node.reduce_vars(tw, descend, compressor);
} : reset_flags); } : reset_flags);
// Flow control for visiting `AST_Defun`s // Flow control for visiting lambda definitions
tw.defun_ids = Object.create(null); tw.fn_scanning = null;
tw.defun_visited = Object.create(null); tw.fn_visited = [];
// Record the loop body in which `AST_SymbolDeclaration` is first encountered // Record the loop body in which `AST_SymbolDeclaration` is first encountered
tw.in_loop = null; tw.in_loop = null;
tw.loop_ids = Object.create(null); tw.loop_ids = Object.create(null);
@@ -1642,9 +1699,7 @@ merge(Compressor.prototype, {
return all(block.body, function(stat) { return all(block.body, function(stat) {
return is_empty(stat) return is_empty(stat)
|| stat instanceof AST_Defun || stat instanceof AST_Defun
|| stat instanceof AST_Var && all(stat.definitions, function(var_def) { || stat instanceof AST_Var && declarations_only(stat);
return !var_def.value;
});
}); });
} }
@@ -6468,7 +6523,7 @@ merge(Compressor.prototype, {
} }
} else if (compressor.option("functions") } else if (compressor.option("functions")
&& !compressor.option("ie8") && !compressor.option("ie8")
&& node instanceof AST_Var && drop_sym
&& var_defs[sym.id] == 1 && var_defs[sym.id] == 1
&& sym.assignments == 0 && sym.assignments == 0
&& value instanceof AST_LambdaExpression && value instanceof AST_LambdaExpression
@@ -6542,7 +6597,7 @@ merge(Compressor.prototype, {
} }
function can_declare_defun(fn) { function can_declare_defun(fn) {
if (compressor.has_directive("use strict") || !(fn instanceof AST_Function)) { if (!is_var || compressor.has_directive("use strict") || !(fn instanceof AST_Function)) {
return parent instanceof AST_Scope; return parent instanceof AST_Scope;
} }
return parent instanceof AST_Block return parent instanceof AST_Block
@@ -9501,9 +9556,7 @@ merge(Compressor.prototype, {
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
var line = fn.body[i]; var line = fn.body[i];
if (line instanceof AST_Var) { if (line instanceof AST_Var) {
var assigned = var_assigned || !all(line.definitions, function(var_def) { var assigned = var_assigned || !declarations_only(line);
return !var_def.value;
});
if (assigned) { if (assigned) {
var_assigned = true; var_assigned = true;
if (stat) return false; if (stat) return false;

View File

@@ -556,6 +556,38 @@ reduce_iife_3: {
node_version: ">=4" node_version: ">=4"
} }
reduce_lambda: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var f = () => {
console.log(a, b);
};
var a = "foo", b = 42;
f();
b = "bar";
f();
}
expect: {
var f = () => {
console.log("foo", b);
};
var b = 42;
f();
b = "bar";
f();
}
expect_stdout: [
"foo 42",
"foo bar",
]
node_version: ">=4"
}
single_use_recursive: { single_use_recursive: {
options = { options = {
reduce_vars: true, reduce_vars: true,

View File

@@ -3081,7 +3081,8 @@ issue_4235: {
} }
expect: { expect: {
void function() { void function() {
var f = console.log(f); var f;
console.log(f);
}(); }();
} }
expect_stdout: "undefined" expect_stdout: "undefined"

View File

@@ -2905,6 +2905,7 @@ issue_2437: {
issue_2485_1: { issue_2485_1: {
options = { options = {
functions: true, functions: true,
passes: 2,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
@@ -2955,6 +2956,7 @@ issue_2485_2: {
options = { options = {
functions: true, functions: true,
inline: true, inline: true,
passes: 2,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,

View File

@@ -152,7 +152,8 @@ issue_4487: {
} }
expect: { expect: {
function a() { function a() {
var f = console.log(typeof f); var f;
console.log(typeof f);
} }
a(); a();
} }

View File

@@ -494,6 +494,41 @@ reduce_vars_3: {
node_version: ">=4" node_version: ">=4"
} }
reduce_lambda: {
options = {
evaluate: true,
functions: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
let f = function() {
console.log(a, b);
};
let a = "foo", b = 42;
f();
b = "bar";
f();
}
expect: {
"use strict";
function f() {
console.log("foo", b);
}
let b = 42;
f();
b = "bar";
f();
}
expect_stdout: [
"foo 42",
"foo bar",
]
node_version: ">=4"
}
hoist_props: { hoist_props: {
options = { options = {
hoist_props: true, hoist_props: true,

View File

@@ -1320,6 +1320,7 @@ issue_2878: {
issue_3427: { issue_3427: {
options = { options = {
assignments: true,
evaluate: true, evaluate: true,
inline: true, inline: true,
pure_getters: "strict", pure_getters: "strict",

View File

@@ -3092,7 +3092,7 @@ accessor_1: {
a = 2; a = 2;
return a; return a;
}, },
b: 1 b: 1,
}.b, a); }.b, a);
} }
expect: { expect: {
@@ -3102,7 +3102,7 @@ accessor_1: {
a = 2; a = 2;
return a; return a;
}, },
b: 1 b: 1,
}.b, a); }.b, a);
} }
expect_stdout: "1 1" expect_stdout: "1 1"
@@ -3122,7 +3122,7 @@ accessor_2: {
var B = { var B = {
get c() { get c() {
console.log(A); console.log(A);
} },
}; };
B.c; B.c;
} }
@@ -3130,7 +3130,7 @@ accessor_2: {
({ ({
get c() { get c() {
console.log(1); console.log(1);
} },
}).c; }).c;
} }
expect_stdout: "1" expect_stdout: "1"
@@ -3176,7 +3176,7 @@ obj_var_1: {
var obj = { var obj = {
bar: function() { bar: function() {
return C + C; return C + C;
} },
}; };
console.log(obj.bar()); console.log(obj.bar());
} }
@@ -3184,7 +3184,7 @@ obj_var_1: {
console.log({ console.log({
bar: function() { bar: function() {
return 2; return 2;
} },
}.bar()); }.bar());
} }
expect_stdout: "2" expect_stdout: "2"
@@ -3208,7 +3208,7 @@ obj_var_2: {
var obj = { var obj = {
bar: function() { bar: function() {
return C + C; return C + C;
} },
}; };
console.log(obj.bar()); console.log(obj.bar());
} }
@@ -4422,6 +4422,7 @@ perf_2: {
perf_3: { perf_3: {
options = { options = {
passes: 2,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
@@ -4430,10 +4431,10 @@ perf_3: {
input: { input: {
var foo = function(x, y, z) { var foo = function(x, y, z) {
return x < y ? x * y + z : x * z - y; return x < y ? x * y + z : x * z - y;
} };
var indirect_foo = function(x, y, z) { var indirect_foo = function(x, y, z) {
return foo(x, y, z); return foo(x, y, z);
} };
var sum = 0; var sum = 0;
for (var i = 0; i < 100; ++i) for (var i = 0; i < 100; ++i)
sum += indirect_foo(i, i + 1, 3 * i); sum += indirect_foo(i, i + 1, 3 * i);
@@ -4462,10 +4463,10 @@ perf_4: {
input: { input: {
var foo = function(x, y, z) { var foo = function(x, y, z) {
return x < y ? x * y + z : x * z - y; return x < y ? x * y + z : x * z - y;
} };
var indirect_foo = function(x, y, z) { var indirect_foo = function(x, y, z) {
return foo(x, y, z); return foo(x, y, z);
} };
var sum = 0; var sum = 0;
for (var i = 0; i < 100; ++i) for (var i = 0; i < 100; ++i)
sum += indirect_foo(i, i + 1, 3 * i); sum += indirect_foo(i, i + 1, 3 * i);
@@ -4474,10 +4475,10 @@ perf_4: {
expect: { expect: {
var foo = function(x, y, z) { var foo = function(x, y, z) {
return x < y ? x * y + z : x * z - y; return x < y ? x * y + z : x * z - y;
} };
var indirect_foo = function(x, y, z) { var indirect_foo = function(x, y, z) {
return foo(x, y, z); return foo(x, y, z);
} };
var sum = 0; var sum = 0;
for (var i = 0; i < 100; ++i) for (var i = 0; i < 100; ++i)
sum += indirect_foo(i, i + 1, 3 * i); sum += indirect_foo(i, i + 1, 3 * i);
@@ -4566,9 +4567,9 @@ perf_7: {
var indirect_foo = function(x, y, z) { var indirect_foo = function(x, y, z) {
var foo = function(x, y, z) { var foo = function(x, y, z) {
return x < y ? x * y + z : x * z - y; return x < y ? x * y + z : x * z - y;
} };
return foo(x, y, z); return foo(x, y, z);
} };
var sum = 0; var sum = 0;
for (var i = 0; i < 100; ++i) for (var i = 0; i < 100; ++i)
sum += indirect_foo(i, i + 1, 3 * i); sum += indirect_foo(i, i + 1, 3 * i);
@@ -4598,9 +4599,9 @@ perf_8: {
var indirect_foo = function(x, y, z) { var indirect_foo = function(x, y, z) {
var foo = function(x, y, z) { var foo = function(x, y, z) {
return x < y ? x * y + z : x * z - y; return x < y ? x * y + z : x * z - y;
} };
return foo(x, y, z); return foo(x, y, z);
} };
var sum = 0; var sum = 0;
for (var i = 0; i < 100; ++i) for (var i = 0; i < 100; ++i)
sum += indirect_foo(i, i + 1, 3 * i); sum += indirect_foo(i, i + 1, 3 * i);
@@ -4611,7 +4612,7 @@ perf_8: {
return function(x, y, z) { return function(x, y, z) {
return x < y ? x * y + z : x * z - y; return x < y ? x * y + z : x * z - y;
}(x, y, z); }(x, y, z);
} };
var sum = 0; var sum = 0;
for (var i = 0; i < 100; ++i) for (var i = 0; i < 100; ++i)
sum += indirect_foo(i, i + 1, 3 * i); sum += indirect_foo(i, i + 1, 3 * i);

View File

@@ -726,7 +726,7 @@ function to_statement_init(node) {
return node instanceof U.AST_Const || node instanceof U.AST_Let ? new U.AST_BlockStatement({ return node instanceof U.AST_Const || node instanceof U.AST_Let ? new U.AST_BlockStatement({
body: [ node ], body: [ node ],
start: {}, start: {},
}) : to_statement(node);; }) : to_statement(node);
} }
function wrap_with_console_log(node) { function wrap_with_console_log(node) {