fix corner case in `unsafe_regexp` (#3609)
authorAlex Lam S.L <alexlamsl@gmail.com>
Wed, 27 Nov 2019 09:35:21 +0000 (17:35 +0800)
committerGitHub <noreply@github.com>
Wed, 27 Nov 2019 09:35:21 +0000 (17:35 +0800)
lib/compress.js
test/compress/collapse_vars.js
test/compress/evaluate.js

index 46a7816..19fba0b 100644 (file)
@@ -362,6 +362,7 @@ merge(Compressor.prototype, {
         function reset_def(tw, compressor, def) {
             def.assignments = 0;
             def.chained = false;
+            def.cross_loop = false;
             def.direct_access = false;
             def.escaped = [];
             def.fixed = !def.scope.pinned()
@@ -765,6 +766,9 @@ merge(Compressor.prototype, {
                         d.fixed = false;
                     }
                 }
+                if (d.fixed && tw.loop_ids[d.id] !== tw.in_loop) {
+                    d.cross_loop = true;
+                }
                 mark_escaped(tw, d, this.scope, this, value, 0, 1);
             }
             var parent;
@@ -6494,14 +6498,13 @@ merge(Compressor.prototype, {
             if (fixed && def.should_replace === undefined) {
                 var init;
                 if (fixed instanceof AST_This) {
-                    if (!(def.orig[0] instanceof AST_SymbolFunarg) && all(def.references, function(ref) {
-                        return def.scope === ref.scope;
-                    })) {
+                    if (!(def.orig[0] instanceof AST_SymbolFunarg) && same_scope(def)) {
                         init = fixed;
                     }
                 } else {
                     var ev = fixed.evaluate(compressor);
-                    if (ev !== fixed && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))) {
+                    if (ev !== fixed && (!(ev instanceof RegExp)
+                        || compressor.option("unsafe_regexp") && !def.cross_loop && same_scope(def))) {
                         init = make_node_from_constant(ev, fixed);
                     }
                 }
@@ -6538,6 +6541,13 @@ merge(Compressor.prototype, {
         }
         return self;
 
+        function same_scope(def) {
+            var scope = def.scope.resolve();
+            return all(def.references, function(ref) {
+                return scope === ref.scope.resolve();
+            });
+        }
+
         function has_symbol_ref(value) {
             var found;
             value.walk(new TreeWalker(function(node) {
index abdd9c2..0f1e59a 100644 (file)
@@ -1633,21 +1633,32 @@ collapse_vars_regexp: {
                 return rx.exec(s);
             };
         }
+        function f3() {
+            var rx = /ab*/g;
+            return function() {
+                return rx;
+            };
+        }
         (function() {
             var result;
-            var s = 'acdabcdeabbb';
+            var s = "acdabcdeabbb";
             var rx = /ab*/g;
-            while (result = rx.exec(s)) {
+            while (result = rx.exec(s))
                 console.log(result[0]);
-            }
         })();
         (function() {
             var result;
-            var s = 'acdabcdeabbb';
+            var s = "acdabcdeabbb";
             var rx = f2();
-            while (result = rx(s)) {
+            while (result = rx(s))
+                console.log(result[0]);
+        })();
+        (function() {
+            var result;
+            var s = "acdabcdeabbb";
+            var rx = f3();
+            while (result = rx().exec(s))
                 console.log(result[0]);
-            }
         })();
     }
     expect: {
@@ -1660,6 +1671,12 @@ collapse_vars_regexp: {
                 return rx.exec(s);
             };
         }
+        function f3() {
+            var rx = /ab*/g;
+            return function() {
+                return rx;
+            };
+        }
         (function() {
             var result, rx = /ab*/g;
             while (result = rx.exec("acdabcdeabbb"))
@@ -1670,8 +1687,23 @@ collapse_vars_regexp: {
             while (result = rx("acdabcdeabbb"))
                 console.log(result[0]);
         })();
+        (function() {
+            var result, rx = f3();
+            while (result = rx().exec("acdabcdeabbb"))
+                console.log(result[0]);
+        })();
     }
-    expect_stdout: true
+    expect_stdout: [
+        "a",
+        "ab",
+        "abbb",
+        "a",
+        "ab",
+        "abbb",
+        "a",
+        "ab",
+        "abbb",
+    ]
 }
 
 issue_1537: {
index 9425804..09fdfb2 100644 (file)
@@ -2057,3 +2057,107 @@ threshold_evaluate_999: {
     }
     expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"
 }
+
+collapse_vars_regexp: {
+    options = {
+        booleans: true,
+        collapse_vars: true,
+        comparisons: true,
+        conditionals: true,
+        dead_code: true,
+        evaluate: true,
+        hoist_funs: true,
+        if_return: true,
+        join_vars: true,
+        keep_fargs: true,
+        loops: false,
+        reduce_funcs: true,
+        reduce_vars: true,
+        side_effects: true,
+        unsafe_regexp: true,
+        unused: true,
+    }
+    input: {
+        function f1() {
+            var k = 9;
+            var rx = /[A-Z]+/;
+            return [rx, k];
+        }
+        function f2() {
+            var rx = /ab*/g;
+            return function(s) {
+                return rx.exec(s);
+            };
+        }
+        function f3() {
+            var rx = /ab*/g;
+            return function() {
+                return rx;
+            };
+        }
+        (function() {
+            var result;
+            var s = "acdabcdeabbb";
+            var rx = /ab*/g;
+            while (result = rx.exec(s))
+                console.log(result[0]);
+        })();
+        (function() {
+            var result;
+            var s = "acdabcdeabbb";
+            var rx = f2();
+            while (result = rx(s))
+                console.log(result[0]);
+        })();
+        (function() {
+            var result;
+            var s = "acdabcdeabbb";
+            var rx = f3();
+            while (result = rx().exec(s))
+                console.log(result[0]);
+        })();
+    }
+    expect: {
+        function f1() {
+            return [/[A-Z]+/, 9];
+        }
+        function f2() {
+            var rx = /ab*/g;
+            return function(s) {
+                return rx.exec(s);
+            };
+        }
+        function f3() {
+            var rx = /ab*/g;
+            return function() {
+                return rx;
+            };
+        }
+        (function() {
+            var result, rx = /ab*/g;
+            while (result = rx.exec("acdabcdeabbb"))
+                console.log(result[0]);
+        })();
+        (function() {
+            var result, rx = f2();
+            while (result = rx("acdabcdeabbb"))
+                console.log(result[0]);
+        })();
+        (function() {
+            var result, rx = f3();
+            while (result = rx().exec("acdabcdeabbb"))
+                console.log(result[0]);
+        })();
+    }
+    expect_stdout: [
+        "a",
+        "ab",
+        "abbb",
+        "a",
+        "ab",
+        "abbb",
+        "a",
+        "ab",
+        "abbb",
+    ]
+}