Skip to content

Commit

Permalink
enhance pure_funcs (#4945)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlamsl committed May 19, 2021
1 parent d6152e6 commit e0695ef
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 30 deletions.
102 changes: 72 additions & 30 deletions lib/compress.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,23 @@ function Compressor(options, false_by_default) {
this.pure_funcs = pure_funcs;
} else if (typeof pure_funcs == "string") {
this.pure_funcs = function(node) {
return pure_funcs !== node.expression.print_to_string();
var expr;
if (node instanceof AST_Call) {
expr = node.expression;
} else if (node instanceof AST_Template) {
expr = node.tag;
}
return !(expr && pure_funcs === expr.print_to_string());
};
} else if (Array.isArray(pure_funcs)) {
this.pure_funcs = function(node) {
return !member(node.expression.print_to_string(), pure_funcs);
var expr;
if (node instanceof AST_Call) {
expr = node.expression;
} else if (node instanceof AST_Template) {
expr = node.tag;
}
return !(expr && member(expr.print_to_string(), pure_funcs));
};
} else {
this.pure_funcs = return_true;
Expand Down Expand Up @@ -2115,7 +2127,7 @@ merge(Compressor.prototype, {
def = fn.definition();
fn = fn.fixed_value();
}
if (!(fn instanceof AST_Lambda)) return true;
if (!(fn instanceof AST_Lambda)) return !node.is_expr_pure(compressor);
if (def && recursive_ref(compressor, def)) return true;
if (fn.collapse_scanning) return false;
fn.collapse_scanning = true;
Expand Down Expand Up @@ -2175,7 +2187,7 @@ merge(Compressor.prototype, {
var def = node.definition();
return (in_try || def.scope.resolve() !== scope) && !can_drop_symbol(node);
}
if (node instanceof AST_Template) return node.tag && !is_raw_tag(compressor, node.tag);
if (node instanceof AST_Template) return !node.is_expr_pure(compressor);
if (node instanceof AST_VarDef) {
if (check_destructured(node.name)) return true;
return (node.value || parent instanceof AST_Let) && node.name.match_symbol(function(node) {
Expand Down Expand Up @@ -4275,6 +4287,7 @@ merge(Compressor.prototype, {
],
String: [
"fromCharCode",
"raw",
],
});

Expand Down Expand Up @@ -4908,6 +4921,19 @@ merge(Compressor.prototype, {
}
return compressor.option("annotations") && this.pure || !compressor.pure_funcs(this);
});
AST_Template.DEFMETHOD("is_expr_pure", function(compressor) {
var tag = this.tag;
if (!tag) return true;
if (compressor.option("unsafe")) {
if (is_undeclared_ref(tag) && global_pure_fns[tag.name]) return true;
if (tag instanceof AST_Dot && is_undeclared_ref(tag.expression)) {
var static_fn = static_fns[tag.expression.name];
return static_fn && (static_fn[tag.property]
|| tag.expression.name == "Math" && tag.property == "random");
}
}
return !compressor.pure_funcs(this);
});
AST_Node.DEFMETHOD("is_call_pure", return_false);
AST_Call.DEFMETHOD("is_call_pure", function(compressor) {
if (!compressor.option("unsafe")) return false;
Expand Down Expand Up @@ -5072,7 +5098,7 @@ merge(Compressor.prototype, {
return !this.is_declared(compressor) || !can_drop_symbol(this, compressor);
});
def(AST_Template, function(compressor) {
return this.tag && !is_raw_tag(compressor, this.tag) || any(this.expressions, compressor);
return !this.is_expr_pure(compressor) || any(this.expressions, compressor);
});
def(AST_Try, function(compressor) {
return any(this.body, compressor)
Expand Down Expand Up @@ -7485,27 +7511,7 @@ merge(Compressor.prototype, {
if (!rhs) return lhs;
return make_sequence(this, [ lhs, rhs ]);
});
def(AST_Call, function(compressor, first_in_statement) {
var self = this;
if (self.is_expr_pure(compressor)) {
if (self.pure) AST_Node.warn("Dropping __PURE__ call [{file}:{line},{col}]", self.start);
var args = trim(self.args, compressor, first_in_statement, array_spread);
return args && make_sequence(self, args.map(convert_spread));
}
var exp = self.expression;
if (self.is_call_pure(compressor)) {
var exprs = self.args.slice();
exprs.unshift(exp.expression);
exprs = trim(exprs, compressor, first_in_statement, array_spread);
return exprs && make_sequence(self, exprs.map(convert_spread));
}
if (compressor.option("yields") && is_generator(exp)) {
var call = self.clone();
call.expression = make_node(AST_Function, exp, exp);
call.expression.body = [];
var opt = call.transform(compressor);
if (opt !== call) return opt.drop_side_effect_free(compressor, first_in_statement);
}
function drop_returns(compressor, exp) {
var drop_body = false;
if (compressor.option("arrows") && is_arrow(exp)) {
if (!exp.value) {
Expand Down Expand Up @@ -7539,6 +7545,31 @@ merge(Compressor.prototype, {
node.value = value.drop_side_effect_free(compressor);
}
});
}
return drop_body;
}
def(AST_Call, function(compressor, first_in_statement) {
var self = this;
if (self.is_expr_pure(compressor)) {
if (self.pure) AST_Node.warn("Dropping __PURE__ call [{file}:{line},{col}]", self.start);
var args = trim(self.args, compressor, first_in_statement, array_spread);
return args && make_sequence(self, args.map(convert_spread));
}
var exp = self.expression;
if (self.is_call_pure(compressor)) {
var exprs = self.args.slice();
exprs.unshift(exp.expression);
exprs = trim(exprs, compressor, first_in_statement, array_spread);
return exprs && make_sequence(self, exprs.map(convert_spread));
}
if (compressor.option("yields") && is_generator(exp)) {
var call = self.clone();
call.expression = make_node(AST_Function, exp, exp);
call.expression.body = [];
var opt = call.transform(compressor);
if (opt !== call) return opt.drop_side_effect_free(compressor, first_in_statement);
}
if (drop_returns(compressor, exp)) {
// always shallow clone to ensure stripping of negated IIFEs
self = self.clone();
self.expression = exp.clone();
Expand Down Expand Up @@ -7734,10 +7765,21 @@ merge(Compressor.prototype, {
return this.is_declared(compressor) && can_drop_symbol(this, compressor) ? null : this;
});
def(AST_Template, function(compressor, first_in_statement) {
if (this.tag && !is_raw_tag(compressor, this.tag)) return this;
var expressions = this.expressions;
if (expressions.length == 0) return null;
return make_sequence(this, expressions).drop_side_effect_free(compressor, first_in_statement);
var self = this;
if (self.is_expr_pure(compressor)) {
var expressions = self.expressions;
if (expressions.length == 0) return null;
return make_sequence(self, expressions).drop_side_effect_free(compressor, first_in_statement);
}
var tag = self.tag;
if (drop_returns(compressor, tag)) {
// always shallow clone to signal internal changes
self = self.clone();
self.tag = tag.clone();
// avoid extraneous traversal
if (tag._squeezed) self.tag._squeezed = true;
}
return self;
});
def(AST_Unary, function(compressor, first_in_statement) {
var exp = this.expression;
Expand Down
15 changes: 15 additions & 0 deletions test/compress/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,21 @@ unsafe_side_effects: {
node_version: ">=4"
}

pure_funcs: {
options = {
pure_funcs: "Math.random",
side_effects: true,
}
input: {
Math.random`${console.log("PASS")}`;
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}

issue_4604: {
options = {
collapse_vars: true,
Expand Down

0 comments on commit e0695ef

Please sign in to comment.