From b33e7f88e60f886ee3403c82ac2e3fb40caa698f Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sun, 5 Mar 2017 13:09:27 +0800 Subject: improve `unsafe` on undefined (#1548) `unsafe` turns undefined keyword into a variable of the same name if found, but that interferes with other related optimisations. Keep track of such transformations to ensure zero information loss in the process. --- lib/compress.js | 24 +++++++++++++++--------- test/compress/issue-1443.js | 16 ++++------------ test/compress/sequences.js | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 4a5f6395..f2269a2f 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -765,7 +765,7 @@ merge(Compressor.prototype, { CHANGED = true; stat = stat.clone(); stat.alternative = ret[0] || make_node(AST_Return, stat, { - value: make_node(AST_Undefined, stat) + value: null }); ret[0] = stat.transform(compressor); continue loop; @@ -798,7 +798,7 @@ merge(Compressor.prototype, { && !stat.alternative) { CHANGED = true; ret.push(make_node(AST_Return, ret[0], { - value: make_node(AST_Undefined, ret[0]) + value: null }).transform(compressor)); ret.unshift(stat); continue loop; @@ -1055,6 +1055,10 @@ merge(Compressor.prototype, { })); }; + function is_undefined(node) { + return node instanceof AST_Undefined || node.is_undefined; + } + /* -----[ boolean/negation helpers ]----- */ // methods to determine whether an expression has a boolean result type @@ -2402,8 +2406,8 @@ merge(Compressor.prototype, { return make_node(self.body.CTOR, self, { value: make_node(AST_Conditional, self, { condition : self.condition, - consequent : self.body.value || make_node(AST_Undefined, self.body).optimize(compressor), - alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).optimize(compressor) + consequent : self.body.value || make_node(AST_Undefined, self.body), + alternative : self.alternative.value || make_node(AST_Undefined, self.alternative) }) }).transform(compressor); } @@ -2834,7 +2838,7 @@ merge(Compressor.prototype, { return self.car; } } - if (self.cdr instanceof AST_Undefined) { + if (is_undefined(self.cdr)) { return make_node(AST_UnaryPrefix, self, { operator : "void", expression : self.car @@ -2873,7 +2877,7 @@ merge(Compressor.prototype, { self.expression = e; return self; } else { - return make_node(AST_Undefined, self); + return make_node(AST_Undefined, self).transform(compressor); } } if (compressor.option("booleans") && compressor.in_boolean_context()) { @@ -3354,7 +3358,7 @@ merge(Compressor.prototype, { && (!self.scope.uses_with || !compressor.find_parent(AST_With))) { switch (self.name) { case "undefined": - return make_node(AST_Undefined, self); + return make_node(AST_Undefined, self).transform(compressor); case "NaN": return make_node(AST_NaN, self).transform(compressor); case "Infinity": @@ -3397,11 +3401,13 @@ merge(Compressor.prototype, { var scope = compressor.find_parent(AST_Scope); var undef = scope.find_variable("undefined"); if (undef) { - return make_node(AST_SymbolRef, self, { + var ref = make_node(AST_SymbolRef, self, { name : "undefined", scope : scope, thedef : undef }); + ref.is_undefined = true; + return ref; } } return self; @@ -3688,7 +3694,7 @@ merge(Compressor.prototype, { OPT(AST_RegExp, literals_in_boolean_context); OPT(AST_Return, function(self, compressor){ - if (self.value instanceof AST_Undefined) { + if (self.value && is_undefined(self.value)) { self.value = null; } return self; diff --git a/test/compress/issue-1443.js b/test/compress/issue-1443.js index a2565872..304a71ac 100644 --- a/test/compress/issue-1443.js +++ b/test/compress/issue-1443.js @@ -2,6 +2,7 @@ unsafe_undefined: { options = { + conditionals: true, if_return: true, unsafe: true } @@ -19,12 +20,7 @@ unsafe_undefined: { expect: { function f(n) { return function() { - if (a) - return b; - if (c) - return d; - else - return n; + return a ? b : c ? d : n; }; } } @@ -32,6 +28,7 @@ unsafe_undefined: { keep_fnames: { options = { + conditionals: true, if_return: true, unsafe: true } @@ -57,12 +54,7 @@ keep_fnames: { function n(n) { return n * n; } - if (a) - return b; - if (c) - return d; - else - return r; + return a ? b : c ? d : r; }; } } diff --git a/test/compress/sequences.js b/test/compress/sequences.js index 7bb274cb..41cfc726 100644 --- a/test/compress/sequences.js +++ b/test/compress/sequences.js @@ -251,3 +251,36 @@ iife: { function d() {}(), function e() {}(), function f() {}(), function g() {}(); } } + +unsafe_undefined: { + options = { + conditionals: true, + if_return: true, + sequences: true, + side_effects: true, + unsafe: true, + } + input: { + function f(undefined) { + if (a) + return b; + if (c) + return d; + } + function g(undefined) { + if (a) + return b; + if (c) + return d; + e(); + } + } + expect: { + function f(undefined) { + return a ? b : c ? d : undefined; + } + function g(undefined) { + return a ? b : c ? d : void e(); + } + } +} -- cgit v1.2.3