enhance reduce_vars (#4392)
This commit is contained in:
115
lib/compress.js
115
lib/compress.js
@@ -672,6 +672,53 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reduce_iife(tw, descend, compressor) {
|
||||||
|
var fn = this;
|
||||||
|
fn.inlined = false;
|
||||||
|
var iife = tw.parent();
|
||||||
|
var hit = fn instanceof AST_AsyncFunction;
|
||||||
|
var aborts = false;
|
||||||
|
fn.walk(new TreeWalker(function(node) {
|
||||||
|
if (hit) return aborts = true;
|
||||||
|
if (node instanceof AST_Return) return hit = true;
|
||||||
|
if (node instanceof AST_Scope && node !== fn) return true;
|
||||||
|
}));
|
||||||
|
if (aborts) push(tw);
|
||||||
|
reset_variables(tw, compressor, fn);
|
||||||
|
// Virtually turn IIFE parameters into variable definitions:
|
||||||
|
// (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
|
||||||
|
// So existing transformation rules can work on them.
|
||||||
|
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() {
|
||||||
|
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) {
|
||||||
|
mark(tw, d);
|
||||||
|
tw.loop_ids[d.id] = tw.in_loop;
|
||||||
|
var value = iife.args[i];
|
||||||
|
d.fixed = fixed;
|
||||||
|
d.fixed.assigns = [ arg ];
|
||||||
|
} else {
|
||||||
|
d.fixed = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (fn instanceof AST_Arrow && fn.value) {
|
||||||
|
fn.value.walk(tw);
|
||||||
|
} else {
|
||||||
|
walk_body(fn, tw);
|
||||||
|
}
|
||||||
|
var safe_ids = tw.safe_ids;
|
||||||
|
pop(tw);
|
||||||
|
walk_defuns(tw, fn);
|
||||||
|
if (!aborts) tw.safe_ids = safe_ids;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
def(AST_Assign, function(tw, descend, compressor) {
|
def(AST_Assign, function(tw, descend, compressor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
var left = node.left;
|
var left = node.left;
|
||||||
@@ -771,10 +818,14 @@ merge(Compressor.prototype, {
|
|||||||
tw.find_parent(AST_Scope).may_call_this();
|
tw.find_parent(AST_Scope).may_call_this();
|
||||||
var exp = this.expression;
|
var exp = this.expression;
|
||||||
if (is_function(exp)) {
|
if (is_function(exp)) {
|
||||||
|
var iife = !exp.name;
|
||||||
this.args.forEach(function(arg) {
|
this.args.forEach(function(arg) {
|
||||||
arg.walk(tw);
|
arg.walk(tw);
|
||||||
|
if (arg instanceof AST_Spread) iife = false;
|
||||||
});
|
});
|
||||||
|
if (iife) exp.reduce_vars = reduce_iife;
|
||||||
exp.walk(tw);
|
exp.walk(tw);
|
||||||
|
if (iife) delete exp.reduce_vars;
|
||||||
return true;
|
return true;
|
||||||
} else if (exp instanceof AST_SymbolRef) {
|
} else if (exp instanceof AST_SymbolRef) {
|
||||||
var def = exp.definition();
|
var def = exp.definition();
|
||||||
@@ -861,62 +912,6 @@ merge(Compressor.prototype, {
|
|||||||
tw.in_loop = saved_loop;
|
tw.in_loop = saved_loop;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Function, function(tw, descend, compressor) {
|
|
||||||
var fn = this;
|
|
||||||
fn.inlined = false;
|
|
||||||
var iife;
|
|
||||||
if (!fn.name
|
|
||||||
&& (iife = tw.parent()) instanceof AST_Call
|
|
||||||
&& iife.expression === fn
|
|
||||||
&& all(iife.args, function(arg) {
|
|
||||||
return !(arg instanceof AST_Spread);
|
|
||||||
})) {
|
|
||||||
var hit = false;
|
|
||||||
var aborts = false;
|
|
||||||
fn.walk(new TreeWalker(function(node) {
|
|
||||||
if (hit) return aborts = true;
|
|
||||||
if (node instanceof AST_Return) return hit = true;
|
|
||||||
if (node instanceof AST_Scope && node !== fn) return true;
|
|
||||||
}));
|
|
||||||
if (aborts) push(tw);
|
|
||||||
reset_variables(tw, compressor, fn);
|
|
||||||
// Virtually turn IIFE parameters into variable definitions:
|
|
||||||
// (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
|
|
||||||
// So existing transformation rules can work on them.
|
|
||||||
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() {
|
|
||||||
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) {
|
|
||||||
mark(tw, d);
|
|
||||||
tw.loop_ids[d.id] = tw.in_loop;
|
|
||||||
var value = iife.args[i];
|
|
||||||
d.fixed = fixed;
|
|
||||||
d.fixed.assigns = [ arg ];
|
|
||||||
} else {
|
|
||||||
d.fixed = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
walk_body(fn, tw);
|
|
||||||
var safe_ids = tw.safe_ids;
|
|
||||||
pop(tw);
|
|
||||||
walk_defuns(tw, fn);
|
|
||||||
if (!aborts) tw.safe_ids = safe_ids;
|
|
||||||
} else {
|
|
||||||
push(tw);
|
|
||||||
reset_variables(tw, compressor, fn);
|
|
||||||
descend();
|
|
||||||
pop(tw);
|
|
||||||
if (fn.name) mark_escaped(tw, fn.name.definition(), fn, fn.name, fn, 0, 1);
|
|
||||||
walk_defuns(tw, fn);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
def(AST_If, function(tw) {
|
def(AST_If, function(tw) {
|
||||||
this.condition.walk(tw);
|
this.condition.walk(tw);
|
||||||
push(tw);
|
push(tw);
|
||||||
@@ -936,12 +931,14 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Lambda, function(tw, descend, compressor) {
|
def(AST_Lambda, function(tw, descend, compressor) {
|
||||||
this.inlined = false;
|
var fn = this;
|
||||||
|
fn.inlined = false;
|
||||||
push(tw);
|
push(tw);
|
||||||
reset_variables(tw, compressor, this);
|
reset_variables(tw, compressor, fn);
|
||||||
descend();
|
descend();
|
||||||
pop(tw);
|
pop(tw);
|
||||||
walk_defuns(tw, this);
|
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_Switch, function(tw, descend, compressor) {
|
def(AST_Switch, function(tw, descend, compressor) {
|
||||||
|
|||||||
@@ -337,6 +337,91 @@ trim_body: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reduce_iife_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
keep_fargs: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(a => console.log(a + a))(21);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(() => console.log(42))();
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_iife_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 21;
|
||||||
|
(() => console.log(a + a))();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(() => console.log(42))();
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_iife_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "foo";
|
||||||
|
(() => {
|
||||||
|
console.log(a);
|
||||||
|
console.log(a);
|
||||||
|
})();
|
||||||
|
a = "bar";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(() => {
|
||||||
|
console.log("foo");
|
||||||
|
console.log("foo");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"foo",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
single_use_recursive: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
return (() => f)();
|
||||||
|
}
|
||||||
|
console.log(typeof f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(typeof function f() {
|
||||||
|
return (() => f)();
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
issue_4388: {
|
issue_4388: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
|||||||
@@ -329,6 +329,77 @@ property_access_expression: {
|
|||||||
node_version: ">=8"
|
node_version: ">=8"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reduce_iife_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
keep_fargs: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(async function(a) {
|
||||||
|
console.log(a + a);
|
||||||
|
})(21);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(async function() {
|
||||||
|
console.log(42);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_iife_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 21;
|
||||||
|
(async function() {
|
||||||
|
console.log(a + a);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(async function() {
|
||||||
|
console.log(42);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_iife_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "foo";
|
||||||
|
(async function() {
|
||||||
|
console.log(a);
|
||||||
|
console.log(await a);
|
||||||
|
})();
|
||||||
|
a = "bar";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "foo";
|
||||||
|
(async function() {
|
||||||
|
console.log(a);
|
||||||
|
console.log(await a);
|
||||||
|
})();
|
||||||
|
a = "bar";
|
||||||
|
}
|
||||||
|
expect_stdout: "foo"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
issue_4347_1: {
|
issue_4347_1: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user