Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 32 additions & 22 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15987,7 +15987,7 @@ namespace ts {
// From within an async function you can return either a non-promise value or a promise. Any
// Promise/A+ compatible implementation will always assimilate any foreign promise, so the
// return type of the body is awaited type of the body, wrapped in a native Promise<T> type.
return (functionFlags & FunctionFlags.AsyncOrAsyncGenerator) === FunctionFlags.Async
return (functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async
? createPromiseReturnType(func, widenedType) // Async function
: widenedType; // Generator function, AsyncGenerator function, or normal function
}
Expand Down Expand Up @@ -16203,7 +16203,7 @@ namespace ts {

const functionFlags = getFunctionFlags(node);
const returnOrPromisedType = node.type &&
((functionFlags & FunctionFlags.AsyncOrAsyncGenerator) === FunctionFlags.Async ?
((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async ?
checkAsyncFunctionReturnType(node) : // Async function
getTypeFromTypeNode(node.type)); // AsyncGenerator function, Generator function, or normal function

Expand Down Expand Up @@ -16233,7 +16233,7 @@ namespace ts {
// its return type annotation.
const exprType = checkExpression(<Expression>node.body);
if (returnOrPromisedType) {
if ((functionFlags & FunctionFlags.AsyncOrAsyncGenerator) === FunctionFlags.Async) { // Async function
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) { // Async function
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);
checkTypeAssignableTo(awaitedType, returnOrPromisedType, node.body);
}
Expand Down Expand Up @@ -16973,12 +16973,16 @@ namespace ts {
// we are in a yield context.
const functionFlags = func && getFunctionFlags(func);
if (node.asteriskToken) {
if (functionFlags & FunctionFlags.Async) {
if (languageVersion < ScriptTarget.ES2017) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncDelegator);
}
// Async generator functions prior to ESNext require the __await, __asyncDelegator,
// and __asyncValues helpers
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator &&
languageVersion < ScriptTarget.ESNext) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncDelegatorIncludes);
}
else if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {

// Generator functions prior to ES2015 require the __values helper
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Generator &&
languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.Values);
}
}
Expand Down Expand Up @@ -17497,18 +17501,20 @@ namespace ts {
}

const functionFlags = getFunctionFlags(<FunctionLikeDeclaration>node);
if ((functionFlags & FunctionFlags.InvalidAsyncOrAsyncGenerator) === FunctionFlags.Async && languageVersion < ScriptTarget.ES2017) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.Awaiter);
if (languageVersion < ScriptTarget.ES2015) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.Generator);
if (!(functionFlags & FunctionFlags.Invalid)) {
// Async generators prior to ESNext require the __await and __asyncGenerator helpers
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator && languageVersion < ScriptTarget.ESNext) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncGeneratorIncludes);
}
}

