Skip to content

Commit 9cc53df

Browse files
committedJan 25, 2020
Defer generic awaited type
1 parent 663b792 commit 9cc53df

File tree

54 files changed

+502
-563
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+502
-563
lines changed
 

‎src/compiler/checker.ts

+15-87
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,7 @@ namespace ts {
819819
let deferredGlobalESSymbolConstructorSymbol: Symbol | undefined;
820820
let deferredGlobalESSymbolType: ObjectType;
821821
let deferredGlobalTypedPropertyDescriptorType: GenericType;
822+
let deferredGlobalAwaitedSymbol: Symbol | undefined;
822823
let deferredGlobalPromiseType: GenericType;
823824
let deferredGlobalPromiseLikeType: GenericType;
824825
let deferredGlobalPromiseConstructorSymbol: Symbol | undefined;
@@ -873,7 +874,6 @@ namespace ts {
873874
const potentialThisCollisions: Node[] = [];
874875
const potentialNewTargetCollisions: Node[] = [];
875876
const potentialWeakMapCollisions: Node[] = [];
876-
const awaitedTypeStack: number[] = [];
877877

878878
const diagnostics = createDiagnosticCollection();
879879
const suggestionDiagnostics = createDiagnosticCollection();
@@ -11288,6 +11288,10 @@ namespace ts {
1128811288
return deferredGlobalESSymbolType || (deferredGlobalESSymbolType = getGlobalType("Symbol" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType;
1128911289
}
1129011290

11291+
function getGlobalAwaitedSymbol(reportErrors: boolean) {
11292+
return deferredGlobalAwaitedSymbol || (deferredGlobalAwaitedSymbol = getGlobalTypeSymbol("Awaited" as __String, reportErrors));
11293+
}
11294+
1129111295
function getGlobalPromiseType(reportErrors: boolean) {
1129211296
return deferredGlobalPromiseType || (deferredGlobalPromiseType = getGlobalType("Promise" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType;
1129311297
}
@@ -29379,98 +29383,22 @@ namespace ts {
2937929383
return typeAsAwaitable.awaitedTypeOfType = type;
2938029384
}
2938129385

29382-
if (type.flags & TypeFlags.Union) {
29383-
let types: Type[] | undefined;
29384-
for (const constituentType of (<UnionType>type).types) {
29385-
types = append<Type>(types, getAwaitedType(constituentType, errorNode, diagnosticMessage, arg0));
29386-
}
29387-
29388-
if (!types) {
29389-
return undefined;
29390-
}
29391-
29392-
return typeAsAwaitable.awaitedTypeOfType = getUnionType(types);
29386+
const symbol = getGlobalAwaitedSymbol(/*reportErrors*/ false);
29387+
if (!symbol) {
29388+
return typeAsAwaitable.awaitedTypeOfType = type;
2939329389
}
2939429390

29395-
const promisedType = getPromisedTypeOfPromise(type);
29396-
if (promisedType) {
29397-
if (type.id === promisedType.id || awaitedTypeStack.indexOf(promisedType.id) >= 0) {
29398-
// Verify that we don't have a bad actor in the form of a promise whose
29399-
// promised type is the same as the promise type, or a mutually recursive
29400-
// promise. If so, we return undefined as we cannot guess the shape. If this
29401-
// were the actual case in the JavaScript, this Promise would never resolve.
29402-
//
29403-
// An example of a bad actor with a singly-recursive promise type might
29404-
// be:
29405-
//
29406-
// interface BadPromise {
29407-
// then(
29408-
// onfulfilled: (value: BadPromise) => any,
29409-
// onrejected: (error: any) => any): BadPromise;
29410-
// }
29411-
// The above interface will pass the PromiseLike check, and return a
29412-
// promised type of `BadPromise`. Since this is a self reference, we
29413-
// don't want to keep recursing ad infinitum.
29414-
//
29415-
// An example of a bad actor in the form of a mutually-recursive
29416-
// promise type might be:
29417-
//
29418-
// interface BadPromiseA {
29419-
// then(
29420-
// onfulfilled: (value: BadPromiseB) => any,
29421-
// onrejected: (error: any) => any): BadPromiseB;
29422-
// }
29423-
//
29424-
// interface BadPromiseB {
29425-
// then(
29426-
// onfulfilled: (value: BadPromiseA) => any,
29427-
// onrejected: (error: any) => any): BadPromiseA;
29428-
// }
29429-
//
29430-
if (errorNode) {
29431-
error(errorNode, Diagnostics.Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method);
29432-
}
29433-
return undefined;
29434-
}
29435-
29436-
// Keep track of the type we're about to unwrap to avoid bad recursive promise types.
29437-
// See the comments above for more information.
29438-
awaitedTypeStack.push(type.id);
29439-
const awaitedType = getAwaitedType(promisedType, errorNode, diagnosticMessage, arg0);
29440-
awaitedTypeStack.pop();
29441-
29442-
if (!awaitedType) {
29443-
return undefined;
29444-
}
29445-
29446-
return typeAsAwaitable.awaitedTypeOfType = awaitedType;
29391+
const result = getTypeAliasInstantiation(symbol, [type]);
29392+
if (result !== unknownType || type === unknownType || getPromisedTypeOfPromise(type) === unknownType) {
29393+
return typeAsAwaitable.awaitedTypeOfType = (result as PromiseOrAwaitableType).awaitedTypeOfType = result;
2944729394
}
2944829395

29449-
// The type was not a promise, so it could not be unwrapped any further.
29450-
// As long as the type does not have a callable "then" property, it is
29451-
// safe to return the type; otherwise, an error will be reported in
29452-
// the call to getNonThenableType and we will return undefined.
29453-
//
29454-
// An example of a non-promise "thenable" might be:
29455-
//
29456-
// await { then(): void {} }
29457-
//
29458-
// The "thenable" does not match the minimal definition for a promise. When
29459-
// a Promise/A+-compatible or ES6 promise tries to adopt this value, the promise
29460-
// will never settle. We treat this as an error to help flag an early indicator
29461-
// of a runtime problem. If the user wants to return this value from an async
29462-
// function, they would need to wrap it in some other value. If they want it to
29463-
// be treated as a promise, they can cast to <any>.
29464-
const thenFunction = getTypeOfPropertyOfType(type, "then" as __String);
29465-
if (thenFunction && getSignaturesOfType(thenFunction, SignatureKind.Call).length > 0) {
29466-
if (errorNode) {
29467-
if (!diagnosticMessage) return Debug.fail();
29468-
error(errorNode, diagnosticMessage, arg0);
29469-
}
29470-
return undefined;
29396+
if (errorNode) {
29397+
if (!diagnosticMessage) return Debug.fail();
29398+
error(errorNode, diagnosticMessage, arg0);
2947129399
}
2947229400

29473-
return typeAsAwaitable.awaitedTypeOfType = type;
29401+
return undefined;
2947429402
}
2947529403

2947629404
/**

‎src/harness/fourslashInterfaceImpl.ts

+1
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,7 @@ namespace FourSlashInterface {
957957
typeEntry("PropertyDecorator"),
958958
typeEntry("MethodDecorator"),
959959
typeEntry("ParameterDecorator"),
960+
typeEntry("Awaited"),
960961
typeEntry("PromiseConstructorLike"),
961962
interfaceEntry("PromiseLike"),
962963
interfaceEntry("Promise"),

0 commit comments

Comments
 (0)