fix corner cases in reduce_vars, side_effects & unused (#5295)

fixes #5294
This commit is contained in:
Alex Lam S.L
2022-01-14 17:44:36 +00:00
committed by GitHub
parent 14e1311bdf
commit 87e8aca245
2 changed files with 141 additions and 28 deletions

View File

@@ -6321,7 +6321,7 @@ Compressor.prototype.compress = function(node) {
function to_class_expr(defcl, drop_name) { function to_class_expr(defcl, drop_name) {
var cl = make_node(AST_ClassExpression, defcl, defcl); 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; return cl;
} }
@@ -6697,9 +6697,9 @@ Compressor.prototype.compress = function(node) {
log(node.name, "Dropping unused class {name}"); log(node.name, "Dropping unused class {name}");
def.eliminated++; def.eliminated++;
descend(node, tt); descend(node, tt);
if (parent instanceof AST_ExportDefault) return to_class_expr(node, true); var trimmed = to_class_expr(node, true);
var trimmed = node.drop_side_effect_free(compressor, true); if (parent instanceof AST_ExportDefault) return trimmed;
if (trimmed === node) trimmed = to_class_expr(node, true); trimmed = trimmed.drop_side_effect_free(compressor, true);
if (trimmed) return make_node(AST_SimpleStatement, node, { body: trimmed }); if (trimmed) return make_node(AST_SimpleStatement, node, { body: trimmed });
return in_list ? List.skip : make_node(AST_EmptyStatement, node); return in_list ? List.skip : make_node(AST_EmptyStatement, node);
} }
@@ -8204,6 +8204,16 @@ Compressor.prototype.compress = function(node) {
} }
return changed && exp.clone(); 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) { def(AST_Call, function(compressor, first_in_statement) {
var self = this; var self = this;
if (self.is_expr_pure(compressor)) { if (self.is_expr_pure(compressor)) {
@@ -8253,17 +8263,8 @@ Compressor.prototype.compress = function(node) {
self.call_only = true; self.call_only = true;
return self; return self;
}); });
function assign_this_only(fn, compressor) { def(AST_ClassExpression, function(compressor, first_in_statement) {
fn.new = true; var self = this;
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) {
var exprs = [], values = []; var exprs = [], values = [];
var props = self.properties; var props = self.properties;
for (var i = 0; i < props.length; i++) { for (var i = 0; i < props.length; i++) {
@@ -8286,11 +8287,11 @@ Compressor.prototype.compress = function(node) {
if (exprs) first_in_statement = false; if (exprs) first_in_statement = false;
values = trim(values, compressor, first_in_statement); values = trim(values, compressor, first_in_statement);
if (!exprs) { if (!exprs) {
if (!base && !values) return null; if (!base && !values && !self.name) return null;
exprs = []; exprs = [];
} }
if (base || !compressor.has_directive("use strict")) { if (base || self.name || !compressor.has_directive("use strict")) {
var node = to_class_expr(self, true); var node = to_class_expr(self);
if (!base) node.extends = null; if (!base) node.extends = null;
node.properties = []; node.properties = [];
if (values) { if (values) {
@@ -8319,12 +8320,6 @@ Compressor.prototype.compress = function(node) {
args: [], args: [],
})); }));
return make_sequence(self, exprs); 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) { def(AST_Conditional, function(compressor) {
var consequent = this.consequent.drop_side_effect_free(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); return exprs.length == 0 ? null : make_sequence(this, exprs);
}); });
def(AST_Constant, return_null); 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) { def(AST_Dot, function(compressor, first_in_statement) {
var expr = this.expression; var expr = this.expression;
if (expr.may_throw_on_access(compressor)) return this; 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) { if (fixed && (state = self.fixed || def.fixed).should_replace !== false) {
var ev, init; var ev, init;
if (fixed instanceof AST_This) { 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 } else if ((ev = fixed.evaluate(compressor, true)) !== fixed
&& typeof ev != "function" && typeof ev != "function"
&& (ev === null && (ev === null
@@ -11715,6 +11707,14 @@ Compressor.prototype.compress = function(node) {
} }
return self; 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) { function has_symbol_ref(value) {
var found; var found;
value.walk(new TreeWalker(function(node) { value.walk(new TreeWalker(function(node) {

View File

@@ -2038,6 +2038,32 @@ issue_5015_3: {
}); });
console.log("PASS"); 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: { expect: {
"use strict"; "use strict";
console.log("PASS"); console.log("PASS");
@@ -2336,3 +2362,90 @@ issue_5142: {
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=12" 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"
}