fix corner case in `arguments` (#4398)
authorAlex Lam S.L <alexlamsl@gmail.com>
Fri, 18 Dec 2020 01:42:07 +0000 (01:42 +0000)
committerGitHub <noreply@github.com>
Fri, 18 Dec 2020 01:42:07 +0000 (09:42 +0800)
fixes #4397

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

index 4279dc7..8d41ab8 100644 (file)
@@ -1048,7 +1048,7 @@ merge(Compressor.prototype, {
         });
         def(AST_Unary, function(tw, descend) {
             var node = this;
-            if (!unary_arithmetic[node.operator]) return;
+            if (!UNARY_POSTFIX[node.operator]) return;
             var exp = node.expression;
             if (!(exp instanceof AST_SymbolRef)) {
                 mark_assignment_to_arguments(exp);
@@ -1978,7 +1978,7 @@ merge(Compressor.prototype, {
                     extract_candidates(expr.expression);
                     expr.body.forEach(extract_candidates);
                 } else if (expr instanceof AST_Unary) {
-                    if (unary_arithmetic[expr.operator]) {
+                    if (UNARY_POSTFIX[expr.operator]) {
                         candidates.push(hit_stack.slice());
                     } else {
                         extract_candidates(expr.expression);
@@ -3473,8 +3473,6 @@ merge(Compressor.prototype, {
     });
 
     var lazy_op = makePredicate("&& ||");
-    var unary_arithmetic = makePredicate("++ --");
-    var unary_side_effects = makePredicate("delete ++ --");
 
     function is_lhs(node, parent) {
         if (parent instanceof AST_Assign) return parent.left === node && node;
@@ -3725,7 +3723,7 @@ merge(Compressor.prototype, {
         });
         var scan_modified = new TreeWalker(function(node) {
             if (node instanceof AST_Assign) modified(node.left);
-            if (node instanceof AST_Unary && unary_arithmetic[node.operator]) modified(node.expression);
+            if (node instanceof AST_Unary && UNARY_POSTFIX[node.operator]) modified(node.expression);
         });
         function modified(node) {
             if (node instanceof AST_PropAccess) {
@@ -4964,7 +4962,7 @@ merge(Compressor.prototype, {
                 return true;
             }
             if (node instanceof AST_Unary) {
-                if (!unary_arithmetic[node.operator]) return;
+                if (!UNARY_POSTFIX[node.operator]) return;
                 var sym = node.expression;
                 if (!(sym instanceof AST_SymbolRef)) return;
                 mark(sym, true, true);
@@ -9885,7 +9883,7 @@ merge(Compressor.prototype, {
             && is_arguments(def = expr.definition())
             && prop instanceof AST_Number
             && (fn = def.scope) === find_lambda()
-            && !(assigned && fn.uses_arguments === "d")) {
+            && fn.uses_arguments < (assigned ? 2 : 3)) {
             var index = prop.value;
             if (parent instanceof AST_UnaryPrefix && parent.operator == "delete") {
                 if (!def.deleted) def.deleted = [];
index a285f91..187309c 100644 (file)
@@ -100,6 +100,8 @@ SymbolDef.prototype = {
     },
 };
 
+var unary_side_effects = makePredicate("delete ++ --");
+
 AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
     options = defaults(options, {
         cache: null,
@@ -256,8 +258,13 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
             } else if (name == "arguments"
                 && sym.orig[0] instanceof AST_SymbolFunarg
                 && !(sym.scope instanceof AST_Arrow)) {
-                if (!(tw.parent() instanceof AST_PropAccess)) {
-                    sym.scope.uses_arguments = "d";
+                var parent = tw.parent();
+                if (parent instanceof AST_Assign && parent.left === node
+                    || parent instanceof AST_Unary && unary_side_effects[parent.operator]) {
+                    sym.scope.uses_arguments = 3;
+                } else if (sym.scope.uses_arguments < 2
+                    && !(parent instanceof AST_PropAccess && parent.expression === node)) {
+                    sym.scope.uses_arguments = 2;
                 } else if (!sym.scope.uses_arguments) {
                     sym.scope.uses_arguments = true;
                 }
index 4b09a99..c3ef226 100644 (file)
@@ -851,3 +851,23 @@ issue_4291_2: {
     }
     expect_stdout: "PASS 42 1"
 }
+
+issue_4397: {
+    options = {
+        arguments: true,
+        keep_fargs: "strict",
+    }
+    input: {
+        console.log(typeof function() {
+            arguments += 0;
+            return arguments[0];
+        }());
+    }
+    expect: {
+        console.log(typeof function() {
+            arguments += 0;
+            return arguments[0];
+        }());
+    }
+    expect_stdout: "string"
+}