fix corner cases in reduce_vars, side_effects & unused (#5295)
fixes #5294
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user