diff options
author | Alex Lam S.L <alexlamsl@gmail.com> | 2020-12-10 07:45:39 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-10 15:45:39 +0800 |
commit | a59593cac8b5acbefa07daf1fca3af6a72c9d262 (patch) | |
tree | 06c805beca2673bedad14c47f15190a08d8fd1a7 | |
parent | 046bbde9d44a131ec60952e369ec4b22b9718def (diff) | |
download | tracifyjs-a59593cac8b5acbefa07daf1fca3af6a72c9d262.tar.gz tracifyjs-a59593cac8b5acbefa07daf1fca3af6a72c9d262.zip |
fix corner case in `loops` & `unused` (#4356)
fixes #4355
-rw-r--r-- | lib/compress.js | 37 | ||||
-rw-r--r-- | lib/scope.js | 35 | ||||
-rw-r--r-- | test/compress/destructured.js | 29 |
3 files changed, 79 insertions, 22 deletions
diff --git a/lib/compress.js b/lib/compress.js index 4da13758..1bb6d542 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -4542,7 +4542,7 @@ merge(Compressor.prototype, { var def = node.definition(); if (member(def.scope, scopes)) return true; if (scope && !def.redefined()) { - var scope_def = scope.find_variable(node); + var scope_def = scope.find_variable(node.name); if (def.undeclared ? !scope_def : scope_def === def) { result = "f"; return true; @@ -4842,7 +4842,9 @@ merge(Compressor.prototype, { if (!(ref instanceof AST_SymbolRef)) return; var def = ref.definition(); var ldef = node.variables.get(ref.name); - if (ldef && (ldef === def || def.undeclared || node.parent_scope.find_variable(ref) === def)) { + if (ldef && (ldef === def + || def.undeclared + || node.parent_scope.find_variable(ref.name) === def)) { references[def.id] = false; references[ldef.id] = false; } else { @@ -5468,7 +5470,7 @@ merge(Compressor.prototype, { }) : def.value === def.name.fixed_value()) && (!def.value.name || (old_def = def.value.name.definition()).assignments == 0 && (old_def.name == def.name.name || all(old_def.references, function(ref) { - return ref.scope.find_variable(def.name) === def.name.definition(); + return ref.scope.find_variable(def.name.name) === def.name.definition(); }))) && can_declare_defun() && can_rename(def.value, def.name.name)) { @@ -5759,6 +5761,33 @@ merge(Compressor.prototype, { if (init instanceof AST_SymbolRef) return init; } + function find_variable(name) { + var level = 0; + var scope = self; + while (true) { + var in_arg = false; + do { + var parent = compressor.parent(level++); + if (parent instanceof AST_DestructuredKeyVal && parent.key === scope) { + var fn = compressor.parent(level + 1); + if (fn instanceof AST_Lambda) { + in_arg = fn.argnames.indexOf(compressor.parent(level)) >= 0; + level += 2; + scope = fn; + break; + } + } + if (!parent) return; + scope = parent; + } while (!(scope instanceof AST_BlockScope)); + var def = scope.variables.get(name); + if (!def) continue; + if (!in_arg) return def; + var sym = def.orig[0]; + if (sym instanceof AST_SymbolFunarg || sym instanceof AST_SymbolLambda) return def; + } + } + function scan_ref_scoped(node, descend, init) { if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef) { var def = node.left.definition(); @@ -5807,7 +5836,7 @@ merge(Compressor.prototype, { if (!sym) return; var def = sym.definition(); if (def.scope !== self) { - var d = self.find_variable(sym); + var d = find_variable(sym.name); if ((d && d.redefined() || d) === def) return; } node.object.walk(tw); diff --git a/lib/scope.js b/lib/scope.js index 6c521bcc..ff0cb58c 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -190,7 +190,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { function entangle(defun, scope) { if (defun === scope) return; node.mark_enclosed(options); - var def = scope.find_variable(node); + var def = scope.find_variable(node.name); if (node.thedef === def) return; node.thedef = def; def.orig.push(node); @@ -219,6 +219,21 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { if (node.label) node.label.thedef.references.push(node); return true; } + // ensure mangling works if `catch` reuses a scope variable + if (node instanceof AST_SymbolCatch) { + var def = node.definition().redefined(); + if (def) for (var s = node.scope; s; s = s.parent_scope) { + push_uniq(s.enclosed, def); + if (s === def.scope) break; + } + return true; + } + // ensure compression works if `const` reuses a scope variable + if (node instanceof AST_SymbolConst) { + var redef = node.definition().redefined(); + if (redef) redef.const_redefs = true; + return true; + } if (node instanceof AST_SymbolRef) { var name = node.name; var sym = node.scope.find_variable(name); @@ -258,21 +273,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { node.reference(options); return true; } - // ensure mangling works if `catch` reuses a scope variable - if (node instanceof AST_SymbolCatch) { - var def = node.definition().redefined(); - if (def) for (var s = node.scope; s; s = s.parent_scope) { - push_uniq(s.enclosed, def); - if (s === def.scope) break; - } - return true; - } - // ensure compression works if `const` reuses a scope variable - if (node instanceof AST_SymbolConst) { - var redef = node.definition().redefined(); - if (redef) redef.const_redefs = true; - return true; - } }); self.walk(tw); @@ -390,9 +390,8 @@ AST_Symbol.DEFMETHOD("reference", function(options) { }); AST_BlockScope.DEFMETHOD("find_variable", function(name) { - if (name instanceof AST_Symbol) name = name.name; return this.variables.get(name) - || (this.parent_scope && this.parent_scope.find_variable(name)); + || this.parent_scope && this.parent_scope.find_variable(name); }); AST_BlockScope.DEFMETHOD("def_function", function(symbol, init) { diff --git a/test/compress/destructured.js b/test/compress/destructured.js index eb6834a4..82d02172 100644 --- a/test/compress/destructured.js +++ b/test/compress/destructured.js @@ -1777,3 +1777,32 @@ issue_4323: { expect_stdout: "function" node_version: ">=6" } + +issue_4355: { + options = { + loops: true, + unused: true, + } + input: { + var a; + (function({ + [function() { + for (a in "foo"); + }()]: b, + }) { + var a; + })(0); + console.log(a); + } + expect: { + var a; + (function({ + [function() { + for (a in "foo"); + }()]: b, + }) {})(0); + console.log(a); + } + expect_stdout: "2" + node_version: ">=6" +} |