@@ -346,6 +346,8 @@ namespace ts {
346
346
let instantiationCount = 0;
347
347
let instantiationDepth = 0;
348
348
let inlineLevel = 0;
349
+ let varianceLevel = 0;
350
+ let nestedVarianceSymbols: Symbol[] | undefined;
349
351
let currentNode: Node | undefined;
350
352
351
353
const emptySymbols = createSymbolTable();
@@ -17947,7 +17949,7 @@ namespace ts {
17947
17949
}
17948
17950
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
17949
17951
const related = relation.get(getRelationKey(source, target, IntersectionState.None, relation, /*ignoreConstraints*/ false));
17950
- if (related !== undefined) {
17952
+ if (related !== undefined && !(related & RelationComparisonResult.ReportsMask) ) {
17951
17953
return !!(related & RelationComparisonResult.Succeeded);
17952
17954
}
17953
17955
}
@@ -20366,35 +20368,49 @@ namespace ts {
20366
20368
return false;
20367
20369
}
20368
20370
20371
+ function getVariances(type: GenericType): VarianceFlags[] {
20372
+ // Arrays and tuples are known to be covariant, no need to spend time computing this.
20373
+ if (type === globalArrayType || type === globalReadonlyArrayType || type.objectFlags & ObjectFlags.Tuple) {
20374
+ return arrayVariances;
20375
+ }
20376
+ return getVariancesWorker(type.symbol, type.typeParameters, getMarkerTypeReference);
20377
+ }
20378
+
20369
20379
// Return a type reference where the source type parameter is replaced with the target marker
20370
20380
// type, and flag the result as a marker type reference.
20371
- function getMarkerTypeReference(type: GenericType, source: TypeParameter, target: Type) {
20381
+ function getMarkerTypeReference(symbol: Symbol, source: TypeParameter, target: Type) {
20382
+ const type = getDeclaredTypeOfSymbol(symbol) as GenericType;
20372
20383
const result = createTypeReference(type, map(type.typeParameters, t => t === source ? target : t));
20373
20384
result.objectFlags |= ObjectFlags.MarkerType;
20374
20385
return result;
20375
20386
}
20376
20387
20377
20388
function getAliasVariances(symbol: Symbol) {
20378
- const links = getSymbolLinks(symbol);
20379
- return getVariancesWorker(links.typeParameters, links, (_links, param, marker) => {
20380
- const type = getTypeAliasInstantiation(symbol, instantiateTypes(links.typeParameters!, makeUnaryTypeMapper(param, marker)));
20381
- type.aliasTypeArgumentsContainsMarker = true;
20382
- return type;
20383
- });
20389
+ return getVariancesWorker(symbol, getSymbolLinks(symbol).typeParameters, getMarkerTypeAliasReference);
20390
+ }
20391
+
20392
+ function getMarkerTypeAliasReference(symbol: Symbol, source: TypeParameter, target: Type) {
20393
+ const result = getTypeAliasInstantiation(symbol, instantiateTypes(getSymbolLinks(symbol).typeParameters!, makeUnaryTypeMapper(source, target)));
20394
+ result.aliasTypeArgumentsContainsMarker = true;
20395
+ return result;
20384
20396
}
20385
20397
20386
20398
// Return an array containing the variance of each type parameter. The variance is effectively
20387
20399
// a digest of the type comparisons that occur for each type argument when instantiations of the
20388
20400
// generic type are structurally compared. We infer the variance information by comparing
20389
20401
// instantiations of the generic type for type arguments with known relations. The function
20390
20402
// returns the emptyArray singleton when invoked recursively for the given generic type.
20391
- function getVariancesWorker<TCache extends { variances?: VarianceFlags[] }>(typeParameters: readonly TypeParameter[] = emptyArray, cache: TCache, createMarkerType: (input: TCache, param: TypeParameter, marker: Type) => Type): VarianceFlags[] {
20392
- let variances = cache.variances;
20393
- if (!variances) {
20394
- tracing?.push(tracing.Phase.CheckTypes, "getVariancesWorker", { arity: typeParameters.length, id: (cache as any).id ?? (cache as any).declaredType?.id ?? -1 });
20403
+ function getVariancesWorker(symbol: Symbol, typeParameters: readonly TypeParameter[] = emptyArray, createMarkerType: (symbol: Symbol, param: TypeParameter, marker: Type) => Type): VarianceFlags[] {
20404
+ const links = getSymbolLinks(symbol);
20405
+ if (!links.variances) {
20406
+ tracing?.push(tracing.Phase.CheckTypes, "getVariancesWorker", { arity: typeParameters.length, id: getSymbolId(symbol) });
20407
+ if (varianceLevel > 0) {
20408
+ nestedVarianceSymbols = append(nestedVarianceSymbols, symbol);
20409
+ }
20410
+ varianceLevel++;
20395
20411
// The emptyArray singleton is used to signal a recursive invocation.
20396
- cache .variances = emptyArray;
20397
- variances = [];
20412
+ links .variances = emptyArray;
20413
+ const variances = [];
20398
20414
for (const tp of typeParameters) {
20399
20415
let unmeasurable = false;
20400
20416
let unreliable = false;
@@ -20403,15 +20419,15 @@ namespace ts {
20403
20419
// We first compare instantiations where the type parameter is replaced with
20404
20420
// marker types that have a known subtype relationship. From this we can infer
20405
20421
// invariance, covariance, contravariance or bivariance.
20406
- const typeWithSuper = createMarkerType(cache , tp, markerSuperType);
20407
- const typeWithSub = createMarkerType(cache , tp, markerSubType);
20422
+ const typeWithSuper = createMarkerType(symbol , tp, markerSuperType);
20423
+ const typeWithSub = createMarkerType(symbol , tp, markerSubType);
20408
20424
let variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? VarianceFlags.Covariant : 0) |
20409
20425
(isTypeAssignableTo(typeWithSuper, typeWithSub) ? VarianceFlags.Contravariant : 0);
20410
20426
// If the instantiations appear to be related bivariantly it may be because the
20411
20427
// type parameter is independent (i.e. it isn't witnessed anywhere in the generic
20412
20428
// type). To determine this we compare instantiations where the type parameter is
20413
20429
// replaced with marker types that are known to be unrelated.
20414
- if (variance === VarianceFlags.Bivariant && isTypeAssignableTo(createMarkerType(cache , tp, markerOtherType), typeWithSuper)) {
20430
+ if (variance === VarianceFlags.Bivariant && isTypeAssignableTo(createMarkerType(symbol , tp, markerOtherType), typeWithSuper)) {
20415
20431
variance = VarianceFlags.Independent;
20416
20432
}
20417
20433
outofbandVarianceMarkerHandler = oldHandler;
@@ -20425,18 +20441,20 @@ namespace ts {
20425
20441
}
20426
20442
variances.push(variance);
20427
20443
}
20428
- cache.variances = variances;
20444
+ links.variances = variances;
20445
+ varianceLevel--;
20446
+ // Recursive invocations of getVariancesWorker occur when two or more types circularly reference each
20447
+ // other. In such cases, the nested invocations might observe in-process variance computations, i.e.
20448
+ // cases where getVariancesWorker returns emptyArray, and thus might compute incomplete variances. For
20449
+ // this reason we clear (and thus re-compute) the results of nested variance computations and only
20450
+ // permanently record the outermost result. See #44572.
20451
+ if (varianceLevel === 0 && nestedVarianceSymbols) {
20452
+ for (const sym of nestedVarianceSymbols) getSymbolLinks(sym).variances = undefined;
20453
+ nestedVarianceSymbols = undefined;
20454
+ }
20429
20455
tracing?.pop();
20430
20456
}
20431
- return variances;
20432
- }
20433
-
20434
- function getVariances(type: GenericType): VarianceFlags[] {
20435
- // Arrays and tuples are known to be covariant, no need to spend time computing this.
20436
- if (type === globalArrayType || type === globalReadonlyArrayType || type.objectFlags & ObjectFlags.Tuple) {
20437
- return arrayVariances;
20438
- }
20439
- return getVariancesWorker(type.typeParameters, type, getMarkerTypeReference);
20457
+ return links.variances;
20440
20458
}
20441
20459
20442
20460
// Return true if the given type reference has a 'void' type argument for a covariant type parameter.
0 commit comments