aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2020-12-08 00:52:14 +0000
committerGitHub <noreply@github.com>2020-12-08 08:52:14 +0800
commit5fba98608ce2ce359cbf788196e64e4bbb48e303 (patch)
tree5c48d020fb1b62655fa0ae1d6634ba81b470e81d
parentc587d7917d445e97ed8580251547870256237b63 (diff)
downloadtracifyjs-5fba98608ce2ce359cbf788196e64e4bbb48e303.tar.gz
tracifyjs-5fba98608ce2ce359cbf788196e64e4bbb48e303.zip
fix corner case in `reduce_vars` (#4348)
fixes #4347
-rw-r--r--lib/compress.js69
-rw-r--r--test/compress/async.js59
2 files changed, 92 insertions, 36 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 1b5b8be6..8936125d 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -340,8 +340,7 @@ merge(Compressor.prototype, {
return !immutable
&& parent.expression === node
&& !parent.is_expr_pure(compressor)
- && (!(value instanceof AST_Function)
- || !(parent instanceof AST_New) && value.contains_this());
+ && (!is_function(value) || !(parent instanceof AST_New) && value.contains_this());
}
if (parent instanceof AST_ForIn) return parent.init === node;
if (parent instanceof AST_ObjectKeyVal) {
@@ -390,13 +389,13 @@ merge(Compressor.prototype, {
def.fixed = !def.const_redefs
&& !def.scope.pinned()
&& !compressor.exposed(def)
- && !(def.init instanceof AST_Function && def.init !== def.scope)
+ && !(is_function(def.init) && def.init !== def.scope)
&& def.init;
- if (def.fixed instanceof AST_Defun && !all(def.references, function(ref) {
+ if (is_defun(def.fixed) && !all(def.references, function(ref) {
var scope = ref.scope.resolve();
do {
if (def.scope === scope) return true;
- } while (scope instanceof AST_Function && (scope = scope.parent_scope.resolve()));
+ } while (is_function(scope) && (scope = scope.parent_scope.resolve()));
})) {
tw.defun_ids[def.id] = false;
}
@@ -421,7 +420,7 @@ merge(Compressor.prototype, {
scope.may_call_this = noop;
if (!scope.contains_this()) return;
scope.functions.each(function(def) {
- if (def.init instanceof AST_Defun && !(def.id in tw.defun_ids)) {
+ if (is_defun(def.init) && !(def.id in tw.defun_ids)) {
tw.defun_ids[def.id] = false;
}
});
@@ -458,7 +457,7 @@ merge(Compressor.prototype, {
function walk_defuns(tw, scope) {
scope.functions.each(function(def) {
- if (def.init instanceof AST_Defun && !tw.defun_visited[def.id]) {
+ if (is_defun(def.init) && !tw.defun_visited[def.id]) {
tw.defun_ids[def.id] = tw.safe_ids;
def.init.walk(tw);
}
@@ -496,7 +495,7 @@ merge(Compressor.prototype, {
}
return !safe.assign || safe.assign === tw.safe_ids;
}
- return def.fixed instanceof AST_Defun;
+ return is_defun(def.fixed);
}
function safe_to_assign(tw, def, declare) {
@@ -651,6 +650,20 @@ merge(Compressor.prototype, {
lhs.walk(scanner);
}
+ function reduce_defun(tw, descend, compressor) {
+ var id = this.name.definition().id;
+ if (tw.defun_visited[id]) return true;
+ if (tw.defun_ids[id] !== tw.safe_ids) return true;
+ tw.defun_visited[id] = true;
+ this.inlined = false;
+ push(tw);
+ reset_variables(tw, compressor, this);
+ descend();
+ pop(tw);
+ walk_defuns(tw, this);
+ return true;
+ }
+
def(AST_Assign, function(tw, descend, compressor) {
var node = this;
var left = node.left;
@@ -732,6 +745,7 @@ merge(Compressor.prototype, {
}
}
});
+ def(AST_AsyncDefun, reduce_defun);
def(AST_Binary, function(tw) {
if (!lazy_op[this.operator]) return;
this.left.walk(tw);
@@ -748,31 +762,27 @@ merge(Compressor.prototype, {
def(AST_Call, function(tw, descend) {
tw.find_parent(AST_Scope).may_call_this();
var exp = this.expression;
- var tail = exp.tail_node();
- if (tail instanceof AST_Function) {
- if (exp !== tail) exp.expressions.slice(0, -1).forEach(function(node) {
- node.walk(tw);
- });
+ if (is_function(exp)) {
this.args.forEach(function(arg) {
arg.walk(tw);
});
- tail.walk(tw);
+ exp.walk(tw);
return true;
- } else if (tail instanceof AST_SymbolRef) {
- var def = tail.definition();
+ } else if (exp instanceof AST_SymbolRef) {
+ var def = exp.definition();
if (this.TYPE == "Call" && tw.in_boolean_context()) def.bool_fn++;
- if (!(def.fixed instanceof AST_Defun)) return;
+ if (!is_defun(def.fixed)) return;
var defun = mark_defun(tw, def);
if (!defun) return;
descend();
defun.walk(tw);
return true;
} else if (this.TYPE == "Call"
- && tail instanceof AST_Assign
- && tail.operator == "="
- && tail.left instanceof AST_SymbolRef
+ && exp instanceof AST_Assign
+ && exp.operator == "="
+ && exp.left instanceof AST_SymbolRef
&& tw.in_boolean_context()) {
- tail.left.definition().bool_fn++;
+ exp.left.definition().bool_fn++;
}
});
def(AST_Conditional, function(tw) {
@@ -785,19 +795,7 @@ merge(Compressor.prototype, {
pop(tw);
return true;
});
- def(AST_Defun, function(tw, descend, compressor) {
- var id = this.name.definition().id;
- if (tw.defun_visited[id]) return true;
- if (tw.defun_ids[id] !== tw.safe_ids) return true;
- tw.defun_visited[id] = true;
- this.inlined = false;
- push(tw);
- reset_variables(tw, compressor, this);
- descend();
- pop(tw);
- walk_defuns(tw, this);
- return true;
- });
+ def(AST_Defun, reduce_defun);
def(AST_Do, function(tw) {
var saved_loop = tw.in_loop;
tw.in_loop = this;
@@ -1007,8 +1005,7 @@ merge(Compressor.prototype, {
}
if (!this.fixed) this.fixed = d.fixed;
var parent;
- if (d.fixed instanceof AST_Defun
- && !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) {
+ if (is_defun(d.fixed) && !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) {
var defun = mark_defun(tw, d);
if (defun) defun.walk(tw);
}
diff --git a/test/compress/async.js b/test/compress/async.js
index ca604034..4f342895 100644
--- a/test/compress/async.js
+++ b/test/compress/async.js
@@ -328,3 +328,62 @@ property_access_expression: {
expect_stdout: "function"
node_version: ">=8"
}
+
+issue_4347_1: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ var a = "foo";
+ f();
+ a = "bar";
+ f();
+ async function f() {
+ console.log(a);
+ }
+ }
+ expect: {
+ var a = "foo";
+ f();
+ a = "bar";
+ f();
+ async function f() {
+ console.log(a);
+ }
+ }
+ expect_stdout: [
+ "foo",
+ "bar",
+ ]
+ node_version: ">=8"
+}
+
+issue_4347_2: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ var a = "PASS";
+ (async function() {
+ throw 42;
+ a = "FAIL";
+ })();
+ console.log(a);
+ }
+ expect: {
+ var a = "PASS";
+ (async function() {
+ throw 42;
+ a = "FAIL";
+ })();
+ console.log(a);
+ }
+ expect_stdout: "PASS"
+ node_version: ">=8"
+}