1 // Copyright 2016 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Flags: --harmony-async-await --allow-natives-syntax 6 7 // Do not install `AsyncFunction` constructor on global object 8 9 function assertThrowsAsync(run, errorType, message) { 10 var actual; 11 var hadValue = false; 12 var hadError = false; 13 var promise = run(); 14 15 if (typeof promise !== "object" || typeof promise.then !== "function") { 16 throw new MjsUnitAssertionError( 17 "Expected " + run.toString() + 18 " to return a Promise, but it returned " + PrettyPrint(promise)); 19 } 20 21 promise.then(function(value) { hadValue = true; actual = value; }, 22 function(error) { hadError = true; actual = error; }); 23 24 assertFalse(hadValue || hadError); 25 26 %RunMicrotasks(); 27 28 if (!hadError) { 29 throw new MjsUnitAssertionError( 30 "Expected " + run + "() to throw " + errorType.name + 31 ", but did not throw."); 32 } 33 if (!(actual instanceof errorType)) 34 throw new MjsUnitAssertionError( 35 "Expected " + run + "() to throw " + errorType.name + 36 ", but threw '" + actual + "'"); 37 if (message !== void 0 && actual.message !== message) 38 throw new MjsUnitAssertionError( 39 "Expected " + run + "() to throw '" + message + "', but threw '" + 40 actual.message + "'"); 41 }; 42 43 function assertEqualsAsync(expected, run, msg) { 44 var actual; 45 var hadValue = false; 46 var hadError = false; 47 var promise = run(); 48 49 if (typeof promise !== "object" || typeof promise.then !== "function") { 50 throw new MjsUnitAssertionError( 51 "Expected " + run.toString() + 52 " to return a Promise, but it returned " + PrettyPrint(promise)); 53 } 54 55 promise.then(function(value) { hadValue = true; actual = value; }, 56 function(error) { hadError = true; actual = error; }); 57 58 assertFalse(hadValue || hadError); 59 60 %RunMicrotasks(); 61 62 if (hadError) throw actual; 63 64 assertTrue( 65 hadValue, "Expected '" + run.toString() + "' to produce a value"); 66 67 assertEquals(expected, actual, msg); 68 }; 69 70 assertEquals(undefined, this.AsyncFunction); 71 let AsyncFunction = (async function() {}).constructor; 72 73 // Let functionPrototype be the intrinsic object %AsyncFunctionPrototype%. 74 async function asyncFunctionForProto() {} 75 assertEquals(AsyncFunction.prototype, 76 Object.getPrototypeOf(asyncFunctionForProto)); 77 assertEquals(AsyncFunction.prototype, 78 Object.getPrototypeOf(async function() {})); 79 assertEquals(AsyncFunction.prototype, Object.getPrototypeOf(async () => {})); 80 assertEquals(AsyncFunction.prototype, 81 Object.getPrototypeOf({ async method() {} }.method)); 82 assertEquals(AsyncFunction.prototype, Object.getPrototypeOf(AsyncFunction())); 83 assertEquals(AsyncFunction.prototype, 84 Object.getPrototypeOf(new AsyncFunction())); 85 86 // AsyncFunctionCreate does not produce an object with a Prototype 87 assertEquals(undefined, asyncFunctionForProto.prototype); 88 assertEquals(false, asyncFunctionForProto.hasOwnProperty("prototype")); 89 assertEquals(undefined, (async function() {}).prototype); 90 assertEquals(false, (async function() {}).hasOwnProperty("prototype")); 91 assertEquals(undefined, (async() => {}).prototype); 92 assertEquals(false, (async() => {}).hasOwnProperty("prototype")); 93 assertEquals(undefined, ({ async method() {} }).method.prototype); 94 assertEquals(false, ({ async method() {} }).method.hasOwnProperty("prototype")); 95 assertEquals(undefined, AsyncFunction().prototype); 96 assertEquals(false, AsyncFunction().hasOwnProperty("prototype")); 97 assertEquals(undefined, (new AsyncFunction()).prototype); 98 assertEquals(false, (new AsyncFunction()).hasOwnProperty("prototype")); 99 100 assertEquals(1, async function(a) { await 1; }.length); 101 assertEquals(2, async function(a, b) { await 1; }.length); 102 assertEquals(1, async function(a, b = 2) { await 1; }.length); 103 assertEquals(2, async function(a, b, ...c) { await 1; }.length); 104 105 assertEquals(1, (async(a) => await 1).length); 106 assertEquals(2, (async(a, b) => await 1).length); 107 assertEquals(1, (async(a, b = 2) => await 1).length); 108 assertEquals(2, (async(a, b, ...c) => await 1).length); 109 110 assertEquals(1, ({ async f(a) { await 1; } }).f.length); 111 assertEquals(2, ({ async f(a, b) { await 1; } }).f.length); 112 assertEquals(1, ({ async f(a, b = 2) { await 1; } }).f.length); 113 assertEquals(2, ({ async f(a, b, ...c) { await 1; } }).f.length); 114 115 assertEquals(1, AsyncFunction("a", "await 1").length); 116 assertEquals(2, AsyncFunction("a", "b", "await 1").length); 117 assertEquals(1, AsyncFunction("a", "b = 2", "await 1").length); 118 assertEquals(2, AsyncFunction("a", "b", "...c", "await 1").length); 119 120 assertEquals(1, (new AsyncFunction("a", "await 1")).length); 121 assertEquals(2, (new AsyncFunction("a", "b", "await 1")).length); 122 assertEquals(1, (new AsyncFunction("a", "b = 2", "await 1")).length); 123 assertEquals(2, (new AsyncFunction("a", "b", "...c", "await 1")).length); 124 125 // AsyncFunction.prototype[ @@toStringTag ] 126 var descriptor = 127 Object.getOwnPropertyDescriptor(AsyncFunction.prototype, 128 Symbol.toStringTag); 129 assertEquals("AsyncFunction", descriptor.value); 130 assertEquals(false, descriptor.enumerable); 131 assertEquals(false, descriptor.writable); 132 assertEquals(true, descriptor.configurable); 133 134 assertEquals(1, AsyncFunction.length); 135 136 // Let F be ! FunctionAllocate(functionPrototype, Strict, "non-constructor") 137 async function asyncNonConstructorDecl() {} 138 assertThrows( 139 () => new asyncNonConstructorDecl(), TypeError); 140 assertThrows( 141 () => new (async function() {}), TypeError); 142 assertThrows( 143 () => new ({ async nonConstructor() {} }).nonConstructor(), TypeError); 144 assertThrows( 145 () => new (() => "not a constructor!"), TypeError); 146 assertThrows( 147 () => new (AsyncFunction()), TypeError); 148 assertThrows( 149 () => new (new AsyncFunction()), TypeError); 150 151 // Normal completion 152 async function asyncDecl() { return "test"; } 153 assertEqualsAsync("test", asyncDecl); 154 assertEqualsAsync("test2", async function() { return "test2"; }); 155 assertEqualsAsync("test3", async () => "test3"); 156 assertEqualsAsync("test4", () => ({ async f() { return "test4"; } }).f()); 157 assertEqualsAsync("test5", () => AsyncFunction("no", "return 'test' + no;")(5)); 158 assertEqualsAsync("test6", 159 () => (new AsyncFunction("no", "return 'test' + no;"))(6)); 160 161 class MyError extends Error {}; 162 163 // Throw completion 164 async function asyncDeclThrower(e) { throw new MyError(e); } 165 assertThrowsAsync(() => asyncDeclThrower("boom!"), MyError, "boom!"); 166 assertThrowsAsync( 167 () => (async function(e) { throw new MyError(e); })("boom!!!"), 168 MyError, "boom!!!"); 169 assertThrowsAsync( 170 () => (async e => { throw new MyError(e) })("boom!!"), MyError, "boom!!"); 171 assertThrowsAsync( 172 () => ({ async thrower(e) { throw new MyError(e); } }).thrower("boom!1!"), 173 MyError, "boom!1!"); 174 assertThrowsAsync( 175 () => AsyncFunction("msg", "throw new MyError(msg)")("boom!2!!"), 176 MyError, "boom!2!!"); 177 assertThrowsAsync( 178 () => (new AsyncFunction("msg", "throw new MyError(msg)"))("boom!2!!!"), 179 MyError, "boom!2!!!"); 180 181 function resolveLater(value) { return Promise.resolve(value); } 182 function rejectLater(error) { return Promise.reject(error); } 183 184 // Resume after Normal completion 185 var log = []; 186 async function resumeAfterNormal(value) { 187 log.push("start:" + value); 188 value = await resolveLater(value + 1); 189 log.push("resume:" + value); 190 value = await resolveLater(value + 1); 191 log.push("resume:" + value); 192 return value + 1; 193 } 194 195 assertEqualsAsync(4, () => resumeAfterNormal(1)); 196 assertEquals("start:1 resume:2 resume:3", log.join(" ")); 197 198 var O = { 199 async resumeAfterNormal(value) { 200 log.push("start:" + value); 201 value = await resolveLater(value + 1); 202 log.push("resume:" + value); 203 value = await resolveLater(value + 1); 204 log.push("resume:" + value); 205 return value + 1; 206 } 207 }; 208 log = []; 209 assertEqualsAsync(5, () => O.resumeAfterNormal(2)); 210 assertEquals("start:2 resume:3 resume:4", log.join(" ")); 211 212 var resumeAfterNormalArrow = async (value) => { 213 log.push("start:" + value); 214 value = await resolveLater(value + 1); 215 log.push("resume:" + value); 216 value = await resolveLater(value + 1); 217 log.push("resume:" + value); 218 return value + 1; 219 }; 220 log = []; 221 assertEqualsAsync(6, () => resumeAfterNormalArrow(3)); 222 assertEquals("start:3 resume:4 resume:5", log.join(" ")); 223 224 var resumeAfterNormalEval = AsyncFunction("value", ` 225 log.push("start:" + value); 226 value = await resolveLater(value + 1); 227 log.push("resume:" + value); 228 value = await resolveLater(value + 1); 229 log.push("resume:" + value); 230 return value + 1;`); 231 log = []; 232 assertEqualsAsync(7, () => resumeAfterNormalEval(4)); 233 assertEquals("start:4 resume:5 resume:6", log.join(" ")); 234 235 var resumeAfterNormalNewEval = new AsyncFunction("value", ` 236 log.push("start:" + value); 237 value = await resolveLater(value + 1); 238 log.push("resume:" + value); 239 value = await resolveLater(value + 1); 240 log.push("resume:" + value); 241 return value + 1;`); 242 log = []; 243 assertEqualsAsync(8, () => resumeAfterNormalNewEval(5)); 244 assertEquals("start:5 resume:6 resume:7", log.join(" ")); 245 246 // Resume after Throw completion 247 async function resumeAfterThrow(value) { 248 log.push("start:" + value); 249 try { 250 value = await rejectLater("throw1"); 251 } catch (e) { 252 log.push("resume:" + e); 253 } 254 try { 255 value = await rejectLater("throw2"); 256 } catch (e) { 257 log.push("resume:" + e); 258 } 259 return value + 1; 260 } 261 262 log = []; 263 assertEqualsAsync(2, () => resumeAfterThrow(1)); 264 assertEquals("start:1 resume:throw1 resume:throw2", log.join(" ")); 265 266 var O = { 267 async resumeAfterThrow(value) { 268 log.push("start:" + value); 269 try { 270 value = await rejectLater("throw1"); 271 } catch (e) { 272 log.push("resume:" + e); 273 } 274 try { 275 value = await rejectLater("throw2"); 276 } catch (e) { 277 log.push("resume:" + e); 278 } 279 return value + 1; 280 } 281 } 282 log = []; 283 assertEqualsAsync(3, () => O.resumeAfterThrow(2)); 284 assertEquals("start:2 resume:throw1 resume:throw2", log.join(" ")); 285 286 var resumeAfterThrowArrow = async (value) => { 287 log.push("start:" + value); 288 try { 289 value = await rejectLater("throw1"); 290 } catch (e) { 291 log.push("resume:" + e); 292 } 293 try { 294 value = await rejectLater("throw2"); 295 } catch (e) { 296 log.push("resume:" + e); 297 } 298 return value + 1; 299 }; 300 301 log = []; 302 303 assertEqualsAsync(4, () => resumeAfterThrowArrow(3)); 304 assertEquals("start:3 resume:throw1 resume:throw2", log.join(" ")); 305 306 var resumeAfterThrowEval = AsyncFunction("value", ` 307 log.push("start:" + value); 308 try { 309 value = await rejectLater("throw1"); 310 } catch (e) { 311 log.push("resume:" + e); 312 } 313 try { 314 value = await rejectLater("throw2"); 315 } catch (e) { 316 log.push("resume:" + e); 317 } 318 return value + 1;`); 319 log = []; 320 assertEqualsAsync(5, () => resumeAfterThrowEval(4)); 321 assertEquals("start:4 resume:throw1 resume:throw2", log.join(" ")); 322 323 var resumeAfterThrowNewEval = new AsyncFunction("value", ` 324 log.push("start:" + value); 325 try { 326 value = await rejectLater("throw1"); 327 } catch (e) { 328 log.push("resume:" + e); 329 } 330 try { 331 value = await rejectLater("throw2"); 332 } catch (e) { 333 log.push("resume:" + e); 334 } 335 return value + 1;`); 336 log = []; 337 assertEqualsAsync(6, () => resumeAfterThrowNewEval(5)); 338 assertEquals("start:5 resume:throw1 resume:throw2", log.join(" ")); 339 340 async function foo() {} 341 assertEquals("async function foo() {}", foo.toString()); 342 assertEquals("async function () {}", async function() {}.toString()); 343 assertEquals("async x => x", (async x => x).toString()); 344 assertEquals("async x => { return x }", (async x => { return x }).toString()); 345 class AsyncMethod { async foo() { } } 346 assertEquals("async foo() { }", 347 Function.prototype.toString.call(AsyncMethod.prototype.foo)); 348 assertEquals("async foo() { }", 349 Function.prototype.toString.call({async foo() { }}.foo)); 350 351 // Async functions are not constructible 352 assertThrows(() => class extends (async function() {}) {}, TypeError); 353 354 // Regress v8:5148 355 assertEqualsAsync("1", () => (async({ a = NaN }) => a)({ a: "1" })); 356 assertEqualsAsync( 357 "10", () => (async(foo, { a = NaN }) => foo + a)("1", { a: "0" })); 358 assertEqualsAsync("2", () => (async({ a = "2" }) => a)({ a: undefined })); 359 assertEqualsAsync( 360 "20", () => (async(foo, { a = "0" }) => foo + a)("2", { a: undefined })); 361 assertThrows(() => eval("async({ foo = 1 })"), SyntaxError); 362 assertThrows(() => eval("async(a, { foo = 1 })"), SyntaxError); 363 364 // https://bugs.chromium.org/p/chromium/issues/detail?id=638019 365 async function gaga() { 366 let i = 1; 367 while (i-- > 0) { await 42 } 368 } 369 assertDoesNotThrow(gaga); 370