Skip to content

Commit e3d54c3

Browse files
committed
Add check for tslib __await helper
1 parent a9ad853 commit e3d54c3

File tree

7 files changed

+134
-35
lines changed

7 files changed

+134
-35
lines changed

src/compiler/checker.ts

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15962,7 +15962,7 @@ namespace ts {
1596215962
// From within an async function you can return either a non-promise value or a promise. Any
1596315963
// Promise/A+ compatible implementation will always assimilate any foreign promise, so the
1596415964
// return type of the body is awaited type of the body, wrapped in a native Promise<T> type.
15965-
return (functionFlags & FunctionFlags.AsyncOrAsyncGenerator) === FunctionFlags.Async
15965+
return (functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async
1596615966
? createPromiseReturnType(func, widenedType) // Async function
1596715967
: widenedType; // Generator function, AsyncGenerator function, or normal function
1596815968
}
@@ -16178,7 +16178,7 @@ namespace ts {
1617816178

1617916179
const functionFlags = getFunctionFlags(node);
1618016180
const returnOrPromisedType = node.type &&
16181-
((functionFlags & FunctionFlags.AsyncOrAsyncGenerator) === FunctionFlags.Async ?
16181+
((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async ?
1618216182
checkAsyncFunctionReturnType(node) : // Async function
1618316183
getTypeFromTypeNode(node.type)); // AsyncGenerator function, Generator function, or normal function
1618416184

@@ -16208,7 +16208,7 @@ namespace ts {
1620816208
// its return type annotation.
1620916209
const exprType = checkExpression(<Expression>node.body);
1621016210
if (returnOrPromisedType) {
16211-
if ((functionFlags & FunctionFlags.AsyncOrAsyncGenerator) === FunctionFlags.Async) { // Async function
16211+
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) { // Async function
1621216212
const awaitedType = checkAwaitedType(exprType, node.body, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
1621316213
checkTypeAssignableTo(awaitedType, returnOrPromisedType, node.body);
1621416214
}
@@ -16948,12 +16948,16 @@ namespace ts {
1694816948
// we are in a yield context.
1694916949
const functionFlags = func && getFunctionFlags(func);
1695016950
if (node.asteriskToken) {
16951-
if (functionFlags & FunctionFlags.Async) {
16952-
if (languageVersion < ScriptTarget.ES2017) {
16953-
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncDelegator);
16954-
}
16951+
// Async generator functions prior to ESNext require the __await, __asyncDelegator,
16952+
// and __asyncValues helpers
16953+
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator &&
16954+
languageVersion < ScriptTarget.ESNext) {
16955+
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncDelegatorIncludes);
1695516956
}
16956-
else if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
16957+
16958+
// Generator functions prior to ES2015 require the __values helper
16959+
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Generator &&
16960+
languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
1695716961
checkExternalEmitHelpers(node, ExternalEmitHelpers.Values);
1695816962
}
1695916963
}
@@ -17472,18 +17476,20 @@ namespace ts {
1747217476
}
1747317477

1747417478
const functionFlags = getFunctionFlags(<FunctionLikeDeclaration>node);
17475-
if ((functionFlags & FunctionFlags.InvalidAsyncOrAsyncGenerator) === FunctionFlags.Async && languageVersion < ScriptTarget.ES2017) {
17476-
checkExternalEmitHelpers(node, ExternalEmitHelpers.Awaiter);
17477-
if (languageVersion < ScriptTarget.ES2015) {
17478-
checkExternalEmitHelpers(node, ExternalEmitHelpers.Generator);
17479+
if (!(functionFlags & FunctionFlags.Invalid)) {
17480+
// Async generators prior to ESNext require the __await and __asyncGenerator helpers
17481+
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator && languageVersion < ScriptTarget.ESNext) {
17482+
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncGeneratorIncludes);
1747917483
}
17480-
}
1748117484

17482-
if ((functionFlags & FunctionFlags.InvalidGenerator) === FunctionFlags.Generator) {
17483-
if (functionFlags & FunctionFlags.Async && languageVersion < ScriptTarget.ES2017) {
17484-
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncGenerator);
17485+
// Async functions prior to ES2017 require the __awaiter helper
17486+
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async && languageVersion < ScriptTarget.ES2017) {
17487+
checkExternalEmitHelpers(node, ExternalEmitHelpers.Awaiter);
1748517488
}
17486-
else if (languageVersion < ScriptTarget.ES2015) {
17489+
17490+
// Generator functions, Async functions, and Async Generator functions prior to
17491+
// ES2015 require the __generator helper
17492+
if ((functionFlags & FunctionFlags.AsyncGenerator) !== FunctionFlags.Normal && languageVersion < ScriptTarget.ES2015) {
1748717493
checkExternalEmitHelpers(node, ExternalEmitHelpers.Generator);
1748817494
}
1748917495
}
@@ -17511,7 +17517,7 @@ namespace ts {
1751117517

1751217518
if (node.type) {
1751317519
const functionFlags = getFunctionFlags(<FunctionDeclaration>node);
17514-
if ((functionFlags & FunctionFlags.InvalidGenerator) === FunctionFlags.Generator) {
17520+
if ((functionFlags & (FunctionFlags.Invalid | FunctionFlags.Generator)) === FunctionFlags.Generator) {
1751517521
const returnType = getTypeFromTypeNode(node.type);
1751617522
if (returnType === voidType) {
1751717523
error(node.type, Diagnostics.A_generator_cannot_have_a_void_type_annotation);
@@ -17531,7 +17537,7 @@ namespace ts {
1753117537
checkTypeAssignableTo(iterableIteratorInstantiation, returnType, node.type);
1753217538
}
1753317539
}
17534-
else if ((functionFlags & FunctionFlags.AsyncOrAsyncGenerator) === FunctionFlags.Async) {
17540+
else if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) {
1753517541
checkAsyncFunctionReturnType(<FunctionLikeDeclaration>node);
1753617542
}
1753717543
}
@@ -19498,11 +19504,14 @@ namespace ts {
1949819504

1949919505
if (node.kind === SyntaxKind.ForOfStatement) {
1950019506
if ((<ForOfStatement>node).awaitModifier) {
19501-
if (languageVersion < ScriptTarget.ES2017) {
19507+
const functionFlags = getFunctionFlags(getContainingFunction(node));
19508+
if ((functionFlags & (FunctionFlags.Invalid | FunctionFlags.Async)) === FunctionFlags.Async && languageVersion < ScriptTarget.ESNext) {
19509+
// for..await..of in an async function or async generator function prior to ESNext requires the __asyncValues helper
1950219510
checkExternalEmitHelpers(node, ExternalEmitHelpers.ForAwaitOfIncludes);
1950319511
}
1950419512
}
19505-
else if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
19513+
else if (compilerOptions.downlevelIteration && languageVersion < ScriptTarget.ES2015) {
19514+
// for..of prior to ES2015 requires the __values helper when downlevelIteration is enabled
1950619515
checkExternalEmitHelpers(node, ExternalEmitHelpers.ForOfIncludes);
1950719516
}
1950819517
}
@@ -19932,7 +19941,7 @@ namespace ts {
1993219941
}
1993319942

1993419943
function isUnwrappedReturnTypeVoidOrAny(func: FunctionLikeDeclaration, returnType: Type): boolean {
19935-
const unwrappedReturnType = (getFunctionFlags(func) & FunctionFlags.AsyncOrAsyncGenerator) === FunctionFlags.Async
19944+
const unwrappedReturnType = (getFunctionFlags(func) & FunctionFlags.AsyncGenerator) === FunctionFlags.Async
1993619945
? getPromisedTypeOfPromise(returnType) // Async function
1993719946
: returnType; // AsyncGenerator function, Generator function, or normal function
1993819947
return unwrappedReturnType && maybeTypeOfKind(unwrappedReturnType, TypeFlags.Void | TypeFlags.Any);
@@ -22942,6 +22951,7 @@ namespace ts {
2294222951
case ExternalEmitHelpers.Values: return "__values";
2294322952
case ExternalEmitHelpers.Read: return "__read";
2294422953
case ExternalEmitHelpers.Spread: return "__spread";
22954+
case ExternalEmitHelpers.Await: return "__await";
2294522955
case ExternalEmitHelpers.AsyncGenerator: return "__asyncGenerator";
2294622956
case ExternalEmitHelpers.AsyncDelegator: return "__asyncDelegator";
2294722957
case ExternalEmitHelpers.AsyncValues: return "__asyncValues";

src/compiler/transformers/esnext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,7 @@ namespace ts {
884884

885885
function createAwaitHelper(context: TransformationContext, expression: Expression) {
886886
context.requestEmitHelper(awaitHelper);
887-
return createCall(createIdentifier("__await"), /*typeArguments*/ undefined, [expression]);
887+
return createCall(getHelperName("__await"), /*typeArguments*/ undefined, [expression]);
888888
}
889889

890890
const asyncGeneratorHelper: EmitHelper = {

src/compiler/types.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3973,18 +3973,25 @@ namespace ts {
39733973
Awaiter = 1 << 6, // __awaiter (used by ES2017 async functions transformation)
39743974
Generator = 1 << 7, // __generator (used by ES2015 generator transformation)
39753975
Values = 1 << 8, // __values (used by ES2015 for..of and yield* transformations)
3976-
Read = 1 << 9, // __read (used by ES2015 iterator destructuring transformation)
3976+
Read = 1 << 9, // __read (used by ES2015 iterator destructuring transformation)
39773977
Spread = 1 << 10, // __spread (used by ES2015 array spread and argument list spread transformations)
3978-
AsyncGenerator = 1 << 11, // __asyncGenerator (used by ES2017 async generator transformation)
3979-
AsyncDelegator = 1 << 12, // __asyncDelegator (used by ES2017 async generator yield* transformation)
3980-
AsyncValues = 1 << 13, // __asyncValues (used by ES2017 for..await..of transformation)
3978+
Await = 1 << 11, // __await (used by ES2017 async generator transformation)
3979+
AsyncGenerator = 1 << 12, // __asyncGenerator (used by ES2017 async generator transformation)
3980+
AsyncDelegator = 1 << 13, // __asyncDelegator (used by ES2017 async generator yield* transformation)
3981+
AsyncValues = 1 << 14, // __asyncValues (used by ES2017 for..await..of transformation)
39813982

39823983
// Helpers included by ES2015 for..of
39833984
ForOfIncludes = Values,
39843985

39853986
// Helpers included by ES2017 for..await..of
39863987
ForAwaitOfIncludes = AsyncValues,
39873988

3989+
// Helpers included by ES2017 async generators
3990+
AsyncGeneratorIncludes = Await | AsyncGenerator,
3991+
3992+
// Helpers included by yield* in ES2017 async generators
3993+
AsyncDelegatorIncludes = Await | AsyncDelegator | AsyncValues,
3994+
39883995
// Helpers included by ES2015 spread
39893996
SpreadIncludes = Read | Spread,
39903997

src/compiler/utilities.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,16 +1925,18 @@ namespace ts {
19251925
}
19261926

19271927
export const enum FunctionFlags {
1928-
Normal = 0,
1929-
Generator = 1 << 0,
1930-
Async = 1 << 1,
1931-
AsyncOrAsyncGenerator = Async | Generator,
1932-
Invalid = 1 << 2,
1933-
InvalidAsyncOrAsyncGenerator = AsyncOrAsyncGenerator | Invalid,
1934-
InvalidGenerator = Generator | Invalid,
1928+
Normal = 0, // Function is a normal function
1929+
Generator = 1 << 0, // Function is a generator function or async generator function
1930+
Async = 1 << 1, // Function is an async function or an async generator function
1931+
Invalid = 1 << 2, // Function is a signature or overload and does not have a body.
1932+
AsyncGenerator = Async | Generator, // Function is an async generator function
19351933
}
19361934

1937-
export function getFunctionFlags(node: FunctionLikeDeclaration) {
1935+
export function getFunctionFlags(node: FunctionLikeDeclaration | undefined) {
1936+
if (!node) {
1937+
return FunctionFlags.Invalid;
1938+
}
1939+
19381940
let flags = FunctionFlags.Normal;
19391941
switch (node.kind) {
19401942
case SyntaxKind.FunctionDeclaration:
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
tests/cases/compiler/main.ts(1,25): error TS2343: This syntax requires an imported helper named '__asyncGenerator', but module 'tslib' has no exported member '__asyncGenerator'.
2+
tests/cases/compiler/main.ts(1,25): error TS2343: This syntax requires an imported helper named '__await', but module 'tslib' has no exported member '__await'.
3+
tests/cases/compiler/main.ts(1,25): error TS2343: This syntax requires an imported helper named '__generator', but module 'tslib' has no exported member '__generator'.
4+
tests/cases/compiler/main.ts(4,5): error TS2343: This syntax requires an imported helper named '__asyncDelegator', but module 'tslib' has no exported member '__asyncDelegator'.
5+
tests/cases/compiler/main.ts(4,5): error TS2343: This syntax requires an imported helper named '__asyncValues', but module 'tslib' has no exported member '__asyncValues'.
6+
7+
8+
==== tests/cases/compiler/main.ts (5 errors) ====
9+
export async function * f() {
10+
~
11+
!!! error TS2343: This syntax requires an imported helper named '__asyncGenerator', but module 'tslib' has no exported member '__asyncGenerator'.
12+
~
13+
!!! error TS2343: This syntax requires an imported helper named '__await', but module 'tslib' has no exported member '__await'.
14+
~
15+
!!! error TS2343: This syntax requires an imported helper named '__generator', but module 'tslib' has no exported member '__generator'.
16+
await 1;
17+
yield 2;
18+
yield* [3];
19+
~~~~~~~~~~
20+
!!! error TS2343: This syntax requires an imported helper named '__asyncDelegator', but module 'tslib' has no exported member '__asyncDelegator'.
21+
~~~~~~~~~~
22+
!!! error TS2343: This syntax requires an imported helper named '__asyncValues', but module 'tslib' has no exported member '__asyncValues'.
23+
}
24+
25+
==== tests/cases/compiler/tslib.d.ts (0 errors) ====
26+
export {}
27+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//// [tests/cases/compiler/importHelpersNoHelpersForAsyncGenerators.ts] ////
2+
3+
//// [main.ts]
4+
export async function * f() {
5+
await 1;
6+
yield 2;
7+
yield* [3];
8+
}
9+
10+
//// [tslib.d.ts]
11+
export {}
12+
13+
14+
//// [main.js]
15+
"use strict";
16+
Object.defineProperty(exports, "__esModule", { value: true });
17+
var tslib_1 = require("tslib");
18+
function f() {
19+
return tslib_1.__asyncGenerator(this, arguments, function f_1() {
20+
return tslib_1.__generator(this, function (_a) {
21+
switch (_a.label) {
22+
case 0: return [4 /*yield*/, tslib_1.__await(1)];
23+
case 1:
24+
_a.sent();
25+
return [4 /*yield*/, 2];
26+
case 2:
27+
_a.sent();
28+
return [5 /*yield**/, tslib_1.__values(tslib_1.__asyncDelegator(tslib_1.__asyncValues([3])))];
29+
case 3: return [4 /*yield*/, tslib_1.__await.apply(void 0, [_a.sent()])];
30+
case 4:
31+
_a.sent();
32+
return [2 /*return*/];
33+
}
34+
});
35+
});
36+
}
37+
exports.f = f;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// @importHelpers: true
2+
// @target: es5
3+
// @module: commonjs
4+
// @lib: esnext
5+
// @moduleResolution: classic
6+
// @experimentalDecorators: true
7+
// @emitDecoratorMetadata: true
8+
// @filename: main.ts
9+
export async function * f() {
10+
await 1;
11+
yield 2;
12+
yield* [3];
13+
}
14+
15+
// @filename: tslib.d.ts
16+
export {}

0 commit comments

Comments
 (0)