fix corner cases in inline (#4640)

fixes #4639
This commit is contained in:
Alex Lam S.L
2021-02-10 12:40:57 +00:00
committed by GitHub
parent a98ec7e4df
commit c6e287331d
4 changed files with 77 additions and 11 deletions

View File

@@ -8336,7 +8336,7 @@ merge(Compressor.prototype, {
var can_inline = can_drop && compressor.option("inline") && !self.is_expr_pure(compressor); var can_inline = can_drop && compressor.option("inline") && !self.is_expr_pure(compressor);
if (can_inline && stat instanceof AST_Return) { if (can_inline && stat instanceof AST_Return) {
var value = stat.value; var value = stat.value;
if (exp === fn && (!value || value.is_constant_expression() && safe_from_await(value))) { if (exp === fn && (!value || value.is_constant_expression() && safe_from_await_yield(value))) {
return make_sequence(self, convert_args(value)).optimize(compressor); return make_sequence(self, convert_args(value)).optimize(compressor);
} }
} }
@@ -8506,8 +8506,17 @@ merge(Compressor.prototype, {
return args; return args;
} }
function safe_from_await(node) { function avoid_await_yield() {
if (!is_async(scope || compressor.find_parent(AST_Scope))) return true; var avoid = [];
var parent_scope = scope || compressor.find_parent(AST_Scope);
if (is_async(parent_scope)) avoid.push("await");
if (is_generator(parent_scope)) avoid.push("yield");
return avoid.length && makePredicate(avoid);
}
function safe_from_await_yield(node) {
var avoid = avoid_await_yield();
if (!avoid) return true;
var safe = true; var safe = true;
var tw = new TreeWalker(function(node) { var tw = new TreeWalker(function(node) {
if (!safe) return true; if (!safe) return true;
@@ -8515,12 +8524,12 @@ merge(Compressor.prototype, {
if (node === fn) return; if (node === fn) return;
if (is_arrow(node)) { if (is_arrow(node)) {
for (var i = 0; safe && i < node.argnames.length; i++) node.argnames[i].walk(tw); for (var i = 0; safe && i < node.argnames.length; i++) node.argnames[i].walk(tw);
} else if (node instanceof AST_LambdaDefinition && node.name.name == "await") { } else if (node instanceof AST_LambdaDefinition && avoid[node.name.name]) {
safe = false; safe = false;
} }
return true; return true;
} }
if (node instanceof AST_Symbol && node.name == "await" && node !== fn.name) safe = false; if (node instanceof AST_Symbol && avoid[node.name] && node !== fn.name) safe = false;
}); });
node.walk(tw); node.walk(tw);
return safe; return safe;
@@ -8579,10 +8588,10 @@ merge(Compressor.prototype, {
return def.references.length - def.replaced < 2 && def.orig[0] instanceof AST_SymbolFunarg; return def.references.length - def.replaced < 2 && def.orig[0] instanceof AST_SymbolFunarg;
})) return; })) return;
var abort = false; var abort = false;
var avoid = avoid_await_yield();
var begin; var begin;
var in_order = []; var in_order = [];
var side_effects = false; var side_effects = false;
var verify_await = true;
value.walk(new TreeWalker(function(node, descend) { value.walk(new TreeWalker(function(node, descend) {
if (abort) return true; if (abort) return true;
if (node instanceof AST_Binary && lazy_op[node.operator] if (node instanceof AST_Binary && lazy_op[node.operator]
@@ -8591,10 +8600,7 @@ merge(Compressor.prototype, {
return; return;
} }
if (node instanceof AST_Scope) return abort = true; if (node instanceof AST_Scope) return abort = true;
if (verify_await && node instanceof AST_Symbol && node.name == "await") { if (avoid && node instanceof AST_Symbol && avoid[node.name]) return abort = true;
if (is_async(compressor.find_parent(AST_Scope))) return abort = true;
verify_await = false;
}
if (node instanceof AST_SymbolRef) { if (node instanceof AST_SymbolRef) {
var def = node.definition(); var def = node.definition();
if (fn.variables.get(node.name) !== def) { if (fn.variables.get(node.name) !== def) {
@@ -8697,7 +8703,7 @@ merge(Compressor.prototype, {
} while (!(scope instanceof AST_Scope)); } while (!(scope instanceof AST_Scope));
insert = scope.body.indexOf(child) + 1; insert = scope.body.indexOf(child) + 1;
if (!insert) return false; if (!insert) return false;
if (!safe_from_await(fn)) return false; if (!safe_from_await_yield(fn)) return false;
var safe_to_inject = exp !== fn || fn.parent_scope.resolve() === scope; var safe_to_inject = exp !== fn || fn.parent_scope.resolve() === scope;
if (scope instanceof AST_Toplevel) { if (scope instanceof AST_Toplevel) {
if (compressor.toplevel.vars) { if (compressor.toplevel.vars) {

View File

@@ -1166,7 +1166,9 @@ function parse($TEXT, options) {
function arrow(exprs, start, async) { function arrow(exprs, start, async) {
var was_async = S.in_async; var was_async = S.in_async;
var was_gen = S.in_generator;
S.in_async = async; S.in_async = async;
S.in_generator = false;
var was_funarg = S.in_funarg; var was_funarg = S.in_funarg;
S.in_funarg = S.in_function; S.in_funarg = S.in_function;
var argnames = exprs.map(to_funarg); var argnames = exprs.map(to_funarg);
@@ -1196,6 +1198,7 @@ function parse($TEXT, options) {
--S.in_function; --S.in_function;
S.in_loop = loop; S.in_loop = loop;
S.labels = labels; S.labels = labels;
S.in_generator = was_gen;
S.in_async = was_async; S.in_async = was_async;
return new (async ? AST_AsyncArrow : AST_Arrow)({ return new (async ? AST_AsyncArrow : AST_Arrow)({
start: start, start: start,

View File

@@ -96,6 +96,18 @@ pause_resume: {
node_version: ">=4" node_version: ">=4"
} }
arrow_yield: {
input: {
yield = "PASS";
console.log(function*() {
return () => yield || "FAIL";
}().next().value());
}
expect_exact: 'yield="PASS";console.log(function*(){return()=>yield||"FAIL"}().next().value());'
expect_stdout: "PASS"
node_version: ">=4"
}
for_of: { for_of: {
input: { input: {
function* f() { function* f() {
@@ -833,3 +845,47 @@ issue_4633: {
] ]
node_version: ">=4" node_version: ">=4"
} }
issue_4639_1: {
options = {
inline: true,
}
input: {
console.log(function*() {
return function() {
return yield => "PASS";
}();
}().next().value());
}
expect: {
console.log(function*() {
return function() {
return yield => "PASS";
}();
}().next().value());
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4639_2: {
options = {
inline: true,
}
input: {
(function*() {
console.log(function() {
return typeof yield;
}());
})().next();
}
expect: {
(function*() {
console.log(function() {
return typeof yield;
}());
})().next();
}
expect_stdout: "undefined"
node_version: ">=4"
}

View File

@@ -333,6 +333,7 @@ var VAR_NAMES = [
"arguments", "arguments",
"async", "async",
"await", "await",
"yield",
]; ];
var INITIAL_NAMES_LEN = VAR_NAMES.length; var INITIAL_NAMES_LEN = VAR_NAMES.length;