diff --git a/lib/compress.js b/lib/compress.js index d3c24529d88..5f35b98a988 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -361,7 +361,7 @@ merge(Compressor.prototype, { if (def.scope === scope) return true; } while (scope instanceof AST_Function && (scope = scope.parent_scope)); })) { - tw.defun_ids[def.id] = undefined; + tw.defun_ids[def.id] = false; } def.recursive_refs = 0; def.references = []; @@ -386,23 +386,29 @@ merge(Compressor.prototype, { if (def.id in tw.defun_ids) { var marker = tw.defun_ids[def.id]; if (!marker) return; - if (marker !== tw.safe_ids) { - tw.defun_ids[def.id] = undefined; - return; + var visited = tw.defun_visited[def.id]; + if (marker === tw.safe_ids) { + if (!visited) return def.fixed; + } else if (visited) { + def.init.enclosed.forEach(function(d) { + if (def.init.variables.get(d.name) === d) return; + if (!safe_to_read(tw, d)) d.fixed = false; + }); + } else { + tw.defun_ids[def.id] = false; } - return def.fixed; - } - if (!tw.in_loop) { - tw.defun_ids[def.id] = tw.safe_ids; - return def.fixed; - } else if (tw.defun_ids[def.id] !== false) { - tw.defun_ids[def.id] = undefined; + } else { + if (!tw.in_loop) { + tw.defun_ids[def.id] = tw.safe_ids; + return def.fixed; + } + tw.defun_ids[def.id] = false; } } function walk_defuns(tw, scope) { scope.functions.each(function(def) { - if (def.init instanceof AST_Defun && tw.defun_ids[def.id] === undefined) { + if (def.init instanceof AST_Defun && !tw.defun_visited[def.id]) { tw.defun_ids[def.id] = tw.safe_ids; def.init.walk(tw); } @@ -587,8 +593,9 @@ merge(Compressor.prototype, { }); def(AST_Defun, function(tw, descend, compressor) { var id = this.name.definition().id; + if (tw.defun_visited[id]) return true; if (tw.defun_ids[id] !== tw.safe_ids) return true; - tw.defun_ids[id] = false; + tw.defun_visited[id] = true; this.inlined = false; push(tw); reset_variables(tw, compressor, this); @@ -820,6 +827,7 @@ merge(Compressor.prototype, { }); // Flow control for visiting `AST_Defun`s tw.defun_ids = Object.create(null); + tw.defun_visited = Object.create(null); // Record the loop body in which `AST_SymbolDeclaration` is first encountered tw.in_loop = null; tw.loop_ids = Object.create(null); diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index bc5fcf1b045..ac55f81db5c 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -6059,6 +6059,38 @@ conditional_nested_2: { expect_stdout: "1" } +conditional_nested_3: { + options = { + evaluate: true, + reduce_vars: true, + } + input: { + var n = 2, c = 0; + (function f(a) { + 0 < n-- && g(a = 1); + function g() { + a && c++; + } + g(); + 0 < n-- && f(); + })(); + console.log(c); + } + expect: { + var n = 2, c = 0; + (function f(a) { + 0 < n-- && g(a = 1); + function g() { + a && c++; + } + g(); + 0 < n-- && f(); + })(); + console.log(c); + } + expect_stdout: "2" +} + issue_2436: { options = { evaluate: true,