diff options
-rw-r--r-- | lib/compress.js | 22 | ||||
-rw-r--r-- | test/compress/pure_getters.js | 94 |
2 files changed, 115 insertions, 1 deletions
diff --git a/lib/compress.js b/lib/compress.js index b9922e18..dc82db02 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -547,8 +547,25 @@ merge(Compressor.prototype, { return fixed(); }); + AST_SymbolRef.DEFMETHOD("is_immutable", function() { + var orig = this.definition().orig; + return orig.length == 1 && orig[0] instanceof AST_SymbolLambda; + }); + function is_lhs_read_only(lhs) { - return lhs instanceof AST_SymbolRef && lhs.definition().orig[0] instanceof AST_SymbolLambda; + if (lhs instanceof AST_SymbolRef) return lhs.definition().orig[0] instanceof AST_SymbolLambda; + if (lhs instanceof AST_PropAccess) { + lhs = lhs.expression; + if (lhs instanceof AST_SymbolRef) { + if (lhs.is_immutable()) return false; + lhs = lhs.fixed_value(); + } + if (!lhs) return true; + if (lhs instanceof AST_RegExp) return false; + if (lhs instanceof AST_Constant) return true; + return is_lhs_read_only(lhs); + } + return false; } function find_variable(compressor, name) { @@ -1287,6 +1304,7 @@ merge(Compressor.prototype, { def(AST_SymbolRef, function(pure_getters) { if (this.is_undefined) return true; if (!is_strict(pure_getters)) return false; + if (this.is_immutable()) return false; var fixed = this.fixed_value(); return !fixed || fixed._throw_on_access(pure_getters); }); @@ -3359,6 +3377,8 @@ merge(Compressor.prototype, { || cdr instanceof AST_PropAccess || cdr instanceof AST_Unary && !unary_side_effects(cdr.operator)) { field = "expression"; + } else if (cdr instanceof AST_Conditional) { + field = "condition"; } else { expressions[++i] = expressions[j]; break; diff --git a/test/compress/pure_getters.js b/test/compress/pure_getters.js index 81a96b73..2e7e17dc 100644 --- a/test/compress/pure_getters.js +++ b/test/compress/pure_getters.js @@ -241,3 +241,97 @@ issue_2110_2: { } expect_stdout: "function" } + +set_immutable_1: { + options = { + collapse_vars: true, + evaluate: true, + pure_getters: "strict", + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var a = 1; + a.foo += ""; + if (a.foo) console.log("FAIL"); + else console.log("PASS"); + } + expect: { + 1..foo += ""; + if (1..foo) console.log("FAIL"); + else console.log("PASS"); + } + expect_stdout: "PASS" +} + +set_immutable_2: { + options = { + cascade: true, + conditionals: true, + pure_getters: "strict", + reduce_vars: true, + sequences: true, + side_effects: true, + toplevel: true, + } + input: { + var a = 1; + a.foo += ""; + if (a.foo) console.log("FAIL"); + else console.log("PASS"); + } + expect: { + var a = 1; + a.foo += "", a.foo ? console.log("FAIL") : console.log("PASS"); + } + expect_stdout: "PASS" +} + +set_mutable_1: { + options = { + collapse_vars: true, + evaluate: true, + pure_getters: "strict", + reduce_vars: true, + unused: true, + } + input: { + !function a() { + a.foo += ""; + if (a.foo) console.log("PASS"); + else console.log("FAIL"); + }(); + } + expect: { + !function a() { + if (a.foo += "") console.log("PASS"); + else console.log("FAIL"); + }(); + } + expect_stdout: "PASS" +} + +set_mutable_2: { + options = { + cascade: true, + conditionals: true, + pure_getters: "strict", + reduce_vars: true, + sequences: true, + side_effects: true, + } + input: { + !function a() { + a.foo += ""; + if (a.foo) console.log("PASS"); + else console.log("FAIL"); + }(); + } + expect: { + !function a() { + (a.foo += "") ? console.log("PASS") : console.log("FAIL"); + }(); + } + expect_stdout: "PASS" +} |