Fix inference of type arguments when source is 'awaited'

This commit is contained in:
Ron Buckton
2020-03-23 13:32:19 -07:00
parent 221a2aeb1b
commit cecab849db
7 changed files with 86 additions and 17 deletions
+30 -8
View File
@@ -929,7 +929,7 @@ namespace ts {
let _jsxNamespace: __String;
let _jsxFactoryEntity: EntityName | undefined;
let outofbandVarianceMarkerHandler: ((onlyUnreliable: boolean) => void) | undefined;
let outofbandVarianceMarkerHandler: ((variance: VarianceFlags) => void) | undefined;
const subtypeRelation = createMap<RelationComparisonResult>();
const strictSubtypeRelation = createMap<RelationComparisonResult>();
@@ -15797,6 +15797,9 @@ namespace ts {
if (saved & RelationComparisonResult.ReportsUnreliable) {
instantiateType(source, makeFunctionTypeMapper(reportUnreliableMarkers));
}
if (saved & RelationComparisonResult.ReportsAwaited) {
instantiateType(source, makeFunctionTypeMapper(reportAwaitedMarkers));
}
}
return entry & RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
}
@@ -15831,10 +15834,12 @@ namespace ts {
let propagatingVarianceFlags: RelationComparisonResult = 0;
if (outofbandVarianceMarkerHandler) {
originalHandler = outofbandVarianceMarkerHandler;
outofbandVarianceMarkerHandler = onlyUnreliable => {
outofbandVarianceMarkerHandler = variance => {
propagatingVarianceFlags |=
onlyUnreliable ? RelationComparisonResult.ReportsUnreliable : RelationComparisonResult.ReportsUnmeasurable;
return originalHandler!(onlyUnreliable);
variance === VarianceFlags.Awaited ? RelationComparisonResult.ReportsAwaited :
variance === VarianceFlags.Unreliable ? RelationComparisonResult.ReportsUnreliable :
RelationComparisonResult.ReportsUnmeasurable;
return originalHandler!(variance);
};
}
const result = expandingFlags !== ExpandingFlags.Both ? structuredTypeRelatedTo(source, target, reportErrors, intersectionState) : Ternary.Maybe;
@@ -15966,7 +15971,7 @@ namespace ts {
}
else if (target.flags & TypeFlags.Awaited && source.flags & TypeFlags.Awaited) {
const targetType = (<AwaitedType>target).awaitedType;
const sourceType = instantiateType((<AwaitedType>source).awaitedType, makeFunctionTypeMapper(reportUnreliableMarkers));
const sourceType = instantiateType((<AwaitedType>source).awaitedType, makeFunctionTypeMapper(reportAwaitedMarkers));
// An `awaited S` is related to an `awaited T` if `S` is related to `T`:
//
// S <: T ⇒ awaited S <: awaited T
@@ -16250,14 +16255,21 @@ namespace ts {
function reportUnmeasurableMarkers(p: TypeParameter) {
if (outofbandVarianceMarkerHandler && (p === markerSuperType || p === markerSubType || p === markerOtherType)) {
outofbandVarianceMarkerHandler(/*onlyUnreliable*/ false);
outofbandVarianceMarkerHandler(VarianceFlags.Unmeasurable);
}
return p;
}
function reportUnreliableMarkers(p: TypeParameter) {
if (outofbandVarianceMarkerHandler && (p === markerSuperType || p === markerSubType || p === markerOtherType)) {
outofbandVarianceMarkerHandler(/*onlyUnreliable*/ true);
outofbandVarianceMarkerHandler(VarianceFlags.Unreliable);
}
return p;
}
function reportAwaitedMarkers(p: TypeParameter) {
if (outofbandVarianceMarkerHandler && (p === markerSuperType || p === markerSubType || p === markerOtherType)) {
outofbandVarianceMarkerHandler(VarianceFlags.Awaited);
}
return p;
}
@@ -16971,8 +16983,12 @@ namespace ts {
for (const tp of typeParameters) {
let unmeasurable = false;
let unreliable = false;
let awaited = false;
const oldHandler = outofbandVarianceMarkerHandler;
outofbandVarianceMarkerHandler = (onlyUnreliable) => onlyUnreliable ? unreliable = true : unmeasurable = true;
outofbandVarianceMarkerHandler = (variance) =>
variance === VarianceFlags.Awaited ? awaited = true :
variance === VarianceFlags.Unreliable ? unreliable = true :
unmeasurable = true;
// We first compare instantiations where the type parameter is replaced with
// marker types that have a known subtype relationship. From this we can infer
// invariance, covariance, contravariance or bivariance.
@@ -16994,6 +17010,9 @@ namespace ts {
if (unreliable) {
variance |= VarianceFlags.Unreliable;
}
if (awaited) {
variance |= VarianceFlags.Awaited;
}
variances.push(variance);
}
cache.variances = variances;
@@ -18449,6 +18468,9 @@ namespace ts {
if (i < variances.length && (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Contravariant) {
inferFromContravariantTypes(sourceTypes[i], targetTypes[i]);
}
else if (variances[i] & VarianceFlags.Awaited) {
inferFromTypes(unwrapAwaitedType(sourceTypes[i]), targetTypes[i]);
}
else {
inferFromTypes(sourceTypes[i], targetTypes[i]);
}
+1 -1
View File
@@ -1231,7 +1231,7 @@ namespace ts {
enableCPUProfiler,
disableCPUProfiler,
realpath,
debugMode: some(<string[]>process.execArgv, arg => /^--(inspect|debug)(-brk)?(=\d+)?$/i.test(arg)),
debugMode: !!process.env.NODE_INSPECTOR_IPC || some(<string[]>process.execArgv, arg => /^--(inspect|debug)(-brk)?(=\d+)?$/i.test(arg)),
tryEnableSourceMapsForHost() {
try {
require("source-map-support").install();
+4 -2
View File
@@ -641,7 +641,8 @@ namespace ts {
ReportsUnmeasurable = 1 << 3,
ReportsUnreliable = 1 << 4,
ReportsMask = ReportsUnmeasurable | ReportsUnreliable
ReportsAwaited = 1 << 5,
ReportsMask = ReportsUnmeasurable | ReportsUnreliable | ReportsAwaited
}
export interface Node extends TextRange {
@@ -4608,7 +4609,8 @@ namespace ts {
VarianceMask = Invariant | Covariant | Contravariant | Independent, // Mask containing all measured variances without the unmeasurable flag
Unmeasurable = 1 << 3, // Variance result is unusable - relationship relies on structural comparisons which are not reflected in generic relationships
Unreliable = 1 << 4, // Variance result is unreliable - checking may produce false negatives, but not false positives
AllowsStructuralFallback = Unmeasurable | Unreliable,
Awaited = 1 << 5, // type argument is awaited
AllowsStructuralFallback = Unmeasurable | Unreliable | Awaited,
}
// Generic class and interface types
+10 -1
View File
@@ -13,7 +13,12 @@ function f<T>() {
}
const x = f<number>(); // number
const y = f<Promise<number>>(); // number ?
const z = f<Promise<number> | number>(); // number ?
const z = f<Promise<number> | number>(); // number ?
// https://github.com/microsoft/TypeScript/issues/37526
function f1<T>(a: T): Promise<awaited T> {
return new Promise(r => r(a));
}
//// [awaitedInference.js]
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
@@ -62,3 +67,7 @@ function f() {
var x = f(); // number
var y = f(); // number ?
var z = f(); // number ?
// https://github.com/microsoft/TypeScript/issues/37526
function f1(a) {
return new Promise(function (r) { return r(a); });
}
@@ -26,12 +26,12 @@ type UnwrapAwaited<T> = T extends awaited infer Inner ? Inner : T;
type Result1 = UnwrapAwaited<awaited Promise<number>>; // number
>Result1 : Symbol(Result1, Decl(awaitedInference.ts, 4, 66))
>UnwrapAwaited : Symbol(UnwrapAwaited, Decl(awaitedInference.ts, 2, 36))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
type Result2 = UnwrapAwaited<awaited Promise<number> | number>; // number
>Result2 : Symbol(Result2, Decl(awaitedInference.ts, 5, 54))
>UnwrapAwaited : Symbol(UnwrapAwaited, Decl(awaitedInference.ts, 2, 36))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
function f<T>() {
>f : Symbol(f, Decl(awaitedInference.ts, 6, 63))
@@ -58,10 +58,25 @@ const x = f<number>(); // number
const y = f<Promise<number>>(); // number ?
>y : Symbol(y, Decl(awaitedInference.ts, 13, 5))
>f : Symbol(f, Decl(awaitedInference.ts, 6, 63))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
const z = f<Promise<number> | number>(); // number ?
>z : Symbol(z, Decl(awaitedInference.ts, 14, 5))
>f : Symbol(f, Decl(awaitedInference.ts, 6, 63))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
// https://github.com/microsoft/TypeScript/issues/37526
function f1<T>(a: T): Promise<awaited T> {
>f1 : Symbol(f1, Decl(awaitedInference.ts, 14, 40))
>T : Symbol(T, Decl(awaitedInference.ts, 17, 12))
>a : Symbol(a, Decl(awaitedInference.ts, 17, 15))
>T : Symbol(T, Decl(awaitedInference.ts, 17, 12))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>T : Symbol(T, Decl(awaitedInference.ts, 17, 12))
return new Promise(r => r(a));
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>r : Symbol(r, Decl(awaitedInference.ts, 18, 23))
>r : Symbol(r, Decl(awaitedInference.ts, 18, 23))
>a : Symbol(a, Decl(awaitedInference.ts, 17, 15))
}
@@ -53,3 +53,17 @@ const z = f<Promise<number> | number>(); // number ?
>f<Promise<number> | number>() : [number | Promise<number>, number]
>f : <T>() => [UnwrapAwaited<T>, UnwrapAwaited<awaited T>]
// https://github.com/microsoft/TypeScript/issues/37526
function f1<T>(a: T): Promise<awaited T> {
>f1 : <T>(a: T) => Promise<awaited T>
>a : T
return new Promise(r => r(a));
>new Promise(r => r(a)) : Promise<T>
>Promise : PromiseConstructor
>r => r(a) : (r: (value?: T | awaited T | PromiseLike<T>) => void) => void
>r : (value?: T | awaited T | PromiseLike<T>) => void
>r(a) : void
>r : (value?: T | awaited T | PromiseLike<T>) => void
>a : T
}
@@ -1,3 +1,5 @@
// @lib: es2015
declare function foo<T>(f: () => PromiseLike<T>, x: T): void;
declare const nullOrNumber: number | null;
foo(async () => nullOrNumber, null);
@@ -12,4 +14,9 @@ function f<T>() {
}
const x = f<number>(); // number
const y = f<Promise<number>>(); // number ?
const z = f<Promise<number> | number>(); // number ?
const z = f<Promise<number> | number>(); // number ?
// https://github.com/microsoft/TypeScript/issues/37526
function f1<T>(a: T): Promise<awaited T> {
return new Promise(r => r(a));
}