support nullish coalescing operator (#4678)
This commit is contained in:
@@ -2182,6 +2182,7 @@ merge(Compressor.prototype, {
|
||||
var lazy = lazy_op[expr.operator];
|
||||
if (unused
|
||||
&& lazy
|
||||
&& expr.operator != "??"
|
||||
&& expr.right instanceof AST_Assign
|
||||
&& expr.right.operator == "="
|
||||
&& !(expr.right.left instanceof AST_Destructured)) {
|
||||
@@ -3840,7 +3841,7 @@ merge(Compressor.prototype, {
|
||||
node.DEFMETHOD("is_string", func);
|
||||
});
|
||||
|
||||
var lazy_op = makePredicate("&& ||");
|
||||
var lazy_op = makePredicate("&& || ??");
|
||||
|
||||
(function(def) {
|
||||
function to_node(value, orig) {
|
||||
@@ -4286,6 +4287,9 @@ merge(Compressor.prototype, {
|
||||
switch (this.operator) {
|
||||
case "&&" : result = left && right; break;
|
||||
case "||" : result = left || right; break;
|
||||
case "??" :
|
||||
result = left == null ? right : left;
|
||||
break;
|
||||
case "|" : result = left | right; break;
|
||||
case "&" : result = left & right; break;
|
||||
case "^" : result = left ^ right; break;
|
||||
@@ -7130,6 +7134,7 @@ merge(Compressor.prototype, {
|
||||
node = this.clone();
|
||||
node.right = right.drop_side_effect_free(compressor);
|
||||
}
|
||||
if (this.operator == "??") return node;
|
||||
return (first_in_statement ? best_of_statement : best_of_expression)(node, make_node(AST_Binary, this, {
|
||||
operator: node.operator == "&&" ? "||" : "&&",
|
||||
left: node.left.negate(compressor, first_in_statement),
|
||||
@@ -9159,7 +9164,7 @@ merge(Compressor.prototype, {
|
||||
// (a = b, x || a = c) ---> a = x ? b : c
|
||||
function to_conditional_assignment(compressor, def, value, node) {
|
||||
if (!(node instanceof AST_Binary)) return;
|
||||
if (!lazy_op[node.operator]) return;
|
||||
if (!(node.operator == "&&" || node.operator == "||")) return;
|
||||
if (!(node.right instanceof AST_Assign)) return;
|
||||
if (node.right.operator != "=") return;
|
||||
if (!(node.right.left instanceof AST_SymbolRef)) return;
|
||||
@@ -9680,22 +9685,41 @@ merge(Compressor.prototype, {
|
||||
}).optimize(compressor);
|
||||
}
|
||||
break;
|
||||
case "??":
|
||||
var nullish = true;
|
||||
case "||":
|
||||
var ll = fuzzy_eval(self.left);
|
||||
if (!ll) {
|
||||
AST_Node.warn("Condition left of || always false [{file}:{line},{col}]", self.start);
|
||||
var ll = fuzzy_eval(self.left, nullish);
|
||||
if (nullish ? ll == null : !ll) {
|
||||
AST_Node.warn("Condition left of {operator} always {value} [{file}:{line},{col}]", {
|
||||
operator: self.operator,
|
||||
value: nullish ? "nulish" : "false",
|
||||
file: self.start.file,
|
||||
line: self.start.line,
|
||||
col: self.start.col,
|
||||
});
|
||||
return make_sequence(self, [ self.left, self.right ]).optimize(compressor);
|
||||
} else if (!(ll instanceof AST_Node)) {
|
||||
AST_Node.warn("Condition left of || always true [{file}:{line},{col}]", self.start);
|
||||
AST_Node.warn("Condition left of {operator} always {value} [{file}:{line},{col}]", {
|
||||
operator: self.operator,
|
||||
value: nullish ? "defined" : "true",
|
||||
file: self.start.file,
|
||||
line: self.start.line,
|
||||
col: self.start.col,
|
||||
});
|
||||
return maintain_this_binding(compressor, parent, compressor.self(), self.left).optimize(compressor);
|
||||
}
|
||||
var rr = self.right.evaluate(compressor);
|
||||
if (!rr) {
|
||||
if (in_bool || parent.operator == "||" && parent.left === compressor.self()) {
|
||||
AST_Node.warn("Dropping side-effect-free || [{file}:{line},{col}]", self.start);
|
||||
AST_Node.warn("Dropping side-effect-free {operator} [{file}:{line},{col}]", {
|
||||
operator: self.operator,
|
||||
file: self.start.file,
|
||||
line: self.start.line,
|
||||
col: self.start.col,
|
||||
});
|
||||
return self.left.optimize(compressor);
|
||||
}
|
||||
} else if (!(rr instanceof AST_Node)) {
|
||||
} else if (!nullish && !(rr instanceof AST_Node)) {
|
||||
if (in_bool) {
|
||||
AST_Node.warn("Boolean || always true [{file}:{line},{col}]", self.start);
|
||||
return make_sequence(self, [
|
||||
@@ -9705,7 +9729,7 @@ merge(Compressor.prototype, {
|
||||
} else self.truthy = true;
|
||||
}
|
||||
// x && true || y ---> x ? true : y
|
||||
if (self.left.operator == "&&") {
|
||||
if (!nullish && self.left.operator == "&&") {
|
||||
var lr = self.left.right.is_truthy() || self.left.right.evaluate(compressor, true);
|
||||
if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, {
|
||||
condition: self.left.left,
|
||||
@@ -10047,9 +10071,9 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
|
||||
function fuzzy_eval(node) {
|
||||
function fuzzy_eval(node, nullish) {
|
||||
if (node.truthy) return true;
|
||||
if (node.falsy) return false;
|
||||
if (node.falsy && !nullish) return false;
|
||||
if (node.is_truthy()) return true;
|
||||
return node.evaluate(compressor, true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user