From: Alex Lam S.L Date: Tue, 8 Dec 2020 03:26:03 +0000 (+0000) Subject: fix corner cases with `await` (#4350) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=47331597825f3feb2915a0c0c789c4e7ea9b57e8;p=UglifyJS.git fix corner cases with `await` (#4350) fixes #4349 --- diff --git a/lib/ast.js b/lib/ast.js index 0605fb8c..262372ee 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -551,7 +551,7 @@ function is_function(node) { return node instanceof AST_AsyncFunction || node instanceof AST_Function; } -var AST_AsyncFunction = DEFNODE("AsyncFunction", null, { +var AST_AsyncFunction = DEFNODE("AsyncFunction", "inlined", { $documentation: "An asynchronous function expression", _validate: function() { if (this.name != null) { @@ -573,7 +573,7 @@ function is_defun(node) { return node instanceof AST_AsyncDefun || node instanceof AST_Defun; } -var AST_AsyncDefun = DEFNODE("AsyncDefun", null, { +var AST_AsyncDefun = DEFNODE("AsyncDefun", "inlined", { $documentation: "An asynchronous function definition", _validate: function() { if (!(this.name instanceof AST_SymbolDefun)) throw new Error("name must be AST_SymbolDefun"); diff --git a/lib/compress.js b/lib/compress.js index 8936125d..144a5334 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -927,6 +927,7 @@ merge(Compressor.prototype, { return true; }); def(AST_Lambda, function(tw, descend, compressor) { + this.inlined = false; push(tw); reset_variables(tw, compressor, this); descend(); @@ -1630,7 +1631,7 @@ merge(Compressor.prototype, { var assign_used = false; var can_replace = !args || !hit; if (!can_replace) { - for (var j = compressor.self().argnames.lastIndexOf(candidate.name) + 1; !abort && j < args.length; j++) { + for (var j = scope.argnames.lastIndexOf(candidate.name) + 1; !abort && j < args.length; j++) { args[j].transform(scanner); } can_replace = true; @@ -1819,7 +1820,7 @@ merge(Compressor.prototype, { function extract_args() { var iife, fn = compressor.self(); - if (fn instanceof AST_Function + if (is_function(fn) && !fn.name && !fn.uses_arguments && !fn.pinned() @@ -1830,6 +1831,29 @@ merge(Compressor.prototype, { })) { var fn_strict = compressor.has_directive("use strict"); if (fn_strict && !member(fn_strict, fn.body)) fn_strict = false; + var has_await = fn instanceof AST_AsyncFunction ? function(node) { + return node instanceof AST_Symbol && node.name == "await"; + } : function(node) { + return node instanceof AST_Await && !tw.find_parent(AST_Scope); + }; + var tw = new TreeWalker(function(node) { + if (!arg) return true; + if (has_await(node)) { + arg = null; + return true; + } + if (node instanceof AST_SymbolRef && fn.variables.has(node.name)) { + var s = node.definition().scope; + if (s !== scope) while (s = s.parent_scope) { + if (s === scope) return true; + } + arg = null; + } + if (node instanceof AST_This && (fn_strict || !tw.find_parent(AST_Scope))) { + arg = null; + return true; + } + }); var len = fn.argnames.length; args = iife.args.slice(len); var names = Object.create(null); @@ -1852,20 +1876,7 @@ merge(Compressor.prototype, { } else if (arg instanceof AST_Lambda && arg.pinned()) { arg = null; } else { - arg.walk(new TreeWalker(function(node) { - if (!arg) return true; - if (node instanceof AST_SymbolRef && fn.variables.has(node.name)) { - var s = node.definition().scope; - if (s !== scope) while (s = s.parent_scope) { - if (s === scope) return true; - } - arg = null; - } - if (node instanceof AST_This && (fn_strict || !this.find_parent(AST_Scope))) { - arg = null; - return true; - } - })); + arg.walk(tw); } if (arg) candidates.unshift([ make_node(AST_VarDef, sym, { name: sym, @@ -8982,7 +8993,7 @@ merge(Compressor.prototype, { single_use = fixed.is_constant_expression(self.scope); if (single_use == "f") { var scope = self.scope; - do if (scope instanceof AST_Defun || scope instanceof AST_Function) { + do if (is_defun(scope) || is_function(scope)) { scope.inlined = true; } while (scope = scope.parent_scope); } diff --git a/lib/parse.js b/lib/parse.js index 5a07ef64..21e6055a 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -1638,6 +1638,7 @@ function parse($TEXT, options) { function maybe_await() { var start = S.token; if (!(S.in_async && is("name", "await"))) return maybe_unary(); + S.input.context().regex_allowed = true; next(); return new AST_Await({ start: start, diff --git a/test/compress/async.js b/test/compress/async.js index 4f342895..3011a6af 100644 --- a/test/compress/async.js +++ b/test/compress/async.js @@ -387,3 +387,60 @@ issue_4347_2: { expect_stdout: "PASS" node_version: ">=8" } + +issue_4349_1: { + input: { + console.log(typeof async function() { + await /abc/; + }().then); + } + expect_exact: "console.log(typeof async function(){await/abc/}().then);" + expect_stdout: "function" + node_version: ">=8" +} + +issue_4349_2: { + options = { + collapse_vars: true, + unused: true, + } + input: { + console.log(typeof async function() { + (function(a) { + this[a]; + }(await 0)); + }().then); + } + expect: { + console.log(typeof async function() { + (function(a) { + this[a]; + }(await 0)); + }().then); + } + expect_stdout: "function" + node_version: ">=8" +} + +issue_4349_3: { + options = { + collapse_vars: true, + unused: true, + } + input: { + console.log(typeof function(await) { + return async function(a) { + this[a]; + }(await); + }(this).then); + } + expect: { + console.log(typeof function(await) { + return async function(a) { + this[a]; + }(await); + }(this).then); + } + expect_stdout: "function" + node_version: ">=8" +}