diff --git a/lib/compress.js b/lib/compress.js index 387b87bb..933dbdbf 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -1384,6 +1384,8 @@ merge(Compressor.prototype, { var in_use = []; var in_use_ids = {}; // avoid expensive linear scans of in_use var initializations = new Dictionary(); + var destructuring_value = null; + var in_definition = false; // pass 1: find out which symbols are directly used in // this scope (not in nested scopes). var scope = this; @@ -1395,9 +1397,17 @@ merge(Compressor.prototype, { } if (node instanceof AST_Definitions && scope === self) { node.definitions.forEach(function(def){ - if (def.is_destructuring()) return; /* Destructurings are type assertions! */ if (def.value) { - initializations.add(def.name.name, def.value); + if (def.is_destructuring()) { + var destructuring_cache = destructuring_value; + destructuring_value = def.value; + in_definition = true; + def.walk(tw); + in_definition = false; + destructuring_value = destructuring_cache; + } else { + initializations.add(def.name.name, def.value); + } if (def.value.has_side_effects(compressor)) { def.value.walk(tw); } @@ -1420,6 +1430,39 @@ merge(Compressor.prototype, { scope = save_scope; return true; } + if (node instanceof AST_Destructuring) { + if (!in_definition) { + return true; + } + for (var i = 0; i < node.names.length; i++) { + if (node.names[i] instanceof AST_Destructuring) { + node.names[i].walk(tw); + } + else if (node.names[i] instanceof AST_Expansion) { + if (node.names[i].expression instanceof AST_Symbol) { + initializations.add(node.names[i].expression.name, destructuring_value); + } else { + throw new Error(string_template("Can't handle expansion of type: {type}", { + type: Object.getPrototypeOf(node.names[i].expression).TYPE + })); + } + } + else if (node.names[i] instanceof AST_Hole) { + continue; + } + else if (node.names[i] instanceof AST_ObjectKeyVal && typeof node.names[i].key === "string") { + initializations.add(node.names[i].key, destructuring_value); + } + else if (node.names[i] instanceof AST_Symbol) { + initializations.add(node.names[i].name, destructuring_value); + } else { + throw new Error(string_template("Unknown destructuring element of type: {type}", { + type: Object.getPrototypeOf(node.names[i]).TYPE + })); + } + } + return true; + } } }); self.walk(tw); diff --git a/test/compress/destructuring.js b/test/compress/destructuring.js index 5468bb81..2f8401a8 100644 --- a/test/compress/destructuring.js +++ b/test/compress/destructuring.js @@ -104,3 +104,99 @@ destructuring_expressions: { expect_exact: "({a,b});[{a}];f({x});" } +destructuring_remove_unused_1: { + options = { + unused: true + } + input: { + function a() { + var unused = "foo"; + var a = [1]; + var [b] = a; + f(b); + } + function b() { + var unused = "foo"; + var a = {b: 1}; + var {b} = a; + f(b); + } + function c() { + var unused = "foo"; + var a = [[1]]; + var [[b]] = a; + f(b); + } + function d() { + var unused = "foo"; + var a = {b: {b:1}}; + var {b:{b}} = a; + f(b); + } + function e() { + var unused = "foo"; + var a = [1, 2, 3, 4, 5]; + var [b, ...c] = a; + f(b, c); + } + } + expect: { + function a() { + var a = [1]; + var [b] = a; + f(b); + } + function b() { + var a = {b: 1}; + var {b} = a; + f(b); + } + function c() { + var a = [[1]]; + var [[b]] = a; + f(b); + } + function d() { + var a = {b: {b:1}}; + var {b:{b}} = a; + f(b); + } + function e() { + var a = [1, 2, 3, 4, 5]; + var [b, ...c] = a; + f(b, c); + } + } +} + +destructuring_remove_unused_2: { + options = { + unused: true + } + input: { + function a() { + var unused = "foo"; + var a = [,,1]; + var [b] = a; + f(b); + } + function b() { + var unused = "foo"; + var a = [{a: [1]}]; + var [{b: a}] = a; + f(b); + } + } + expect: { + function a() { + var a = [,,1]; + var [b] = a; + f(b); + } + function b() { + var a = [{a: [1]}]; + var [{b: a}] = a; + f(b); + } + } +}