enhance pure_funcs (#4945)
This commit is contained in:
100
lib/compress.js
100
lib/compress.js
@@ -136,11 +136,23 @@ function Compressor(options, false_by_default) {
|
|||||||
this.pure_funcs = pure_funcs;
|
this.pure_funcs = pure_funcs;
|
||||||
} else if (typeof pure_funcs == "string") {
|
} else if (typeof pure_funcs == "string") {
|
||||||
this.pure_funcs = function(node) {
|
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)) {
|
} else if (Array.isArray(pure_funcs)) {
|
||||||
this.pure_funcs = function(node) {
|
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 {
|
} else {
|
||||||
this.pure_funcs = return_true;
|
this.pure_funcs = return_true;
|
||||||
@@ -2115,7 +2127,7 @@ merge(Compressor.prototype, {
|
|||||||
def = fn.definition();
|
def = fn.definition();
|
||||||
fn = fn.fixed_value();
|
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 (def && recursive_ref(compressor, def)) return true;
|
||||||
if (fn.collapse_scanning) return false;
|
if (fn.collapse_scanning) return false;
|
||||||
fn.collapse_scanning = true;
|
fn.collapse_scanning = true;
|
||||||
@@ -2175,7 +2187,7 @@ merge(Compressor.prototype, {
|
|||||||
var def = node.definition();
|
var def = node.definition();
|
||||||
return (in_try || def.scope.resolve() !== scope) && !can_drop_symbol(node);
|
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 (node instanceof AST_VarDef) {
|
||||||
if (check_destructured(node.name)) return true;
|
if (check_destructured(node.name)) return true;
|
||||||
return (node.value || parent instanceof AST_Let) && node.name.match_symbol(function(node) {
|
return (node.value || parent instanceof AST_Let) && node.name.match_symbol(function(node) {
|
||||||
@@ -4275,6 +4287,7 @@ merge(Compressor.prototype, {
|
|||||||
],
|
],
|
||||||
String: [
|
String: [
|
||||||
"fromCharCode",
|
"fromCharCode",
|
||||||
|
"raw",
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -4908,6 +4921,19 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return compressor.option("annotations") && this.pure || !compressor.pure_funcs(this);
|
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_Node.DEFMETHOD("is_call_pure", return_false);
|
||||||
AST_Call.DEFMETHOD("is_call_pure", function(compressor) {
|
AST_Call.DEFMETHOD("is_call_pure", function(compressor) {
|
||||||
if (!compressor.option("unsafe")) return false;
|
if (!compressor.option("unsafe")) return false;
|
||||||
@@ -5072,7 +5098,7 @@ merge(Compressor.prototype, {
|
|||||||
return !this.is_declared(compressor) || !can_drop_symbol(this, compressor);
|
return !this.is_declared(compressor) || !can_drop_symbol(this, compressor);
|
||||||
});
|
});
|
||||||
def(AST_Template, function(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) {
|
def(AST_Try, function(compressor) {
|
||||||
return any(this.body, compressor)
|
return any(this.body, compressor)
|
||||||
@@ -7485,27 +7511,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!rhs) return lhs;
|
if (!rhs) return lhs;
|
||||||
return make_sequence(this, [ lhs, rhs ]);
|
return make_sequence(this, [ lhs, rhs ]);
|
||||||
});
|
});
|
||||||
def(AST_Call, function(compressor, first_in_statement) {
|
function drop_returns(compressor, exp) {
|
||||||
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);
|
|
||||||
}
|
|
||||||
var drop_body = false;
|
var drop_body = false;
|
||||||
if (compressor.option("arrows") && is_arrow(exp)) {
|
if (compressor.option("arrows") && is_arrow(exp)) {
|
||||||
if (!exp.value) {
|
if (!exp.value) {
|
||||||
@@ -7539,6 +7545,31 @@ merge(Compressor.prototype, {
|
|||||||
node.value = value.drop_side_effect_free(compressor);
|
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
|
// always shallow clone to ensure stripping of negated IIFEs
|
||||||
self = self.clone();
|
self = self.clone();
|
||||||
self.expression = exp.clone();
|
self.expression = exp.clone();
|
||||||
@@ -7734,10 +7765,21 @@ merge(Compressor.prototype, {
|
|||||||
return this.is_declared(compressor) && can_drop_symbol(this, compressor) ? null : this;
|
return this.is_declared(compressor) && can_drop_symbol(this, compressor) ? null : this;
|
||||||
});
|
});
|
||||||
def(AST_Template, function(compressor, first_in_statement) {
|
def(AST_Template, function(compressor, first_in_statement) {
|
||||||
if (this.tag && !is_raw_tag(compressor, this.tag)) return this;
|
var self = this;
|
||||||
var expressions = this.expressions;
|
if (self.is_expr_pure(compressor)) {
|
||||||
|
var expressions = self.expressions;
|
||||||
if (expressions.length == 0) return null;
|
if (expressions.length == 0) return null;
|
||||||
return make_sequence(this, expressions).drop_side_effect_free(compressor, first_in_statement);
|
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) {
|
def(AST_Unary, function(compressor, first_in_statement) {
|
||||||
var exp = this.expression;
|
var exp = this.expression;
|
||||||
|
|||||||
@@ -315,6 +315,21 @@ unsafe_side_effects: {
|
|||||||
node_version: ">=4"
|
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: {
|
issue_4604: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user