fix corner cases in evaluate & side_effects (#5726)

This commit is contained in:
Alex Lam S.L
2022-11-01 01:38:33 +00:00
committed by GitHub
parent f40dbd6e33
commit 8d28052182
4 changed files with 126 additions and 12 deletions

View File

@@ -2566,7 +2566,7 @@ Compressor.prototype.compress = function(node) {
function is_last_node(node, parent) { function is_last_node(node, parent) {
if (node instanceof AST_Await) return true; if (node instanceof AST_Await) return true;
if (node.TYPE == "Binary") return !can_drop_op(node.operator, node.right, compressor); if (node.TYPE == "Binary") return !can_drop_op(node, compressor);
if (node instanceof AST_Call) { if (node instanceof AST_Call) {
var def, fn = node.expression; var def, fn = node.expression;
if (fn instanceof AST_SymbolRef) { if (fn instanceof AST_SymbolRef) {
@@ -5820,7 +5820,7 @@ Compressor.prototype.compress = function(node) {
def(AST_Binary, function(compressor) { def(AST_Binary, function(compressor) {
return this.left.has_side_effects(compressor) return this.left.has_side_effects(compressor)
|| this.right.has_side_effects(compressor) || this.right.has_side_effects(compressor)
|| !can_drop_op(this.operator, this.right, compressor); || !can_drop_op(this, compressor);
}); });
def(AST_Block, function(compressor) { def(AST_Block, function(compressor) {
return any(this.body, compressor); return any(this.body, compressor);
@@ -5974,7 +5974,7 @@ Compressor.prototype.compress = function(node) {
def(AST_Binary, function(compressor) { def(AST_Binary, function(compressor) {
return this.left.may_throw(compressor) return this.left.may_throw(compressor)
|| this.right.may_throw(compressor) || this.right.may_throw(compressor)
|| !can_drop_op(this.operator, this.right, compressor); || !can_drop_op(this, compressor);
}); });
def(AST_Block, function(compressor) { def(AST_Block, function(compressor) {
return any(this.body, compressor); return any(this.body, compressor);
@@ -6091,7 +6091,7 @@ Compressor.prototype.compress = function(node) {
def(AST_Binary, function(scope) { def(AST_Binary, function(scope) {
return this.left.is_constant_expression(scope) return this.left.is_constant_expression(scope)
&& this.right.is_constant_expression(scope) && this.right.is_constant_expression(scope)
&& can_drop_op(this.operator, this.right); && can_drop_op(this);
}); });
def(AST_Class, function(scope) { def(AST_Class, function(scope) {
var base = this.extends; var base = this.extends;
@@ -8813,11 +8813,17 @@ Compressor.prototype.compress = function(node) {
var left = this.left; var left = this.left;
var right = this.right; var right = this.right;
var op = this.operator; var op = this.operator;
if (!can_drop_op(op, right, compressor)) { if (!can_drop_op(this, compressor)) {
var lhs = left.drop_side_effect_free(compressor, first_in_statement); var lhs = left.drop_side_effect_free(compressor, first_in_statement);
if (lhs === left) return this; if (lhs === left) return this;
var node = this.clone(); var node = this.clone();
node.left = lhs || make_node(AST_Number, left, { value: 0 }); if (lhs) {
node.left = lhs;
} else if (op == "instanceof" && !left.is_constant()) {
node.left = make_node(AST_Array, left, { elements: [] });
} else {
node.left = make_node(AST_Number, left, { value: 0 });
}
return node; return node;
} }
var rhs = right.drop_side_effect_free(compressor, first_in_statement); var rhs = right.drop_side_effect_free(compressor, first_in_statement);
@@ -11566,13 +11572,16 @@ Compressor.prototype.compress = function(node) {
|| node instanceof AST_Object; || node instanceof AST_Object;
} }
function can_drop_op(op, rhs, compressor) { function can_drop_op(node, compressor) {
switch (op) { var rhs = node.right;
switch (node.operator) {
case "in": case "in":
return is_object(rhs) || compressor && compressor.option("unsafe_comps"); return is_object(rhs) || compressor && compressor.option("unsafe_comps");
case "instanceof": case "instanceof":
if (rhs instanceof AST_SymbolRef) rhs = rhs.fixed_value(); if (rhs instanceof AST_SymbolRef) rhs = rhs.fixed_value();
return is_lambda(rhs) || compressor && compressor.option("unsafe_comps"); if (rhs instanceof AST_Defun || rhs instanceof AST_Function || is_generator(rhs)) return true;
if (is_lambda(rhs) && node.left.is_constant()) return true;
return compressor && compressor.option("unsafe_comps");
default: default:
return true; return true;
} }
@@ -12118,8 +12127,10 @@ Compressor.prototype.compress = function(node) {
} }
break; break;
case "instanceof": case "instanceof":
if (!can_drop_op(self, compressor)) break;
if (is_lambda(self.right)) return make_sequence(self, [ if (is_lambda(self.right)) return make_sequence(self, [
self, self.left,
self.right,
make_node(AST_False, self), make_node(AST_False, self),
]).optimize(compressor); ]).optimize(compressor);
break; break;

View File

@@ -690,6 +690,65 @@ inline_iife_within_arrow: {
node_version: ">=4" node_version: ">=4"
} }
instanceof_lambda_1: {
options = {
evaluate: true,
side_effects: true,
}
input: {
console.log(42 instanceof (() => {}));
}
expect: {
console.log(false);
}
expect_stdout: "false"
node_version: ">=4"
}
instanceof_lambda_2: {
options = {
evaluate: true,
side_effects: false,
}
input: {
console.log(null instanceof (() => {}));
}
expect: {
console.log((null, () => {}, false));
}
expect_stdout: "false"
node_version: ">=4"
}
instanceof_lambda_3: {
options = {
evaluate: true,
side_effects: true,
}
input: {
console.log({} instanceof (() => {}));
}
expect: {
console.log({} instanceof (() => {}));
}
expect_stdout: TypeError("Function has non-object prototype 'undefined' in instanceof check")
node_version: ">=4"
}
instanceof_lambda_4: {
options = {
side_effects: true,
}
input: {
({ p: "foo" }) instanceof (() => {});
}
expect: {
[] instanceof (() => {});
}
expect_stdout: TypeError("Function has non-object prototype 'undefined' in instanceof check")
node_version: ">=4"
}
issue_4388: { issue_4388: {
options = { options = {
inline: true, inline: true,

View File

@@ -1348,7 +1348,7 @@ functions_inner_var: {
node_version: ">=8" node_version: ">=8"
} }
instanceof_lambda: { instanceof_lambda_1: {
options = { options = {
evaluate: true, evaluate: true,
side_effects: true, side_effects: true,
@@ -1363,6 +1363,50 @@ instanceof_lambda: {
node_version: ">=8" node_version: ">=8"
} }
instanceof_lambda_2: {
options = {
evaluate: true,
side_effects: false,
}
input: {
console.log(null instanceof async function() {});
}
expect: {
console.log((null, async function() {}, false));
}
expect_stdout: "false"
node_version: ">=8"
}
instanceof_lambda_3: {
options = {
evaluate: true,
side_effects: true,
}
input: {
console.log({} instanceof async function() {});
}
expect: {
console.log({} instanceof async function() {});
}
expect_stdout: TypeError("Function has non-object prototype 'undefined' in instanceof check")
node_version: ">=8"
}
instanceof_lambda_4: {
options = {
side_effects: true,
}
input: {
({ p: "foo" }) instanceof async function() {};
}
expect: {
[] instanceof async function() {};
}
expect_stdout: TypeError("Function has non-object prototype 'undefined' in instanceof check")
node_version: ">=8"
}
issue_4335_1: { issue_4335_1: {
options = { options = {
inline: true, inline: true,

View File

@@ -147,7 +147,7 @@ relational: {
"bar" >= "bar"; "bar" >= "bar";
} }
expect: { expect: {
0 instanceof bar(); [] instanceof bar();
bar(); bar();
bar(), bar(); bar(), bar();
bar(); bar();