[Pkg-javascript-commits] [uglifyjs] 49/228: warn & drop `#__PURE__` iff IIFE is dropped (#1511)
Jonas Smedegaard
dr at jones.dk
Sat Apr 15 14:25:15 UTC 2017
This is an automated email from the git hooks/post-receive script.
js pushed a commit to branch master
in repository uglifyjs.
commit 858e6c78a44f236e6e4d460a2ac187eef59823c8
Author: Alex Lam S.L <alexlamsl at gmail.com>
Date: Tue Feb 28 02:25:44 2017 +0800
warn & drop `#__PURE__` iff IIFE is dropped (#1511)
- consolidate `side-effects` optimisations
- improve string `+` optimisation
- enhance literal & `conditionals` optimisations
---
lib/compress.js | 154 ++++++++++++++++++++++--------------------
test/compress/conditionals.js | 40 +++++++++--
test/compress/dead-code.js | 3 +-
test/compress/evaluate.js | 42 +++++++-----
test/compress/issue-1261.js | 58 ++++++++++++++++
test/compress/issue-1275.js | 2 +-
test/compress/typeof.js | 5 +-
test/mocha/minify.js | 11 +++
8 files changed, 216 insertions(+), 99 deletions(-)
diff --git a/lib/compress.js b/lib/compress.js
index 5383311..24ca105 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -1375,9 +1375,7 @@ merge(Compressor.prototype, {
&& (comments = this.start.comments_before)
&& comments.length
&& /[@#]__PURE__/.test((last_comment = comments[comments.length - 1]).value)) {
- compressor.warn("Dropping __PURE__ call [{file}:{line},{col}]", this.start);
- last_comment.value = last_comment.value.replace(/[@#]__PURE__/g, ' ');
- pure = true;
+ pure = last_comment;
}
return this.pure = pure;
});
@@ -1676,8 +1674,7 @@ merge(Compressor.prototype, {
line : def.name.start.line,
col : def.name.start.col
};
- if (def.value && def.value.has_side_effects(compressor)) {
- def._unused_side_effects = true;
+ if (def.value && (def._unused_side_effects = def.value.drop_side_effect_free(compressor))) {
compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w);
return true;
}
@@ -1697,7 +1694,7 @@ merge(Compressor.prototype, {
for (var i = 0; i < def.length;) {
var x = def[i];
if (x._unused_side_effects) {
- side_effects.push(x.value);
+ side_effects.push(x._unused_side_effects);
def.splice(i, 1);
} else {
if (side_effects.length > 0) {
@@ -1927,6 +1924,10 @@ merge(Compressor.prototype, {
def(AST_This, return_null);
def(AST_Call, function(compressor, first_in_statement){
if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) return this;
+ if (this.pure) {
+ compressor.warn("Dropping __PURE__ call [{file}:{line},{col}]", this.start);
+ this.pure.value = this.pure.value.replace(/[@#]__PURE__/g, ' ');
+ }
var args = trim(this.args, compressor, first_in_statement);
return args && AST_Seq.from_array(args);
});
@@ -1978,8 +1979,17 @@ merge(Compressor.prototype, {
case "typeof":
if (this.expression instanceof AST_SymbolRef) return null;
default:
- if (first_in_statement && is_iife_call(this.expression)) return this;
- return this.expression.drop_side_effect_free(compressor, first_in_statement);
+ var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
+ if (first_in_statement
+ && this instanceof AST_UnaryPrefix
+ && is_iife_call(expression)) {
+ if (expression === this.expression && this.operator.length === 1) return this;
+ return make_node(AST_UnaryPrefix, this, {
+ operator: this.operator.length === 1 ? this.operator : "!",
+ expression: expression
+ });
+ }
+ return expression;
}
});
def(AST_SymbolRef, function() {
@@ -2027,10 +2037,6 @@ merge(Compressor.prototype, {
OPT(AST_SimpleStatement, function(self, compressor){
if (compressor.option("side_effects")) {
var body = self.body;
- if (!body.has_side_effects(compressor)) {
- compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
- return make_node(AST_EmptyStatement, self);
- }
var node = body.drop_side_effect_free(compressor, true);
if (!node) {
compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
@@ -2647,17 +2653,10 @@ merge(Compressor.prototype, {
}
}
if (!self.car.has_side_effects(compressor)
- && !self.cdr.has_side_effects(compressor)
&& self.car.equivalent_to(self.cdr)) {
return self.car;
}
}
- if (self.cdr instanceof AST_UnaryPrefix
- && self.cdr.operator == "void"
- && !self.cdr.expression.has_side_effects(compressor)) {
- self.cdr.expression = self.car;
- return self.cdr;
- }
if (self.cdr instanceof AST_Undefined) {
return make_node(AST_UnaryPrefix, self, {
operator : "void",
@@ -2686,8 +2685,20 @@ merge(Compressor.prototype, {
});
OPT(AST_UnaryPrefix, function(self, compressor){
- self = self.lift_sequences(compressor);
+ var seq = self.lift_sequences(compressor);
+ if (seq !== self) {
+ return seq;
+ }
var e = self.expression;
+ if (compressor.option("side_effects") && self.operator == "void") {
+ e = e.drop_side_effect_free(compressor);
+ if (e) {
+ self.expression = e;
+ return self;
+ } else {
+ return make_node(AST_Undefined, self);
+ }
+ }
if (compressor.option("booleans") && compressor.in_boolean_context()) {
switch (self.operator) {
case "!":
@@ -2704,13 +2715,10 @@ merge(Compressor.prototype, {
// typeof always returns a non-empty string, thus it's
// always true in booleans
compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
- if (self.expression.has_side_effects(compressor)) {
- return make_node(AST_Seq, self, {
- car: self.expression,
- cdr: make_node(AST_True, self)
- });
- }
- return make_node(AST_True, self);
+ return make_node(AST_Seq, self, {
+ car: e,
+ cdr: make_node(AST_True, self)
+ }).optimize(compressor);
}
}
return self.evaluate(compressor)[0];
@@ -2840,13 +2848,10 @@ merge(Compressor.prototype, {
var rr = self.right.evaluate(compressor);
if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) {
compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
- if (self.left.has_side_effects(compressor)) {
- return make_node(AST_Seq, self, {
- car: self.left,
- cdr: make_node(AST_False)
- }).optimize(compressor);
- }
- return make_node(AST_False, self);
+ return make_node(AST_Seq, self, {
+ car: self.left,
+ cdr: make_node(AST_False)
+ }).optimize(compressor);
}
if (ll.length > 1 && ll[1]) {
return rr[0];
@@ -2860,13 +2865,10 @@ merge(Compressor.prototype, {
var rr = self.right.evaluate(compressor);
if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) {
compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
- if (self.left.has_side_effects(compressor)) {
- return make_node(AST_Seq, self, {
- car: self.left,
- cdr: make_node(AST_True)
- }).optimize(compressor);
- }
- return make_node(AST_True, self);
+ return make_node(AST_Seq, self, {
+ car: self.left,
+ cdr: make_node(AST_True, self)
+ }).optimize(compressor);
}
if (ll.length > 1 && !ll[1]) {
return rr[0];
@@ -2878,10 +2880,19 @@ merge(Compressor.prototype, {
case "+":
var ll = self.left.evaluate(compressor);
var rr = self.right.evaluate(compressor);
- if ((ll.length > 1 && ll[0] instanceof AST_String && ll[1] && !self.right.has_side_effects(compressor)) ||
- (rr.length > 1 && rr[0] instanceof AST_String && rr[1] && !self.left.has_side_effects(compressor))) {
+ if (ll.length > 1 && ll[0] instanceof AST_String && ll[1]) {
+ compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
+ return make_node(AST_Seq, self, {
+ car: self.right,
+ cdr: make_node(AST_True, self)
+ }).optimize(compressor);
+ }
+ if (rr.length > 1 && rr[0] instanceof AST_String && rr[1]) {
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
- return make_node(AST_True, self);
+ return make_node(AST_Seq, self, {
+ car: self.left,
+ cdr: make_node(AST_True, self)
+ }).optimize(compressor);
}
break;
}
@@ -3131,7 +3142,8 @@ merge(Compressor.prototype, {
&& alternative instanceof AST_Assign
&& consequent.operator == alternative.operator
&& consequent.left.equivalent_to(alternative.left)
- && !consequent.left.has_side_effects(compressor)
+ && (!consequent.left.has_side_effects(compressor)
+ || !self.condition.has_side_effects(compressor))
) {
/*
* Stuff like this:
@@ -3149,25 +3161,19 @@ merge(Compressor.prototype, {
})
});
}
+ // x ? y(a) : y(b) --> y(x ? a : b)
if (consequent instanceof AST_Call
&& alternative.TYPE === consequent.TYPE
- && consequent.args.length == alternative.args.length
- && !consequent.expression.has_side_effects(compressor)
- && consequent.expression.equivalent_to(alternative.expression)) {
- if (consequent.args.length == 0) {
- return make_node(AST_Seq, self, {
- car: self.condition,
- cdr: consequent
- });
- }
- if (consequent.args.length == 1) {
- consequent.args[0] = make_node(AST_Conditional, self, {
- condition: self.condition,
- consequent: consequent.args[0],
- alternative: alternative.args[0]
- });
- return consequent;
- }
+ && consequent.args.length == 1
+ && alternative.args.length == 1
+ && consequent.expression.equivalent_to(alternative.expression)
+ && !consequent.expression.has_side_effects(compressor)) {
+ consequent.args[0] = make_node(AST_Conditional, self, {
+ condition: self.condition,
+ consequent: consequent.args[0],
+ alternative: alternative.args[0]
+ });
+ return consequent;
}
// x?y?z:a:a --> x&&y?z:a
if (consequent instanceof AST_Conditional
@@ -3182,16 +3188,12 @@ merge(Compressor.prototype, {
alternative: alternative
});
}
- // y?1:1 --> 1
- if (consequent.is_constant()
- && alternative.is_constant()
- && consequent.equivalent_to(alternative)) {
- var consequent_value = consequent.evaluate(compressor)[0];
- if (self.condition.has_side_effects(compressor)) {
- return AST_Seq.from_array([self.condition, consequent_value]);
- } else {
- return consequent_value;
- }
+ // x ? y : y --> x, y
+ if (consequent.equivalent_to(alternative)) {
+ return make_node(AST_Seq, self, {
+ car: self.condition,
+ cdr: consequent
+ }).optimize(compressor);
}
if (is_true(self.consequent)) {
@@ -3350,8 +3352,12 @@ merge(Compressor.prototype, {
});
function literals_in_boolean_context(self, compressor) {
- if (compressor.option("booleans") && compressor.in_boolean_context() && !self.has_side_effects(compressor)) {
- return make_node(AST_True, self);
+ if (compressor.option("booleans") && compressor.in_boolean_context()) {
+ var best = first_in_statement(compressor) ? best_of_statement : best_of;
+ return best(self, make_node(AST_Seq, self, {
+ car: self,
+ cdr: make_node(AST_True, self)
+ }).optimize(compressor));
}
return self;
};
diff --git a/test/compress/conditionals.js b/test/compress/conditionals.js
index d88c5b9..074d2a6 100644
--- a/test/compress/conditionals.js
+++ b/test/compress/conditionals.js
@@ -50,7 +50,8 @@ ifs_3_should_warn: {
conditionals : true,
dead_code : true,
evaluate : true,
- booleans : true
+ booleans : true,
+ side_effects : true,
};
input: {
var x, y;
@@ -135,16 +136,28 @@ ifs_6: {
comparisons: true
};
input: {
- var x;
+ var x, y;
if (!foo && !bar && !baz && !boo) {
x = 10;
} else {
x = 20;
}
+ if (y) {
+ x[foo] = 10;
+ } else {
+ x[foo] = 20;
+ }
+ if (foo) {
+ x[bar] = 10;
+ } else {
+ x[bar] = 20;
+ }
}
expect: {
- var x;
+ var x, y;
x = foo || bar || baz || boo ? 20 : 10;
+ x[foo] = y ? 10 : 20;
+ foo ? x[bar] = 10 : x[bar] = 20;
}
}
@@ -159,10 +172,16 @@ cond_1: {
} else {
do_something(y);
}
+ if (some_condition()) {
+ side_effects(x);
+ } else {
+ side_effects(y);
+ }
}
expect: {
var do_something;
do_something(some_condition() ? x : y);
+ some_condition() ? side_effects(x) : side_effects(y);
}
}
@@ -213,10 +232,16 @@ cond_4: {
} else {
do_something();
}
+ if (some_condition()) {
+ side_effects();
+ } else {
+ side_effects();
+ }
}
expect: {
var do_something;
some_condition(), do_something();
+ some_condition(), side_effects();
}
}
@@ -250,7 +275,8 @@ cond_5: {
cond_7: {
options = {
conditionals: true,
- evaluate : true
+ evaluate : true,
+ side_effects: true,
};
input: {
var x, y, z, a, b;
@@ -714,6 +740,7 @@ issue_1154: {
conditionals: true,
evaluate : true,
booleans : true,
+ side_effects: true,
};
input: {
function f1(x) { return x ? -1 : -1; }
@@ -742,7 +769,7 @@ issue_1154: {
function g2() { return g(), 2; }
function g3() { return g(), -4; }
function g4() { return g(), !1; }
- function g5() { return g(), void 0; }
+ function g5() { return void g(); }
function g6() { return g(), "number"; }
}
}
@@ -750,7 +777,8 @@ issue_1154: {
no_evaluate: {
options = {
conditionals: true,
- evaluate : false
+ evaluate : false,
+ side_effects: true,
}
input: {
function f(b) {
diff --git a/test/compress/dead-code.js b/test/compress/dead-code.js
index 2596e80..cd96d02 100644
--- a/test/compress/dead-code.js
+++ b/test/compress/dead-code.js
@@ -64,7 +64,8 @@ dead_code_constant_boolean_should_warn_more: {
loops : true,
booleans : true,
conditionals : true,
- evaluate : true
+ evaluate : true,
+ side_effects : true,
};
input: {
while (!((foo && bar) || (x + "0"))) {
diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js
index 5cefadc..6bed73f 100644
--- a/test/compress/evaluate.js
+++ b/test/compress/evaluate.js
@@ -624,25 +624,35 @@ in_boolean_context: {
options = {
booleans: true,
evaluate: true,
+ sequences: true,
+ side_effects: true,
}
input: {
- !42;
- !"foo";
- ![1, 2];
- !/foo/;
- !b(42);
- !b("foo");
- !b([1, 2]);
- !b(/foo/);
+ console.log(
+ !42,
+ !"foo",
+ ![1, 2],
+ !/foo/,
+ !b(42),
+ !b("foo"),
+ !b([1, 2]),
+ !b(/foo/),
+ ![1, foo()],
+ ![1, foo(), 2]
+ );
}
expect: {
- !1;
- !1;
- !1;
- !1;
- !b(42);
- !b("foo");
- !b([1, 2]);
- !b(/foo/);
+ console.log(
+ !1,
+ !1,
+ !1,
+ !1,
+ !b(42),
+ !b("foo"),
+ !b([1, 2]),
+ !b(/foo/),
+ ![1, foo()],
+ (foo(), !1)
+ );
}
}
diff --git a/test/compress/issue-1261.js b/test/compress/issue-1261.js
index dfbe210..a872c57 100644
--- a/test/compress/issue-1261.js
+++ b/test/compress/issue-1261.js
@@ -116,3 +116,61 @@ pure_function_calls_toplevel: {
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]",
]
}
+
+should_warn: {
+ options = {
+ booleans: true,
+ conditionals: true,
+ evaluate: true,
+ side_effects: true,
+ }
+ input: {
+ /* @__PURE__ */(function(){x})(), void/* @__PURE__ */(function(){y})();
+ /* @__PURE__ */(function(){x})() || true ? foo() : bar();
+ true || /* @__PURE__ */(function(){y})() ? foo() : bar();
+ /* @__PURE__ */(function(){x})() && false ? foo() : bar();
+ false && /* @__PURE__ */(function(){y})() ? foo() : bar();
+ /* @__PURE__ */(function(){x})() + "foo" ? bar() : baz();
+ "foo" + /* @__PURE__ */(function(){y})() ? bar() : baz();
+ /* @__PURE__ */(function(){x})() ? foo() : foo();
+ [/* @__PURE__ */(function(){x})()] ? foo() : bar();
+ !{ foo: /* @__PURE__ */(function(){x})() } ? bar() : baz();
+ }
+ expect: {
+ foo();
+ foo();
+ bar();
+ bar();
+ bar();
+ bar();
+ foo();
+ foo();
+ baz();
+ }
+ expect_warnings: [
+ "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,61]",
+ "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,23]",
+ "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:128,23]",
+ "WARN: Boolean || always true [test/compress/issue-1261.js:129,23]",
+ "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:129,23]",
+ "WARN: Condition always true [test/compress/issue-1261.js:129,23]",
+ "WARN: Boolean || always true [test/compress/issue-1261.js:130,8]",
+ "WARN: Condition always true [test/compress/issue-1261.js:130,8]",
+ "WARN: Boolean && always false [test/compress/issue-1261.js:131,23]",
+ "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:131,23]",
+ "WARN: Condition always false [test/compress/issue-1261.js:131,23]",
+ "WARN: Boolean && always false [test/compress/issue-1261.js:132,8]",
+ "WARN: Condition always false [test/compress/issue-1261.js:132,8]",
+ "WARN: + in boolean context always true [test/compress/issue-1261.js:133,23]",
+ "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:133,23]",
+ "WARN: Condition always true [test/compress/issue-1261.js:133,23]",
+ "WARN: + in boolean context always true [test/compress/issue-1261.js:134,8]",
+ "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:134,31]",
+ "WARN: Condition always true [test/compress/issue-1261.js:134,8]",
+ "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,23]",
+ "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:136,24]",
+ "WARN: Condition always true [test/compress/issue-1261.js:136,8]",
+ "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,31]",
+ "WARN: Condition always false [test/compress/issue-1261.js:137,8]",
+ ]
+}
diff --git a/test/compress/issue-1275.js b/test/compress/issue-1275.js
index e88e284..51f696a 100644
--- a/test/compress/issue-1275.js
+++ b/test/compress/issue-1275.js
@@ -35,7 +35,7 @@ string_plus_optimization: {
throw "nope";
}
try {
- console.log('0' + throwing_function() ? "yes" : "no");
+ console.log((throwing_function(), "yes"));
} catch (ex) {
console.log(ex);
}
diff --git a/test/compress/typeof.js b/test/compress/typeof.js
index fb39157..7bf8e5e 100644
--- a/test/compress/typeof.js
+++ b/test/compress/typeof.js
@@ -29,6 +29,7 @@ typeof_in_boolean_context: {
booleans : true,
evaluate : true,
conditionals : true,
+ side_effects : true,
};
input: {
function f1(x) { return typeof x ? "yes" : "no"; }
@@ -36,12 +37,14 @@ typeof_in_boolean_context: {
typeof 0 ? foo() : bar();
!typeof console.log(1);
var a = !typeof console.log(2);
+ if (typeof (1 + foo()));
}
expect: {
function f1(x) { return "yes"; }
function f2() { return g(), "Yes"; }
foo();
- !(console.log(1), !0);
+ console.log(1);
var a = !(console.log(2), !0);
+ foo();
}
}
diff --git a/test/mocha/minify.js b/test/mocha/minify.js
index 0cf8c5c..baac2a4 100644
--- a/test/mocha/minify.js
+++ b/test/mocha/minify.js
@@ -154,6 +154,17 @@ describe("minify", function() {
var code = result.code;
assert.strictEqual(code, "// comment1 comment2\nbar();");
});
+ it("should not drop #__PURE__ hint if function is retained", function() {
+ var result = Uglify.minify("var a = /*#__PURE__*/(function(){return 1})();", {
+ fromString: true,
+ output: {
+ comments: "all",
+ beautify: false,
+ }
+ });
+ var code = result.code;
+ assert.strictEqual(code, "var a=/*#__PURE__*/function(){return 1}();");
+ })
});
describe("JS_Parse_Error", function() {
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/uglifyjs.git
More information about the Pkg-javascript-commits
mailing list