Skip to content

Commit 4855d04

Browse files
authored
diagnose unsupported async generators and for-await-of (#1717)
* diagnose unsupported async generators and for-await-of * prettier
1 parent 9158ace commit 4855d04

4 files changed

Lines changed: 45 additions & 2 deletions

File tree

src/transformation/utils/diagnostics.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ export const awaitMustBeInAsyncFunction = createErrorDiagnosticFactory(
145145
"Await can only be used inside async functions."
146146
);
147147

148+
export const unsupportedAsyncGenerator = createErrorDiagnosticFactory("Async generator functions are not supported.");
149+
150+
export const unsupportedForAwaitOf = createErrorDiagnosticFactory("'for await...of' loops are not supported.");
151+
148152
export const unsupportedBuiltinOptionalCall = createErrorDiagnosticFactory(
149153
"Optional calls are not supported for builtin or language extension functions."
150154
);

src/transformation/visitors/function.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib";
1616
import { transformInPrecedingStatementScope } from "../utils/preceding-statements";
1717
import { peekScope, performHoisting, Scope, ScopeType } from "../utils/scope";
1818
import { isFunctionType } from "../utils/typescript";
19+
import { unsupportedAsyncGenerator } from "../utils/diagnostics";
1920
import { isAsyncFunction, wrapInAsyncAwaiter } from "./async-await";
2021
import { transformIdentifier } from "./identifier";
2122
import { transformExpressionBodyToReturnStatement } from "./return";
@@ -224,6 +225,10 @@ export function transformFunctionToExpression(
224225
): [lua.Expression, Scope] {
225226
assert(node.body);
226227

228+
if (node.asteriskToken && isAsyncFunction(node)) {
229+
context.diagnostics.push(unsupportedAsyncGenerator(node));
230+
}
231+
227232
const type = context.checker.getTypeAtLocation(node);
228233
let functionContext: lua.Identifier | undefined;
229234

src/transformation/visitors/loops/for-of.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
import { isRangeFunction, transformRangeStatement } from "../language-extensions/range";
1212
import { transformForInitializer, transformLoopBody } from "./utils";
1313
import { getIterableExtensionKindForNode, IterableExtensionKind } from "../../utils/language-extensions";
14+
import { unsupportedForAwaitOf } from "../../utils/diagnostics";
1415
import { assertNever } from "../../../utils";
1516

1617
function transformForOfArrayStatement(
@@ -43,6 +44,10 @@ function transformForOfIteratorStatement(
4344
}
4445

4546
export const transformForOfStatement: FunctionVisitor<ts.ForOfStatement> = (node, context) => {
47+
if (node.awaitModifier) {
48+
context.diagnostics.push(unsupportedForAwaitOf(node.awaitModifier));
49+
}
50+
4651
const body = lua.createBlock(transformLoopBody(context, node));
4752

4853
if (ts.isCallExpression(node.expression) && isRangeFunction(context, node.expression)) {

test/unit/builtins/async-await.spec.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { ModuleKind, ScriptTarget } from "typescript";
22
import { LuaTarget } from "../../../src";
3-
import { unsupportedForTargetButOverrideAvailable } from "../../../src/transformation/utils/diagnostics";
4-
import { awaitMustBeInAsyncFunction } from "../../../src/transformation/utils/diagnostics";
3+
import {
4+
awaitMustBeInAsyncFunction,
5+
unsupportedAsyncGenerator,
6+
unsupportedForAwaitOf,
7+
unsupportedForTargetButOverrideAvailable,
8+
} from "../../../src/transformation/utils/diagnostics";
59
import * as util from "../../util";
610

711
const promiseTestLib = `
@@ -1123,3 +1127,28 @@ describe("try/catch in async function", () => {
11231127
.expectToEqual(["finally", "ok"]);
11241128
});
11251129
});
1130+
1131+
describe("async generators are unsupported", () => {
1132+
test.each([
1133+
"async function* gen() { yield 1; }",
1134+
"const gen = async function*() { yield 1; };",
1135+
"const gen = { async *m() { yield 1; } };",
1136+
"class C { async *m() { yield 1; } }",
1137+
])("diagnoses %p", source => {
1138+
util.testModule`
1139+
${source}
1140+
export {}
1141+
`.expectToHaveDiagnostics([unsupportedAsyncGenerator.code]);
1142+
});
1143+
});
1144+
1145+
test("for-await-of is unsupported", () => {
1146+
util.testModule`
1147+
async function run(items: AsyncIterable<number>) {
1148+
for await (const x of items) {
1149+
void x;
1150+
}
1151+
}
1152+
export {}
1153+
`.expectToHaveDiagnostics([unsupportedForAwaitOf.code]);
1154+
});

0 commit comments

Comments
 (0)