From 0c7b016fa780725c3ef7ae6ed157afe6b5a90f07 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Mon, 6 Jun 2022 15:52:22 +0100 Subject: [PATCH] fix corner case in `inline` & `module` (#5492) fixes #5491 --- lib/compress.js | 19 +++++++++++-------- test/mocha/minify.js | 19 +++++++++++++++++++ test/reduce.js | 9 +++++++-- test/ufuzz/index.js | 5 ++++- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index c97474ad..6d9f2c48 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -9958,9 +9958,12 @@ Compressor.prototype.compress = function(node) { }) : arg); } - function avoid_await_yield(parent_scope) { + function avoid_await_yield(compressor, parent_scope) { + if (!parent_scope) parent_scope = compressor.find_parent(AST_Scope); var avoid = []; - if (is_async(parent_scope)) avoid.push("await"); + if (is_async(parent_scope) || parent_scope instanceof AST_Toplevel && compressor.option("module")) { + avoid.push("await"); + } if (is_generator(parent_scope)) avoid.push("yield"); return avoid.length && makePredicate(avoid); } @@ -10322,7 +10325,7 @@ Compressor.prototype.compress = function(node) { if (exp === fn && !fn.name && (!value || value.is_constant_expression()) - && safe_from_await_yield(fn, avoid_await_yield(compressor.find_parent(AST_Scope)))) { + && safe_from_await_yield(fn, avoid_await_yield(compressor))) { return make_sequence(self, convert_args(value)).optimize(compressor); } } @@ -10400,7 +10403,7 @@ Compressor.prototype.compress = function(node) { && all(fn.body, is_empty) && (fn === exp ? fn_name_unused(fn, compressor) : !has_default && !has_destructured && !fn.rest) && !(is_arrow(fn) && fn.value) - && safe_from_await_yield(fn, avoid_await_yield(compressor.find_parent(AST_Scope)))) { + && safe_from_await_yield(fn, avoid_await_yield(compressor))) { return make_sequence(self, convert_args()).optimize(compressor); } } @@ -10559,7 +10562,7 @@ Compressor.prototype.compress = function(node) { })) return; var scope = compressor.find_parent(AST_Scope); var abort = false; - var avoid = avoid_await_yield(scope); + var avoid = avoid_await_yield(compressor, scope); var begin; var in_order = []; var side_effects = false; @@ -10674,7 +10677,7 @@ Compressor.prototype.compress = function(node) { } while (!(scope instanceof AST_Scope)); insert = scope.body.indexOf(child) + 1; if (!insert) return false; - if (!safe_from_await_yield(fn, avoid_await_yield(scope))) return false; + if (!safe_from_await_yield(fn, avoid_await_yield(compressor, scope))) return false; var safe_to_inject = (exp !== fn || fn.parent_scope.resolve() === scope) && !scope.pinned(); if (scope instanceof AST_Toplevel) { if (compressor.toplevel.vars) { @@ -13074,7 +13077,7 @@ Compressor.prototype.compress = function(node) { var arrow = !(value.uses_arguments || is_generator(value) || value.contains_this()); if (arrow) { if (!scope) scope = compressor.find_parent(AST_Scope); - var avoid = avoid_await_yield(scope); + var avoid = avoid_await_yield(compressor, scope); value.each_argname(function(argname) { if (avoid[argname.name]) arrow = false; }); @@ -13491,7 +13494,7 @@ Compressor.prototype.compress = function(node) { })); return !abort; })) return; - if (!safe_from_await_yield(fn, avoid_await_yield(scope))) return; + if (!safe_from_await_yield(fn, avoid_await_yield(compressor, scope))) return; fn.functions.each(function(def, name) { scope.functions.set(name, def); }); diff --git a/test/mocha/minify.js b/test/mocha/minify.js index a57f2755..4340ede6 100644 --- a/test/mocha/minify.js +++ b/test/mocha/minify.js @@ -1,6 +1,7 @@ var assert = require("assert"); var readFileSync = require("fs").readFileSync; var run_code = require("../sandbox").run_code; +var semver = require("semver"); var UglifyJS = require("../.."); function read(path) { @@ -320,6 +321,24 @@ describe("minify", function() { }); }); + describe("module", function() { + it("Should not inline `await` variables", function() { + if (semver.satisfies(process.version, "<8")) return; + var code = [ + "console.log(function() {", + " return typeof await;", + "}());", + ].join("\n"); + assert.strictEqual(run_code("(async function(){" + code + "})();"), "undefined\n"); + var result = UglifyJS.minify(code, { + module: true, + }); + if (result.error) throw result.error; + assert.strictEqual(result.code, "console.log(function(){return typeof await}());"); + assert.strictEqual(run_code("(async function(){" + result.code + "})();"), "undefined\n"); + }); + }); + describe("rename", function() { it("Should be repeatable", function() { var code = "!function(x){return x(x)}(y);"; diff --git a/test/reduce.js b/test/reduce.js index 4a8b86fb..83c174b0 100644 --- a/test/reduce.js +++ b/test/reduce.js @@ -760,9 +760,9 @@ function compare_run_code(code, minify_options, result_cache, max_timeout) { if (minified.error) return minified; var toplevel = sandbox.has_toplevel(minify_options); - var unminified = run_code(code, toplevel, result_cache, max_timeout); + var unminified = run(code, max_timeout); var timeout = Math.min(100 * unminified.elapsed, max_timeout); - var minified_result = run_code(minified.code, toplevel, result_cache, timeout).result; + var minified_result = run(minified.code, timeout).result; if (sandbox.same_stdout(unminified.result, minified_result)) { return is_timed_out(unminified.result) && is_timed_out(minified_result) && { @@ -774,6 +774,11 @@ function compare_run_code(code, minify_options, result_cache, max_timeout) { minified_result: minified_result, elapsed: unminified.elapsed, }; + + function run(code, timeout) { + if (minify_options.module) code = "(async function(){\n" + code + "\n})();"; + return run_code(code, toplevel, result_cache, timeout); + } } function test_minify(code, minify_options) { diff --git a/test/ufuzz/index.js b/test/ufuzz/index.js index fd11005a..b32cd81b 100644 --- a/test/ufuzz/index.js +++ b/test/ufuzz/index.js @@ -2517,8 +2517,11 @@ for (var round = 1; round <= num_iterations; round++) { })) continue; minify_options.forEach(function(options) { var o = JSON.parse(options); + if (async && has_await) { + o.module = true; + options = JSON.stringify(o); + } var toplevel = sandbox.has_toplevel(o); - if (async && has_await) o.parse = { module: true }; o.validate = true; uglify_code = UglifyJS.minify(original_code, o); original_result = orig_result[toplevel ? 1 : 0];