diff --git a/src/printer.js b/src/printer.js index 46669003f..0ae22486d 100644 --- a/src/printer.js +++ b/src/printer.js @@ -1064,24 +1064,25 @@ function genericPrintNoParens(path, options, print) { ")", adjustClause(path.call(print, "body"), options) ]); + case "ForOfStatement": - return concat([ - "for (", - path.call(print, "left"), - " of ", - path.call(print, "right"), - ")", - adjustClause(path.call(print, "body"), options) - ]); case "ForAwaitStatement": + // Babylon 7 removed ForAwaitStatement in favor of ForOfStatement + // with `"await": true`: + // https://github.com/estree/estree/pull/138 + const isAwait = (n.type === "ForAwaitStatement" || n.await); + return concat([ - "for await (", + "for", + isAwait ? " await" : "", + " (", path.call(print, "left"), " of ", path.call(print, "right"), ")", adjustClause(path.call(print, "body"), options) ]); + case "DoWhileStatement": var clause = adjustClause(path.call(print, "body"), options); var doBody = concat(["do", clause]); diff --git a/tests/flow/async_iteration/__snapshots__/jsfmt.spec.js.snap b/tests/flow/async_iteration/__snapshots__/jsfmt.spec.js.snap index 5a62f4532..5849be1b9 100644 --- a/tests/flow/async_iteration/__snapshots__/jsfmt.spec.js.snap +++ b/tests/flow/async_iteration/__snapshots__/jsfmt.spec.js.snap @@ -57,6 +57,63 @@ async function* delegate_return() { " `; +exports[`delegate_yield.js 2`] = ` +"async function *delegate_next() { + async function *inner() { + var x: void = yield; // error: number ~> void + } + yield *inner(); +} +delegate_next().next(0); + +async function *delegate_yield() { + async function *inner() { + yield 0; + } + yield *inner(); +} +(async () => { + for await (const x of delegate_yield()) { + (x: void); // error: number ~> void + } +}); + +async function *delegate_return() { + async function *inner() { + return 0; + } + var x: void = yield *inner(); // error: number ~> void +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +async function* delegate_next() { + async function* inner() { + var x: void = yield; // error: number ~> void + } + yield* inner(); +} +delegate_next().next(0); + +async function* delegate_yield() { + async function* inner() { + yield 0; + } + yield* inner(); +} +async () => { + for await (const x of delegate_yield()) { + (x: void); // error: number ~> void + } +}; + +async function* delegate_return() { + async function* inner() { + return 0; + } + var x: void = yield* inner(); // error: number ~> void +} +" +`; + exports[`generator.js 1`] = ` "declare interface File { readLine(): Promise; @@ -112,6 +169,61 @@ async function f() { " `; +exports[`generator.js 2`] = ` +"declare interface File { + readLine(): Promise; + close(): void; + EOF: boolean; +} + +declare function fileOpen(path: string): Promise; + +async function* readLines(path) { + let file: File = await fileOpen(path); + + try { + while (!file.EOF) { + yield await file.readLine(); + } + } finally { + file.close(); + } +} + +async function f() { + for await (const line of readLines(\\"/path/to/file\\")) { + (line: void); // error: string ~> void + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +declare interface File { + readLine(): Promise, + close(): void, + EOF: boolean +} + +declare function fileOpen(path: string): Promise; + +async function* readLines(path) { + let file: File = await fileOpen(path); + + try { + while (!file.EOF) { + yield await file.readLine(); + } + } finally { + file.close(); + } +} + +async function f() { + for await (const line of readLines(\\"/path/to/file\\")) { + (line: void); // error: string ~> void + } +} +" +`; + exports[`return.js 1`] = ` "declare var gen: AsyncGenerator; @@ -161,6 +273,55 @@ refuse_return().return(\\"string\\").then(result => { " `; +exports[`return.js 2`] = ` +"declare var gen: AsyncGenerator; + +// You can pass whatever you like to return, it doesn't need to be related to +// the AsyncGenerator's return type +gen.return(0).then(result => { + (result.value: void); // error: string | number ~> void +}); + +// However, a generator can \\"refuse\\" the return by catching an exception and +// yielding or returning internally. +async function *refuse_return() { + try { + yield 1; + } finally { + return 0; + } +} +refuse_return().return(\\"string\\").then(result => { + if (result.done) { + (result.value: string); // error: number | void ~> string + } +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +declare var gen: AsyncGenerator; + +// You can pass whatever you like to return, it doesn't need to be related to +// the AsyncGenerator's return type +gen.return(0).then(result => { + (result.value: void); // error: string | number ~> void +}); + +// However, a generator can \\"refuse\\" the return by catching an exception and +// yielding or returning internally. +async function* refuse_return() { + try { + yield 1; + } finally { + return 0; + } +} +refuse_return().return(\\"string\\").then(result => { + if (result.done) { + (result.value: string); // error: number | void ~> string + } +}); +" +`; + exports[`throw.js 1`] = ` "async function *catch_return() { try { @@ -229,3 +390,72 @@ async () => { }; " `; + +exports[`throw.js 2`] = ` +"async function *catch_return() { + try { + yield 0; + } catch (e) { + return e; + } +} + +(async () => { + catch_return().throw(\\"\\").then(({value}) => { + if (value !== undefined) { + (value: void); // error: number ~> void + } + }); +}); + +async function *yield_return() { + try { + yield 0; + return; + } catch (e) { + yield e; + } +} + +(async () => { + yield_return().throw(\\"\\").then(({value}) => { + if (value !== undefined) { + (value: void); // error: number ~> void + } + }); +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +async function* catch_return() { + try { + yield 0; + } catch (e) { + return e; + } +} + +async () => { + catch_return().throw(\\"\\").then(({ value }) => { + if (value !== undefined) { + (value: void); // error: number ~> void + } + }); +}; + +async function* yield_return() { + try { + yield 0; + return; + } catch (e) { + yield e; + } +} + +async () => { + yield_return().throw(\\"\\").then(({ value }) => { + if (value !== undefined) { + (value: void); // error: number ~> void + } + }); +}; +" +`; diff --git a/tests/flow/async_iteration/jsfmt.spec.js b/tests/flow/async_iteration/jsfmt.spec.js index 989047bcc..cd6102665 100644 --- a/tests/flow/async_iteration/jsfmt.spec.js +++ b/tests/flow/async_iteration/jsfmt.spec.js @@ -1 +1,2 @@ run_spec(__dirname); +run_spec(__dirname, { parser: 'babylon' });