fix corner cases with `import` (#4709)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sun, 28 Feb 2021 23:13:49 +0000 (23:13 +0000)
committerGitHub <noreply@github.com>
Sun, 28 Feb 2021 23:13:49 +0000 (07:13 +0800)
fixes #4708

lib/compress.js
test/compress/imports.js
test/sandbox.js
test/ufuzz/index.js

index ba7ab4a..fb6d16f 100644 (file)
@@ -1127,6 +1127,9 @@ merge(Compressor.prototype, {
         def(AST_SymbolCatch, function() {
             this.definition().fixed = false;
         });
+        def(AST_SymbolImport, function() {
+            this.definition().fixed = false;
+        });
         def(AST_SymbolRef, function(tw, descend, compressor) {
             var d = this.definition();
             push_ref(d, this);
@@ -5836,6 +5839,14 @@ merge(Compressor.prototype, {
                     assignments.add(def.id, node);
                     return true;
                 }
+                if (node instanceof AST_SymbolImport) {
+                    var def = node.definition();
+                    if (!(def.id in in_use_ids) && (!drop_vars || !is_safe_lexical(def))) {
+                        in_use_ids[def.id] = true;
+                        in_use.push(def);
+                    }
+                    return true;
+                }
             } else if (node instanceof AST_This && scope instanceof AST_DefClass) {
                 var def = scope.name.definition();
                 if (!(def.id in in_use_ids)) {
index 558dd6a..50b3fb6 100644 (file)
@@ -165,3 +165,38 @@ forbid_merge: {
         f();
     }
 }
+
+issue_4708_1: {
+    options = {
+        imports: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var a;
+        import a from "foo";
+    }
+    expect: {
+        var a;
+        import a from "foo";
+    }
+}
+
+issue_4708_2: {
+    options = {
+        imports: true,
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        var a;
+        console.log(a);
+        import a from "foo";
+    }
+    expect: {
+        var a;
+        console.log(a);
+        import a from "foo";
+    }
+}
index b2b5e00..bdce418 100644 (file)
@@ -61,7 +61,7 @@ exports.patch_module_statements = function(code) {
             symbols = symbols.replace(/[{}]/g, "").trim().replace(/\s*,\s*/g, ",");
             symbols = symbols.replace(/\*/, '"*"').replace(/\bas\s+(?!$|,|as\s)/g, ":");
             imports.push([
-                "var {",
+                "const {",
                 symbols,
                 "} = new Proxy(Object.create(null), { get(_, value) { return { value }; } });",
             ].join(""));
index b066e2f..f38cdd9 100644 (file)
@@ -1020,22 +1020,30 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
         return "switch (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") { " + createSwitchParts(recurmax, 4, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}";
       case STMT_VAR:
         if (SUPPORT.destructuring && stmtDepth == 1 && rng(5) == 0) {
-            unique_vars.push("c");
-            var s = rng(2) ? " " + createVarName(MANDATORY) : "";
+            unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
+            var s = "";
+            if (rng(2)) {
+                var name = createVarName(MANDATORY);
+                block_vars.push(name);
+                s += " " + name;
+            }
             if (rng(10)) {
                 if (s) s += ",";
                 if (rng(2)) {
-                    s += " * as " + createVarName(MANDATORY);
+                    var name = createVarName(MANDATORY);
+                    block_vars.push(name);
+                    s += " * as " + name;
                 } else {
                     var names = [];
                     for (var i = rng(4); --i >= 0;) {
                         var name = createVarName(MANDATORY);
+                        block_vars.push(name);
                         names.push(rng(2) ? getDotKey() + " as " + name : name);
                     }
                     s += " { " + names.join(", ") + " }";
                 }
             }
-            unique_vars.pop();
+            unique_vars.length -= 6;
             if (s) s += " from";
             return "import" + s + ' "path/to/module.js";';
         } else if (SUPPORT.destructuring && rng(20) == 0) {
@@ -2217,6 +2225,10 @@ function is_error_recursion(ex) {
     return ex.name == "RangeError" && /Invalid string length|Maximum call stack size exceeded/.test(ex.message);
 }
 
+function is_error_redeclaration(ex) {
+    return ex.name == "SyntaxError" && /already been declared|redeclaration/.test(ex.message);
+}
+
 function is_error_destructuring(ex) {
     return ex.name == "TypeError" && /^Cannot destructure /.test(ex.message);
 }
@@ -2409,6 +2421,10 @@ for (var round = 1; round <= num_iterations; round++) {
                     ok = sandbox.same_stdout(original_strict, uglify_strict);
                 }
             }
+            // ignore difference in error message caused by `import` symbol redeclaration
+            if (!ok && errored && /\bimport\b/.test(original_code)) {
+                if (is_error_redeclaration(uglify_result) && is_error_redeclaration(original_result)) ok = true;
+            }
             // ignore difference in error message caused by `in`
             if (!ok && errored && is_error_in(uglify_result) && is_error_in(original_result)) ok = true;
             // ignore difference in error message caused by spread syntax