aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2021-01-14 16:22:34 +0000
committerGitHub <noreply@github.com>2021-01-15 00:22:34 +0800
commit65d39a3702643a8dc6a3b797a15470e6715d6f84 (patch)
tree7287a22133ed77e1ffcea7ee8a1560e4fc554b5e
parent24917e7084a9ce240660f8d4b69dcbf1515af084 (diff)
downloadtracifyjs-65d39a3702643a8dc6a3b797a15470e6715d6f84.tar.gz
tracifyjs-65d39a3702643a8dc6a3b797a15470e6715d6f84.zip
fix corner cases in `collapse_vars` (#4555)
fixes #4554
-rw-r--r--lib/compress.js49
-rw-r--r--test/compress/destructured.js31
2 files changed, 71 insertions, 9 deletions
diff --git a/lib/compress.js b/lib/compress.js
index f0ed6773..fadd7415 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -1715,7 +1715,7 @@ merge(Compressor.prototype, {
var funarg = candidate.name instanceof AST_SymbolFunarg;
var may_throw = return_false;
if (candidate.may_throw(compressor)) {
- if (funarg && scope instanceof AST_AsyncFunction) continue;
+ if (funarg && is_async(scope)) continue;
may_throw = in_try ? function(node) {
return node.has_side_effects(compressor);
} : side_effects_external;
@@ -1727,6 +1727,9 @@ merge(Compressor.prototype, {
var lhs_local = is_lhs_local(lhs);
var rvalue = get_rvalue(candidate);
if (!side_effects) side_effects = value_has_side_effects();
+ var check_destructured = in_try || !lhs_local ? function(node) {
+ return node instanceof AST_Destructured;
+ } : return_false;
var replace_all = replace_all_symbols(candidate);
var hit = funarg;
var abort = false;
@@ -1833,7 +1836,6 @@ merge(Compressor.prototype, {
}
if (node instanceof AST_Debugger) return true;
if (node instanceof AST_Defun) return funarg && lhs.name === node.name.name;
- if (node instanceof AST_Destructured) return (in_try || !lhs_local) && parent instanceof AST_Assign;
if (node instanceof AST_DestructuredKeyVal) return node.key instanceof AST_Node;
if (node instanceof AST_DWLoop) return true;
if (node instanceof AST_LoopControl) return true;
@@ -1931,7 +1933,7 @@ merge(Compressor.prototype, {
}
if (node instanceof AST_This) return symbol_in_lvalues(node, parent);
if (node instanceof AST_VarDef) {
- if ((in_try || !lhs_local) && node.name instanceof AST_Destructured) return true;
+ if (check_destructured(node.name)) return true;
return (node.value || parent instanceof AST_Let) && node.name.match_symbol(function(node) {
return node instanceof AST_SymbolDeclaration
&& (lvalues.has(node.name) || side_effects && may_modify(node));
@@ -1940,13 +1942,38 @@ merge(Compressor.prototype, {
var sym = is_lhs(node.left, node);
if (!sym) return false;
if (sym instanceof AST_PropAccess) return true;
- if ((in_try || !lhs_local) && sym instanceof AST_Destructured) return true;
+ if (check_destructured(sym)) return true;
return sym.match_symbol(function(node) {
return node instanceof AST_SymbolRef
&& (lvalues.has(node.name) || read_toplevel && compressor.exposed(node.definition()));
}, true);
}
+ function may_throw_destructured(node, value) {
+ if (!value) return !(node instanceof AST_Symbol);
+ if (node instanceof AST_DefaultValue) {
+ return value.has_side_effects(compressor)
+ || node.value.has_side_effects(compressor)
+ || may_throw_destructured(node.name, is_undefined(value) && node.value);
+ }
+ if (node instanceof AST_Destructured) {
+ if (node.rest && may_throw_destructured(node.rest)) return true;
+ if (node instanceof AST_DestructuredArray) {
+ if (!(value instanceof AST_Array || value.is_string(compressor))) return true;
+ return !all(node.elements, function(element) {
+ return !may_throw_destructured(element);
+ });
+ }
+ if (node instanceof AST_DestructuredObject) {
+ if (!value.is_defined(compressor)) return true;
+ return !all(node.properties, function(prop) {
+ if (prop instanceof AST_Node && prop.has_side_effects(compressor)) return false;
+ return !may_throw_destructured(prop.value);
+ });
+ }
+ }
+ }
+
function extract_args() {
var iife, fn = compressor.self();
if (is_function(fn)
@@ -1960,7 +1987,7 @@ merge(Compressor.prototype, {
})) {
var fn_strict = compressor.has_directive("use strict");
if (fn_strict && !member(fn_strict, fn.body)) fn_strict = false;
- var has_await = fn instanceof AST_AsyncFunction ? function(node) {
+ var has_await = is_async(fn) ? function(node) {
return node instanceof AST_Symbol && node.name == "await";
} : function(node) {
return node instanceof AST_Await && !tw.find_parent(AST_Scope);
@@ -1984,18 +2011,19 @@ merge(Compressor.prototype, {
}
});
args = iife.args.slice();
+ var len = args.length;
var names = Object.create(null);
for (var i = fn.argnames.length; --i >= 0;) {
var sym = fn.argnames[i];
- var arg = iife.args[i];
+ var arg = args[i];
var value;
if (sym instanceof AST_DefaultValue) {
value = sym.value;
sym = sym.name;
- args[iife.args.length + i] = value;
+ args[len + i] = value;
}
if (sym instanceof AST_Destructured) {
- if (!sym.match_symbol(return_false)) continue;
+ if (!may_throw_destructured(sym, arg)) continue;
candidates.length = 0;
break;
}
@@ -2015,7 +2043,7 @@ merge(Compressor.prototype, {
value: arg
});
candidate.name_index = i;
- candidate.arg_index = value ? iife.args.length + i : i;
+ candidate.arg_index = value ? len + i : i;
candidates.unshift([ candidate ]);
}
}
@@ -2273,7 +2301,10 @@ merge(Compressor.prototype, {
can_replace = false;
var after = stop_after;
var if_hit = stop_if_hit;
+ var stack = scanner.stack;
+ scanner.stack = [ parent ];
lhs.transform(scanner);
+ scanner.stack = stack;
stop_if_hit = if_hit;
stop_after = after;
can_replace = replace;
diff --git a/test/compress/destructured.js b/test/compress/destructured.js
index 029b4427..7cc6f46d 100644
--- a/test/compress/destructured.js
+++ b/test/compress/destructured.js
@@ -2456,3 +2456,34 @@ issue_4519_2: {
expect_stdout: "PASS"
node_version: ">=6"
}
+
+issue_4554: {
+ options = {
+ collapse_vars: true,
+ unused: true,
+ }
+ input: {
+ A = "PASS";
+ var a = "FAIL";
+ try {
+ (function({}, b) {
+ return b;
+ })(void 0, a = A);
+ } catch (e) {
+ console.log(a);
+ }
+ }
+ expect: {
+ A = "PASS";
+ var a = "FAIL";
+ try {
+ (function({}, b) {
+ return b;
+ })(void 0, a = A);
+ } catch (e) {
+ console.log(a);
+ }
+ }
+ expect_stdout: "PASS"
+ node_version: ">=6"
+}