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;
|
||||
}
|
||||
|
||||
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) {
|
||||
var node = this;
|
||||
var left = node.left;
|
||||
@@ -771,10 +818,14 @@ merge(Compressor.prototype, {
|
||||
tw.find_parent(AST_Scope).may_call_this();
|
||||
var exp = this.expression;
|
||||
if (is_function(exp)) {
|
||||
var iife = !exp.name;
|
||||
this.args.forEach(function(arg) {
|
||||
arg.walk(tw);
|
||||
if (arg instanceof AST_Spread) iife = false;
|
||||
});
|
||||
if (iife) exp.reduce_vars = reduce_iife;
|
||||
exp.walk(tw);
|
||||
if (iife) delete exp.reduce_vars;
|
||||
return true;
|
||||
} else if (exp instanceof AST_SymbolRef) {
|
||||
var def = exp.definition();
|
||||
@@ -861,62 +912,6 @@ merge(Compressor.prototype, {
|
||||
tw.in_loop = saved_loop;
|
||||
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) {
|
||||
this.condition.walk(tw);
|
||||
push(tw);
|
||||
@@ -936,12 +931,14 @@ merge(Compressor.prototype, {
|
||||
return true;
|
||||
});
|
||||
def(AST_Lambda, function(tw, descend, compressor) {
|
||||
this.inlined = false;
|
||||
var fn = this;
|
||||
fn.inlined = false;
|
||||
push(tw);
|
||||
reset_variables(tw, compressor, this);
|
||||
reset_variables(tw, compressor, fn);
|
||||
descend();
|
||||
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;
|
||||
});
|
||||
def(AST_Switch, function(tw, descend, compressor) {
|
||||
|
||||
@@ -337,6 +337,91 @@ trim_body: {
|
||||
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: {
|
||||
options = {
|
||||
inline: true,
|
||||
|
||||
@@ -329,6 +329,77 @@ property_access_expression: {
|
||||
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: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
|
||||
Reference in New Issue
Block a user