enhance collapse_vars (#2952)
- `a = b, b` => `a = b` - `a.b = c, c()` => `(a.b = c)()`
This commit is contained in:
parent
ace5811691
commit
36bca6934d
|
|
@ -890,6 +890,11 @@ merge(Compressor.prototype, {
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function root_expr(prop) {
|
||||||
|
while (prop instanceof AST_PropAccess) prop = prop.expression;
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
function is_iife_call(node) {
|
function is_iife_call(node) {
|
||||||
if (node.TYPE != "Call") return false;
|
if (node.TYPE != "Call") return false;
|
||||||
return node.expression instanceof AST_Function || is_iife_call(node.expression);
|
return node.expression instanceof AST_Function || is_iife_call(node.expression);
|
||||||
|
|
@ -994,17 +999,19 @@ merge(Compressor.prototype, {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
// Stop only if candidate is found within conditional branches
|
// Stop only if candidate is found within conditional branches
|
||||||
if (!stop_if_hit && (!lhs_local || !replace_all)
|
if (!stop_if_hit
|
||||||
&& (parent instanceof AST_Binary && lazy_op(parent.operator) && parent.left !== node
|
&& (parent instanceof AST_Binary && lazy_op(parent.operator) && parent.left !== node
|
||||||
|| parent instanceof AST_Conditional && parent.condition !== node
|
|| parent instanceof AST_Conditional && parent.condition !== node
|
||||||
|| parent instanceof AST_If && parent.condition !== node)) {
|
|| parent instanceof AST_If && parent.condition !== node)) {
|
||||||
stop_if_hit = parent;
|
stop_if_hit = parent;
|
||||||
}
|
}
|
||||||
// Replace variable with assignment when found
|
// Replace variable with assignment when found
|
||||||
|
var hit_lhs, hit_rhs;
|
||||||
if (can_replace
|
if (can_replace
|
||||||
&& !(node instanceof AST_SymbolDeclaration)
|
&& !(node instanceof AST_SymbolDeclaration)
|
||||||
&& lhs.equivalent_to(node)) {
|
&& (scan_lhs && (hit_lhs = lhs.equivalent_to(node))
|
||||||
if (stop_if_hit) {
|
|| scan_rhs && (hit_rhs = rhs.equivalent_to(node)))) {
|
||||||
|
if (stop_if_hit && (hit_rhs || !lhs_local || !replace_all)) {
|
||||||
abort = true;
|
abort = true;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
@ -1056,7 +1063,7 @@ merge(Compressor.prototype, {
|
||||||
|| node instanceof AST_PropAccess
|
|| node instanceof AST_PropAccess
|
||||||
&& (side_effects || node.expression.may_throw_on_access(compressor))
|
&& (side_effects || node.expression.may_throw_on_access(compressor))
|
||||||
|| node instanceof AST_SymbolRef
|
|| node instanceof AST_SymbolRef
|
||||||
&& (lvalues[node.name] || side_effects && may_modify(node))
|
&& (symbol_in_lvalues(node) || side_effects && may_modify(node))
|
||||||
|| node instanceof AST_VarDef && node.value
|
|| node instanceof AST_VarDef && node.value
|
||||||
&& (node.name.name in lvalues || side_effects && may_modify(node.name))
|
&& (node.name.name in lvalues || side_effects && may_modify(node.name))
|
||||||
|| (sym = is_lhs(node.left, node))
|
|| (sym = is_lhs(node.left, node))
|
||||||
|
|
@ -1111,12 +1118,15 @@ merge(Compressor.prototype, {
|
||||||
var stop_after = null;
|
var stop_after = null;
|
||||||
var stop_if_hit = null;
|
var stop_if_hit = null;
|
||||||
var lhs = get_lhs(candidate);
|
var lhs = get_lhs(candidate);
|
||||||
if (!lhs || is_lhs_read_only(lhs) || lhs.has_side_effects(compressor)) continue;
|
var rhs = get_rhs(candidate);
|
||||||
|
var side_effects = lhs && lhs.has_side_effects(compressor);
|
||||||
|
var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs);
|
||||||
|
var scan_rhs = rhs && foldable(rhs);
|
||||||
|
if (!scan_lhs && !scan_rhs) continue;
|
||||||
// Locate symbols which may execute code outside of scanning range
|
// Locate symbols which may execute code outside of scanning range
|
||||||
var lvalues = get_lvalues(candidate);
|
var lvalues = get_lvalues(candidate);
|
||||||
var lhs_local = is_lhs_local(lhs);
|
var lhs_local = is_lhs_local(lhs);
|
||||||
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
|
if (!side_effects) side_effects = value_has_side_effects(candidate);
|
||||||
var side_effects = value_has_side_effects(candidate);
|
|
||||||
var replace_all = replace_all_symbols();
|
var replace_all = replace_all_symbols();
|
||||||
var may_throw = candidate.may_throw(compressor);
|
var may_throw = candidate.may_throw(compressor);
|
||||||
var funarg = candidate.name instanceof AST_SymbolFunarg;
|
var funarg = candidate.name instanceof AST_SymbolFunarg;
|
||||||
|
|
@ -1221,9 +1231,7 @@ merge(Compressor.prototype, {
|
||||||
function extract_candidates(expr) {
|
function extract_candidates(expr) {
|
||||||
hit_stack.push(expr);
|
hit_stack.push(expr);
|
||||||
if (expr instanceof AST_Assign) {
|
if (expr instanceof AST_Assign) {
|
||||||
if (!expr.left.has_side_effects(compressor)) {
|
candidates.push(hit_stack.slice());
|
||||||
candidates.push(hit_stack.slice());
|
|
||||||
}
|
|
||||||
extract_candidates(expr.right);
|
extract_candidates(expr.right);
|
||||||
} else if (expr instanceof AST_Binary) {
|
} else if (expr instanceof AST_Binary) {
|
||||||
extract_candidates(expr.left);
|
extract_candidates(expr.left);
|
||||||
|
|
@ -1361,21 +1369,47 @@ merge(Compressor.prototype, {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get_rhs(expr) {
|
||||||
|
if (!(candidate instanceof AST_Assign && candidate.operator == "=")) return;
|
||||||
|
return candidate.right;
|
||||||
|
}
|
||||||
|
|
||||||
function get_rvalue(expr) {
|
function get_rvalue(expr) {
|
||||||
return expr[expr instanceof AST_Assign ? "right" : "value"];
|
return expr[expr instanceof AST_Assign ? "right" : "value"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function foldable(expr) {
|
||||||
|
if (expr.is_constant()) return true;
|
||||||
|
if (expr instanceof AST_Array) return false;
|
||||||
|
if (expr instanceof AST_Function) return false;
|
||||||
|
if (expr instanceof AST_Object) return false;
|
||||||
|
if (expr instanceof AST_RegExp) return false;
|
||||||
|
if (expr instanceof AST_Symbol) return true;
|
||||||
|
if (!(lhs instanceof AST_SymbolRef)) return false;
|
||||||
|
if (expr.has_side_effects(compressor)) return false;
|
||||||
|
var circular;
|
||||||
|
var def = lhs.definition();
|
||||||
|
expr.walk(new TreeWalker(function(node) {
|
||||||
|
if (circular) return true;
|
||||||
|
if (node instanceof AST_SymbolRef && node.definition() === def) {
|
||||||
|
circular = true;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
return !circular;
|
||||||
|
}
|
||||||
|
|
||||||
function get_lvalues(expr) {
|
function get_lvalues(expr) {
|
||||||
var lvalues = Object.create(null);
|
var lvalues = Object.create(null);
|
||||||
if (expr instanceof AST_Unary) return lvalues;
|
if (candidate instanceof AST_VarDef) {
|
||||||
var tw = new TreeWalker(function(node, descend) {
|
lvalues[candidate.name.name] = lhs;
|
||||||
var sym = node;
|
}
|
||||||
while (sym instanceof AST_PropAccess) sym = sym.expression;
|
var tw = new TreeWalker(function(node) {
|
||||||
|
var sym = root_expr(node);
|
||||||
if (sym instanceof AST_SymbolRef || sym instanceof AST_This) {
|
if (sym instanceof AST_SymbolRef || sym instanceof AST_This) {
|
||||||
lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent());
|
lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
get_rvalue(expr).walk(tw);
|
expr.walk(tw);
|
||||||
return lvalues;
|
return lvalues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1408,11 +1442,11 @@ merge(Compressor.prototype, {
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_lhs_local(lhs) {
|
function is_lhs_local(lhs) {
|
||||||
while (lhs instanceof AST_PropAccess) lhs = lhs.expression;
|
var sym = root_expr(lhs);
|
||||||
return lhs instanceof AST_SymbolRef
|
return sym instanceof AST_SymbolRef
|
||||||
&& lhs.definition().scope === scope
|
&& sym.definition().scope === scope
|
||||||
&& !(in_loop
|
&& !(in_loop
|
||||||
&& (lhs.name in lvalues
|
&& (sym.name in lvalues && lvalues[sym.name] !== lhs
|
||||||
|| candidate instanceof AST_Unary
|
|| candidate instanceof AST_Unary
|
||||||
|| candidate instanceof AST_Assign && candidate.operator != "="));
|
|| candidate instanceof AST_Assign && candidate.operator != "="));
|
||||||
}
|
}
|
||||||
|
|
@ -1434,6 +1468,13 @@ merge(Compressor.prototype, {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function symbol_in_lvalues(sym) {
|
||||||
|
var lvalue = lvalues[sym.name];
|
||||||
|
if (!lvalue) return;
|
||||||
|
if (lvalue !== lhs) return true;
|
||||||
|
scan_rhs = false;
|
||||||
|
}
|
||||||
|
|
||||||
function may_modify(sym) {
|
function may_modify(sym) {
|
||||||
var def = sym.definition();
|
var def = sym.definition();
|
||||||
if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun) return false;
|
if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun) return false;
|
||||||
|
|
@ -3639,10 +3680,7 @@ merge(Compressor.prototype, {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
this.write_only = true;
|
this.write_only = true;
|
||||||
while (left instanceof AST_PropAccess) {
|
if (root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) {
|
||||||
left = left.expression;
|
|
||||||
}
|
|
||||||
if (left.is_constant_expression(compressor.find_parent(AST_Scope))) {
|
|
||||||
return this.right.drop_side_effect_free(compressor);
|
return this.right.drop_side_effect_free(compressor);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
|
|
||||||
|
|
@ -4770,3 +4770,392 @@ issue_2954_3: {
|
||||||
}
|
}
|
||||||
expect_stdout: Error("PASS")
|
expect_stdout: Error("PASS")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
collapse_rhs_conditional_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "PASS", b = "FAIL";
|
||||||
|
b = a;
|
||||||
|
"function" == typeof f && f(a);
|
||||||
|
console.log(a, b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "PASS", b = "FAIL";
|
||||||
|
b = a;
|
||||||
|
"function" == typeof f && f(a);
|
||||||
|
console.log(a, b);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_conditional_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL", b;
|
||||||
|
while ((a = "PASS", --b) && "PASS" == b);
|
||||||
|
console.log(a, b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL", b;
|
||||||
|
while ((a = "PASS", --b) && "PASS" == b);
|
||||||
|
console.log(a, b);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS NaN"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_lhs_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = 0;
|
||||||
|
new function() {
|
||||||
|
this[c++] = 1;
|
||||||
|
c += 1;
|
||||||
|
}();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = 0;
|
||||||
|
new function() {
|
||||||
|
this[c++] = 1;
|
||||||
|
c += 1;
|
||||||
|
}();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_lhs_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var b = 1;
|
||||||
|
(function f(f) {
|
||||||
|
f = b;
|
||||||
|
f[b] = 0;
|
||||||
|
})();
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var b = 1;
|
||||||
|
(function f(f) {
|
||||||
|
f = b;
|
||||||
|
f[b] = 0;
|
||||||
|
})();
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_side_effects: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1, c = 0;
|
||||||
|
new function f() {
|
||||||
|
this[a-- && f()] = 1;
|
||||||
|
c += 1;
|
||||||
|
}();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1, c = 0;
|
||||||
|
new function f() {
|
||||||
|
this[a-- && f()] = 1;
|
||||||
|
c += 1;
|
||||||
|
}();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_vardef: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b = 1;
|
||||||
|
a = --b + function c() {
|
||||||
|
var b;
|
||||||
|
c[--b] = 1;
|
||||||
|
}();
|
||||||
|
b |= a;
|
||||||
|
console.log(a, b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b = 1;
|
||||||
|
a = --b + function c() {
|
||||||
|
var b;
|
||||||
|
c[--b] = 1;
|
||||||
|
}();
|
||||||
|
b |= a;
|
||||||
|
console.log(a, b);
|
||||||
|
}
|
||||||
|
expect_stdout: "NaN 0"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_array: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = [];
|
||||||
|
b = [];
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = [];
|
||||||
|
b = [];
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect_stdout: "false false false"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_boolean: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = !0;
|
||||||
|
b = !0;
|
||||||
|
return !0;
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
return b = a = !0;
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect_stdout: "true true true"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_function: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = function() {};
|
||||||
|
b = function() {};
|
||||||
|
return function() {};
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = function() {};
|
||||||
|
b = function() {};
|
||||||
|
return function() {};
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect_stdout: "false false false"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_number: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = 42;
|
||||||
|
b = 42;
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
return b = a = 42;
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect_stdout: "true true true"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_object: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = {};
|
||||||
|
b = {};
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = {};
|
||||||
|
b = {};
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect_stdout: "false false false"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_regexp: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = /bar/;
|
||||||
|
b = /bar/;
|
||||||
|
return /bar/;
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = /bar/;
|
||||||
|
b = /bar/;
|
||||||
|
return /bar/;
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect_stdout: "false false false"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_string: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = "foo";
|
||||||
|
b = "foo";
|
||||||
|
return "foo";
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
return b = a = "foo";
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect_stdout: "true true true"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_var: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = f;
|
||||||
|
b = f;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
return b = a = f;
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect_stdout: "true true true"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_this: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = this;
|
||||||
|
b = this;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
return b = a = this;
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect_stdout: "true true true"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_undefined: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
a = void 0;
|
||||||
|
b = void 0;
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
function f() {
|
||||||
|
b = a = void 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var c = f();
|
||||||
|
console.log(a === b, b === c, c === a);
|
||||||
|
}
|
||||||
|
expect_stdout: "true true true"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -830,3 +830,334 @@ issue_2938_4: {
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
collapse_vars_1_true: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
for (;;) {
|
||||||
|
var c = a.g();
|
||||||
|
var d = b.p;
|
||||||
|
if (c || d) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
for (;;) {
|
||||||
|
if (a.g() || b.p) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_1_false: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: false,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
for (;;) {
|
||||||
|
var c = a.g();
|
||||||
|
var d = b.p;
|
||||||
|
if (c || d) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
for (;;) {
|
||||||
|
var c = a.g();
|
||||||
|
var d = b.p;
|
||||||
|
if (c || d) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_1_strict: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
for (;;) {
|
||||||
|
var c = a.g();
|
||||||
|
var d = b.p;
|
||||||
|
if (c || d) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
for (;;) {
|
||||||
|
var c = a.g();
|
||||||
|
var d = b.p;
|
||||||
|
if (c || d) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_2_true: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
function g() {}
|
||||||
|
g.a = function() {};
|
||||||
|
g.b = g.a;
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
function g() {}
|
||||||
|
g.b = g.a = function() {};
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_2_false: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: false,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
function g() {}
|
||||||
|
g.a = function() {};
|
||||||
|
g.b = g.a;
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
function g() {}
|
||||||
|
g.a = function() {};
|
||||||
|
g.b = g.a;
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_vars_2_strict: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
function g() {}
|
||||||
|
g.a = function() {};
|
||||||
|
g.b = g.a;
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
function g() {}
|
||||||
|
g.b = g.a = function() {};
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_true: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log((42..length = "PASS", "PASS"));
|
||||||
|
console.log(("foo".length = "PASS", "PASS"));
|
||||||
|
console.log((false.length = "PASS", "PASS"));
|
||||||
|
console.log((function() {}.length = "PASS", "PASS"));
|
||||||
|
console.log(({
|
||||||
|
get length() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
}.length = "PASS", "PASS"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(42..length = "PASS");
|
||||||
|
console.log("foo".length = "PASS");
|
||||||
|
console.log(false.length = "PASS");
|
||||||
|
console.log(function() {}.length = "PASS");
|
||||||
|
console.log({
|
||||||
|
get length() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
}.length = "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_false: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log((42..length = "PASS", "PASS"));
|
||||||
|
console.log(("foo".length = "PASS", "PASS"));
|
||||||
|
console.log((false.length = "PASS", "PASS"));
|
||||||
|
console.log((function() {}.length = "PASS", "PASS"));
|
||||||
|
console.log(({
|
||||||
|
get length() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
}.length = "PASS", "PASS"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(42..length = "PASS");
|
||||||
|
console.log("foo".length = "PASS");
|
||||||
|
console.log(false.length = "PASS");
|
||||||
|
console.log(function() {}.length = "PASS");
|
||||||
|
console.log({
|
||||||
|
get length() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
}.length = "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_strict: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log((42..length = "PASS", "PASS"));
|
||||||
|
console.log(("foo".length = "PASS", "PASS"));
|
||||||
|
console.log((false.length = "PASS", "PASS"));
|
||||||
|
console.log((function() {}.length = "PASS", "PASS"));
|
||||||
|
console.log(({
|
||||||
|
get length() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
}.length = "PASS", "PASS"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(42..length = "PASS");
|
||||||
|
console.log("foo".length = "PASS");
|
||||||
|
console.log(false.length = "PASS");
|
||||||
|
console.log(function() {}.length = "PASS");
|
||||||
|
console.log({
|
||||||
|
get length() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
}.length = "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_setter: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
console.log(({
|
||||||
|
set length(v) {
|
||||||
|
throw "PASS";
|
||||||
|
}
|
||||||
|
}.length = "FAIL", "FAIL"));
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
console.log({
|
||||||
|
set length(v) {
|
||||||
|
throw "PASS";
|
||||||
|
}
|
||||||
|
}.length = "FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_call: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
passes: 2,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {};
|
||||||
|
function f() {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
o.f = f;
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
({}.f = function() {
|
||||||
|
console.log("PASS");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_rhs_lhs: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
a.b = b, b += 2;
|
||||||
|
console.log(a.b, b);
|
||||||
|
}
|
||||||
|
f({}, 1);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
a.b = b, b += 2;
|
||||||
|
console.log(a.b, b);
|
||||||
|
}
|
||||||
|
f({}, 1);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 3"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -668,8 +668,7 @@ side_effects_cascade_2: {
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f(a, b) {
|
function f(a, b) {
|
||||||
b = a,
|
!(b = a) + (b += a) || (b += a),
|
||||||
!a + (b += a) || (b += a),
|
|
||||||
b = a;
|
b = a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user