Part 1: Implement ES6 function name property semantics

Issue #78
This commit is contained in:
janekptacijarabaci 2018-03-19 15:47:10 +01:00 • committed by Roy Tam
commit 748c69d7fd
30 changed files with 750 additions and 81 deletions

View file

@ -0,0 +1,139 @@
var BUGNUMBER = 883377;
var summary = "Anonymous function name should be set based on assignment";
print(BUGNUMBER + ": " + summary);
var fooSymbol = Symbol("foo");
var emptySymbol = Symbol("");
var undefSymbol = Symbol();
var globalVar;
var exprs = [
["function() {}", false],
["function named() {}", true],
["function*() {}", false],
["function* named() {}", true],
["async function() {}", false],
["async function named() {}", true],
["() => {}", false],
["async () => {}", false],
["class {}", false],
["class named {}", true],
];
function testAssignmentExpression(expr, named) {
eval(`
var assignment;
assignment = ${expr};
assertEq(assignment.name, named ? "named" : "assignment");
globalVar = ${expr};
assertEq(globalVar.name, named ? "named" : "globalVar");
var obj = { dynamic: null };
with (obj) {
dynamic = ${expr};
}
assertEq(obj.dynamic.name, named ? "named" : "dynamic");
(function namedLambda(param1, param2) {
var assignedToNamedLambda;
assignedToNamedLambda = namedLambda = ${expr};
assertEq(namedLambda.name, "namedLambda");
assertEq(assignedToNamedLambda.name, named ? "named" : "namedLambda");
param1 = ${expr};
assertEq(param1.name, named ? "named" : "param1");
{
let param1 = ${expr};
assertEq(param1.name, named ? "named" : "param1");
param2 = ${expr};
assertEq(param2.name, named ? "named" : "param2");
}
})();
{
let nextedLexical1, nextedLexical2;
{
let nextedLexical1 = ${expr};
assertEq(nextedLexical1.name, named ? "named" : "nextedLexical1");
nextedLexical2 = ${expr};
assertEq(nextedLexical2.name, named ? "named" : "nextedLexical2");
}
}
`);
// Not applicable cases: not IsIdentifierRef.
eval(`
var inParen;
(inParen) = ${expr};
assertEq(inParen.name, named ? "named" : "");
`);
// Not applicable cases: not direct RHS.
if (!expr.includes("=>")) {
eval(`
var a = true && ${expr};
assertEq(a.name, named ? "named" : "");
`);
} else {
// Arrow function cannot be RHS of &&.
eval(`
var a = true && (${expr});
assertEq(a.name, named ? "named" : "");
`);
}
// Not applicable cases: property.
eval(`
var obj = {};
obj.prop = ${expr};
assertEq(obj.prop.name, named ? "named" : "");
obj["literal"] = ${expr};
assertEq(obj["literal"].name, named ? "named" : "");
`);
// Not applicable cases: assigned again.
eval(`
var tmp = [${expr}];
assertEq(tmp[0].name, named ? "named" : "");
var assignment;
assignment = tmp[0];
assertEq(assignment.name, named ? "named" : "");
`);
}
for (var [expr, named] of exprs) {
testAssignmentExpression(expr, named);
}
function testVariableDeclaration(expr, named) {
eval(`
var varDecl = ${expr};
assertEq(varDecl.name, named ? "named" : "varDecl");
`);
}
for (var [expr, named] of exprs) {
testVariableDeclaration(expr, named);
}
function testLexicalBinding(expr, named) {
eval(`
let lexical = ${expr};
assertEq(lexical.name, named ? "named" : "lexical");
const constLexical = ${expr};
assertEq(constLexical.name, named ? "named" : "constLexical");
`);
}
for (var [expr, named] of exprs) {
testLexicalBinding(expr, named);
}
if (typeof reportCompare === "function")
reportCompare(0, 0);

View file

