@@ -7653,7 +7653,7 @@ namespace ts {
7653
7653
// Promise/A+ compatible implementation will always assimilate any foreign promise, so the
7654
7654
// return type of the body should be unwrapped to its awaited type, which we will wrap in
7655
7655
// 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);
7657
7657
}
7658
7658
}
7659
7659
else {
@@ -7762,7 +7762,7 @@ namespace ts {
7762
7762
// Promise/A+ compatible implementation will always assimilate any foreign promise, so the
7763
7763
// return type of the body should be unwrapped to its awaited type, which should be wrapped in
7764
7764
// 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);
7766
7766
}
7767
7767
7768
7768
if (!contains(aggregatedTypes, type)) {
@@ -7914,7 +7914,7 @@ namespace ts {
7914
7914
let exprType = checkExpression(<Expression>node.body);
7915
7915
if (returnType) {
7916
7916
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);
7918
7918
checkTypeAssignableTo(awaitedType, promisedType, node.body);
7919
7919
}
7920
7920
else {
@@ -8041,7 +8041,7 @@ namespace ts {
8041
8041
}
8042
8042
8043
8043
let operandType = checkExpression(node.expression);
8044
- return getAwaitedType (operandType, node);
8044
+ return checkAwaitedType (operandType, node);
8045
8045
}
8046
8046
8047
8047
function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type {
@@ -9474,10 +9474,10 @@ namespace ts {
9474
9474
error(location, message);
9475
9475
}
9476
9476
9477
- return false ;
9477
+ return unknownType ;
9478
9478
}
9479
9479
9480
- return true ;
9480
+ return type ;
9481
9481
}
9482
9482
9483
9483
/**
@@ -9537,7 +9537,7 @@ namespace ts {
9537
9537
return getTypeAtPosition(signature, 0);
9538
9538
}
9539
9539
9540
- let alreadySeenTypesForAwait: boolean [] = [];
9540
+ let awaitedTypeStack: number [] = [];
9541
9541
9542
9542
/**
9543
9543
* Gets the "awaited type" of a type.
@@ -9546,76 +9546,96 @@ namespace ts {
9546
9546
* Promise-like type; otherwise, it is the type of the expression. This is used to reflect
9547
9547
* The runtime behavior of the `await` keyword.
9548
9548
*/
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));
9572
9561
}
9573
9562
9574
- break ;
9563
+ return getUnionType(types) ;
9575
9564
}
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;
9607
9636
}
9608
-
9609
- type = unknownType;
9610
- break;
9611
9637
}
9612
-
9613
- type = promisedType;
9614
9638
}
9615
-
9616
- // Cleanup, reset the set of visited types
9617
- alreadySeenTypesForAwait.length = 0;
9618
- return type;
9619
9639
}
9620
9640
9621
9641
/**
@@ -9691,7 +9711,7 @@ namespace ts {
9691
9711
}
9692
9712
9693
9713
// 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);
9695
9715
}
9696
9716
9697
9717
/** Check a decorator */
@@ -10664,7 +10684,7 @@ namespace ts {
10664
10684
else if (func.type || isGetAccessorWithAnnotatatedSetAccessor(func) || signature.typePredicate) {
10665
10685
if (isAsyncFunctionLike(func)) {
10666
10686
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);
10668
10688
checkTypeAssignableTo(awaitedType, promisedType, node.expression);
10669
10689
}
10670
10690
else {
0 commit comments