diff --git a/lib/compress.js b/lib/compress.js index 0f1ff39b292..99ddf1708ee 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -654,12 +654,20 @@ Compressor.prototype.compress = function(node) { } function access(tw, def) { - tw.defined_ids[def.id] = [ tw.defined_ids.seq ]; + tw.defined_ids[def.id] = tw.defined_ids.seq; } function assign(tw, def) { + tw.assigned_ids[def.id] = tw.defined_ids.seq; + tw.defined_ids[def.id] = false; + } + + function safe_to_access(tw, def) { + var seq = tw.defined_ids.seq; var defined = tw.defined_ids[def.id]; - if (defined) defined[0] = false; + if (defined !== seq) return false; + var assigned = tw.assigned_ids[def.id]; + return !assigned || assigned === seq; } function mark(tw, def) { @@ -1424,8 +1432,7 @@ Compressor.prototype.compress = function(node) { var d = ref.definition(); var fixed = d.fixed || d.last_ref && d.last_ref.fixed; push_ref(d, ref); - var defined = tw.defined_ids[d.id]; - if (defined && defined[0] === tw.defined_ids.seq) ref.defined = true; + if (safe_to_access(tw, d)) ref.defined = true; if (d.references.length == 1 && !d.fixed && d.orig[0] instanceof AST_SymbolDefun) { tw.loop_ids[d.id] = tw.in_loop; } @@ -1656,6 +1663,7 @@ Compressor.prototype.compress = function(node) { return node.reduce_vars(tw, descend, compressor); } : reset_flags); // Side-effect tracking on sequential property access + tw.assigned_ids = Object.create(null); tw.defined_ids = Object.create(null); tw.defined_ids.seq = {}; // Flow control for visiting lambda definitions diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index aa9c45aba82..7b7cb67066d 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -8346,3 +8346,119 @@ issue_1666_undefined_strict: { } expect_stdout: true } + +issue_5872_1: { + options = { + pure_getters: "strict", + reduce_vars: true, + side_effects: true, + } + input: { + var a = 42; + try { + while (!function f() { + a.p; + a = null; + }(a.q)) { + a.r; + console.log("FAIL"); + } + } catch (e) { + console.log("PASS"); + } + } + expect: { + var a = 42; + try { + while (!function f() { + a.p; + a = null; + }(a.q)) { + a.r; + console.log("FAIL"); + } + } catch (e) { + console.log("PASS"); + } + } + expect_stdout: "PASS" +} + +issue_5872_2: { + options = { + pure_getters: "strict", + reduce_vars: true, + side_effects: true, + toplevel: true, + } + input: { + function f() { + a.p; + a = null; + } + + var a = 42; + try { + while (!f(a.q)) { + a.r; + console.log("FAIL"); + } + } catch (e) { + console.log("PASS"); + } + } + expect: { + function f() { + a.p; + a = null; + } + + var a = 42; + try { + while (!f(a.q)) { + a.r; + console.log("FAIL"); + } + } catch (e) { + console.log("PASS"); + } + } + expect_stdout: "PASS" +} + +issue_5872_3: { + options = { + pure_getters: "strict", + reduce_vars: true, + side_effects: true, + } + input: { + var a = 42; + try { + while (new function() { + a.p; + a = null; + }(a.q)) { + a.r; + console.log("FAIL"); + } + } catch (e) { + console.log("PASS"); + } + } + expect: { + var a = 42; + try { + while (new function() { + a.p; + a = null; + }(a.q)) { + a.r; + console.log("FAIL"); + } + } catch (e) { + console.log("PASS"); + } + } + expect_stdout: "PASS" +}