if ((functionFlags & FunctionFlags.InvalidGenerator) === FunctionFlags.Generator) {
if (functionFlags & FunctionFlags.Async && languageVersion < ScriptTarget.ES2017) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncGenerator);
// Async functions prior to ES2017 require the __awaiter helper
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async && languageVersion < ScriptTarget.ES2017) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.Awaiter);
}
else if (languageVersion < ScriptTarget.ES2015) {

// Generator functions, Async functions, and Async Generator functions prior to
// ES2015 require the __generator helper
if ((functionFlags & FunctionFlags.AsyncGenerator) !== FunctionFlags.Normal && languageVersion < ScriptTarget.ES2015) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.Generator);
}
}
Expand Down Expand Up @@ -17536,7 +17542,7 @@ namespace ts {

if (node.type) {
const functionFlags = getFunctionFlags(<FunctionDeclaration>node);
if ((functionFlags & FunctionFlags.InvalidGenerator) === FunctionFlags.Generator) {
if ((functionFlags & (FunctionFlags.Invalid | FunctionFlags.Generator)) === FunctionFlags.Generator) {
const returnType = getTypeFromTypeNode(node.type);
if (returnType === voidType) {
error(node.type, Diagnostics.A_generator_cannot_have_a_void_type_annotation);
Expand All @@ -17556,7 +17562,7 @@ namespace ts {
checkTypeAssignableTo(iterableIteratorInstantiation, returnType, node.type);
}
}
else if ((functionFlags & FunctionFlags.AsyncOrAsyncGenerator) === FunctionFlags.Async) {
else if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) {
checkAsyncFunctionReturnType(<FunctionLikeDeclaration>node);
}
}
Expand Down Expand Up @@ -19523,11 +19529,14 @@ namespace ts {

if (node.kind === SyntaxKind.ForOfStatement) {
if ((<ForOfStatement>node).awaitModifier) {
if (languageVersion < ScriptTarget.ES2017) {
const functionFlags = getFunctionFlags(getContainingFunction(node));
if ((functionFlags & (FunctionFlags.Invalid | FunctionFlags.Async)) === FunctionFlags.Async && languageVersion < ScriptTarget.ESNext) {
// for..await..of in an async function or async generator function prior to ESNext requires the __asyncValues helper
checkExternalEmitHelpers(node, ExternalEmitHelpers.ForAwaitOfIncludes);
}
}
else if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
else if (compilerOptions.downlevelIteration && languageVersion < ScriptTarget.ES2015) {
// for..of prior to ES2015 requires the __values helper when downlevelIteration is enabled
checkExternalEmitHelpers(node, ExternalEmitHelpers.ForOfIncludes);
}
}
Expand Down Expand Up @@ -19957,7 +19966,7 @@ namespace ts {
}

function isUnwrappedReturnTypeVoidOrAny(func: FunctionLikeDeclaration, returnType: Type): boolean {
const unwrappedReturnType = (getFunctionFlags(func) & FunctionFlags.AsyncOrAsyncGenerator) === FunctionFlags.Async
const unwrappedReturnType = (getFunctionFlags(func) & FunctionFlags.AsyncGenerator) === FunctionFlags.Async
? getPromisedTypeOfPromise(returnType) // Async function
: returnType; // AsyncGenerator function, Generator function, or normal function
return unwrappedReturnType && maybeTypeOfKind(unwrappedReturnType, TypeFlags.Void | TypeFlags.Any);
Expand Down Expand Up @@ -22964,6 +22973,7 @@ namespace ts {
case ExternalEmitHelpers.Values: return "__values";
case ExternalEmitHelpers.Read: return "__read";
case ExternalEmitHelpers.Spread: return "__spread";
case ExternalEmitHelpers.Await: return "__await";
case ExternalEmitHelpers.AsyncGenerator: return "__asyncGenerator";
case ExternalEmitHelpers.AsyncDelegator: return "__asyncDelegator";
case ExternalEmitHelpers.AsyncValues: return "__asyncValues";
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/transformers/esnext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,7 @@ namespace ts {

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

const asyncGeneratorHelper: EmitHelper = {
Expand Down
15 changes: 11 additions & 4 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3973,18 +3973,25 @@ namespace ts {
Awaiter = 1 << 6, // __awaiter (used by ES2017 async functions transformation)
Generator = 1 << 7, // __generator (used by ES2015 generator transformation)
Values = 1 << 8, // __values (used by ES2015 for..of and yield* transformations)
Read = 1 << 9, // __read (used by ES2015 iterator destructuring transformation)
Read = 1 << 9, // __read (used by ES2015 iterator destructuring transformation)
Spread = 1 << 10, // __spread (used by ES2015 array spread and argument list spread transformations)
AsyncGenerator = 1 << 11, // __asyncGenerator (used by ES2017 async generator transformation)
AsyncDelegator = 1 << 12, // __asyncDelegator (used by ES2017 async generator yield* transformation)
AsyncValues = 1 << 13, // __asyncValues (used by ES2017 for..await..of transformation)
Await = 1 << 11, // __await (used by ES2017 async generator transformation)
AsyncGenerator = 1 << 12, // __asyncGenerator (used by ES2017 async generator transformation)
AsyncDelegator = 1 << 13, // __asyncDelegator (used by ES2017 async generator yield* transformation)
AsyncValues = 1 << 14, // __asyncValues (used by ES2017 for..await..of transformation)

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

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

// Helpers included by ES2017 async generators
AsyncGeneratorIncludes = Await | AsyncGenerator,

// Helpers included by yield* in ES2017 async generators
AsyncDelegatorIncludes = Await | AsyncDelegator | AsyncValues,

// Helpers included by ES2015 spread
SpreadIncludes = Read | Spread,

Expand Down
18 changes: 10 additions & 8 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1925,16 +1925,18 @@ namespace ts {
}

export const enum FunctionFlags {
Normal = 0,
Generator = 1 << 0,
Async = 1 << 1,
AsyncOrAsyncGenerator = Async | Generator,
Invalid = 1 << 2,
InvalidAsyncOrAsyncGenerator = AsyncOrAsyncGenerator | Invalid,
InvalidGenerator = Generator | Invalid,
Normal = 0, // Function is a normal function
Generator = 1 << 0, // Function is a generator function or async generator function
Async = 1 << 1, // Function is an async function or an async generator function
Invalid = 1 << 2, // Function is a signature or overload and does not have a body.
AsyncGenerator = Async | Generator, // Function is an async generator function
}

export function getFunctionFlags(node: FunctionLikeDeclaration) {
export function getFunctionFlags(node: FunctionLikeDeclaration | undefined) {
if (!node) {
return FunctionFlags.Invalid;
}

let flags = FunctionFlags.Normal;
switch (node.kind) {
case SyntaxKind.FunctionDeclaration:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,13 @@ var C4 = (function () {
}
C4.prototype.f = function () {
return __asyncGenerator(this, arguments, function f_1() {
var x, _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = __await;
return [5 /*yield**/, __values(__asyncDelegator(__asyncValues([1])))];
case 1: return [4 /*yield*/, _a.apply(void 0, [_b.sent()])];
var x;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [5 /*yield**/, __values(__asyncDelegator(__asyncValues([1])))];
case 1: return [4 /*yield*/, __await.apply(void 0, [_a.sent()])];
case 2:
x = _b.sent();
x = _a.sent();
return [2 /*return*/];
}
});
Expand Down Expand Up @@ -374,22 +372,20 @@ var C5 = (function () {
}
C5.prototype.f = function () {
return __asyncGenerator(this, arguments, function f_1() {
var x, _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = __await;
return [5 /*yield**/, __values(__asyncDelegator(__asyncValues((function () { return __asyncGenerator(this, arguments, function () { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, 1];
case 1:
_a.sent();
return [2 /*return*/];
}
}); }); })())))];
case 1: return [4 /*yield*/, _a.apply(void 0, [_b.sent()])];
var x;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [5 /*yield**/, __values(__asyncDelegator(__asyncValues((function () { return __asyncGenerator(this, arguments, function () { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, 1];
case 1:
_a.sent();
return [2 /*return*/];
}
}); }); })())))];
case 1: return [4 /*yield*/, __await.apply(void 0, [_a.sent()])];
case 2:
x = _b.sent();
x = _a.sent();
return [2 /*return*/];
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,15 +244,13 @@ var __values = (this && this.__values) || function (o) {
};
function f4() {
return __asyncGenerator(this, arguments, function f4_1() {
var x, _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = __await;
return [5 /*yield**/, __values(__asyncDelegator(__asyncValues([1])))];
case 1: return [4 /*yield*/, _a.apply(void 0, [_b.sent()])];
var x;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [5 /*yield**/, __values(__asyncDelegator(__asyncValues([1])))];
case 1: return [4 /*yield*/, __await.apply(void 0, [_a.sent()])];
case 2:
x = _b.sent();
x = _a.sent();
return [2 /*return*/];
}
});
Expand Down Expand Up @@ -320,22 +318,20 @@ var __values = (this && this.__values) || function (o) {
};
function f5() {
return __asyncGenerator(this, arguments, function f5_1() {
var x, _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = __await;
return [5 /*yield**/, __values(__asyncDelegator(__asyncValues((function () { return __asyncGenerator(this, arguments, function () { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, 1];
case 1:
_a.sent();
return [2 /*return*/];
}
}); }); })())))];
case 1: return [4 /*yield*/, _a.apply(void 0, [_b.sent()])];
var x;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [5 /*yield**/, __values(__asyncDelegator(__asyncValues((function () { return __asyncGenerator(this, arguments, function () { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, 1];
case 1:
_a.sent();
return [2 /*return*/];
}
}); }); })())))];
case 1: return [4 /*yield*/, __await.apply(void 0, [_a.sent()])];
case 2:
x = _b.sent();
x = _a.sent();
return [2 /*return*/];
}
});
Expand Down
Loading