From: Alex Lam S.L Date: Wed, 3 Jan 2018 09:18:38 +0000 (+0800) Subject: fix `reduce_vars` on `AST_Defun` (#2708) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=14778e049b12e131fc05ddacff9cda56dfede77d;p=UglifyJS.git fix `reduce_vars` on `AST_Defun` (#2708) --- diff --git a/lib/compress.js b/lib/compress.js index 06873df8..1e096ade 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -316,7 +316,7 @@ merge(Compressor.prototype, { if (def.scope.uses_eval || def.scope.uses_with) { def.fixed = false; } else if (!compressor.exposed(def)) { - def.fixed = undefined; + def.fixed = def.init; } else { def.fixed = false; } @@ -329,10 +329,12 @@ merge(Compressor.prototype, { function reset_variables(tw, compressor, node) { node.variables.each(function(def) { reset_def(compressor, def); - if (def.fixed === undefined && def.orig[0].TYPE == "SymbolVar") { - def.fixed = null; + if (def.fixed === null) { def.safe_ids = tw.safe_ids; mark(tw, def, true); + } else if (def.fixed) { + tw.loop_ids[def.id] = tw.in_loop; + mark(tw, def, true); } }); } @@ -504,15 +506,6 @@ merge(Compressor.prototype, { }); def(AST_Defun, function(tw, descend, compressor) { this.inlined = false; - var d = this.name.definition(); - if (compressor.exposed(d) || safe_to_read(tw, d)) { - d.fixed = false; - } else { - d.fixed = this; - d.single_use = ref_once(tw, compressor, d); - tw.loop_ids[d.id] = tw.in_loop; - mark(tw, d, true); - } var save_ids = tw.safe_ids; tw.safe_ids = Object.create(null); reset_variables(tw, compressor, this); diff --git a/lib/scope.js b/lib/scope.js index bceec289..79b2475d 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -43,9 +43,10 @@ "use strict"; -function SymbolDef(scope, orig) { +function SymbolDef(scope, orig, init) { this.name = orig.name; this.orig = [ orig ]; + this.init = init; this.eliminated = 0; this.scope = scope; this.references = []; @@ -158,10 +159,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ // scope when we encounter the AST_Defun node (which is // instanceof AST_Scope) but we get to the symbol a bit // later. - (node.scope = defun.parent_scope).def_function(node); + (node.scope = defun.parent_scope).def_function(node, defun); } else if (node instanceof AST_SymbolVar) { - defun.def_variable(node); + defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined); if (defun !== scope) { node.mark_enclosed(options); var def = scope.find_variable(node); @@ -306,21 +307,21 @@ AST_Scope.DEFMETHOD("find_variable", function(name){ || (this.parent_scope && this.parent_scope.find_variable(name)); }); -AST_Scope.DEFMETHOD("def_function", function(symbol){ - var def = this.def_variable(symbol); +AST_Scope.DEFMETHOD("def_function", function(symbol, init){ + var def = this.def_variable(symbol, init); + if (!def.init) def.init = init; this.functions.set(symbol.name, def); return def; }); -AST_Scope.DEFMETHOD("def_variable", function(symbol){ - var def; - if (!this.variables.has(symbol.name)) { - def = new SymbolDef(this, symbol); +AST_Scope.DEFMETHOD("def_variable", function(symbol, init){ + var def = this.variables.get(symbol.name); + if (def) { + def.orig.push(symbol); + } else { + def = new SymbolDef(this, symbol, init); this.variables.set(symbol.name, def); def.global = !this.parent_scope; - } else { - def = this.variables.get(symbol.name); - def.orig.push(symbol); } return symbol.thedef = def; }); diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index 058e9dde..e370e5be 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -4999,3 +4999,241 @@ var_if: { } } } + +defun_assign: { + options = { + reduce_vars: true, + toplevel: true, + } + input: { + console.log(typeof a); + a = 42; + console.log(typeof a); + function a() {} + console.log(typeof a); + } + expect: { + console.log(typeof a); + a = 42; + console.log(typeof a); + function a() {} + console.log(typeof a); + } + expect_stdout: [ + "function", + "number", + "number", + ] +} + +defun_var_1: { + options = { + evaluate: true, + reduce_vars: true, + toplevel: true, + typeofs: true, + unused: true, + } + input: { + var a = 42, b; + function a() {} + function b() {} + console.log(typeof a, typeof b); + } + expect: { + var a = 42; + function a() {} + console.log(typeof a, "function"); + } + expect_stdout: "number function" +} + +defun_var_2: { + options = { + evaluate: true, + reduce_vars: true, + toplevel: true, + typeofs: true, + unused: true, + } + input: { + function a() {} + function b() {} + var a = 42, b; + console.log(typeof a, typeof b); + } + expect: { + function a() {} + var a = 42; + console.log(typeof a, "function"); + } + expect_stdout: "number function" +} + +defun_var_3: { + options = { + evaluate: true, + reduce_vars: true, + toplevel: true, + typeofs: true, + unused: true, + } + input: { + function a() {} + function b() {} + console.log(typeof a, typeof b); + var a = 42, b; + } + expect: { + function a() {} + console.log(typeof a, "function"); + var a = 42; + } + expect_stdout: "function function" +} + +defun_catch_1: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + function a() {} + try { + throw 42; + } catch (a) { + console.log(a); + } + } + expect: { + try { + throw 42; + } catch (a) { + console.log(a); + } + } + expect_stdout: "42" +} + +defun_catch_2: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + try { + function a() {} + throw 42; + } catch (a) { + console.log(a); + } + } + expect: { + try { + throw 42; + } catch (a) { + console.log(a); + } + } + expect_stdout: "42" +} + +defun_catch_3: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + try { + throw 42; + function a() {} + } catch (a) { + console.log(a); + } + } + expect: { + try { + throw 42; + } catch (a) { + console.log(a); + } + } + expect_stdout: "42" +} + +defun_catch_4: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + try { + throw 42; + } catch (a) { + function a() {} + console.log(a); + } + } + expect: { + try { + throw 42; + } catch (a) { + function a() {} + console.log(a); + } + } + expect_stdout: true +} + +defun_catch_5: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + try { + throw 42; + } catch (a) { + console.log(a); + function a() {} + } + } + expect: { + try { + throw 42; + } catch (a) { + console.log(a); + function a() {} + } + } + expect_stdout: true +} + +defun_catch_6: { + options = { + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + try { + throw 42; + } catch (a) { + console.log(a); + } + function a() {} + } + expect: { + try { + throw 42; + } catch (a) { + console.log(a); + } + } + expect_stdout: "42" +} diff --git a/test/compress/typeof.js b/test/compress/typeof.js index 180e5451..9eaf05e4 100644 --- a/test/compress/typeof.js +++ b/test/compress/typeof.js @@ -100,7 +100,7 @@ typeof_defun_1: { g = 42; console.log("YES"); "function" == typeof g && g(); - h(); + "function" == typeof h && h(); } expect_stdout: [ "YES",