@ -0,0 +1,54 @@
var BUGNUMBER = 883377;
var summary = "Anonymous function name should be set based on binding pattern";
print(BUGNUMBER + ": " + summary);
var exprs = [
["function() {}", false],
["function named() {}", true],
["function*() {}", false],
["function* named() {}", true],
["async function() {}", false],
["async function named() {}", true],
["() => {}", false],
["async () => {}", false],
["class {}", false],
["class named {}", true],
];
function testAssignmentProperty(expr, named) {
var f = eval(`(function({ prop1 = ${expr} }) { return prop1; })`);
assertEq(f({}).name, named ? "named" : "prop1");
eval(`
var { prop1 = ${expr} } = {};
assertEq(prop1.name, named ? "named" : "prop1");
`);
}
for (var [expr, named] of exprs) {
testAssignmentProperty(expr, named);
}
function testAssignmentElement(expr, named) {
var f = eval(`(function([elem1 = ${expr}]) { return elem1; })`);
assertEq(f([]).name, named ? "named" : "elem1");
eval(`
var [elem1 = ${expr}] = [];
assertEq(elem1.name, named ? "named" : "elem1");
`);
}
for (var [expr, named] of exprs) {
testAssignmentElement(expr, named);
}
function testSingleNameBinding(expr, named) {
var f = eval(`(function(param1 = ${expr}) { return param1; })`);
assertEq(f().name, named ? "named" : "param1");
}
for (var [expr, named] of exprs) {
testSingleNameBinding(expr, named);
}
if (typeof reportCompare === "function")
reportCompare(0, 0);

View file

@ -0,0 +1,32 @@
var BUGNUMBER = 883377;
var summary = "Anonymous class with name method shouldn't be affected by assignment";
print(BUGNUMBER + ": " + summary);
var classWithStaticNameMethod = class { static name() {} };
assertEq(typeof classWithStaticNameMethod.name, "function");
var classWithStaticNameGetter = class { static get name() { return "static name"; } };
assertEq(typeof Object.getOwnPropertyDescriptor(classWithStaticNameGetter, "name").get, "function");
assertEq(classWithStaticNameGetter.name, "static name");
var classWithStaticNameSetter = class { static set name(v) {} };
assertEq(typeof Object.getOwnPropertyDescriptor(classWithStaticNameSetter, "name").set, "function");
var n = "NAME".toLowerCase();
var classWithStaticNameMethodComputed = class { static [n]() {} };
assertEq(typeof classWithStaticNameMethodComputed.name, "function");
// It doesn't apply for non-static method.
var classWithNameMethod = class { name() {} };
assertEq(classWithNameMethod.name, "classWithNameMethod");
var classWithNameGetter = class { get name() { return "name"; } };
assertEq(classWithNameGetter.name, "classWithNameGetter");
var classWithNameSetter = class { set name(v) {} };
assertEq(classWithNameSetter.name, "classWithNameSetter");
if (typeof reportCompare === "function")
reportCompare(0, 0);

View file

@ -0,0 +1,31 @@
var BUGNUMBER = 883377;
var summary = "Anonymous function name should be set based on for-in initializer";
print(BUGNUMBER + ": " + summary);
var exprs = [
["function() {}", false],
["function named() {}", true],
["function*() {}", false],
["function* named() {}", true],
["async function() {}", false],
["async function named() {}", true],
["() => {}", false],
["async () => {}", false],
["class {}", false],
["class named {}", true],
];
function testForInHead(expr, named) {
eval(`
for (var forInHead = ${expr} in {}) {
}
`);
assertEq(forInHead.name, named ? "named" : "forInHead");
}
for (var [expr, named] of exprs) {
testForInHead(expr, named);
}
if (typeof reportCompare === "function")
reportCompare(0, 0);

View file

