fix corner cases with await (#4350)

fixes #4349
This commit is contained in:
Alex Lam S.L
2020-12-08 03:26:03 +00:00
committed by GitHub
parent 5fba98608c
commit 4733159782
4 changed files with 88 additions and 19 deletions

View File

@@ -551,7 +551,7 @@ function is_function(node) {
return node instanceof AST_AsyncFunction || node instanceof AST_Function; 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", $documentation: "An asynchronous function expression",
_validate: function() { _validate: function() {
if (this.name != null) { if (this.name != null) {
@@ -573,7 +573,7 @@ function is_defun(node) {
return node instanceof AST_AsyncDefun || node instanceof AST_Defun; 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", $documentation: "An asynchronous function definition",
_validate: function() { _validate: function() {
if (!(this.name instanceof AST_SymbolDefun)) throw new Error("name must be AST_SymbolDefun"); if (!(this.name instanceof AST_SymbolDefun)) throw new Error("name must be AST_SymbolDefun");

View File

@@ -927,6 +927,7 @@ merge(Compressor.prototype, {
return true; return true;
}); });
def(AST_Lambda, function(tw, descend, compressor) { def(AST_Lambda, function(tw, descend, compressor) {
this.inlined = false;
push(tw); push(tw);
reset_variables(tw, compressor, this); reset_variables(tw, compressor, this);
descend(); descend();
@@ -1630,7 +1631,7 @@ merge(Compressor.prototype, {
var assign_used = false; var assign_used = false;
var can_replace = !args || !hit; var can_replace = !args || !hit;
if (!can_replace) { 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); args[j].transform(scanner);
} }
can_replace = true; can_replace = true;
@@ -1819,7 +1820,7 @@ merge(Compressor.prototype, {
function extract_args() { function extract_args() {
var iife, fn = compressor.self(); var iife, fn = compressor.self();
if (fn instanceof AST_Function if (is_function(fn)
&& !fn.name && !fn.name
&& !fn.uses_arguments && !fn.uses_arguments
&& !fn.pinned() && !fn.pinned()
@@ -1830,6 +1831,29 @@ merge(Compressor.prototype, {
})) { })) {
var fn_strict = compressor.has_directive("use strict"); var fn_strict = compressor.has_directive("use strict");
if (fn_strict && !member(fn_strict, fn.body)) fn_strict = false; 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; var len = fn.argnames.length;
args = iife.args.slice(len); args = iife.args.slice(len);
var names = Object.create(null); var names = Object.create(null);
@@ -1852,20 +1876,7 @@ merge(Compressor.prototype, {
} else if (arg instanceof AST_Lambda && arg.pinned()) { } else if (arg instanceof AST_Lambda && arg.pinned()) {
arg = null; arg = null;
} else { } else {
arg.walk(new TreeWalker(function(node) { arg.walk(tw);
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;
}
}));
} }
if (arg) candidates.unshift([ make_node(AST_VarDef, sym, { if (arg) candidates.unshift([ make_node(AST_VarDef, sym, {
name: sym, name: sym,
@@ -8982,7 +8993,7 @@ merge(Compressor.prototype, {
single_use = fixed.is_constant_expression(self.scope); single_use = fixed.is_constant_expression(self.scope);
if (single_use == "f") { if (single_use == "f") {
var scope = self.scope; 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; scope.inlined = true;
} while (scope = scope.parent_scope); } while (scope = scope.parent_scope);
} }

View File

@@ -1638,6 +1638,7 @@ function parse($TEXT, options) {
function maybe_await() { function maybe_await() {
var start = S.token; var start = S.token;
if (!(S.in_async && is("name", "await"))) return maybe_unary(); if (!(S.in_async && is("name", "await"))) return maybe_unary();
S.input.context().regex_allowed = true;
next(); next();
return new AST_Await({ return new AST_Await({
start: start, start: start,

View File

@@ -387,3 +387,60 @@ issue_4347_2: {
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=8" 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"
}