@@ -7653,7 +7653,7 @@ namespace ts {
76537653 // Promise/A+ compatible implementation will always assimilate any foreign promise, so the
76547654 // return type of the body should be unwrapped to its awaited type, which we will wrap in
76557655 // the native Promise<T> type later in this function.
7656- type = getAwaitedType (type, func, Diagnostics.Return_expression_in_async_function_does_not_have_a_valid_callable_then_member);
7656+ type = checkAwaitedType (type, func, Diagnostics.Return_expression_in_async_function_does_not_have_a_valid_callable_then_member);
76577657 }
76587658 }
76597659 else {
@@ -7762,7 +7762,7 @@ namespace ts {
77627762 // Promise/A+ compatible implementation will always assimilate any foreign promise, so the
77637763 // return type of the body should be unwrapped to its awaited type, which should be wrapped in
77647764 // the native Promise<T> type by the caller.
7765- type = getAwaitedType (type, body.parent, Diagnostics.Return_expression_in_async_function_does_not_have_a_valid_callable_then_member);
7765+ type = checkAwaitedType (type, body.parent, Diagnostics.Return_expression_in_async_function_does_not_have_a_valid_callable_then_member);
77667766 }
77677767
77687768 if (!contains(aggregatedTypes, type)) {
@@ -7914,7 +7914,7 @@ namespace ts {
79147914 let exprType = checkExpression(<Expression>node.body);
79157915 if (returnType) {
79167916 if (isAsync) {
7917- let awaitedType = getAwaitedType (exprType, node.body, Diagnostics.Expression_body_for_async_arrow_function_does_not_have_a_valid_callable_then_member);
7917+ let awaitedType = checkAwaitedType (exprType, node.body, Diagnostics.Expression_body_for_async_arrow_function_does_not_have_a_valid_callable_then_member);
79187918 checkTypeAssignableTo(awaitedType, promisedType, node.body);
79197919 }
79207920 else {
@@ -8041,7 +8041,7 @@ namespace ts {
80418041 }
80428042
80438043 let operandType = checkExpression(node.expression);
8044- return getAwaitedType (operandType, node);
8044+ return checkAwaitedType (operandType, node);
80458045 }
80468046
80478047 function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type {
@@ -9474,10 +9474,10 @@ namespace ts {
94749474 error(location, message);
94759475 }
94769476
9477- return false ;
9477+ return unknownType ;
94789478 }
94799479
9480- return true ;
9480+ return type ;
94819481 }
94829482
94839483 /**
@@ -9537,7 +9537,7 @@ namespace ts {
95379537 return getTypeAtPosition(signature, 0);
95389538 }
95399539
9540- let alreadySeenTypesForAwait: boolean [] = [];
9540+ let awaitedTypeStack: number [] = [];
95419541
95429542 /**
95439543 * Gets the "awaited type" of a type.
@@ -9546,76 +9546,96 @@ namespace ts {
95469546 * Promise-like type; otherwise, it is the type of the expression. This is used to reflect
95479547 * The runtime behavior of the `await` keyword.
95489548 */
9549- function getAwaitedType(type: Type, location?: Node, message?: DiagnosticMessage): Type {
9550- // reset the set of visited types
9551- alreadySeenTypesForAwait.length = 0;
9552- while (true) {
9553- let promisedType = getPromisedType(type);
9554- if (promisedType === undefined) {
9555- // The type was not a PromiseLike, so it could not be unwrapped any further.
9556- // As long as the type does not have a callable "then" property, then it is
9557- // safe to return the type; otherwise, an error will have been reported in
9558- // the call to checkNonThenableType and we will return unknownType.
9559- //
9560- // An example of a non-promise "thenable" might be:
9561- //
9562- // await { then(): void {} }
9563- //
9564- // The "thenable" does not match the minimal definition for a PromiseLike. When
9565- // a Promise/A+-compatible or ES6 promise tries to adopt this value, the promise
9566- // will never settle. We treat this as an error to help flag an early indicator
9567- // of a runtime problem. If the user wants to return this value from an async
9568- // function, they would need to wrap it in some other value. If they want it to
9569- // be treated as a promise, they can cast to <any>.
9570- if (!checkNonThenableType(type, location, message)) {
9571- type = unknownType;
9549+ function getAwaitedType(type: Type) {
9550+ return checkAwaitedType(type, /*location*/ undefined, /*message*/ undefined);
9551+ }
9552+
9553+ function checkAwaitedType(type: Type, location?: Node, message?: DiagnosticMessage) {
9554+ return getAwaitedTypeWorker(type);
9555+
9556+ function getAwaitedTypeWorker(type: Type): Type {
9557+ if (type.flags & TypeFlags.Union) {
9558+ let types: Type[] = [];
9559+ for (let constituentType of (<UnionType>type).types) {
9560+ types.push(getAwaitedTypeWorker(constituentType));
95729561 }
95739562
9574- break ;
9563+ return getUnionType(types) ;
95759564 }
9576-
9577- // Keep track of the type we're about to unwrap to avoid bad recursive promise types.
9578- // See the comments below for more information.
9579- alreadySeenTypesForAwait[type.id] = true;
9580-
9581- if (alreadySeenTypesForAwait[promisedType.id]) {
9582- // We have a bad actor in the form of a promise whose promised type is the same
9583- // promise type, or a mutually recursive promise. Return the unknown type as we cannot guess
9584- // the shape. If this were the actual case in the JavaScript, this Promise would never resolve.
9585- //
9586- // An example of a bad actor with a singly-recursive promise type might be:
9587- //
9588- // interface BadPromise {
9589- // then(onfulfilled: (value: BadPromise) => any, onrejected: (error: any) => any): BadPromise;
9590- // }
9591- //
9592- // The above interface will pass the PromiseLike check, and return a promised type of `BadPromise`.
9593- // Since this is a self reference, we don't want to keep recursing ad infinitum.
9594- //
9595- // An example of a bad actor in the form of a mutually-recursive promise type might be:
9596- //
9597- // interface BadPromiseA {
9598- // then(onfulfilled: (value: BadPromiseB) => any, onrejected: (error: any) => any): BadPromiseB;
9599- // }
9600- //
9601- // interface BadPromiseB {
9602- // then(onfulfilled: (value: BadPromiseA) => any, onrejected: (error: any) => any): BadPromiseA;
9603- // }
9604- //
9605- if (location) {
9606- error(location, Diagnostics._0_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method, symbolToString(type.symbol));
9565+ else {
9566+ let promisedType = getPromisedType(type);
9567+ if (promisedType === undefined) {
9568+ // The type was not a PromiseLike, so it could not be unwrapped any further.
9569+ // As long as the type does not have a callable "then" property, it is
9570+ // safe to return the type; otherwise, an error will have been reported in
9571+ // the call to checkNonThenableType and we will return unknownType.
9572+ //
9573+ // An example of a non-promise "thenable" might be:
9574+ //
9575+ // await { then(): void {} }
9576+ //
9577+ // The "thenable" does not match the minimal definition for a PromiseLike. When
9578+ // a Promise/A+-compatible or ES6 promise tries to adopt this value, the promise
9579+ // will never settle. We treat this as an error to help flag an early indicator
9580+ // of a runtime problem. If the user wants to return this value from an async
9581+ // function, they would need to wrap it in some other value. If they want it to
9582+ // be treated as a promise, they can cast to <any>.
9583+ return checkNonThenableType(type, location, message);
9584+ }
9585+ else {
9586+ if (type.id === promisedType.id || awaitedTypeStack.indexOf(promisedType.id) >= 0) {
9587+ // We have a bad actor in the form of a promise whose promised type is
9588+ // the same promise type, or a mutually recursive promise. Return the
9589+ // unknown type as we cannot guess the shape. If this were the actual
9590+ // case in the JavaScript, this Promise would never resolve.
9591+ //
9592+ // An example of a bad actor with a singly-recursive promise type might
9593+ // be:
9594+ //
9595+ // interface BadPromise {
9596+ // then(
9597+ // onfulfilled: (value: BadPromise) => any,
9598+ // onrejected: (error: any) => any): BadPromise;
9599+ // }
9600+ //
9601+ // The above interface will pass the PromiseLike check, and return a
9602+ // promised type of `BadPromise`. Since this is a self reference, we
9603+ // don't want to keep recursing ad infinitum.
9604+ //
9605+ // An example of a bad actor in the form of a mutually-recursive
9606+ // promise type might be:
9607+ //
9608+ // interface BadPromiseA {
9609+ // then(
9610+ // onfulfilled: (value: BadPromiseB) => any,
9611+ // onrejected: (error: any) => any): BadPromiseB;
9612+ // }
9613+ //
9614+ // interface BadPromiseB {
9615+ // then(
9616+ // onfulfilled: (value: BadPromiseA) => any,
9617+ // onrejected: (error: any) => any): BadPromiseA;
9618+ // }
9619+ //
9620+ if (location) {
9621+ error(
9622+ location,
9623+ Diagnostics._0_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method,
9624+ symbolToString(type.symbol));
9625+ }
9626+
9627+ return unknownType;
9628+ }
9629+
9630+ // Keep track of the type we're about to unwrap to avoid bad recursive promise types.
9631+ // See the comments above for more information.
9632+ awaitedTypeStack.push(type.id);
9633+ let awaitedType = getAwaitedTypeWorker(promisedType);
9634+ awaitedTypeStack.pop();
9635+ return awaitedType;
96079636 }
9608-
9609- type = unknownType;
9610- break;
96119637 }
9612-
9613- type = promisedType;
96149638 }
9615-
9616- // Cleanup, reset the set of visited types
9617- alreadySeenTypesForAwait.length = 0;
9618- return type;
96199639 }
96209640
96219641 /**
@@ -9691,7 +9711,7 @@ namespace ts {
96919711 }
96929712
96939713 // Get and return the awaited type of the return type.
9694- return getAwaitedType (promiseType, node, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
9714+ return checkAwaitedType (promiseType, node, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
96959715 }
96969716
96979717 /** Check a decorator */
@@ -10664,7 +10684,7 @@ namespace ts {
1066410684 else if (func.type || isGetAccessorWithAnnotatatedSetAccessor(func) || signature.typePredicate) {
1066510685 if (isAsyncFunctionLike(func)) {
1066610686 let promisedType = getPromisedType(returnType);
10667- let awaitedType = getAwaitedType (exprType, node.expression, Diagnostics.Return_expression_in_async_function_does_not_have_a_valid_callable_then_member);
10687+ let awaitedType = checkAwaitedType (exprType, node.expression, Diagnostics.Return_expression_in_async_function_does_not_have_a_valid_callable_then_member);
1066810688 checkTypeAssignableTo(awaitedType, promisedType, node.expression);
1066910689 }
1067010690 else {
0 commit comments