@ -0,0 +1,70 @@
var BUGNUMBER = 883377;
var summary = "Anonymous function name should be set based on method definition";
print(BUGNUMBER + ": " + summary);
var fooSymbol = Symbol("foo");
var emptySymbol = Symbol("");
var undefSymbol = Symbol();
function testMethod(prefix, classPrefix="", prototype=false) {
var param = (prefix == "set" || prefix == "static set") ? "v" : "";
var sep = classPrefix ? "" : ",";
var objOrClass = eval(`(${classPrefix}{
${prefix} prop(${param}) {} ${sep}
${prefix} "literal"(${param}) {} ${sep}
${prefix} ""(${param}) {} ${sep}
${prefix} 5(${param}) {} ${sep}
${prefix} [Symbol.iterator](${param}) {} ${sep}
${prefix} [fooSymbol](${param}) {} ${sep}
${prefix} [emptySymbol](${param}) {} ${sep}
${prefix} [undefSymbol](${param}) {} ${sep}
${prefix} [/a/](${param}) {} ${sep}
})`);
var target = prototype ? objOrClass.prototype : objOrClass;
function testOne(methodName, expectedName) {
var f;
if (prefix == "get" || prefix == "static get") {
f = Object.getOwnPropertyDescriptor(target, methodName).get;
expectedName = "get " + expectedName;
} else if (prefix == "set" || prefix == "static set") {
f = Object.getOwnPropertyDescriptor(target, methodName).set;
expectedName = "set " + expectedName;
} else {
f = Object.getOwnPropertyDescriptor(target, methodName).value;
}
assertEq(f.name, expectedName);
}
testOne("prop", "prop");
testOne("literal", "literal");
testOne("", "");
testOne(5, "5");
testOne(Symbol.iterator, "[Symbol.iterator]");
testOne(fooSymbol, "[foo]");
testOne(emptySymbol, "[]");
testOne(undefSymbol, "");
testOne(/a/, "/a/");
}
testMethod("");
testMethod("*");
testMethod("async");
testMethod("get");
testMethod("set");
testMethod("", "class", true);
testMethod("*", "class", true);
testMethod("async", "class", true);
testMethod("get", "class", true);
testMethod("set", "class", true);
testMethod("static", "class");
testMethod("static *", "class");
testMethod("static async", "class");
testMethod("static get", "class");
testMethod("static set", "class");
if (typeof reportCompare === "function")
reportCompare(0, 0);

View file

@ -0,0 +1,58 @@
var BUGNUMBER = 883377;
var summary = "Anonymous function name should be set based on property name";
print(BUGNUMBER + ": " + summary);
var fooSymbol = Symbol("foo");
var emptySymbol = Symbol("");
var undefSymbol = Symbol();
var exprs = [
["function() {}", false],
["function named() {}", true],
["function*() {}", false],
["function* named() {}", true],
["async function() {}", false],
["async function named() {}", true],
["() => {}", false],
["async () => {}", false],
["class {}", false],
["class named {}", true],
];
function testPropertyDefinition(expr, named) {
var obj = eval(`({
prop: ${expr},
"literal": ${expr},
"": ${expr},
5: ${expr},
0.4: ${expr},
[Symbol.iterator]: ${expr},
[fooSymbol]: ${expr},
[emptySymbol]: ${expr},
[undefSymbol]: ${expr},
[/a/]: ${expr},
})`);
assertEq(obj.prop.name, named ? "named" : "prop");
assertEq(obj["literal"].name, named ? "named" : "literal");
assertEq(obj[""].name, named ? "named" : "");
assertEq(obj[5].name, named ? "named" : "5");
assertEq(obj[0.4].name, named ? "named" : "0.4");
assertEq(obj[Symbol.iterator].name, named ? "named" : "[Symbol.iterator]");
assertEq(obj[fooSymbol].name, named ? "named" : "[foo]");
assertEq(obj[emptySymbol].name, named ? "named" : "[]");
assertEq(obj[undefSymbol].name, named ? "named" : "");
assertEq(obj[/a/].name, named ? "named" : "/a/");
// Not applicable cases: __proto__.
obj = {
__proto__: function() {}
};
assertEq(obj.__proto__.name, "");
}
for (var [expr, named] of exprs) {
testPropertyDefinition(expr, named);
}
if (typeof reportCompare === "function")
reportCompare(0, 0);