fix corner case in `arguments` (#3330)
authorAlex Lam S.L <alexlamsl@gmail.com>
Tue, 12 Mar 2019 22:59:53 +0000 (06:59 +0800)
committerGitHub <noreply@github.com>
Tue, 12 Mar 2019 22:59:53 +0000 (06:59 +0800)
Track modifications to `arguments[i]` under Strict Mode.

fixes #3273

lib/compress.js
test/compress/arguments.js

index 61c3a26..9109a69 100644 (file)
@@ -497,6 +497,15 @@ merge(Compressor.prototype, {
             d.direct_access = true;
         }
 
+        function mark_assignment_to_arguments(node) {
+            if (!(node instanceof AST_Sub)) return;
+            var expr = node.expression;
+            var prop = node.property;
+            if (expr instanceof AST_SymbolRef && expr.name == "arguments" && prop instanceof AST_Number) {
+                expr.definition().reassigned = true;
+            }
+        }
+
         var suppressor = new TreeWalker(function(node) {
             if (!(node instanceof AST_Symbol)) return;
             var d = node.definition();
@@ -515,7 +524,10 @@ merge(Compressor.prototype, {
         def(AST_Assign, function(tw, descend, compressor) {
             var node = this;
             var sym = node.left;
-            if (!(sym instanceof AST_SymbolRef)) return;
+            if (!(sym instanceof AST_SymbolRef)) {
+                mark_assignment_to_arguments(sym);
+                return;
+            }
             var d = sym.definition();
             var safe = safe_to_assign(tw, d, sym.scope, node.right);
             d.assignments++;
@@ -758,7 +770,10 @@ merge(Compressor.prototype, {
             var node = this;
             if (node.operator != "++" && node.operator != "--") return;
             var exp = node.expression;
-            if (!(exp instanceof AST_SymbolRef)) return;
+            if (!(exp instanceof AST_SymbolRef)) {
+                mark_assignment_to_arguments(exp);
+                return;
+            }
             var d = exp.definition();
             var safe = safe_to_assign(tw, d, exp.scope, true);
             d.assignments++;
@@ -6325,7 +6340,10 @@ merge(Compressor.prototype, {
             var argname = fn.argnames[index];
             if (argname && compressor.has_directive("use strict")) {
                 var def = argname.definition();
-                if (!compressor.option("reduce_vars") || def.assignments || def.orig.length > 1) {
+                if (!compressor.option("reduce_vars")
+                    || expr.definition().reassigned
+                    || def.assignments
+                    || def.orig.length > 1) {
                     argname = null;
                 }
             } else if (!argname && !compressor.option("keep_fargs") && index < fn.argnames.length + 5) {
index 0485744..8a19c8a 100644 (file)
@@ -237,3 +237,170 @@ duplicate_argname: {
     }
     expect_stdout: "bar 42 foo 42 bar"
 }
+
+issue_3273: {
+    options = {
+        arguments: true,
+    }
+    input: {
+        function f(a) {
+            console.log(arguments[0], a);
+            arguments[0]++;
+            console.log(arguments[0], a);
+        }
+        f(0);
+    }
+    expect: {
+        function f(a) {
+            console.log(a, a);
+            a++;
+            console.log(a, a);
+        }
+        f(0);
+    }
+    expect_stdout: [
+        "0 0",
+        "1 1",
+    ]
+}
+
+issue_3273_reduce_vars: {
+    options = {
+        arguments: true,
+        reduce_vars: true,
+    }
+    input: {
+        function f(a) {
+            console.log(arguments[0], a);
+            arguments[0]++;
+            console.log(arguments[0], a);
+        }
+        f(0);
+    }
+    expect: {
+        function f(a) {
+            console.log(a, a);
+            a++;
+            console.log(a, a);
+        }
+        f(0);
+    }
+    expect_stdout: [
+        "0 0",
+        "1 1",
+    ]
+}
+
+issue_3273_local_strict: {
+    options = {
+        arguments: true,
+    }
+    input: {
+        function f(a) {
+            "use strict";
+            console.log(arguments[0], a);
+            arguments[0]++;
+            console.log(arguments[0], a);
+        }
+        f(0);
+    }
+    expect: {
+        function f(a) {
+            "use strict";
+            console.log(arguments[0], a);
+            arguments[0]++;
+            console.log(arguments[0], a);
+        }
+        f(0);
+    }
+    expect_stdout: [
+        "0 0",
+        "1 0",
+    ]
+}
+
+issue_3273_local_strict_reduce_vars: {
+    options = {
+        arguments: true,
+        reduce_vars: true,
+    }
+    input: {
+        function f(a) {
+            "use strict";
+            console.log(arguments[0], a);
+            arguments[0]++;
+            console.log(arguments[0], a);
+        }
+        f(0);
+    }
+    expect: {
+        function f(a) {
+            "use strict";
+            console.log(arguments[0], a);
+            arguments[0]++;
+            console.log(arguments[0], a);
+        }
+        f(0);
+    }
+    expect_stdout: [
+        "0 0",
+        "1 0",
+    ]
+}
+
+issue_3273_global_strict: {
+    options = {
+        arguments: true,
+    }
+    input: {
+        "use strict";
+        function f(a) {
+            console.log(arguments[0], a);
+            arguments[0]++;
+            console.log(arguments[0], a);
+        }
+        f(0);
+    }
+    expect: {
+        "use strict";
+        function f(a) {
+            console.log(arguments[0], a);
+            arguments[0]++;
+            console.log(arguments[0], a);
+        }
+        f(0);
+    }
+    expect_stdout: [
+        "0 0",
+        "1 0",
+    ]
+}
+
+issue_3273_global_strict_reduce_vars: {
+    options = {
+        arguments: true,
+        reduce_vars: true,
+    }
+    input: {
+        "use strict";
+        function f(a) {
+            console.log(arguments[0], a);
+            arguments[0]++;
+            console.log(arguments[0], a);
+        }
+        f(0);
+    }
+    expect: {
+        "use strict";
+        function f(a) {
+            console.log(arguments[0], a);
+            arguments[0]++;
+            console.log(arguments[0], a);
+        }
+        f(0);
+    }
+    expect_stdout: [
+        "0 0",
+        "1 0",
+    ]
+}