aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2020-06-05 11:51:21 +0100
committerGitHub <noreply@github.com>2020-06-05 18:51:21 +0800
commiteb481cee8cebcb0bee778827cab6d625e5cb30b8 (patch)
tree3bbc3618621b28d32146b4617ede0f3414c50823
parentfbc9d8009bee522fe784602ba8b157a38a45bd69 (diff)
downloadtracifyjs-eb481cee8cebcb0bee778827cab6d625e5cb30b8.tar.gz
tracifyjs-eb481cee8cebcb0bee778827cab6d625e5cb30b8.zip
fix corner cases in `reduce_vars` & `unused` (#3955)
fixes #3953 fixes #3956 fixes #3957
-rw-r--r--lib/compress.js26
-rw-r--r--test/compress/drop-unused.js38
-rw-r--r--test/compress/evaluate.js20
-rw-r--r--test/compress/reduce_vars.js50
4 files changed, 124 insertions, 10 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 23a9f923..db445bbc 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -495,6 +495,12 @@ merge(Compressor.prototype, {
});
}
+ function to_value(def, sym, fixed) {
+ if (fixed instanceof AST_Node) return fixed;
+ if (typeof fixed == "function") return fixed();
+ return make_node(AST_Undefined, sym);
+ }
+
function ref_once(compressor, def) {
return compressor.option("unused")
&& !def.scope.pinned()
@@ -576,8 +582,9 @@ merge(Compressor.prototype, {
var eq = node.operator == "=";
var value = eq ? node.right : node;
if (is_modified(compressor, tw, node, value, 0)) return;
+ var safe = eq || safe_to_read(tw, d);
node.right.walk(tw);
- if ((eq || safe_to_read(tw, d)) && safe_to_assign(tw, d)) {
+ if (safe && safe_to_assign(tw, d)) {
push_ref(d, sym);
mark(tw, d);
if (eq) {
@@ -587,9 +594,8 @@ merge(Compressor.prototype, {
return node.right;
};
} else {
- if (fixed == null) fixed = make_node(AST_Undefined, d.orig[0]);
sym.fixed = d.fixed = function() {
- var value = fixed instanceof AST_Node ? fixed : fixed();
+ var value = to_value(d, sym, fixed);
return value && make_node(AST_Binary, node, {
operator: node.operator.slice(0, -1),
left: value,
@@ -597,7 +603,7 @@ merge(Compressor.prototype, {
});
};
}
- sym.fixed.assigns = eq || !fixed.assigns ? [] : fixed.assigns.slice();
+ sym.fixed.assigns = eq || !fixed || !fixed.assigns ? [] : fixed.assigns.slice();
sym.fixed.assigns.push(node);
} else {
sym.walk(tw);
@@ -740,8 +746,8 @@ merge(Compressor.prototype, {
fn.argnames.forEach(function(arg, i) {
var d = arg.definition();
if (d.fixed === undefined && (!fn.uses_arguments || tw.has_directive("use strict"))) {
- tw.loop_ids[d.id] = tw.in_loop;
mark(tw, d);
+ tw.loop_ids[d.id] = tw.in_loop;
var value = iife.args[i];
d.fixed = function() {
var j = fn.argnames.indexOf(arg);
@@ -870,9 +876,8 @@ merge(Compressor.prototype, {
if (safe_to_read(tw, d) && safe_to_assign(tw, d)) {
push_ref(d, exp);
mark(tw, d);
- if (fixed == null) fixed = make_node(AST_Undefined, d.orig[0]);
d.fixed = function() {
- var value = fixed instanceof AST_Node ? fixed : fixed();
+ var value = to_value(d, exp, fixed);
return value && make_node(AST_Binary, node, {
operator: node.operator.slice(0, -1),
left: make_node(AST_UnaryPrefix, node, {
@@ -884,19 +889,19 @@ merge(Compressor.prototype, {
})
});
};
- d.fixed.assigns = fixed.assigns ? fixed.assigns.slice() : [];
+ d.fixed.assigns = fixed && fixed.assigns ? fixed.assigns.slice() : [];
d.fixed.assigns.push(node);
if (node instanceof AST_UnaryPrefix) {
exp.fixed = d.fixed;
} else {
exp.fixed = function() {
- var value = fixed instanceof AST_Node ? fixed : fixed();
+ var value = to_value(d, exp, fixed);
return value && make_node(AST_UnaryPrefix, node, {
operator: "+",
expression: value
});
};
- exp.fixed.assigns = fixed.assigns;
+ exp.fixed.assigns = fixed && fixed.assigns;
}
} else {
exp.walk(tw);
@@ -4429,6 +4434,7 @@ merge(Compressor.prototype, {
if (!drop_vars || sym.id in in_use_ids) {
if (def.value && indexOf_assign(sym, def) < 0) {
def.value = def.value.drop_side_effect_free(compressor);
+ if (def.value) def.value.tail_node().write_only = false;
}
var old_def, var_defs = var_defs_by_id.get(sym.id);
if (!def.value) {
diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js
index f3aeab21..a4a8595b 100644
--- a/test/compress/drop-unused.js
+++ b/test/compress/drop-unused.js
@@ -2652,3 +2652,41 @@ issue_3951: {
"0",
]
}
+
+issue_3956: {
+ options = {
+ collapse_vars: true,
+ evaluate: true,
+ inline: true,
+ passes: 2,
+ reduce_vars: true,
+ sequences: true,
+ side_effects: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ (function(a) {
+ function f(b) {
+ console.log(b);
+ a = 1;
+ }
+ var c = f(c += 0);
+ (function(d) {
+ console.log(d);
+ })(console.log(a) ^ 1, c);
+ })();
+ }
+ expect: {
+ var c, d;
+ c += 0,
+ console.log(NaN),
+ d = 1 ^ console.log(1),
+ console.log(d);
+ }
+ expect_stdout: [
+ "NaN",
+ "1",
+ "1",
+ ]
+}
diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js
index fd8deab5..0f3a9fd1 100644
--- a/test/compress/evaluate.js
+++ b/test/compress/evaluate.js
@@ -2715,3 +2715,23 @@ issue_3944: {
}
expect_stdout: "false"
}
+
+issue_3953: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ }
+ input: {
+ function f(a) {
+ (a += 0 * (a = 0)) && console.log("PASS");
+ }
+ f(1);
+ }
+ expect: {
+ function f(a) {
+ (a += 0 * (a = 0)) && console.log("PASS");
+ }
+ f(1);
+ }
+ expect_stdout: "PASS"
+}
diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js
index 3368cc6f..1a782b44 100644
--- a/test/compress/reduce_vars.js
+++ b/test/compress/reduce_vars.js
@@ -7273,3 +7273,53 @@ local_assignment_loop: {
}
expect_stdout: "PASS"
}
+
+issue_3957_1: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ }
+ input: {
+ function f(a) {
+ while (a += console.log(a = 0))
+ a = 0;
+ }
+ f("FAIL");
+ }
+ expect: {
+ function f(a) {
+ while (a += console.log(a = 0))
+ a = 0;
+ }
+ f("FAIL");
+ }
+ expect_stdout: [
+ "0",
+ "0",
+ ]
+}
+
+issue_3957_2: {
+ options = {
+ reduce_vars: true,
+ unused: true,
+ }
+ input: {
+ function f(a) {
+ while (a += console.log(a = 0))
+ a = 0;
+ }
+ f("FAIL");
+ }
+ expect: {
+ function f(a) {
+ while (a += console.log(a = 0))
+ a = 0;
+ }
+ f("FAIL");
+ }
+ expect_stdout: [
+ "0",
+ "0",
+ ]
+}