fix corner case in `reduce_vars` (#3241)
authorAlex Lam S.L <alexlamsl@gmail.com>
Wed, 29 Aug 2018 14:14:25 +0000 (22:14 +0800)
committerGitHub <noreply@github.com>
Wed, 29 Aug 2018 14:14:25 +0000 (22:14 +0800)
fixes #3240

lib/compress.js
test/compress/reduce_vars.js

index f84409f..9e4ab31 100644 (file)
@@ -5751,38 +5751,34 @@ merge(Compressor.prototype, {
         }
         var parent = compressor.parent();
         if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
-            var d = self.definition();
+            var def = self.definition();
             var fixed = self.fixed_value();
-            var single_use = d.single_use
-                && !(parent instanceof AST_Call && parent.is_expr_pure(compressor));
+            var single_use = def.single_use && !(parent instanceof AST_Call && parent.is_expr_pure(compressor));
             if (single_use && fixed instanceof AST_Lambda) {
-                if (d.scope !== self.scope
-                    && (!compressor.option("reduce_funcs")
-                        || d.escaped == 1
-                        || fixed.inlined)) {
+                if (def.scope !== self.scope
+                    && (!compressor.option("reduce_funcs") || def.escaped == 1 || fixed.inlined)) {
                     single_use = false;
-                } else if (recursive_ref(compressor, d)) {
+                } else if (recursive_ref(compressor, def)) {
                     single_use = false;
-                } else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) {
+                } else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
                     single_use = fixed.is_constant_expression(self.scope);
                     if (single_use == "f") {
                         var scope = self.scope;
-                        do {
-                            if (scope instanceof AST_Defun || scope instanceof AST_Function) {
-                                scope.inlined = true;
-                            }
+                        do if (scope instanceof AST_Defun || scope instanceof AST_Function) {
+                            scope.inlined = true;
                         } while (scope = scope.parent_scope);
                     }
                 }
             }
             if (single_use && fixed) {
+                def.single_use = false;
                 if (fixed instanceof AST_Defun) {
                     fixed._squeezed = true;
                     fixed = make_node(AST_Function, fixed, fixed);
                     fixed.name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
                 }
                 var value;
-                if (d.recursive_refs > 0) {
+                if (def.recursive_refs > 0) {
                     value = fixed.clone(true);
                     var defun_def = value.name.definition();
                     var lambda_def = value.variables.get(value.name.name);
@@ -5794,9 +5790,13 @@ merge(Compressor.prototype, {
                         lambda_def = value.def_function(name);
                     }
                     value.walk(new TreeWalker(function(node) {
-                        if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
+                        if (!(node instanceof AST_SymbolRef)) return;
+                        var def = node.definition();
+                        if (def === defun_def) {
                             node.thedef = lambda_def;
                             lambda_def.references.push(node);
+                        } else {
+                            def.single_use = false;
                         }
                     }));
                 } else {
@@ -5805,13 +5805,12 @@ merge(Compressor.prototype, {
                 }
                 return value;
             }
-            if (fixed && d.should_replace === undefined) {
+            if (fixed && def.should_replace === undefined) {
                 var init;
                 if (fixed instanceof AST_This) {
-                    if (!(d.orig[0] instanceof AST_SymbolFunarg)
-                        && all(d.references, function(ref) {
-                            return d.scope === ref.scope;
-                        })) {
+                    if (!(def.orig[0] instanceof AST_SymbolFunarg) && all(def.references, function(ref) {
+                        return def.scope === ref.scope;
+                    })) {
                         init = fixed;
                     }
                 } else {
@@ -5835,18 +5834,18 @@ merge(Compressor.prototype, {
                             return result === init || result === fixed ? result.clone(true) : result;
                         };
                     }
-                    var name_length = d.name.length;
+                    var name_length = def.name.length;
                     var overhead = 0;
-                    if (compressor.option("unused") && !compressor.exposed(d)) {
-                        overhead = (name_length + 2 + value_length) / (d.references.length - d.assignments);
+                    if (compressor.option("unused") && !compressor.exposed(def)) {
+                        overhead = (name_length + 2 + value_length) / (def.references.length - def.assignments);
                     }
-                    d.should_replace = value_length <= name_length + overhead ? fn : false;
+                    def.should_replace = value_length <= name_length + overhead ? fn : false;
                 } else {
-                    d.should_replace = false;
+                    def.should_replace = false;
                 }
             }
-            if (d.should_replace) {
-                return d.should_replace();
+            if (def.should_replace) {
+                return def.should_replace();
             }
         }
         return self;
index dad8ca3..b040a3f 100644 (file)
@@ -5354,6 +5354,7 @@ issue_2774: {
 
 issue_2799_1: {
     options = {
+        passes: 2,
         reduce_funcs: true,
         reduce_vars: true,
         unused: true,
@@ -6429,3 +6430,159 @@ issue_3140_5: {
     }
     expect_stdout: "1"
 }
+
+issue_3240_1: {
+    options = {
+        reduce_funcs: true,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        (function() {
+            f(1);
+            function f(a) {
+                console.log(a);
+                var g = function() {
+                    f(a - 1);
+                };
+                if (a) g();
+            }
+        })();
+    }
+    expect: {
+        (function() {
+            (function f(a) {
+                console.log(a);
+                var g = function() {
+                    f(a - 1);
+                };
+                if (a) g();
+            })(1);
+        })();
+    }
+    expect_stdout: [
+        "1",
+        "0",
+    ]
+}
+
+issue_3240_2: {
+    options = {
+        passes: 2,
+        reduce_funcs: true,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        (function() {
+            f(1);
+            function f(a) {
+                console.log(a);
+                var g = function() {
+                    f(a - 1);
+                };
+                if (a) g();
+            }
+        })();
+    }
+    expect: {
+        (function() {
+            (function f(a) {
+                console.log(a);
+                if (a) (function() {
+                    f(a - 1);
+                })();
+            })(1);
+        })();
+    }
+    expect_stdout: [
+        "1",
+        "0",
+    ]
+}
+
+issue_3240_3: {
+    options = {
+        reduce_funcs: true,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        (function() {
+            f();
+            function f(b) {
+                if (!f.a) f.a = 0;
+                console.log(f.a.toString());
+                var g = function() {
+                    (b ? function() {} : function() {
+                        f.a++;
+                        f(1);
+                    })();
+                };
+                g();
+            }
+        })();
+    }
+    expect: {
+        (function() {
+            (function f(b) {
+                if (!f.a) f.a = 0;
+                console.log(f.a.toString());
+                var g = function() {
+                    (b ? function() {} : function() {
+                        f.a++;
+                        f(1);
+                    })();
+                };
+                g();
+            })();
+        })();
+    }
+    expect_stdout: [
+        "0",
+        "1",
+    ]
+}
+
+issue_3240_4: {
+    options = {
+        passes: 2,
+        reduce_funcs: true,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        (function() {
+            f();
+            function f(b) {
+                if (!f.a) f.a = 0;
+                console.log(f.a.toString());
+                var g = function() {
+                    (b ? function() {} : function() {
+                        f.a++;
+                        f(1);
+                    })();
+                };
+                g();
+            }
+        })();
+    }
+    expect: {
+        (function() {
+            (function f(b) {
+                if (!f.a) f.a = 0;
+                console.log(f.a.toString());
+                (function() {
+                    (b ? function() {} : function() {
+                        f.a++;
+                        f(1);
+                    })();
+                })();
+            })();
+        })();
+    }
+    expect_stdout: [
+        "0",
+        "1",
+    ]
+}