diff --git a/lib/compress.js b/lib/compress.js index 4a91e17e..473fd38c 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -6321,7 +6321,7 @@ Compressor.prototype.compress = function(node) { function to_class_expr(defcl, drop_name) { var cl = make_node(AST_ClassExpression, defcl, defcl); - cl.name = drop_name ? null : make_node(AST_SymbolClass, defcl.name, defcl.name); + if (cl.name) cl.name = drop_name ? null : make_node(AST_SymbolClass, cl.name, cl.name); return cl; } @@ -6697,9 +6697,9 @@ Compressor.prototype.compress = function(node) { log(node.name, "Dropping unused class {name}"); def.eliminated++; descend(node, tt); - if (parent instanceof AST_ExportDefault) return to_class_expr(node, true); - var trimmed = node.drop_side_effect_free(compressor, true); - if (trimmed === node) trimmed = to_class_expr(node, true); + var trimmed = to_class_expr(node, true); + if (parent instanceof AST_ExportDefault) return trimmed; + trimmed = trimmed.drop_side_effect_free(compressor, true); if (trimmed) return make_node(AST_SimpleStatement, node, { body: trimmed }); return in_list ? List.skip : make_node(AST_EmptyStatement, node); } @@ -8204,6 +8204,16 @@ Compressor.prototype.compress = function(node) { } return changed && exp.clone(); } + function assign_this_only(fn, compressor) { + fn.new = true; + var result = all(fn.body, function(stat) { + return !stat.has_side_effects(compressor); + }) && all(fn.argnames, function(argname) { + return !argname.match_symbol(return_false); + }) && !(fn.rest && fn.rest.match_symbol(return_false)); + fn.new = false; + return result; + } def(AST_Call, function(compressor, first_in_statement) { var self = this; if (self.is_expr_pure(compressor)) { @@ -8253,17 +8263,8 @@ Compressor.prototype.compress = function(node) { self.call_only = true; return self; }); - function assign_this_only(fn, compressor) { - fn.new = true; - var result = all(fn.body, function(stat) { - return !stat.has_side_effects(compressor); - }) && all(fn.argnames, function(argname) { - return !argname.match_symbol(return_false); - }) && !(fn.rest && fn.rest.match_symbol(return_false)); - fn.new = false; - return result; - } - function drop_class(self, compressor, first_in_statement) { + def(AST_ClassExpression, function(compressor, first_in_statement) { + var self = this; var exprs = [], values = []; var props = self.properties; for (var i = 0; i < props.length; i++) { @@ -8286,11 +8287,11 @@ Compressor.prototype.compress = function(node) { if (exprs) first_in_statement = false; values = trim(values, compressor, first_in_statement); if (!exprs) { - if (!base && !values) return null; + if (!base && !values && !self.name) return null; exprs = []; } - if (base || !compressor.has_directive("use strict")) { - var node = to_class_expr(self, true); + if (base || self.name || !compressor.has_directive("use strict")) { + var node = to_class_expr(self); if (!base) node.extends = null; node.properties = []; if (values) { @@ -8319,12 +8320,6 @@ Compressor.prototype.compress = function(node) { args: [], })); return make_sequence(self, exprs); - } - def(AST_ClassExpression, function(compressor, first_in_statement) { - var self = this; - var name = self.name; - if (name && name.fixed_value() !== self && name.definition().references.length > 0) return self; - return drop_class(self, compressor, first_in_statement); }); def(AST_Conditional, function(compressor) { var consequent = this.consequent.drop_side_effect_free(compressor); @@ -8365,9 +8360,6 @@ Compressor.prototype.compress = function(node) { return exprs.length == 0 ? null : make_sequence(this, exprs); }); def(AST_Constant, return_null); - def(AST_DefClass, function(compressor, first_in_statement) { - return drop_class(this, compressor, first_in_statement); - }); def(AST_Dot, function(compressor, first_in_statement) { var expr = this.expression; if (expr.may_throw_on_access(compressor)) return this; @@ -11673,7 +11665,7 @@ Compressor.prototype.compress = function(node) { if (fixed && (state = self.fixed || def.fixed).should_replace !== false) { var ev, init; if (fixed instanceof AST_This) { - if (!is_funarg(def) && same_scope(def)) init = fixed; + if (!is_funarg(def) && same_scope(def) && !cross_class(def)) init = fixed; } else if ((ev = fixed.evaluate(compressor, true)) !== fixed && typeof ev != "function" && (ev === null @@ -11715,6 +11707,14 @@ Compressor.prototype.compress = function(node) { } return self; + function cross_class(def) { + var scope = self.scope; + while (scope !== def.scope) { + if (scope instanceof AST_Class) return true; + scope = scope.parent_scope; + } + } + function has_symbol_ref(value) { var found; value.walk(new TreeWalker(function(node) { diff --git a/test/compress/classes.js b/test/compress/classes.js index c55b41ff..4e613fc4 100644 --- a/test/compress/classes.js +++ b/test/compress/classes.js @@ -2038,6 +2038,32 @@ issue_5015_3: { }); console.log("PASS"); } + expect: { + "use strict"; + (class A {}); + console.log("PASS"); + } + expect_stdout: "PASS" + node_version: ">=4" +} + +issue_5015_4: { + options = { + reduce_vars: true, + sequences: true, + side_effects: true, + toplevel: true, + unused: true, + } + input: { + "use strict"; + (class A { + static f() { + return A; + } + }); + console.log("PASS"); + } expect: { "use strict"; console.log("PASS"); @@ -2336,3 +2362,90 @@ issue_5142: { expect_stdout: "PASS" node_version: ">=12" } + +issue_5294_1: { + options = { + reduce_vars: true, + side_effects: true, + toplevel: true, + } + input: { + (class A { + static p = console.log(typeof A); + }); + } + expect: { + (class A { + static c = console.log(typeof A); + }); + } + expect_stdout: "function" + node_version: ">=12" +} + +issue_5294_2: { + options = { + reduce_vars: true, + side_effects: true, + toplevel: true, + } + input: { + class A { + static p = console.log(typeof A); + } + } + expect: { + class A { + static p = console.log(typeof A); + } + } + expect_stdout: "function" + node_version: ">=12" +} + +issue_5294_3: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var a = this; + (class A { + static p = console.log(a === A ? "FAIL" : "PASS"); + }); + } + expect: { + var a = this; + (class A { + static p = console.log(a === A ? "FAIL" : "PASS"); + }); + } + expect_stdout: "PASS" + node_version: ">=12" +} + +issue_5294_4: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + (class A { + static p = function() { + var a = this; + console.log(a === A ? "FAIL" : "PASS"); + }(); + }); + } + expect: { + (class A { + static p = function() { + console.log(this === A ? "FAIL" : "PASS"); + }(); + }); + } + expect_stdout: "PASS" + node_version: ">=12" +}