improve `collapse_vars` (#3103)
authorAlex Lam S.L <alexlamsl@gmail.com>
Thu, 26 Apr 2018 11:26:01 +0000 (19:26 +0800)
committerGitHub <noreply@github.com>
Thu, 26 Apr 2018 11:26:01 +0000 (19:26 +0800)
lib/compress.js

index 06ed35f..dfd2f7f 100644 (file)
@@ -980,24 +980,12 @@ merge(Compressor.prototype, {
                 }
                 // Stop immediately if these node types are encountered
                 var parent = scanner.parent();
-                if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left)
-                    || node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
-                    || node instanceof AST_Debugger
-                    || node instanceof AST_IterationStatement && !(node instanceof AST_For)
-                    || node instanceof AST_LoopControl
-                    || node instanceof AST_Try
-                    || node instanceof AST_With
-                    || parent instanceof AST_For && node !== parent.init
-                    || !replace_all
-                        && (node instanceof AST_SymbolRef && !node.is_declared(compressor))) {
+                if (should_stop(node, parent)) {
                     abort = true;
                     return node;
                 }
                 // Stop only if candidate is found within conditional branches
-                if (!stop_if_hit
-                    && (parent instanceof AST_Binary && lazy_op[parent.operator] && parent.left !== node
-                        || parent instanceof AST_Conditional && parent.condition !== node
-                        || parent instanceof AST_If && parent.condition !== node)) {
+                if (!stop_if_hit && in_conditional(node, parent)) {
                     stop_if_hit = parent;
                 }
                 // Replace variable with assignment when found
@@ -1047,20 +1035,7 @@ merge(Compressor.prototype, {
                 // These node types have child nodes that execute sequentially,
                 // but are otherwise not safe to scan into or beyond them.
                 var sym;
-                if (node instanceof AST_Call
-                    || node instanceof AST_Exit
-                        && (side_effects || lhs instanceof AST_PropAccess || may_modify(lhs))
-                    || node instanceof AST_PropAccess
-                        && (side_effects || node.expression.may_throw_on_access(compressor))
-                    || node instanceof AST_SymbolRef
-                        && (symbol_in_lvalues(node) || side_effects && may_modify(node))
-                    || node instanceof AST_This && symbol_in_lvalues(node)
-                    || node instanceof AST_VarDef && node.value
-                        && (node.name.name in lvalues || side_effects && may_modify(node.name))
-                    || (sym = is_lhs(node.left, node))
-                        && (sym instanceof AST_PropAccess || sym.name in lvalues)
-                    || may_throw
-                        && (in_try ? node.has_side_effects(compressor) : side_effects_external(node))) {
+                if (is_last_node(node, parent) || may_throw(node)) {
                     stop_after = node;
                     if (node instanceof AST_Scope) abort = true;
                 }
@@ -1119,7 +1094,9 @@ merge(Compressor.prototype, {
                     var lhs_local = is_lhs_local(lhs);
                     if (!side_effects) side_effects = value_has_side_effects(candidate);
                     var replace_all = replace_all_symbols();
-                    var may_throw = candidate.may_throw(compressor);
+                    var may_throw = candidate.may_throw(compressor) ? in_try ? function(node) {
+                        return node.has_side_effects(compressor);
+                    } : side_effects_external : return_false;
                     var funarg = candidate.name instanceof AST_SymbolFunarg;
                     var hit = funarg;
                     var abort = false, replaced = 0, can_replace = !args || !hit;
@@ -1171,6 +1148,51 @@ merge(Compressor.prototype, {
                 }
             }
 
+            function should_stop(node, parent) {
+                if (node instanceof AST_Assign) return node.operator != "=" && lhs.equivalent_to(node.left);
+                if (node instanceof AST_Call) {
+                    return lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression);
+                }
+                if (node instanceof AST_Debugger) return true;
+                if (node instanceof AST_IterationStatement) return !(node instanceof AST_For);
+                if (node instanceof AST_LoopControl) return true;
+                if (node instanceof AST_Try) return true;
+                if (node instanceof AST_With) return true;
+                if (parent instanceof AST_For) return node !== parent.init;
+                if (replace_all) return false;
+                return node instanceof AST_SymbolRef && !node.is_declared(compressor);
+            }
+
+            function in_conditional(node, parent) {
+                if (parent instanceof AST_Binary) return lazy_op[parent.operator] && parent.left !== node;
+                if (parent instanceof AST_Conditional) return parent.condition !== node;
+                return parent instanceof AST_If && parent.condition !== node;
+            }
+
+            function is_last_node(node, parent) {
+                if (node instanceof AST_Call) return true;
+                if (node instanceof AST_Exit) {
+                    return side_effects || lhs instanceof AST_PropAccess || may_modify(lhs);
+                }
+                if (node instanceof AST_PropAccess) {
+                    return side_effects || node.expression.may_throw_on_access(compressor);
+                }
+                if (node instanceof AST_SymbolRef) {
+                    if (symbol_in_lvalues(node, parent)) {
+                        return !parent || parent.operator != "=" || parent.left !== node;
+                    }
+                    return side_effects && may_modify(node);
+                }
+                if (node instanceof AST_This) return symbol_in_lvalues(node, parent);
+                if (node instanceof AST_VarDef) {
+                    if (!node.value) return false;
+                    return node.name.name in lvalues || side_effects && may_modify(node.name);
+                }
+                var sym = is_lhs(node.left, node);
+                if (sym && sym.name in lvalues) return true;
+                if (sym instanceof AST_PropAccess) return true;
+            }
+
             function extract_args() {
                 var iife, fn = compressor.self();
                 if (fn instanceof AST_Function
@@ -1482,10 +1504,10 @@ merge(Compressor.prototype, {
                 return false;
             }
 
-            function symbol_in_lvalues(sym) {
+            function symbol_in_lvalues(sym, parent) {
                 var lvalue = lvalues[sym.name];
                 if (!lvalue) return;
-                if (lvalue !== lhs) return true;
+                if (lvalue !== lhs) return !(parent instanceof AST_Call);
                 scan_rhs = false;
             }