diff --git a/lib/compress/index.js b/lib/compress/index.js index cd9b4fa4b..8b901a3bf 100644 --- a/lib/compress/index.js +++ b/lib/compress/index.js @@ -2750,16 +2750,16 @@ def_optimize(AST_UnaryPostfix, function(self, compressor) { def_optimize(AST_UnaryPrefix, function(self, compressor) { var e = self.expression; - if (self.operator == "delete" - && !(e instanceof AST_SymbolRef - || e instanceof AST_PropAccess - || is_identifier_atom(e))) { - if (e instanceof AST_Sequence) { - const exprs = e.expressions.slice(); - exprs.push(make_node(AST_True, self)); - return make_sequence(self, exprs).optimize(compressor); - } - return make_sequence(self, [ e, make_node(AST_True, self) ]).optimize(compressor); + if ( + self.operator == "delete" && + !( + e instanceof AST_SymbolRef || + e instanceof AST_PropAccess || + e instanceof AST_Chain || + is_identifier_atom(e) + ) + ) { + return make_sequence(self, [e, make_node(AST_True, self)]).optimize(compressor); } var seq = self.lift_sequences(compressor); if (seq !== self) { @@ -4251,7 +4251,16 @@ def_optimize(AST_Sub, function(self, compressor) { }); def_optimize(AST_Chain, function (self, compressor) { - if (is_nullish(self.expression, compressor)) return make_node(AST_Undefined, self); + if (is_nullish(self.expression, compressor)) { + let parent = compressor.parent(); + // It's valid to delete a nullish optional chain, but if we optimized + // this to `delete undefined` then it would appear to be a syntax error + // when we try to optimize the delete. Thankfully, `delete 0` is fine. + if (parent instanceof AST_UnaryPrefix && parent.operator === "delete") { + return make_node_from_constant(0, self); + } + return make_node(AST_Undefined, self); + } return self; }); diff --git a/test/compress/nullish.js b/test/compress/nullish.js index 52bf27af0..601e4da4e 100644 --- a/test/compress/nullish.js +++ b/test/compress/nullish.js @@ -145,3 +145,33 @@ nullish_coalescing_parens: { "PASS", ] } + +delete_nullish: { + input: { + delete obj?.key; + const other = { key: true }; + delete other?.key; + } + expect: { + delete obj?.key; + const other = { key: true }; + delete other?.key; + } +} + +delete_nullish_2: { + options = { + defaults: true, + evaluate: true, + passes: 3, + } + input: { + delete null?.key; + delete null?.deep.key; + delete null.deep?.key; + delete null?.deep?.key; + } + expect: { + delete null.deep?.key; + } +}