mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Cache propagating variance flags in the relationship cache (#32225)
* Cache propagating variance flags in the relationship cache * Convert base fields in relation comparison result to flags
This commit is contained in:
parent
367b82055c
commit
00a43d7b49
@ -12561,12 +12561,12 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
const id = getSymbolId(sourceSymbol) + "," + getSymbolId(targetSymbol);
|
||||
const relation = enumRelation.get(id);
|
||||
if (relation !== undefined && !(relation === RelationComparisonResult.Failed && errorReporter)) {
|
||||
return relation === RelationComparisonResult.Succeeded;
|
||||
const entry = enumRelation.get(id);
|
||||
if (entry !== undefined && !(!(entry & RelationComparisonResult.Reported) && entry & RelationComparisonResult.Failed && errorReporter)) {
|
||||
return !!(entry & RelationComparisonResult.Succeeded);
|
||||
}
|
||||
if (sourceSymbol.escapedName !== targetSymbol.escapedName || !(sourceSymbol.flags & SymbolFlags.RegularEnum) || !(targetSymbol.flags & SymbolFlags.RegularEnum)) {
|
||||
enumRelation.set(id, RelationComparisonResult.FailedAndReported);
|
||||
enumRelation.set(id, RelationComparisonResult.Failed | RelationComparisonResult.Reported);
|
||||
return false;
|
||||
}
|
||||
const targetEnumType = getTypeOfSymbol(targetSymbol);
|
||||
@ -12577,7 +12577,7 @@ namespace ts {
|
||||
if (errorReporter) {
|
||||
errorReporter(Diagnostics.Property_0_is_missing_in_type_1, symbolName(property),
|
||||
typeToString(getDeclaredTypeOfSymbol(targetSymbol), /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType));
|
||||
enumRelation.set(id, RelationComparisonResult.FailedAndReported);
|
||||
enumRelation.set(id, RelationComparisonResult.Failed | RelationComparisonResult.Reported);
|
||||
}
|
||||
else {
|
||||
enumRelation.set(id, RelationComparisonResult.Failed);
|
||||
@ -12642,7 +12642,7 @@ namespace ts {
|
||||
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
|
||||
const related = relation.get(getRelationKey(source, target, relation));
|
||||
if (related !== undefined) {
|
||||
return related === RelationComparisonResult.Succeeded;
|
||||
return !!(related & RelationComparisonResult.Succeeded);
|
||||
}
|
||||
}
|
||||
if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) {
|
||||
@ -13463,18 +13463,6 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function propagateSidebandVarianceFlags(typeArguments: readonly Type[], variances: VarianceFlags[]) {
|
||||
for (let i = 0; i < variances.length; i++) {
|
||||
const v = variances[i];
|
||||
if (v & VarianceFlags.Unmeasurable) {
|
||||
instantiateType(typeArguments[i], reportUnmeasurableMarkers);
|
||||
}
|
||||
if (v & VarianceFlags.Unreliable) {
|
||||
instantiateType(typeArguments[i], reportUnreliableMarkers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if possibly recursive types are related. First, check if the result is already available in the global cache.
|
||||
// Second, check if we have already started a comparison of the given two types in which case we assume the result to be true.
|
||||
// Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are
|
||||
@ -13485,24 +13473,24 @@ namespace ts {
|
||||
return Ternary.False;
|
||||
}
|
||||
const id = getRelationKey(source, target, relation);
|
||||
const related = relation.get(id);
|
||||
if (related !== undefined) {
|
||||
if (reportErrors && related === RelationComparisonResult.Failed) {
|
||||
const entry = relation.get(id);
|
||||
if (entry !== undefined) {
|
||||
if (reportErrors && entry & RelationComparisonResult.Failed && !(entry & RelationComparisonResult.Reported)) {
|
||||
// We are elaborating errors and the cached result is an unreported failure. The result will be reported
|
||||
// as a failure, and should be updated as a reported failure by the bottom of this function.
|
||||
}
|
||||
else {
|
||||
if (outofbandVarianceMarkerHandler) {
|
||||
// We're in the middle of variance checking - integrate any unmeasurable/unreliable flags from this cached component
|
||||
if (source.flags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol &&
|
||||
source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol) {
|
||||
propagateSidebandVarianceFlags(source.aliasTypeArguments, getAliasVariances(source.aliasSymbol));
|
||||
const saved = entry & RelationComparisonResult.ReportsMask;
|
||||
if (saved & RelationComparisonResult.ReportsUnmeasurable) {
|
||||
instantiateType(source, reportUnmeasurableMarkers);
|
||||
}
|
||||
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target && length((<TypeReference>source).typeArguments)) {
|
||||
propagateSidebandVarianceFlags((<TypeReference>source).typeArguments!, getVariances((<TypeReference>source).target));
|
||||
if (saved & RelationComparisonResult.ReportsUnreliable) {
|
||||
instantiateType(source, reportUnreliableMarkers);
|
||||
}
|
||||
}
|
||||
return related === RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
|
||||
return entry & RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
|
||||
}
|
||||
}
|
||||
if (!maybeKeys) {
|
||||
@ -13531,14 +13519,26 @@ namespace ts {
|
||||
const saveExpandingFlags = expandingFlags;
|
||||
if (!(expandingFlags & ExpandingFlags.Source) && isDeeplyNestedType(source, sourceStack, depth)) expandingFlags |= ExpandingFlags.Source;
|
||||
if (!(expandingFlags & ExpandingFlags.Target) && isDeeplyNestedType(target, targetStack, depth)) expandingFlags |= ExpandingFlags.Target;
|
||||
let originalHandler: typeof outofbandVarianceMarkerHandler;
|
||||
let propagatingVarianceFlags: RelationComparisonResult = 0;
|
||||
if (outofbandVarianceMarkerHandler) {
|
||||
originalHandler = outofbandVarianceMarkerHandler;
|
||||
outofbandVarianceMarkerHandler = onlyUnreliable => {
|
||||
propagatingVarianceFlags |= onlyUnreliable ? RelationComparisonResult.ReportsUnreliable : RelationComparisonResult.ReportsUnmeasurable;
|
||||
return originalHandler!(onlyUnreliable);
|
||||
};
|
||||
}
|
||||
const result = expandingFlags !== ExpandingFlags.Both ? structuredTypeRelatedTo(source, target, reportErrors, isIntersectionConstituent) : Ternary.Maybe;
|
||||
if (outofbandVarianceMarkerHandler) {
|
||||
outofbandVarianceMarkerHandler = originalHandler;
|
||||
}
|
||||
expandingFlags = saveExpandingFlags;
|
||||
depth--;
|
||||
if (result) {
|
||||
if (result === Ternary.True || depth === 0) {
|
||||
// If result is definitely true, record all maybe keys as having succeeded
|
||||
for (let i = maybeStart; i < maybeCount; i++) {
|
||||
relation.set(maybeKeys[i], RelationComparisonResult.Succeeded);
|
||||
relation.set(maybeKeys[i], RelationComparisonResult.Succeeded | propagatingVarianceFlags);
|
||||
}
|
||||
maybeCount = maybeStart;
|
||||
}
|
||||
@ -13546,7 +13546,7 @@ namespace ts {
|
||||
else {
|
||||
// A false result goes straight into global cache (when something is false under
|
||||
// assumptions it will also be false without assumptions)
|
||||
relation.set(id, reportErrors ? RelationComparisonResult.FailedAndReported : RelationComparisonResult.Failed);
|
||||
relation.set(id, (reportErrors ? RelationComparisonResult.Reported : 0) | RelationComparisonResult.Failed | propagatingVarianceFlags);
|
||||
maybeCount = maybeStart;
|
||||
}
|
||||
return result;
|
||||
|
||||
@ -614,9 +614,13 @@ namespace ts {
|
||||
|
||||
/* @internal */
|
||||
export const enum RelationComparisonResult {
|
||||
Succeeded = 1, // Should be truthy
|
||||
Failed = 2,
|
||||
FailedAndReported = 3
|
||||
Succeeded = 1 << 0, // Should be truthy
|
||||
Failed = 1 << 1,
|
||||
Reported = 1 << 2,
|
||||
|
||||
ReportsUnmeasurable = 1 << 3,
|
||||
ReportsUnreliable = 1 << 4,
|
||||
ReportsMask = ReportsUnmeasurable | ReportsUnreliable
|
||||
}
|
||||
|
||||
export interface Node extends TextRange {
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
//// [varianceRepeatedlyPropegatesWithUnreliableFlag.ts]
|
||||
type A = { a: number };
|
||||
type B = { b: number };
|
||||
type X<T> = ({ [K in keyof T]: T[K] } & Record<string, void>)[keyof T];
|
||||
type P1<T> = { data: X<T> };
|
||||
type P2<T> = { data: X<T> };
|
||||
|
||||
interface I<T> {
|
||||
fn<K extends keyof T>(p1: P1<Pick<T, K>>, p2: P2<Pick<T, K>>): void;
|
||||
}
|
||||
|
||||
const i: I<A & B> = null as any;
|
||||
const p2: P2<A> = null as any;
|
||||
|
||||
// Commenting out the below line will remove the error on the `const _i: I<A> = i;`
|
||||
i.fn(null as any, p2);
|
||||
|
||||
const _i: I<A> = i;
|
||||
|
||||
//// [varianceRepeatedlyPropegatesWithUnreliableFlag.js]
|
||||
var i = null;
|
||||
var p2 = null;
|
||||
// Commenting out the below line will remove the error on the `const _i: I<A> = i;`
|
||||
i.fn(null, p2);
|
||||
var _i = i;
|
||||
@ -0,0 +1,77 @@
|
||||
=== tests/cases/compiler/varianceRepeatedlyPropegatesWithUnreliableFlag.ts ===
|
||||
type A = { a: number };
|
||||
>A : Symbol(A, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 0, 0))
|
||||
>a : Symbol(a, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 0, 10))
|
||||
|
||||
type B = { b: number };
|
||||
>B : Symbol(B, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 0, 23))
|
||||
>b : Symbol(b, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 1, 10))
|
||||
|
||||
type X<T> = ({ [K in keyof T]: T[K] } & Record<string, void>)[keyof T];
|
||||
>X : Symbol(X, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 1, 23))
|
||||
>T : Symbol(T, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 2, 7))
|
||||
>K : Symbol(K, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 2, 16))
|
||||
>T : Symbol(T, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 2, 7))
|
||||
>T : Symbol(T, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 2, 7))
|
||||
>K : Symbol(K, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 2, 16))
|
||||
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 2, 7))
|
||||
|
||||
type P1<T> = { data: X<T> };
|
||||
>P1 : Symbol(P1, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 2, 71))
|
||||
>T : Symbol(T, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 3, 8))
|
||||
>data : Symbol(data, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 3, 14))
|
||||
>X : Symbol(X, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 1, 23))
|
||||
>T : Symbol(T, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 3, 8))
|
||||
|
||||
type P2<T> = { data: X<T> };
|
||||
>P2 : Symbol(P2, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 3, 28))
|
||||
>T : Symbol(T, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 4, 8))
|
||||
>data : Symbol(data, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 4, 14))
|
||||
>X : Symbol(X, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 1, 23))
|
||||
>T : Symbol(T, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 4, 8))
|
||||
|
||||
interface I<T> {
|
||||
>I : Symbol(I, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 4, 28))
|
||||
>T : Symbol(T, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 6, 12))
|
||||
|
||||
fn<K extends keyof T>(p1: P1<Pick<T, K>>, p2: P2<Pick<T, K>>): void;
|
||||
>fn : Symbol(I.fn, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 6, 16))
|
||||
>K : Symbol(K, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 7, 7))
|
||||
>T : Symbol(T, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 6, 12))
|
||||
>p1 : Symbol(p1, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 7, 26))
|
||||
>P1 : Symbol(P1, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 2, 71))
|
||||
>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 6, 12))
|
||||
>K : Symbol(K, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 7, 7))
|
||||
>p2 : Symbol(p2, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 7, 45))
|
||||
>P2 : Symbol(P2, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 3, 28))
|
||||
>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 6, 12))
|
||||
>K : Symbol(K, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 7, 7))
|
||||
}
|
||||
|
||||
const i: I<A & B> = null as any;
|
||||
>i : Symbol(i, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 10, 5))
|
||||
>I : Symbol(I, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 4, 28))
|
||||
>A : Symbol(A, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 0, 23))
|
||||
|
||||
const p2: P2<A> = null as any;
|
||||
>p2 : Symbol(p2, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 11, 5))
|
||||
>P2 : Symbol(P2, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 3, 28))
|
||||
>A : Symbol(A, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 0, 0))
|
||||
|
||||
// Commenting out the below line will remove the error on the `const _i: I<A> = i;`
|
||||
i.fn(null as any, p2);
|
||||
>i.fn : Symbol(I.fn, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 6, 16))
|
||||
>i : Symbol(i, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 10, 5))
|
||||
>fn : Symbol(I.fn, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 6, 16))
|
||||
>p2 : Symbol(p2, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 11, 5))
|
||||
|
||||
const _i: I<A> = i;
|
||||
>_i : Symbol(_i, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 16, 5))
|
||||
>I : Symbol(I, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 4, 28))
|
||||
>A : Symbol(A, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 0, 0))
|
||||
>i : Symbol(i, Decl(varianceRepeatedlyPropegatesWithUnreliableFlag.ts, 10, 5))
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
=== tests/cases/compiler/varianceRepeatedlyPropegatesWithUnreliableFlag.ts ===
|
||||
type A = { a: number };
|
||||
>A : A
|
||||
>a : number
|
||||
|
||||
type B = { b: number };
|
||||
>B : B
|
||||
>b : number
|
||||
|
||||
type X<T> = ({ [K in keyof T]: T[K] } & Record<string, void>)[keyof T];
|
||||
>X : ({ [K in keyof T]: T[K]; } & Record<string, void>)[keyof T]
|
||||
|
||||
type P1<T> = { data: X<T> };
|
||||
>P1 : P1<T>
|
||||
>data : ({ [K in keyof T]: T[K]; } & Record<string, void>)[keyof T]
|
||||
|
||||
type P2<T> = { data: X<T> };
|
||||
>P2 : P2<T>
|
||||
>data : ({ [K in keyof T]: T[K]; } & Record<string, void>)[keyof T]
|
||||
|
||||
interface I<T> {
|
||||
fn<K extends keyof T>(p1: P1<Pick<T, K>>, p2: P2<Pick<T, K>>): void;
|
||||
>fn : <K extends keyof T>(p1: P1<Pick<T, K>>, p2: P2<Pick<T, K>>) => void
|
||||
>p1 : P1<Pick<T, K>>
|
||||
>p2 : P2<Pick<T, K>>
|
||||
}
|
||||
|
||||
const i: I<A & B> = null as any;
|
||||
>i : I<A & B>
|
||||
>null as any : any
|
||||
>null : null
|
||||
|
||||
const p2: P2<A> = null as any;
|
||||
>p2 : P2<A>
|
||||
>null as any : any
|
||||
>null : null
|
||||
|
||||
// Commenting out the below line will remove the error on the `const _i: I<A> = i;`
|
||||
i.fn(null as any, p2);
|
||||
>i.fn(null as any, p2) : void
|
||||
>i.fn : <K extends "a" | "b">(p1: P1<Pick<A & B, K>>, p2: P2<Pick<A & B, K>>) => void
|
||||
>i : I<A & B>
|
||||
>fn : <K extends "a" | "b">(p1: P1<Pick<A & B, K>>, p2: P2<Pick<A & B, K>>) => void
|
||||
>null as any : any
|
||||
>null : null
|
||||
>p2 : P2<A>
|
||||
|
||||
const _i: I<A> = i;
|
||||
>_i : I<A>
|
||||
>i : I<A & B>
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
type A = { a: number };
|
||||
type B = { b: number };
|
||||
type X<T> = ({ [K in keyof T]: T[K] } & Record<string, void>)[keyof T];
|
||||
type P1<T> = { data: X<T> };
|
||||
type P2<T> = { data: X<T> };
|
||||
|
||||
interface I<T> {
|
||||
fn<K extends keyof T>(p1: P1<Pick<T, K>>, p2: P2<Pick<T, K>>): void;
|
||||
}
|
||||
|
||||
const i: I<A & B> = null as any;
|
||||
const p2: P2<A> = null as any;
|
||||
|
||||
// Commenting out the below line will remove the error on the `const _i: I<A> = i;`
|
||||
i.fn(null as any, p2);
|
||||
|
||||
const _i: I<A> = i;
|
||||
Loading…
x
Reference in New Issue
Block a user