@@ -346,9 +346,6 @@ 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;
351
- let incompleteVariancesObserved = false;
352
349
let currentNode: Node | undefined;
353
350
354
351
const emptySymbols = createSymbolTable();
@@ -16629,6 +16626,7 @@ namespace ts {
16629
16626
return result;
16630
16627
}
16631
16628
16629
+
16632
16630
function getObjectTypeInstantiation(type: AnonymousType | DeferredTypeReference, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]) {
16633
16631
const declaration = type.objectFlags & ObjectFlags.Reference ? (type as TypeReference).node! :
16634
16632
type.objectFlags & ObjectFlags.InstantiationExpressionType ? (type as InstantiationExpressionType).node :
@@ -16686,15 +16684,16 @@ namespace ts {
16686
16684
}
16687
16685
16688
16686
function isTypeParameterPossiblyReferenced(tp: TypeParameter, node: Node) {
16689
- // If the type parameter doesn't have exactly one declaration, if there are invening statement blocks
16690
- // between the node and the type parameter declaration, if the node contains actual references to the
16691
- // type parameter, or if the node contains type queries, we consider the type parameter possibly referenced.
16692
- if (tp.symbol && tp.symbol.declarations && tp.symbol.declarations.length === 1 ) {
16693
- const container = tp.symbol.declarations[0].parent ;
16694
- for (let n = node; n !== container; n = n .parent) {
16687
+ // If there are intervening statement blocks between the node and the type parameter declaration, if the node
16688
+ // contains actual references to the type parameter, or if the node contains type queries, we consider the
16689
+ // type parameter possibly referenced.
16690
+ if (tp.symbol && tp.symbol.declarations) {
16691
+ let n = node ;
16692
+ while (!some(tp.symbol.declarations, d => n === d .parent) ) {
16695
16693
if (!n || n.kind === SyntaxKind.Block || n.kind === SyntaxKind.ConditionalType && forEachChild((n as ConditionalTypeNode).extendsType, containsReference)) {
16696
16694
return true;
16697
16695
}
16696
+ n = n.parent;
16698
16697
}
16699
16698
return containsReference(node);
16700
16699
}
@@ -19052,16 +19051,13 @@ namespace ts {
19052
19051
// We limit alias variance probing to only object and conditional types since their alias behavior
19053
19052
// is more predictable than other, interned types, which may or may not have an alias depending on
19054
19053
// the order in which things were checked.
19055
- if (sourceFlags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol &&
19056
- source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol &&
19057
- !(source.aliasTypeArgumentsContainsMarker || target.aliasTypeArgumentsContainsMarker)) {
19054
+ if (sourceFlags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol && source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol) {
19058
19055
const variances = getAliasVariances(source.aliasSymbol);
19059
- if (variances === emptyArray) {
19060
- return Ternary.Unknown;
19061
- }
19062
- const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances, intersectionState);
19063
- if (varianceResult !== undefined) {
19064
- return varianceResult;
19056
+ if (variances !== emptyArray) {
19057
+ const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances, intersectionState);
19058
+ if (varianceResult !== undefined) {
19059
+ return varianceResult;
19060
+ }
19065
19061
}
19066
19062
}
19067
19063
@@ -19432,26 +19428,21 @@ namespace ts {
19432
19428
else if (isGenericMappedType(source)) {
19433
19429
return Ternary.False;
19434
19430
}
19435
- if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source as TypeReference).target === (target as TypeReference).target &&
19436
- !isTupleType(source) && !(getObjectFlags(source) & ObjectFlags.MarkerType || getObjectFlags(target) & ObjectFlags.MarkerType)) {
19431
+ if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source as TypeReference).target === (target as TypeReference).target && !isTupleType(source)) {
19437
19432
// When strictNullChecks is disabled, the element type of the empty array literal is undefinedWideningType,
19438
19433
// and an empty array literal wouldn't be assignable to a `never[]` without this check.
19439
19434
if (isEmptyArrayLiteralType(source)) {
19440
19435
return Ternary.True;
19441
19436
}
19442
- // We have type references to the same generic type, and the type references are not marker
19443
- // type references (which are intended by be compared structurally). Obtain the variance
19444
- // information for the type parameters and relate the type arguments accordingly .
19437
+ // We have type references to the same generic type. Obtain the variance information for the type
19438
+ // parameters and relate the type arguments accordingly. If variance information for the type is in
19439
+ // the process of being computed, fall through and relate the type references structurally .
19445
19440
const variances = getVariances((source as TypeReference).target);
19446
- // We return Ternary.Maybe for a recursive invocation of getVariances (signalled by emptyArray). This
19447
- // effectively means we measure variance only from type parameter occurrences that aren't nested in
19448
- // recursive instantiations of the generic type.
19449
- if (variances === emptyArray) {
19450
- return Ternary.Unknown;
19451
- }
19452
- const varianceResult = relateVariances(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), variances, intersectionState);
19453
- if (varianceResult !== undefined) {
19454
- return varianceResult;
19441
+ if (variances !== emptyArray) {
19442
+ const varianceResult = relateVariances(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), variances, intersectionState);
19443
+ if (varianceResult !== undefined) {
19444
+ return varianceResult;
19445
+ }
19455
19446
}
19456
19447
}
19457
19448
else if (isReadonlyArrayType(target) ? isArrayType(source) || isTupleType(source) : isArrayType(target) && isTupleType(source) && !source.target.readonly) {
@@ -20371,45 +20362,24 @@ namespace ts {
20371
20362
20372
20363
function getVariances(type: GenericType): VarianceFlags[] {
20373
20364
// Arrays and tuples are known to be covariant, no need to spend time computing this.
20374
- if (type === globalArrayType || type === globalReadonlyArrayType || type.objectFlags & ObjectFlags.Tuple) {
20375
- return arrayVariances;
20376
- }
20377
- return getVariancesWorker(type.symbol, type.typeParameters, getMarkerTypeReference);
20378
- }
20379
-
20380
- // Return a type reference where the source type parameter is replaced with the target marker
20381
- // type, and flag the result as a marker type reference.
20382
- function getMarkerTypeReference(symbol: Symbol, source: TypeParameter, target: Type) {
20383
- const type = getDeclaredTypeOfSymbol(symbol) as GenericType;
20384
- const result = createTypeReference(type, map(type.typeParameters, t => t === source ? target : t));
20385
- result.objectFlags |= ObjectFlags.MarkerType;
20386
- return result;
20365
+ return type === globalArrayType || type === globalReadonlyArrayType || type.objectFlags & ObjectFlags.Tuple ?
20366
+ arrayVariances :
20367
+ getVariancesWorker(type.symbol, type.typeParameters);
20387
20368
}
20388
20369
20389
20370
function getAliasVariances(symbol: Symbol) {
20390
- return getVariancesWorker(symbol, getSymbolLinks(symbol).typeParameters, getMarkerTypeAliasReference);
20391
- }
20392
-
20393
- function getMarkerTypeAliasReference(symbol: Symbol, source: TypeParameter, target: Type) {
20394
- const result = getTypeAliasInstantiation(symbol, instantiateTypes(getSymbolLinks(symbol).typeParameters!, makeUnaryTypeMapper(source, target)));
20395
- result.aliasTypeArgumentsContainsMarker = true;
20396
- return result;
20371
+ return getVariancesWorker(symbol, getSymbolLinks(symbol).typeParameters);
20397
20372
}
20398
20373
20399
20374
// Return an array containing the variance of each type parameter. The variance is effectively
20400
20375
// a digest of the type comparisons that occur for each type argument when instantiations of the
20401
20376
// generic type are structurally compared. We infer the variance information by comparing
20402
20377
// instantiations of the generic type for type arguments with known relations. The function
20403
20378
// returns the emptyArray singleton when invoked recursively for the given generic type.
20404
- function getVariancesWorker(symbol: Symbol, typeParameters: readonly TypeParameter[] = emptyArray, createMarkerType: (symbol: Symbol, param: TypeParameter, marker: Type) => Type ): VarianceFlags[] {
20379
+ function getVariancesWorker(symbol: Symbol, typeParameters: readonly TypeParameter[] = emptyArray): VarianceFlags[] {
20405
20380
const links = getSymbolLinks(symbol);
20406
20381
if (!links.variances) {
20407
20382
tracing?.push(tracing.Phase.CheckTypes, "getVariancesWorker", { arity: typeParameters.length, id: getSymbolId(symbol) });
20408
- if (varianceLevel > 0) {
20409
- nestedVarianceSymbols = append(nestedVarianceSymbols, symbol);
20410
- }
20411
- varianceLevel++;
20412
- // The emptyArray singleton is used to signal a recursive invocation.
20413
20383
links.variances = emptyArray;
20414
20384
const variances = [];
20415
20385
for (const tp of typeParameters) {
@@ -20443,28 +20413,20 @@ namespace ts {
20443
20413
variances.push(variance);
20444
20414
}
20445
20415
links.variances = variances;
20446
- varianceLevel--;
20447
- // Recursive invocations of getVariancesWorker occur when two or more types circularly reference each
20448
- // other. In such cases, the nested invocations might observe in-process variance computations, i.e.
20449
- // cases where getVariancesWorker returns emptyArray. If that happens we clear (and thus re-compute) the
20450
- // results of nested variance computations and only permanently record the outermost result. See #44572.
20451
- if (varianceLevel === 0) {
20452
- if (nestedVarianceSymbols && incompleteVariancesObserved) {
20453
- for (const sym of nestedVarianceSymbols) {
20454
- getSymbolLinks(sym).variances = undefined;
20455
- }
20456
- }
20457
- nestedVarianceSymbols = undefined;
20458
- incompleteVariancesObserved = false;
20459
- }
20460
20416
tracing?.pop();
20461
20417
}
20462
- else {
20463
- incompleteVariancesObserved ||= links.variances === emptyArray;
20464
- }
20465
20418
return links.variances;
20466
20419
}
20467
20420
20421
+ function createMarkerType(symbol: Symbol, source: TypeParameter, target: Type) {
20422
+ const mapper = makeUnaryTypeMapper(source, target);
20423
+ if (symbol.flags & SymbolFlags.TypeAlias) {
20424
+ return getTypeAliasInstantiation(symbol, instantiateTypes(getSymbolLinks(symbol).typeParameters!, mapper));
20425
+ }
20426
+ const type = getDeclaredTypeOfSymbol(symbol) as GenericType;
20427
+ return createTypeReference(type, instantiateTypes(type.typeParameters, mapper));
20428
+ }
20429
+
20468
20430
// Return true if the given type reference has a 'void' type argument for a covariant type parameter.
20469
20431
// See comment at call in recursiveTypeRelatedTo for when this case matters.
20470
20432
function hasCovariantVoidArgument(typeArguments: readonly Type[], variances: VarianceFlags[]): boolean {
0 commit comments