diff --git a/lib/compress.js b/lib/compress.js index 5a06572f..06873df8 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -4031,7 +4031,7 @@ merge(Compressor.prototype, { if (compressor.option("inline") && !fn.uses_arguments && !fn.uses_eval - && can_flatten_body() + && (value = can_flatten_body(stat)) && (exp === fn ? !fn.name : compressor.option("unused") && (def = exp.definition()).references.length == 1 @@ -4039,8 +4039,7 @@ merge(Compressor.prototype, { && fn.is_constant_expression(exp.scope)) && !self.pure && !fn.contains_this() - && can_inject_symbols() - && (value = return_value(stat))) { + && can_inject_symbols()) { return make_sequence(self, flatten_fn()).optimize(compressor); } if (compressor.option("side_effects") && all(fn.body, is_empty)) { @@ -4071,10 +4070,25 @@ merge(Compressor.prototype, { } return self; - function can_flatten_body() { + function return_value(stat) { + if (!stat) return make_node(AST_Undefined, self); + if (stat instanceof AST_Return) { + if (!stat.value) return make_node(AST_Undefined, self); + return stat.value.clone(true); + } + if (stat instanceof AST_SimpleStatement) { + return make_node(AST_UnaryPrefix, stat, { + operator: "void", + expression: stat.body.clone(true) + }); + } + } + + function can_flatten_body(stat) { var len = fn.body.length; - if (len == 1) return true; - if (compressor.option("inline") < 3) return false; + if (compressor.option("inline") < 3) { + return len == 1 && return_value(stat); + } stat = null; for (var i = 0; i < len; i++) { var line = fn.body[i]; @@ -4090,7 +4104,7 @@ merge(Compressor.prototype, { stat = line; } } - return stat; + return return_value(stat); } function can_inject_args(catches, defs, safe_to_inject) { @@ -4108,21 +4122,18 @@ merge(Compressor.prototype, { return true; } - function can_inject_vars(catches, defs, safe_to_inject) { + function can_inject_vars(catches, safe_to_inject) { var len = fn.body.length; - if (len == 1) return true; - if (!safe_to_inject) return false; for (var i = 0; i < len; i++) { var stat = fn.body[i]; - if (stat instanceof AST_Definitions) { - for (var j = stat.definitions.length; --j >= 0;) { - var name = stat.definitions[j].name; - if (catches[name.name] - || identifier_atom(name.name) - || scope.var_names()[name.name]) { - return false; - } - if (defs) defs.push(name.definition()); + if (!(stat instanceof AST_Definitions)) continue; + if (!safe_to_inject) return false; + for (var j = stat.definitions.length; --j >= 0;) { + var name = stat.definitions[j].name; + if (catches[name.name] + || identifier_atom(name.name) + || scope.var_names()[name.name]) { + return false; } } } @@ -4143,7 +4154,7 @@ merge(Compressor.prototype, { } while (!(scope instanceof AST_Scope)); var safe_to_inject = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars; var inline = compressor.option("inline"); - if (!can_inject_vars(catches, in_loop, inline >= 3 && safe_to_inject)) return false; + if (!can_inject_vars(catches, !in_loop && inline >= 3 && safe_to_inject)) return false; if (!can_inject_args(catches, in_loop, inline >= 2 && safe_to_inject)) return false; return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop); } @@ -4193,10 +4204,9 @@ merge(Compressor.prototype, { stat.definitions.forEach(function(var_def) { append_var(decls, expressions, var_def.name, var_def.value); }); - } else { - expressions.push(value.clone(true)); } } + expressions.push(value); } function flatten_fn() { @@ -4212,17 +4222,6 @@ merge(Compressor.prototype, { } return expressions; } - - function return_value(stat) { - if (stat instanceof AST_Return) { - return stat.value; - } else if (stat instanceof AST_SimpleStatement) { - return make_node(AST_UnaryPrefix, stat, { - operator: "void", - expression: stat.body - }); - } - } }); OPT(AST_New, function(self, compressor){ diff --git a/test/compress/functions.js b/test/compress/functions.js index 7f5d048b..f38977b3 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -1901,3 +1901,27 @@ inline_true: { "3", ] } + +use_before_init_in_loop: { + options = { + inline: true, + toplevel: true, + } + input: { + var a = "PASS"; + for (var b = 2; --b >= 0;) (function() { + var c = function() { + return 1; + }(c && (a = "FAIL")); + })(); + console.log(a); + } + expect: { + var a = "PASS"; + for (var b = 2; --b >= 0;) (function() { + var c = (c && (a = "FAIL"), 1); + })(); + console.log(a); + } + expect_stdout: "PASS" +}