From 6dbacb5e3f4b3be40fab132575c2e5e3f820b32f Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Tue, 17 Nov 2020 04:35:00 +0000 Subject: [PATCH] enhance `varify` (#4279) --- lib/compress.js | 52 ++++++++++++------ test/compress/varify.js | 119 ++++++++++++++++++++++++++++++++++++++++ test/ufuzz/index.js | 2 +- 3 files changed, 156 insertions(+), 17 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index d9446e87..7297938a 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -6551,6 +6551,19 @@ merge(Compressor.prototype, { return if_break_in_loop(self, compressor); }); + OPT(AST_ForIn, function(self, compressor) { + if (compressor.option("varify") && (self.init instanceof AST_Const || self.init instanceof AST_Let)) { + var name = self.init.definitions[0].name; + if ((name instanceof AST_Destructured || name instanceof AST_SymbolLet) + && !name.match_symbol(function(node) { + if (node instanceof AST_SymbolDeclaration) return may_overlap(compressor, node.definition()); + })) { + self.init = to_var(self.init); + } + } + return self; + }); + function mark_locally_defined(condition, consequent, alternative) { if (!(condition instanceof AST_Binary)) return; if (!(condition.left instanceof AST_String)) { @@ -7051,21 +7064,18 @@ merge(Compressor.prototype, { return make_sequence(this, assignments); }); - function varify(self, compressor) { - return compressor.option("varify") && all(self.definitions, function(defn) { - return !defn.name.match_symbol(function(node) { - if (!(node instanceof AST_SymbolDeclaration)) return; - if (!node.fixed_value()) return true; - var def = node.definition(); - if (compressor.exposed(def)) return true; - var scope = def.scope.resolve(); - for (var s = def.scope; s !== scope;) { - s = s.parent_scope; - if (s.var_names()[node.name]) return true; - } - }); - }) ? make_node(AST_Var, self, { - definitions: self.definitions.map(function(defn) { + function may_overlap(compressor, def) { + if (compressor.exposed(def)) return true; + var scope = def.scope.resolve(); + for (var s = def.scope; s !== scope;) { + s = s.parent_scope; + if (s.var_names()[def.name]) return true; + } + } + + function to_var(stat) { + return make_node(AST_Var, stat, { + definitions: stat.definitions.map(function(defn) { return make_node(AST_VarDef, defn, { name: defn.name.convert_symbol(AST_SymbolVar, function(name, node) { var def = name.definition(); @@ -7076,7 +7086,17 @@ merge(Compressor.prototype, { value: defn.value }); }) - }) : self; + }); + } + + function varify(self, compressor) { + return compressor.option("varify") && all(self.definitions, function(defn) { + return !defn.name.match_symbol(function(node) { + if (node instanceof AST_SymbolDeclaration) { + return !node.fixed_value() || may_overlap(compressor, node.definition()); + } + }); + }) ? to_var(self) : self; } OPT(AST_Const, varify); diff --git a/test/compress/varify.js b/test/compress/varify.js index 1286fc67..d4894d2d 100644 --- a/test/compress/varify.js +++ b/test/compress/varify.js @@ -234,3 +234,122 @@ issue_4191_let: { expect_stdout: "function undefined" node_version: ">=4" } + +forin_const_1: { + options = { + join_vars: true, + reduce_vars: true, + toplevel: true, + varify: true, + } + input: { + const o = { + foo: 42, + bar: "PASS", + }; + for (const k in o) + console.log(k, o[k]); + } + expect: { + var o = { + foo: 42, + bar: "PASS", + }; + for (const k in o) + console.log(k, o[k]); + } + expect_stdout: true + node_version: ">=4" +} + +forin_const_2: { + options = { + join_vars: true, + reduce_vars: true, + toplevel: true, + varify: true, + } + input: { + const o = { + p: 42, + q: "PASS", + }; + for (const [ k ] in o) + console.log(k, o[k]); + } + expect: { + var o = { + p: 42, + q: "PASS", + }, k; + for ([ k ] in o) + console.log(k, o[k]); + } + expect_stdout: [ + "p 42", + "q PASS", + ] + node_version: ">=6" +} + +forin_let_1: { + options = { + join_vars: true, + reduce_vars: true, + toplevel: true, + varify: true, + } + input: { + "use strict"; + let o = { + foo: 42, + bar: "PASS", + }; + for (let k in o) + console.log(k, o[k]); + } + expect: { + "use strict"; + var o = { + foo: 42, + bar: "PASS", + }, k; + for (k in o) + console.log(k, o[k]); + } + expect_stdout: [ + "foo 42", + "bar PASS", + ] + node_version: ">=4" +} + +forin_let_2: { + options = { + join_vars: true, + reduce_vars: true, + toplevel: true, + varify: true, + } + input: { + let o = { + p: 42, + q: "PASS", + }; + for (let [ k ] in o) + console.log(k, o[k]); + } + expect: { + var o = { + p: 42, + q: "PASS", + }, k; + for ([ k ] in o) + console.log(k, o[k]); + } + expect_stdout: [ + "p 42", + "q PASS", + ] + node_version: ">=6" +} diff --git a/test/ufuzz/index.js b/test/ufuzz/index.js index 1c4af3c3..70041966 100644 --- a/test/ufuzz/index.js +++ b/test/ufuzz/index.js @@ -708,7 +708,7 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn "{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ", label.target + " for (", !/^key/.test(key) ? rng(10) ? "" : "var " : rng(10) ? "var " : rng(2) ? "let " : "const ", - rng(20) ? key : "{ length: " + key + " }", + rng(10) ? key : rng(5) ? "[ " + key + " ]" : "{ length: " + key + " }", " in expr" + loop + ") {", rng(5) > 1 ? "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; " : "", createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth), -- 2.34.1