Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance assignments & unused #3428

Merged
merged 1 commit into from May 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
77 changes: 53 additions & 24 deletions lib/compress.js
Expand Up @@ -2282,16 +2282,23 @@ merge(Compressor.prototype, {
// returns true if this node may be null, undefined or contain `AST_Accessor`
(function(def) {
AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
return !compressor.option("pure_getters")
|| this._dot_throw(compressor);
return !compressor.option("pure_getters") || this._dot_throw(compressor);
});
function is_strict(compressor) {
return /strict/.test(compressor.option("pure_getters"));
}
def(AST_Node, is_strict);
def(AST_Array, return_false);
def(AST_Assign, function(compressor) {
return this.operator == "=" && this.right._dot_throw(compressor);
if (this.operator != "=") return false;
var rhs = this.right;
if (!rhs._dot_throw(compressor)) return false;
var sym = this.left;
if (!(sym instanceof AST_SymbolRef)) return true;
if (rhs instanceof AST_Binary && rhs.operator == "||" && sym.name == rhs.left.name) {
return rhs.right._dot_throw(compressor);
}
return true;
});
def(AST_Binary, function(compressor) {
return lazy_op[this.operator] && (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
Expand Down Expand Up @@ -3618,7 +3625,7 @@ merge(Compressor.prototype, {
var value = null;
if (node instanceof AST_Assign) {
if (!in_use || node.left === sym && def.id in fixed_ids && fixed_ids[def.id] !== node) {
value = node.right;
value = get_rhs(node);
}
} else if (!in_use) {
value = make_node(AST_Number, node, {
Expand Down Expand Up @@ -3843,16 +3850,26 @@ merge(Compressor.prototype, {
}
}

function get_rhs(assign) {
var rhs = assign.right;
if (!assign.write_only) return rhs;
if (!(rhs instanceof AST_Binary && lazy_op[rhs.operator])) return rhs;
var sym = assign.left;
if (!(sym instanceof AST_SymbolRef) || sym.name != rhs.left.name) return rhs;
return rhs.right;
}

function scan_ref_scoped(node, descend) {
var node_def, props = [], sym = assign_as_unused(node, props);
if (sym && self.variables.get(sym.name) === (node_def = sym.definition())) {
props.forEach(function(prop) {
prop.walk(tw);
});
if (node instanceof AST_Assign) {
node.right.walk(tw);
var right = get_rhs(node);
right.walk(tw);
if (node.left === sym) {
if (!node_def.chained && sym.fixed_value(true) === node.right) {
if (!node_def.chained && sym.fixed_value(true) === right) {
fixed_ids[node_def.id] = node;
}
if (!node.write_only) {
Expand Down Expand Up @@ -4163,12 +4180,14 @@ merge(Compressor.prototype, {
});
def(AST_Assign, function(compressor) {
var left = this.left;
if (left.has_side_effects(compressor)
|| compressor.has_directive("use strict")
&& left instanceof AST_PropAccess
&& left.expression.is_constant()) {
return this;
if (left instanceof AST_PropAccess) {
var expr = left.expression;
if (expr instanceof AST_Assign && !expr.may_throw_on_access(compressor)) {
expr.write_only = true;
}
if (compressor.has_directive("use strict") && expr.is_constant()) return this;
}
if (left.has_side_effects(compressor)) return this;
this.write_only = true;
if (root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) {
return this.right.drop_side_effect_free(compressor);
Expand Down Expand Up @@ -4243,8 +4262,9 @@ merge(Compressor.prototype, {
});
def(AST_Constant, return_null);
def(AST_Dot, function(compressor, first_in_statement) {
if (this.expression.may_throw_on_access(compressor)) return this;
return this.expression.drop_side_effect_free(compressor, first_in_statement);
var expr = this.expression;
if (expr.may_throw_on_access(compressor)) return this;
return expr.drop_side_effect_free(compressor, first_in_statement);
});
def(AST_Function, function(compressor) {
return this.name && compressor.option("ie8") ? this : null;
Expand Down Expand Up @@ -5556,20 +5576,29 @@ merge(Compressor.prototype, {
self.right = tmp;
}
}
if (commutativeOperators[self.operator]) {
if (self.right.is_constant()
&& !self.left.is_constant()) {
// if right is a constant, whatever side effects the
// left side might have could not influence the
// result. hence, force switch.

if (!(self.left instanceof AST_Binary
&& PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) {
reverse();
}
if (commutativeOperators[self.operator] && self.right.is_constant() && !self.left.is_constant()) {
// if right is a constant, whatever side effects the
// left side might have could not influence the
// result. hence, force switch.
if (!(self.left instanceof AST_Binary
&& PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) {
reverse();
}
}
self = self.lift_sequences(compressor);
if (compressor.option("assignments") && lazy_op[self.operator]) {
var assign = self.right;
// a || (a = x) => a = a || x
// a && (a = x) => a = a && x
if (self.left instanceof AST_SymbolRef
&& assign instanceof AST_Assign
&& assign.operator == "="
&& self.left.equivalent_to(assign.left)) {
self.right = assign.right;
assign.right = self;
return assign;
}
}
if (compressor.option("comparisons")) switch (self.operator) {
case "===":
case "!==":
Expand Down
16 changes: 16 additions & 0 deletions test/compress/assignment.js
Expand Up @@ -311,3 +311,19 @@ issue_3375: {
}
expect_stdout: "string"
}

issue_3427: {
options = {
assignments: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
var a;
a || (a = {});
})();
}
expect: {}
}
34 changes: 34 additions & 0 deletions test/compress/drop-unused.js
Expand Up @@ -2028,3 +2028,37 @@ issue_3375: {
}
expect_stdout: "0 0"
}

issue_3427_1: {
options = {
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
var a;
a = a || {};
})();
}
expect: {}
}

issue_3427_2: {
options = {
unused: true,
}
input: {
(function() {
var s = "PASS";
console.log(s = s || "FAIL");
})();
}
expect: {
(function() {
var s = "PASS";
console.log(s = s || "FAIL");
})();
}
expect_stdout: "PASS"
}
20 changes: 20 additions & 0 deletions test/compress/pure_getters.js
Expand Up @@ -1187,3 +1187,23 @@ drop_arguments: {
}
expect_stdout: "PASS"
}

issue_3427: {
options = {
assignments: true,
collapse_vars: true,
inline: true,
pure_getters: "strict",
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a;
(function(b) {
b.p = 42;
})(a || (a = {}));
}
expect: {}
}