Skip to content

Commit fc15aa2

Browse files
committed
Only permanently record non-nested getVariancesWorker results
1 parent 8f9b653 commit fc15aa2

File tree

1 file changed

+45
-27
lines changed

1 file changed

+45
-27
lines changed

src/compiler/checker.ts

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,8 @@ namespace ts {
346346
let instantiationCount = 0;
347347
let instantiationDepth = 0;
348348
let inlineLevel = 0;
349+
let varianceLevel = 0;
350+
let nestedVarianceSymbols: Symbol[] | undefined;
349351
let currentNode: Node | undefined;
350352

351353
const emptySymbols = createSymbolTable();
@@ -17947,7 +17949,7 @@ namespace ts {
1794717949
}
1794817950
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
1794917951
const related = relation.get(getRelationKey(source, target, IntersectionState.None, relation, /*ignoreConstraints*/ false));
17950-
if (related !== undefined) {
17952+
if (related !== undefined && !(related & RelationComparisonResult.ReportsMask)) {
1795117953
return !!(related & RelationComparisonResult.Succeeded);
1795217954
}
1795317955
}
@@ -20366,35 +20368,49 @@ namespace ts {
2036620368
return false;
2036720369
}
2036820370

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+
2036920379
// Return a type reference where the source type parameter is replaced with the target marker
2037020380
// 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;
2037220383
const result = createTypeReference(type, map(type.typeParameters, t => t === source ? target : t));
2037320384
result.objectFlags |= ObjectFlags.MarkerType;
2037420385
return result;
2037520386
}
2037620387

2037720388
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;
2038420396
}
2038520397

2038620398
// Return an array containing the variance of each type parameter. The variance is effectively
2038720399
// a digest of the type comparisons that occur for each type argument when instantiations of the
2038820400
// generic type are structurally compared. We infer the variance information by comparing
2038920401
// instantiations of the generic type for type arguments with known relations. The function
2039020402
// 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++;
2039520411
// The emptyArray singleton is used to signal a recursive invocation.
20396-
cache.variances = emptyArray;
20397-
variances = [];
20412+
links.variances = emptyArray;
20413+
const variances = [];
2039820414
for (const tp of typeParameters) {
2039920415
let unmeasurable = false;
2040020416
let unreliable = false;
@@ -20403,15 +20419,15 @@ namespace ts {
2040320419
// We first compare instantiations where the type parameter is replaced with
2040420420
// marker types that have a known subtype relationship. From this we can infer
2040520421
// 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);
2040820424
let variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? VarianceFlags.Covariant : 0) |
2040920425
(isTypeAssignableTo(typeWithSuper, typeWithSub) ? VarianceFlags.Contravariant : 0);
2041020426
// If the instantiations appear to be related bivariantly it may be because the
2041120427
// type parameter is independent (i.e. it isn't witnessed anywhere in the generic
2041220428
// type). To determine this we compare instantiations where the type parameter is
2041320429
// 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)) {
2041520431
variance = VarianceFlags.Independent;
2041620432
}
2041720433
outofbandVarianceMarkerHandler = oldHandler;
@@ -20425,18 +20441,20 @@ namespace ts {
2042520441
}
2042620442
variances.push(variance);
2042720443
}
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+
}
2042920455
tracing?.pop();
2043020456
}
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;
2044020458
}
2044120459

2044220460
// Return true if the given type reference has a 'void' type argument for a covariant type parameter.

0 commit comments

Comments
 (0)