fix corner cases with new.target (#4784)

This commit is contained in:
Alex Lam S.L
2021-03-16 06:34:36 +00:00
committed by GitHub
parent 77c9116c91
commit 352a944868
5 changed files with 126 additions and 30 deletions

View File

@@ -55,9 +55,10 @@ function DEFNODE(type, props, methods, base) {
props.forEach(function(prop) { props.forEach(function(prop) {
code.push("this.", prop, "=props.", prop, ";"); code.push("this.", prop, "=props.", prop, ";");
}); });
code.push("}");
var proto = base && new base; var proto = base && new base;
if (proto && proto.initialize || methods && methods.initialize) code.push("this.initialize();"); if (proto && proto.initialize || methods && methods.initialize) code.push("this.initialize();");
code.push("}}"); code.push("}");
var ctor = new Function(code.join(""))(); var ctor = new Function(code.join(""))();
if (proto) { if (proto) {
ctor.prototype = proto; ctor.prototype = proto;
@@ -1818,6 +1819,9 @@ var AST_This = DEFNODE("This", null, {
var AST_NewTarget = DEFNODE("NewTarget", null, { var AST_NewTarget = DEFNODE("NewTarget", null, {
$documentation: "The `new.target` symbol", $documentation: "The `new.target` symbol",
initialize: function() {
this.name = "new.target";
},
_validate: function() { _validate: function() {
if (this.name !== "new.target") throw new Error('name must be "new.target": ' + this.name); if (this.name !== "new.target") throw new Error('name must be "new.target": ' + this.name);
}, },

View File

@@ -916,7 +916,7 @@ merge(Compressor.prototype, {
tw.find_parent(AST_Scope).may_call_this(); tw.find_parent(AST_Scope).may_call_this();
var exp = this.expression; var exp = this.expression;
if (exp instanceof AST_LambdaExpression) { if (exp instanceof AST_LambdaExpression) {
var iife = !exp.name; var iife = is_iife_single(this);
this.args.forEach(function(arg) { this.args.forEach(function(arg) {
arg.walk(tw); arg.walk(tw);
if (arg instanceof AST_Spread) iife = false; if (arg instanceof AST_Spread) iife = false;
@@ -1591,6 +1591,19 @@ merge(Compressor.prototype, {
return node instanceof AST_LambdaExpression ? !is_arrow(node) : is_iife_call(node); return node instanceof AST_LambdaExpression ? !is_arrow(node) : is_iife_call(node);
} }
function is_iife_single(call) {
var exp = call.expression;
if (exp.name) return false;
if (!(call instanceof AST_New)) return true;
var found = false;
exp.walk(new TreeWalker(function(node) {
if (found) return true;
if (node instanceof AST_NewTarget) return found = true;
if (node instanceof AST_Scope && node !== exp) return true;
}));
return !found;
}
function is_undeclared_ref(node) { function is_undeclared_ref(node) {
return node instanceof AST_SymbolRef && node.definition().undeclared; return node instanceof AST_SymbolRef && node.definition().undeclared;
} }
@@ -2127,11 +2140,11 @@ merge(Compressor.prototype, {
var iife, fn = compressor.self(); var iife, fn = compressor.self();
if (fn instanceof AST_LambdaExpression if (fn instanceof AST_LambdaExpression
&& !is_generator(fn) && !is_generator(fn)
&& !fn.name
&& !fn.uses_arguments && !fn.uses_arguments
&& !fn.pinned() && !fn.pinned()
&& (iife = compressor.parent()) instanceof AST_Call && (iife = compressor.parent()) instanceof AST_Call
&& iife.expression === fn && iife.expression === fn
&& is_iife_single(iife)
&& all(iife.args, function(arg) { && all(iife.args, function(arg) {
return !(arg instanceof AST_Spread); return !(arg instanceof AST_Spread);
})) { })) {

View File

@@ -1737,28 +1737,23 @@ function parse($TEXT, options) {
var new_ = function(allow_calls) { var new_ = function(allow_calls) {
var start = S.token; var start = S.token;
expect_token("operator", "new"); expect_token("operator", "new");
var call;
if (is("punc", ".") && is_token(peek(), "name", "target")) { if (is("punc", ".") && is_token(peek(), "name", "target")) {
next(); next();
next(); next();
return new AST_NewTarget({ call = new AST_NewTarget();
name: "new.target",
start: start,
end: prev(),
});
}
var newexp = expr_atom(false), args;
if (is("punc", "(")) {
next();
args = expr_list(")", !options.strict);
} else { } else {
args = []; var exp = expr_atom(false), args;
if (is("punc", "(")) {
next();
args = expr_list(")", !options.strict);
} else {
args = [];
}
call = new AST_New({ expression: exp, args: args });
} }
var call = new AST_New({ call.start = start;
start : start, call.end = prev();
expression : newexp,
args : args,
end : prev()
});
return subscripts(call, allow_calls); return subscripts(call, allow_calls);
}; };

View File

@@ -5753,22 +5753,102 @@ issue_4725_2: {
node_version: ">=4" node_version: ">=4"
} }
new_target: { new_target_1: {
input: { input: {
console.log(typeof new function() { new function f() {
return new.target; console.log(new.target === f);
}, function() { }();
console.log(function() {
return new.target; return new.target;
}()); }());
} }
expect: { expect: {
console.log(typeof new function() { new function f() {
return new.target; console.log(new.target === f);
}(), function() { }();
console.log(function() {
return new.target; return new.target;
}()); }());
} }
expect_stdout: "function undefined" expect_stdout: [
"true",
"undefined",
]
node_version: ">=6"
}
new_target_2: {
input: {
new function(a) {
if (!new.target)
console.log("FAIL");
else if (a)
console.log("PASS");
else
new new.target(new.target.length);
}();
}
expect: {
new function(a) {
if (!new.target)
console.log("FAIL");
else if (a)
console.log("PASS");
else
new new.target(new.target.length);
}();
}
expect_stdout: "PASS"
node_version: ">=6"
}
new_target_collapse_vars: {
options = {
collapse_vars: true,
unused: true,
}
input: {
new function(a) {
if (a)
console.log("PASS");
else
new new.target(new.target.length);
}(0);
}
expect: {
new function(a) {
if (a)
console.log("PASS");
else
new new.target(new.target.length);
}(0);
}
expect_stdout: "PASS"
node_version: ">=6"
}
new_target_reduce_vars: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
new function(a) {
if (a)
console.log("PASS");
else
new new.target(new.target.length);
}(0);
}
expect: {
new function(a) {
if (a)
console.log("PASS");
else
new new.target(new.target.length);
}(0);
}
expect_stdout: "PASS"
node_version: ">=6" node_version: ">=6"
} }

View File

@@ -149,6 +149,7 @@ var SUPPORT = function(matrix) {
for_of: "for (var a of []);", for_of: "for (var a of []);",
generator: "function* f(){}", generator: "function* f(){}",
let: "let a;", let: "let a;",
new_target: "function f() { new.target; }",
nullish: "0 ?? 0", nullish: "0 ?? 0",
rest: "var [...a] = [];", rest: "var [...a] = [];",
rest_object: "var {...a} = {};", rest_object: "var {...a} = {};",
@@ -1401,13 +1402,16 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) { createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
s.push( s.push(
instantiate + makeFunction(name) + "(" + createParams(save_async, save_generator) + "){", instantiate + makeFunction(name) + "(" + createParams(save_async, save_generator) + "){",
strictMode(), strictMode()
defns()
); );
var add_new_target = SUPPORT.new_target && VALUES.indexOf("new.target") < 0;
if (add_new_target) VALUES.push("new.target");
s.push(defns());
if (instantiate) for (var i = rng(4); --i >= 0;) { if (instantiate) for (var i = rng(4); --i >= 0;) {
s.push((in_class ? "if (this) " : "") + createThisAssignment(recurmax, stmtDepth, canThrow)); s.push((in_class ? "if (this) " : "") + createThisAssignment(recurmax, stmtDepth, canThrow));
} }
s.push(_createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth)); s.push(_createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth));
if (add_new_target) VALUES.splice(VALUES.indexOf("new.target"), 1);
}); });
generator = save_generator; generator = save_generator;
async = save_async; async = save_async;