diff --git a/lib/compress.js b/lib/compress.js index 279d8522226..ac6c8fd6212 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -2693,13 +2693,13 @@ Compressor.prototype.compress = function(node) { } if (node instanceof AST_ObjectIdentity) return symbol_in_lvalues(node, parent); if (node instanceof AST_PropAccess) { - if (side_effects) return true; var exp = node.expression; - if (exp instanceof AST_SymbolRef && is_arguments(exp.definition())) return true; if (compressor.option("unsafe")) { if (is_undeclared_ref(exp) && global_names[exp.name]) return false; if (is_static_fn(exp)) return false; } + if (exp instanceof AST_SymbolRef && is_arguments(exp.definition())) return true; + if (side_effects) return true; if (!well_defined) return true; if (value_def) return false; if (!in_try && lhs_local) return false; @@ -2708,6 +2708,7 @@ Compressor.prototype.compress = function(node) { } if (node instanceof AST_Spread) return true; if (node instanceof AST_SymbolRef) { + if (is_undeclared_ref(node) && node.is_declared(compressor)) return false; if (symbol_in_lvalues(node, parent)) return !is_direct_assignment(node, parent); if (side_effects && may_modify(node)) return true; var def = node.definition(); @@ -8219,23 +8220,34 @@ Compressor.prototype.compress = function(node) { } if (!native) { elements.length = node.elements.length; - } else if (!node.rest) switch (elements.length) { + } else if (!node.rest) SHORTHAND: switch (elements.length) { case 0: if (node === root) break; if (drop) value = value.drop_side_effect_free(compressor); return null; - case 1: + default: if (!drop) break; if (!unwind) break; if (node === root) break; - var sym = elements[0]; + var pos = elements.length, sym; + while (--pos >= 0) { + var element = elements[pos]; + if (element) { + sym = element; + break; + } + } + if (pos < 0) break; + for (var i = pos; --i >= 0;) { + if (elements[i]) break SHORTHAND; + } if (sym.has_side_effects(compressor)) break; if (value.has_side_effects(compressor) && sym.match_symbol(function(node) { return node instanceof AST_PropAccess; })) break; value = make_node(AST_Sub, node, { expression: value, - property: make_node(AST_Number, node, { value: 0 }), + property: make_node(AST_Number, node, { value: pos }), }); return sym; } diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index bad26eadd4d..68f650e2615 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -4996,7 +4996,7 @@ cascade_forin: { ] } -unsafe_builtin: { +unsafe_builtin_1: { options = { collapse_vars: true, pure_getters: "strict", @@ -5020,6 +5020,46 @@ unsafe_builtin: { expect_stdout: "1 4" } +unsafe_builtin_2: { + options = { + collapse_vars: true, + toplevel: true, + unsafe: true, + unused: true, + } + input: { + A = "PASS"; + var a = A; + console.log(a); + } + expect: { + console.log(A = "PASS"); + } + expect_stdout: "PASS" +} + +unsafe_builtin_3: { + options = { + collapse_vars: true, + unsafe: true, + unused: true, + } + input: { + A = "PASS"; + (function() { + var a = A; + console.log(a); + })(); + } + expect: { + A = "PASS"; + (function() { + console.log(A); + })(); + } + expect_stdout: "PASS" +} + return_1: { options = { collapse_vars: true, @@ -7350,30 +7390,39 @@ substitution_assign: { b = 1 + (b = a); console.log(a, b); } + function f4(a, b) { + b = 1 + (a = b); + console.log(a, b); + } f1(42, "foo"); f2(42, "foo"); f3(42, "foo"); + f4("bar", 41); } expect: { function f1(a, b) { console.log(f1 = a, a); } function f2(a, b) { - a = 1 + (b = a); - console.log(a, b); + console.log(a = 1 + (b = a), b); } function f3(a, b) { - b = 1 + (b = a); + console.log(a, b = 1 + (b = a)); + } + function f4(a, b) { + b = 1 + (a = b); console.log(a, b); } f1(42, "foo"); f2(42, "foo"); f3(42, "foo"); + f4("bar", 41); } expect_stdout: [ "42 42", "43 42", "42 43", + "41 42", ] } diff --git a/test/compress/destructured.js b/test/compress/destructured.js index 49180ccacca..a283c3ac0ea 100644 --- a/test/compress/destructured.js +++ b/test/compress/destructured.js @@ -1339,7 +1339,7 @@ maintain_position_var: { } expect: { A = "FAIL"; - var [ , b ] = [ A ]; + var b = [ A ][1]; console.log(b || "PASS"); } expect_stdout: "PASS"