diff --git a/lib/compress.js b/lib/compress.js index 8358e70c5a2..5d97c82ef31 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -2566,7 +2566,7 @@ Compressor.prototype.compress = function(node) { function is_last_node(node, parent) { 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) { var def, fn = node.expression; if (fn instanceof AST_SymbolRef) { @@ -5820,7 +5820,7 @@ Compressor.prototype.compress = function(node) { def(AST_Binary, function(compressor) { return this.left.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) { return any(this.body, compressor); @@ -5974,7 +5974,7 @@ Compressor.prototype.compress = function(node) { def(AST_Binary, function(compressor) { return this.left.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) { return any(this.body, compressor); @@ -6091,7 +6091,7 @@ Compressor.prototype.compress = function(node) { def(AST_Binary, function(scope) { return this.left.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) { var base = this.extends; @@ -8813,11 +8813,17 @@ Compressor.prototype.compress = function(node) { var left = this.left; var right = this.right; 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); if (lhs === left) return this; 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; } var rhs = right.drop_side_effect_free(compressor, first_in_statement); @@ -11566,13 +11572,16 @@ Compressor.prototype.compress = function(node) { || node instanceof AST_Object; } - function can_drop_op(op, rhs, compressor) { - switch (op) { + function can_drop_op(node, compressor) { + var rhs = node.right; + switch (node.operator) { case "in": return is_object(rhs) || compressor && compressor.option("unsafe_comps"); case "instanceof": 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: return true; } @@ -12118,8 +12127,10 @@ Compressor.prototype.compress = function(node) { } break; case "instanceof": + if (!can_drop_op(self, compressor)) break; if (is_lambda(self.right)) return make_sequence(self, [ - self, + self.left, + self.right, make_node(AST_False, self), ]).optimize(compressor); break; diff --git a/test/compress/arrows.js b/test/compress/arrows.js index 83025c25597..86ac8d494ca 100644 --- a/test/compress/arrows.js +++ b/test/compress/arrows.js @@ -690,6 +690,65 @@ inline_iife_within_arrow: { 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: { options = { inline: true, diff --git a/test/compress/awaits.js b/test/compress/awaits.js index f1d3628ccdb..42e86c8033a 100644 --- a/test/compress/awaits.js +++ b/test/compress/awaits.js @@ -1348,7 +1348,7 @@ functions_inner_var: { node_version: ">=8" } -instanceof_lambda: { +instanceof_lambda_1: { options = { evaluate: true, side_effects: true, @@ -1363,6 +1363,50 @@ instanceof_lambda: { 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: { options = { inline: true, diff --git a/test/compress/pure_funcs.js b/test/compress/pure_funcs.js index 688a105719f..76f57cd9c4e 100644 --- a/test/compress/pure_funcs.js +++ b/test/compress/pure_funcs.js @@ -147,7 +147,7 @@ relational: { "bar" >= "bar"; } expect: { - 0 instanceof bar(); + [] instanceof bar(); bar(); bar(), bar(); bar();