diff options
Diffstat (limited to 'js/src/tests/ecma_7/AsyncFunctions')
17 files changed, 788 insertions, 0 deletions
diff --git a/js/src/tests/ecma_7/AsyncFunctions/BoundNames.js b/js/src/tests/ecma_7/AsyncFunctions/BoundNames.js new file mode 100644 index 000000000..743f4fdcc --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/BoundNames.js @@ -0,0 +1,21 @@ +var BUGNUMBER = 1185106; +var summary = "Bound names of async functions"; + +print(BUGNUMBER + ": " + summary); + +async function test() {} +assertEq(test.name, "test"); + +var test2 = (async function test2() {}); +assertEq(test2.name, "test2"); + +var anon = async function() {}; +assertEq(anon.name, ""); + +if (typeof Reflect !== "undefined" && Reflect.parse) { + var tree = Reflect.parse("export default async function() {}", { target: "module" }); + assertEq(tree.body[0].declaration.id.name, "*default*"); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/EarlyErrors.js b/js/src/tests/ecma_7/AsyncFunctions/EarlyErrors.js new file mode 100644 index 000000000..cb28d104b --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/EarlyErrors.js @@ -0,0 +1,51 @@ +var BUGNUMBER = 1185106; +var summary = "EarlyErrors for async function"; + +print(BUGNUMBER + ": " + summary); + +function assertThrowsSE(code) { + assertThrows(() => Reflect.parse(code), SyntaxError); +} + +if (typeof Reflect !== "undefined" && Reflect.parse) { + // If FormalParameters Contains AwaitExpression is true. + assertThrowsSE("async function a(k = await 3) {}"); + assertThrowsSE("(async function(k = await 3) {})"); + assertThrowsSE("(async function a(k = await 3) {})"); + + // If BindingIdentifier is `eval` or `arguments`. + assertThrowsSE("'use strict'; async function eval() {}"); + assertThrowsSE("'use strict'; (async function eval() {})"); + + assertThrowsSE("'use strict'; async function arguments() {}"); + assertThrowsSE("'use strict'; (async function arguments() {})"); + + // If any element of the BoundNames of FormalParameters also occurs in the + // LexicallyDeclaredNames of AsyncFunctionBody. + assertThrowsSE("async function a(x) { let x; }"); + assertThrowsSE("(async function(x) { let x; })"); + assertThrowsSE("(async function a(x) { let x; })"); + + // If FormalParameters contains SuperProperty is true. + assertThrowsSE("async function a(k = super.prop) { }"); + assertThrowsSE("(async function(k = super.prop) {})"); + assertThrowsSE("(async function a(k = super.prop) {})"); + + // If AsyncFunctionBody contains SuperProperty is true. + assertThrowsSE("async function a() { super.prop(); }"); + assertThrowsSE("(async function() { super.prop(); })"); + assertThrowsSE("(async function a() { super.prop(); })"); + + // If FormalParameters contains SuperCall is true. + assertThrowsSE("async function a(k = super()) {}"); + assertThrowsSE("(async function(k = super()) {})"); + assertThrowsSE("(async function a(k = super()) {})"); + + // If AsyncFunctionBody contains SuperCall is true. + assertThrowsSE("async function a() { super(); }"); + assertThrowsSE("(async function() { super(); })"); + assertThrowsSE("(async function a() { super(); })"); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/arguments_callee.js b/js/src/tests/ecma_7/AsyncFunctions/arguments_callee.js new file mode 100644 index 000000000..2a577e0b9 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/arguments_callee.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue + +var BUGNUMBER = 1185106; +var summary = "arguments.callee in sloppy mode should return wrapped function"; + +print(BUGNUMBER + ": " + summary); + +async function decl1() { + return arguments.callee; +} +assertEventuallyEq(decl1(), decl1); + +var expr1 = async function foo() { + return arguments.callee; +}; +assertEventuallyEq(expr1(), expr1); + +var expr2 = async function() { + return arguments.callee; +}; +assertEventuallyEq(expr2(), expr2); + +var obj = { + async method1() { + return arguments.callee; + } +}; +assertEventuallyEq(obj.method1(), obj.method1); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/await-newline.js b/js/src/tests/ecma_7/AsyncFunctions/await-newline.js new file mode 100644 index 000000000..dc42fa481 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/await-newline.js @@ -0,0 +1,15 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue + +var BUGNUMBER = 1331009; +var summary = "Newline is allowed between await and operand"; + +print(BUGNUMBER + ": " + summary); + +var expr = async function foo() { + return await + 10; +}; +assertEventuallyEq(expr(), 10); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/clone.js b/js/src/tests/ecma_7/AsyncFunctions/clone.js new file mode 100644 index 000000000..2a4d5f8e0 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/clone.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs clone, cloneAndExecuteScript, drainJobQueue + +// Async function cannot be cloned. +assertThrowsInstanceOf(() => clone(async function f() {}), TypeError); + +// unwrapped async function can be cloned. +let g = newGlobal(); +cloneAndExecuteScript(` +async function f() { + var a = await 1; + var b = await 2; + var c = await 3; + return a + b + c; +} +var V; +f().then(v => V = v); +drainJobQueue(); +`, g); +assertEq(g.V, 6); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/constructor.js b/js/src/tests/ecma_7/AsyncFunctions/constructor.js new file mode 100644 index 000000000..ccacb4363 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/constructor.js @@ -0,0 +1,33 @@ +var BUGNUMBER = 1185106; +var summary = "async function constructor and prototype"; + +print(BUGNUMBER + ": " + summary); + +var f1 = async function() {}; + +var AsyncFunction = f1.constructor; +var AsyncFunctionPrototype = AsyncFunction.prototype; + +assertEq(AsyncFunction.name, "AsyncFunction"); +assertEq(AsyncFunction.length, 1); +assertEq(Object.getPrototypeOf(async function() {}), AsyncFunctionPrototype); + +assertEq(AsyncFunctionPrototype.constructor, AsyncFunction); + +var f2 = AsyncFunction("await 1"); +assertEq(f2.constructor, AsyncFunction); +assertEq(f2.length, 0); +assertEq(Object.getPrototypeOf(f2), AsyncFunctionPrototype); + +var f3 = new AsyncFunction("await 1"); +assertEq(f3.constructor, AsyncFunction); +assertEq(f3.length, 0); +assertEq(Object.getPrototypeOf(f3), AsyncFunctionPrototype); + +var f4 = AsyncFunction("a", "b", "c", "await 1"); +assertEq(f4.constructor, AsyncFunction); +assertEq(f4.length, 3); +assertEq(Object.getPrototypeOf(f4), AsyncFunctionPrototype); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/identity.js b/js/src/tests/ecma_7/AsyncFunctions/identity.js new file mode 100644 index 000000000..f3876bf23 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/identity.js @@ -0,0 +1,14 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue + +var BUGNUMBER = 1185106; +var summary = "Named async function expression should get wrapped function for the name inside it"; + +print(BUGNUMBER + ": " + summary); + +var expr = async function foo() { + return foo; +}; +assertEventuallyEq(expr(), expr); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/length.js b/js/src/tests/ecma_7/AsyncFunctions/length.js new file mode 100644 index 000000000..da95e23b8 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/length.js @@ -0,0 +1,12 @@ +var BUGNUMBER = 1185106; +var summary = "async function length"; + +print(BUGNUMBER + ": " + summary); + +assertEq(async function() {}.length, 0); +assertEq(async function(a) {}.length, 1); +assertEq(async function(a, b, c) {}.length, 3); +assertEq(async function(a, b, c, ...d) {}.length, 3); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/methods.js b/js/src/tests/ecma_7/AsyncFunctions/methods.js new file mode 100644 index 000000000..061a0e826 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/methods.js @@ -0,0 +1,61 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue +var BUGNUMBER = 1185106; +var summary = "async methods semantics"; + +print(BUGNUMBER + ": " + summary); + +class X { + constructor() { + this.value = 42; + } + async getValue() { + return this.value; + } + setValue(value) { + this.value = value; + } + async increment() { + var value = await this.getValue(); + this.setValue(value + 1); + return this.getValue(); + } + async getBaseClassName() { + return 'X'; + } + static async getStaticValue() { + return 44; + } + async 10() { + return 46; + } + async ["foo"]() { + return 47; + } +} + +class Y extends X { + async getBaseClassName() { + return super.getBaseClassName(); + } +} + +var objLiteral = { + async get() { + return 45; + }, + someStuff: 5 +}; + +var x = new X(); +var y = new Y(); + +assertEventuallyEq(x.getValue(), 42); +assertEventuallyEq(x.increment(), 43); +assertEventuallyEq(x[10](), 46); +assertEventuallyEq(x.foo(), 47); +assertEventuallyEq(X.getStaticValue(), 44); +assertEventuallyEq(objLiteral.get(), 45); +assertEventuallyEq(y.getBaseClassName(), 'X'); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/property.js b/js/src/tests/ecma_7/AsyncFunctions/property.js new file mode 100644 index 000000000..53f779c33 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/property.js @@ -0,0 +1,49 @@ +var BUGNUMBER = 1185106; +var summary = "async name token in property and object destructuring pattern"; + +print(BUGNUMBER + ": " + summary); + +{ + let a = { async: 10 }; + assertEq(a.async, 10); +} + +{ + let a = { async() {} }; + assertEq(a.async instanceof Function, true); + assertEq(a.async.name, "async"); +} + +{ + let async = 11; + let a = { async }; + assertEq(a.async, 11); +} + +{ + let { async } = { async: 12 }; + assertEq(async, 12); +} + +{ + let { async = 13 } = {}; + assertEq(async, 13); +} + +{ + let { async: a = 14 } = {}; + assertEq(a, 14); +} + +{ + let { async, other } = { async: 15, other: 16 }; + assertEq(async, 15); + assertEq(other, 16); + + let a = { async, other }; + assertEq(a.async, 15); + assertEq(a.other, 16); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/semantics.js b/js/src/tests/ecma_7/AsyncFunctions/semantics.js new file mode 100644 index 000000000..cb2a04c3f --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/semantics.js @@ -0,0 +1,169 @@ +// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue +var BUGNUMBER = 1185106; +var summary = "async functions semantics"; + +print(BUGNUMBER + ": " + summary); + +async function empty() { +} +assertEventuallyEq(empty(), undefined); + +async function simpleReturn() { + return 1; +} +assertEventuallyEq(simpleReturn(), 1); + +async function simpleAwait() { + var result = await 2; + return result; +} +assertEventuallyEq(simpleAwait(), 2); + +async function simpleAwaitAsync() { + var result = await simpleReturn(); + return 2 + result; +} +assertEventuallyEq(simpleAwaitAsync(), 3); + +async function returnOtherAsync() { + return 1 + await simpleAwaitAsync(); +} +assertEventuallyEq(returnOtherAsync(), 4); + +async function simpleThrower() { + throw new Error(); +} +assertEventuallyThrows(simpleThrower(), Error); + +async function delegatedThrower() { + var val = await simpleThrower(); + return val; +} + +async function tryCatch() { + try { + await delegatedThrower(); + return 'FAILED'; + } catch (_) { + return 5; + } +} +assertEventuallyEq(tryCatch(), 5); + +async function tryCatchThrow() { + try { + await delegatedThrower(); + return 'FAILED'; + } catch (_) { + return delegatedThrower(); + } +} +assertEventuallyThrows(tryCatchThrow(), Error); + +async function wellFinally() { + try { + await delegatedThrower(); + } catch (_) { + return 'FAILED'; + } finally { + return 6; + } +} +assertEventuallyEq(wellFinally(), 6); + +async function finallyMayFail() { + try { + await delegatedThrower(); + } catch (_) { + return 5; + } finally { + return delegatedThrower(); + } +} +assertEventuallyThrows(finallyMayFail(), Error); + +async function embedded() { + async function inner() { + return 7; + } + return await inner(); +} +assertEventuallyEq(embedded(), 7); + +// recursion, it works! +async function fib(n) { + return (n == 0 || n == 1) ? n : await fib(n - 1) + await fib(n - 2); +} +assertEventuallyEq(fib(6), 8); + +// mutual recursion +async function isOdd(n) { + async function isEven(n) { + return n === 0 || await isOdd(n - 1); + } + return n !== 0 && await isEven(n - 1); +} +assertEventuallyEq(isOdd(12).then(v => v ? "oops" : 12), 12); + +// recursion, take three! +var hardcoreFib = async function fib2(n) { + return (n == 0 || n == 1) ? n : await fib2(n - 1) + await fib2(n - 2); +} +assertEventuallyEq(hardcoreFib(7), 13); + +var asyncExpr = async function() { + return 10; +} +assertEventuallyEq(asyncExpr(), 10); + +var namedAsyncExpr = async function simple() { + return 11; +} +assertEventuallyEq(namedAsyncExpr(), 11); + +async function executionOrder() { + var value = 0; + async function first() { + return (value = value === 0 ? 1 : value); + } + async function second() { + return (value = value === 0 ? 2 : value); + } + async function third() { + return (value = value === 0 ? 3 : value); + } + return await first() + await second() + await third() + 6; +} +assertEventuallyEq(executionOrder(), 9); + +async function miscellaneous() { + if (arguments.length === 3 && + arguments.callee.name === "miscellaneous") + return 14; +} +assertEventuallyEq(miscellaneous(1, 2, 3), 14); + +function thrower() { + throw 15; +} + +async function defaultArgs(arg = thrower()) { +} +assertEventuallyEq(defaultArgs().catch(e => e), 15); + +let arrowAwaitExpr = async () => await 2; +assertEventuallyEq(arrowAwaitExpr(), 2); + +let arrowAwaitBlock = async () => { return await 2; }; +assertEventuallyEq(arrowAwaitBlock(), 2); + +// Async functions are not constructible +assertThrows(() => { + async function Person() { + + } + new Person(); +}, TypeError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/shell.js b/js/src/tests/ecma_7/AsyncFunctions/shell.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/shell.js diff --git a/js/src/tests/ecma_7/AsyncFunctions/syntax-arrow.js b/js/src/tests/ecma_7/AsyncFunctions/syntax-arrow.js new file mode 100644 index 000000000..6dc8d8621 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/syntax-arrow.js @@ -0,0 +1,104 @@ +var BUGNUMBER = 1185106; +var summary = "async arrow function syntax"; + +print(BUGNUMBER + ": " + summary); + +if (typeof Reflect !== "undefined" && Reflect.parse) { + // Parameters. + Reflect.parse("async () => 1"); + Reflect.parse("async a => 1"); + Reflect.parse("async (a) => 1"); + Reflect.parse("async async => 1"); + Reflect.parse("async (async) => 1"); + Reflect.parse("async ([a]) => 1"); + Reflect.parse("async ([a, b]) => 1"); + Reflect.parse("async ({a}) => 1"); + Reflect.parse("async ({a, b}) => 1"); + + assertThrows(() => Reflect.parse("async await => 1"), SyntaxError); + assertThrows(() => Reflect.parse("async (await) => 1"), SyntaxError); + assertThrows(() => Reflect.parse("async ([await]) => 1"), SyntaxError); + assertThrows(() => Reflect.parse("async ({await}) => 1"), SyntaxError); + + assertThrows(() => Reflect.parse("async (a=await) => 1"), SyntaxError); + assertThrows(() => Reflect.parse("async ([a=await]) => 1"), SyntaxError); + assertThrows(() => Reflect.parse("async ({a=await}) => 1"), SyntaxError); + + assertThrows(() => Reflect.parse("async (a=await 1) => 1"), SyntaxError); + assertThrows(() => Reflect.parse("async ([a=await 1]) => 1"), SyntaxError); + assertThrows(() => Reflect.parse("async ({a=await 1}) => 1"), SyntaxError); + + assertThrows(() => Reflect.parse("async [a] => 1"), SyntaxError); + assertThrows(() => Reflect.parse("async [a, b] => 1"), SyntaxError); + assertThrows(() => Reflect.parse("async {a} => 1"), SyntaxError); + assertThrows(() => Reflect.parse("async {a: b} => 1"), SyntaxError); + + // Expression body. + Reflect.parse("async a => a == b"); + + // Expression body with nested async function. + Reflect.parse("async a => async"); + Reflect.parse("async a => async b => c"); + Reflect.parse("async a => async function() {}"); + Reflect.parse("async a => async function b() {}"); + + assertThrows(() => Reflect.parse("async a => async b"), SyntaxError); + assertThrows(() => Reflect.parse("async a => async function"), SyntaxError); + assertThrows(() => Reflect.parse("async a => async function()"), SyntaxError); + + // Expression body with `await`. + Reflect.parse("async a => await 1"); + Reflect.parse("async a => await await 1"); + Reflect.parse("async a => await await await 1"); + + assertThrows(() => Reflect.parse("async a => await"), SyntaxError); + assertThrows(() => Reflect.parse("async a => await await"), SyntaxError); + + // `await` is Unary Expression and it cannot have `async` function as an + // operand. + assertThrows(() => Reflect.parse("async a => await async X => Y"), SyntaxError); + Reflect.parse("async a => await (async X => Y)"); + // But it can have `async` identifier as an operand. + Reflect.parse("async async => await async"); + + // Block body. + Reflect.parse("async X => {yield}"); + + // `yield` handling. + Reflect.parse("async X => yield"); + Reflect.parse("async yield => X"); + Reflect.parse("async yield => yield"); + Reflect.parse("async X => {yield}"); + + Reflect.parse("async X => {yield}"); + Reflect.parse("async yield => {X}"); + Reflect.parse("async yield => {yield}"); + Reflect.parse("function* g() { async X => yield }"); + + assertThrows(() => Reflect.parse("'use strict'; async yield => X"), SyntaxError); + assertThrows(() => Reflect.parse("'use strict'; async (yield) => X"), SyntaxError); + assertThrows(() => Reflect.parse("'use strict'; async X => yield"), SyntaxError); + assertThrows(() => Reflect.parse("'use strict'; async X => {yield}"), SyntaxError); + + assertThrows(() => Reflect.parse("function* g() { async yield => X }")); + assertThrows(() => Reflect.parse("function* g() { async (yield) => X }")); + assertThrows(() => Reflect.parse("function* g() { async ([yield]) => X }")); + assertThrows(() => Reflect.parse("function* g() { async ({yield}) => X }")); + + // Not async functions. + Reflect.parse("async ()"); + Reflect.parse("async (a)"); + Reflect.parse("async (async)"); + Reflect.parse("async ([a])"); + Reflect.parse("async ([a, b])"); + Reflect.parse("async ({a})"); + Reflect.parse("async ({a, b})"); + + // Async arrow function is assignment expression. + Reflect.parse("a ? async () => {1} : b"); + Reflect.parse("a ? b : async () => {1}"); + assertThrows(() => Reflect.parse("async () => {1} ? a : b"), SyntaxError); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js b/js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js new file mode 100644 index 000000000..c83056f54 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js @@ -0,0 +1,25 @@ +var BUGNUMBER = 1185106; +var summary = "async/await syntax in module"; + +print(BUGNUMBER + ": " + summary); + +if (typeof parseModule === "function") { + parseModule("async function f() { await 3; }"); + parseModule("async function f() { await 3; }"); + assertThrows(() => parseModule("var await = 5;"), SyntaxError); + assertThrows(() => parseModule("await;"), SyntaxError); + assertThrows(() => parseModule("await 5;"), SyntaxError); + assertThrows(() => parseModule("function f() { await 5; }"), SyntaxError); + assertThrows(() => parseModule("() => { await 5; }"), SyntaxError); + assertThrows(() => parseModule("export var await;"), SyntaxError); + assertThrows(() => parseModule("await => 1;"), SyntaxError); + assertThrows(() => parseModule("async function f() { function g() { await 3; } }"), SyntaxError); + + if (typeof Reflect !== "undefined" && Reflect.parse) { + assertThrows(() => Reflect.parse("export default async function() { yield; }", { target: "module" }), SyntaxError); + assertThrows(() => Reflect.parse("export default async function() { yield = 1; }", { target: "module" }), SyntaxError); + } +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/syntax.js b/js/src/tests/ecma_7/AsyncFunctions/syntax.js new file mode 100644 index 000000000..28e5febc1 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/syntax.js @@ -0,0 +1,86 @@ +var BUGNUMBER = 1185106; +var summary = "async/await syntax"; + +print(BUGNUMBER + ": " + summary); + +if (typeof Reflect !== "undefined" && Reflect.parse) { + assertEq(Reflect.parse("function a() {}").body[0].async, false); + assertEq(Reflect.parse("function* a() {}").body[0].async, false); + assertEq(Reflect.parse("async function a() {}").body[0].async, true); + assertEq(Reflect.parse("() => {}").body[0].async, undefined); + + // Async generators are not allowed (with regards to spec) + assertThrows(() => Reflect.parse("async function* a() {}"), SyntaxError); + + // No line terminator after async + assertEq(Reflect.parse("async\nfunction a(){}").body[0].expression.name, "async"); + + // Async function expressions + assertEq(Reflect.parse("(async function() {})()").body[0].expression.callee.async, true); + assertEq(Reflect.parse("var k = async function() {}").body[0].declarations[0].init.async, true); + assertEq(Reflect.parse("var nmd = async function named() {}").body[0].declarations[0].init.id.name, "named"); + + // `await` handling for function declaration name inherits. + assertEq(Reflect.parse("async function await() {}").body[0].id.name, "await"); + assertThrows(() => Reflect.parse("async function f() { async function await() {} }"), SyntaxError); + + // `await` is not allowed in function expression name. + assertThrows(() => Reflect.parse("(async function await() {})"), SyntaxError); + + // Awaiting not directly inside an async function is not allowed + assertThrows(() => Reflect.parse("await 4;"), SyntaxError); + assertThrows(() => Reflect.parse("function a() { await 4; }"), SyntaxError); + assertThrows(() => Reflect.parse("function* a() { await 4; }"), SyntaxError); + assertThrows(() => Reflect.parse("async function k() { function a() { await 4; } }"), SyntaxError); + + // Await is not allowed as a default expr. + assertThrows(() => Reflect.parse("async function a(k = await 3) {}"), SyntaxError); + assertThrows(() => Reflect.parse("async function a() { async function b(k = await 3) {} }"), SyntaxError); + assertThrows(() => Reflect.parse("async function a() { async function b(k = [await 3]) {} }"), SyntaxError); + + assertThrows(() => Reflect.parse("async function a() { async function b([k = await 3]) {} }"), SyntaxError); + assertThrows(() => Reflect.parse("async function a() { async function b([k = [await 3]]) {} }"), SyntaxError); + assertThrows(() => Reflect.parse("async function a() { async function b({k = await 3}) {} }"), SyntaxError); + assertThrows(() => Reflect.parse("async function a() { async function b({k = [await 3]}) {} }"), SyntaxError); + + // Await is not legal as an identifier in an async function. + assertThrows(() => Reflect.parse("async function a() { var await = 4; }"), SyntaxError); + assertThrows(() => Reflect.parse("async function a() { return await; }"), SyntaxError); + + // Await is still available as an identifier name in strict mode code. + Reflect.parse("function a() { 'use strict'; var await = 3; }"); + Reflect.parse("'use strict'; var await = 3;"); + + // Await is treated differently depending on context. Various cases. + Reflect.parse("var await = 3; async function a() { await 4; }"); + Reflect.parse("async function a() { await 4; } var await = 5"); + Reflect.parse("async function a() { function b() { return await; } }"); + + Reflect.parse("async function a() { var k = { async: 4 } }"); + + Reflect.parse("function a() { await: 4 }"); + + assertEq(Reflect.parse("async function a() { await 4; }") + .body[0].body.body[0].expression.operator, "await"); + + assertEq(Reflect.parse("async function a() { async function b() { await 4; } }") + .body[0].body.body[0].body.body[0].expression.operator, "await"); + + // operator priority test + assertEq(Reflect.parse("async function a() { await 2 + 3; }") + .body[0].body.body[0].expression.left.argument.value, 2); + assertEq(Reflect.parse("async function a() { await 2 + 3; }") + .body[0].body.body[0].expression.left.operator, "await"); + assertEq(Reflect.parse("async function a() { await 2 + 3; }") + .body[0].body.body[0].expression.right.value, 3); + + // blocks and other constructions + assertEq(Reflect.parse("{ async function a() { return 2; } }") + .body[0].body[0].async, true); + + // Async function expression is primary expression. + Reflect.parse("(async function a() {}.constructor)"); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/toString.js b/js/src/tests/ecma_7/AsyncFunctions/toString.js new file mode 100644 index 000000000..39ae938c3 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/toString.js @@ -0,0 +1,24 @@ +var BUGNUMBER = 1185106; +var summary = "async function toString"; + +print(BUGNUMBER + ": " + summary); + +async function f1(a, b, c) { await a; } + +assertEq(f1.toString(), + "async function f1(a, b, c) { await a; }"); + +assertEq(async function (a, b, c) { await a; }.toString(), + "async function (a, b, c) { await a; }"); + +assertEq((async (a, b, c) => await a).toString(), + "async (a, b, c) => await a"); + +assertEq((async (a, b, c) => { await a; }).toString(), + "async (a, b, c) => { await a; }"); + +assertEq({ async foo(a, b, c) { await a; } }.foo.toString(), + "async function foo(a, b, c) { await a; }"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/yield.js b/js/src/tests/ecma_7/AsyncFunctions/yield.js new file mode 100644 index 000000000..348d11f3d --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/yield.js @@ -0,0 +1,71 @@ +var BUGNUMBER = 1185106; +var summary = "yield handling in async function"; + +print(BUGNUMBER + ": " + summary); + +function testPassArgsBody(argsbody) { + Reflect.parse(`async function a${argsbody}`); + Reflect.parse(`(async function a${argsbody})`); + Reflect.parse(`(async function ${argsbody})`); + Reflect.parse(`({ async m${argsbody} })`); +} + +function testErrorArgsBody(argsbody, prefix="") { + assertThrows(() => Reflect.parse(`${prefix} async function a${argsbody}`), SyntaxError); + assertThrows(() => Reflect.parse(`${prefix} (async function a${argsbody})`), SyntaxError); + assertThrows(() => Reflect.parse(`${prefix} (async function ${argsbody})`), SyntaxError); + assertThrows(() => Reflect.parse(`${prefix} ({ async m${argsbody} })`), SyntaxError); +} + +function testErrorArgsBodyStrict(argsbody) { + testErrorArgsBody(argsbody); + testErrorArgsBody(argsbody, "'use strict'; "); + assertThrows(() => Reflect.parse(`class X { async m${argsbody} }`), SyntaxError); + assertThrows(() => Reflect.parse(`class X { static async m${argsbody} }`), SyntaxError); + assertThrows(() => Reflect.parse(`export default async function ${argsbody}`, { target: "module" }), SyntaxError); +} + +if (typeof Reflect !== "undefined" && Reflect.parse) { + // `yield` handling is inherited in async function declaration name. + Reflect.parse("async function yield() {}"); + Reflect.parse("function f() { async function yield() {} }"); + assertThrows(() => Reflect.parse("function* g() { async function yield() {} }"), SyntaxError); + assertThrows(() => Reflect.parse("'use strict'; async function yield() {}"), SyntaxError); + + // `yield` is treated as an identifier in an async function expression name. + // `yield` is not allowed as an identifier in strict code. + Reflect.parse("(async function yield() {});"); + Reflect.parse("function f() { (async function yield() {}); }"); + Reflect.parse("function* g() { (async function yield() {}); }"); + assertThrows(() => Reflect.parse("'use strict'; (async function yield() {});"), SyntaxError); + + // `yield` handling is inherited in async method name. + Reflect.parse("({ async yield() {} });"); + Reflect.parse("function f() { ({ async yield() {} }); }"); + Reflect.parse("function* g() { ({ async yield() {} }); }"); + Reflect.parse("'use strict'; ({ async yield() {} });"); + Reflect.parse("class X { async yield() {} }"); + + Reflect.parse("({ async [yield]() {} });"); + Reflect.parse("function f() { ({ async [yield]() {} }); }"); + Reflect.parse("function* g() { ({ async [yield]() {} }); }"); + assertThrows(() => Reflect.parse("'use strict'; ({ async [yield]() {} });"), SyntaxError); + assertThrows(() => Reflect.parse("class X { async [yield]() {} }"), SyntaxError); + + // `yield` is treated as an identifier in an async function parameter + // `yield` is not allowed as an identifier in strict code. + testPassArgsBody("(yield) {}"); + testPassArgsBody("(yield = 1) {}"); + testPassArgsBody("(a = yield) {}"); + testErrorArgsBodyStrict("(yield 3) {}"); + testErrorArgsBodyStrict("(a = yield 3) {}"); + + // `yield` is treated as an identifier in an async function body + // `yield` is not allowed as an identifier in strict code. + testPassArgsBody("() { yield; }"); + testPassArgsBody("() { yield = 1; }"); + testErrorArgsBodyStrict("() { yield 3; }"); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); |