fix corner case in conditionals (#5674)

fixes #5673
This commit is contained in:
Alex Lam S.L
2022-09-22 03:58:44 +01:00
committed by GitHub
parent 63b04a687a
commit 43ec350cd2
2 changed files with 74 additions and 27 deletions

View File

@@ -1828,6 +1828,29 @@ Compressor.prototype.compress = function(node) {
return wrap ? make_sequence(orig, [ make_node(AST_Number, orig, { value: 0 }), val ]) : val; return wrap ? make_sequence(orig, [ make_node(AST_Number, orig, { value: 0 }), val ]) : val;
} }
function merge_expression(base, target, scope) {
var fixed_by_id = new Dictionary();
base.walk(new TreeWalker(function(node) {
if (!(node instanceof AST_SymbolRef)) return;
var def = node.definition();
if (scope && def.scope.resolve() !== scope) return;
var fixed = node.fixed;
if (!fixed || !fixed_by_id.has(def.id)) {
fixed_by_id.set(def.id, fixed);
} else if (fixed_by_id.get(def.id) !== fixed) {
fixed_by_id.set(def.id, false);
}
}));
if (fixed_by_id.size() > 0) target.walk(new TreeWalker(function(node) {
if (!(node instanceof AST_SymbolRef)) return;
var def = node.definition();
var fixed = node.fixed;
if (!fixed || !fixed_by_id.has(def.id)) return;
if (fixed_by_id.get(def.id) !== fixed) node.fixed = false;
}));
return target;
}
function merge_sequence(array, node) { function merge_sequence(array, node) {
if (node instanceof AST_Sequence) { if (node instanceof AST_Sequence) {
[].push.apply(array, node.expressions); [].push.apply(array, node.expressions);
@@ -3813,25 +3836,7 @@ Compressor.prototype.compress = function(node) {
case 2: case 2:
value = value.tail_node(); value = value.tail_node();
} }
var fixed_by_id = new Dictionary(); merge_expression(value, jump.value, scope);
value.walk(new TreeWalker(function(node) {
if (!(node instanceof AST_SymbolRef)) return;
var def = node.definition();
if (def.scope.resolve() !== scope) return;
var fixed = node.fixed;
if (!fixed || !fixed_by_id.has(def.id)) {
fixed_by_id.set(def.id, fixed);
} else if (fixed_by_id.get(def.id) !== fixed) {
fixed_by_id.set(def.id, false);
}
}));
if (fixed_by_id.size() > 0) jump.value.walk(new TreeWalker(function(node) {
if (!(node instanceof AST_SymbolRef)) return;
var def = node.definition();
var fixed = node.fixed;
if (!fixed || !fixed_by_id.has(def.id)) return;
if (fixed_by_id.get(def.id) !== fixed) node.fixed = false;
}));
} }
function next_index(i) { function next_index(i) {
@@ -12933,7 +12938,7 @@ Compressor.prototype.compress = function(node) {
right: fuse(consequent, seq_tail, "condition"), right: fuse(consequent, seq_tail, "condition"),
}), }),
consequent: seq_tail.consequent, consequent: seq_tail.consequent,
alternative: alternative, alternative: merge_expression(seq_tail.alternative, alternative),
}); });
} }
// x ? (y ? a : b) : a ---> !x || y ? a : b // x ? (y ? a : b) : a ---> !x || y ? a : b
@@ -12945,7 +12950,7 @@ Compressor.prototype.compress = function(node) {
operator: "||", operator: "||",
right: fuse(consequent, seq_tail, "condition"), right: fuse(consequent, seq_tail, "condition"),
}), }),
consequent: alternative, consequent: merge_expression(seq_tail.consequent, alternative),
alternative: seq_tail.alternative, alternative: seq_tail.alternative,
}); });
} }
@@ -12958,7 +12963,7 @@ Compressor.prototype.compress = function(node) {
operator: "||", operator: "||",
right: fuse(alternative, alt_tail, "condition"), right: fuse(alternative, alt_tail, "condition"),
}), }),
consequent: consequent, consequent: merge_expression(consequent, alt_tail.consequent),
alternative: alt_tail.alternative, alternative: alt_tail.alternative,
}); });
} }
@@ -12972,7 +12977,7 @@ Compressor.prototype.compress = function(node) {
right: fuse(alternative, alt_tail, "condition"), right: fuse(alternative, alt_tail, "condition"),
}), }),
consequent: alt_tail.consequent, consequent: alt_tail.consequent,
alternative: consequent, alternative: merge_expression(consequent, alt_tail.alternative),
}); });
} }
// x ? y && a : a ---> (!x || y) && a // x ? y && a : a ---> (!x || y) && a
@@ -12986,7 +12991,7 @@ Compressor.prototype.compress = function(node) {
left: negated, left: negated,
right: fuse(consequent, seq_tail, "left"), right: fuse(consequent, seq_tail, "left"),
}), }),
right: alternative, right: merge_expression(seq_tail.right, alternative),
}).optimize(compressor); }).optimize(compressor);
} }
// x ? y || a : a ---> x && y || a // x ? y || a : a ---> x && y || a
@@ -13000,7 +13005,7 @@ Compressor.prototype.compress = function(node) {
left: condition, left: condition,
right: fuse(consequent, seq_tail, "left"), right: fuse(consequent, seq_tail, "left"),
}), }),
right: alternative, right: merge_expression(seq_tail.right, alternative),
}).optimize(compressor); }).optimize(compressor);
} }
// x ? a : y && a ---> (x || y) && a // x ? a : y && a ---> (x || y) && a
@@ -13014,7 +13019,7 @@ Compressor.prototype.compress = function(node) {
left: condition, left: condition,
right: fuse(alternative, alt_tail, "left"), right: fuse(alternative, alt_tail, "left"),
}), }),
right: consequent, right: merge_expression(consequent, alt_tail.right),
}).optimize(compressor); }).optimize(compressor);
} }
// x ? a : y || a ---> !x && y || a // x ? a : y || a ---> !x && y || a
@@ -13028,7 +13033,7 @@ Compressor.prototype.compress = function(node) {
left: negated, left: negated,
right: fuse(alternative, alt_tail, "left"), right: fuse(alternative, alt_tail, "left"),
}), }),
right: consequent, right: merge_expression(consequent, alt_tail.right),
}).optimize(compressor); }).optimize(compressor);
} }
var in_bool = compressor.option("booleans") && compressor.in_boolean_context(); var in_bool = compressor.option("booleans") && compressor.in_boolean_context();

View File

@@ -2928,3 +2928,45 @@ issue_5666_2: {
} }
expect_stdout: "NaN" expect_stdout: "NaN"
} }
issue_5673_1: {
options = {
conditionals: true,
reduce_vars: true,
unused: true,
}
input: {
var a = "PASS", b = null;
console.log(function(c) {
return c || (b ? c : (c = a) && c);
}());
}
expect: {
var a = "PASS", b = null;
console.log(function(c) {
return c || (b || (c = a)) && c;
}());
}
expect_stdout: "PASS"
}
issue_5673_2: {
options = {
conditionals: true,
reduce_vars: true,
unused: true,
}
input: {
var a = "PASS";
console.log(function(b) {
return (b = a) ? b : (b = a) && b;
}());
}
expect: {
var a = "PASS";
console.log(function(b) {
return ((b = a) || (b = a)) && b;
}());
}
expect_stdout: "PASS"
}