@@ -19059,6 +19059,9 @@ namespace ts {
19059
19059
return varianceResult;
19060
19060
}
19061
19061
}
19062
+ else if (!someContainsMarkerType(source.aliasTypeArguments) && !someContainsMarkerType(target.aliasTypeArguments)) {
19063
+ return Ternary.Unknown;
19064
+ }
19062
19065
}
19063
19066
19064
19067
// For a generic type T and a type U that is assignable to T, [...U] is assignable to T, U is assignable to readonly [...T],
@@ -19436,14 +19439,18 @@ namespace ts {
19436
19439
}
19437
19440
// We have type references to the same generic type. Obtain the variance information for the type
19438
19441
// 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.
19442
+ // the process of being computed, structurally relate references that contain marker types in their
19443
+ // type arguments, but otherwise return Ternary.Unknown (the non-cached version of Ternary.Maybe).
19440
19444
const variances = getVariances((source as TypeReference).target);
19441
19445
if (variances !== emptyArray) {
19442
19446
const varianceResult = relateVariances(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), variances, intersectionState);
19443
19447
if (varianceResult !== undefined) {
19444
19448
return varianceResult;
19445
19449
}
19446
19450
}
19451
+ else if (!someContainsMarkerType(getTypeArguments(source as TypeReference)) && !someContainsMarkerType(getTypeArguments(target as TypeReference))) {
19452
+ return Ternary.Unknown;
19453
+ }
19447
19454
}
19448
19455
else if (isReadonlyArrayType(target) ? isArrayType(source) || isTupleType(source) : isArrayType(target) && isTupleType(source) && !source.target.readonly) {
19449
19456
if (relation !== identityRelation) {
@@ -20427,6 +20434,49 @@ namespace ts {
20427
20434
return createTypeReference(type, instantiateTypes(type.typeParameters, mapper));
20428
20435
}
20429
20436
20437
+ // Check if any of the given types contain marker types. We visit type arguments of generic classes, interfaces, and
20438
+ // type aliases, members of anonymous type literals and mapped types, constituents of union, intersection, and
20439
+ // template literal types, and targets of index types and string mapping types. This is by design a limited set of
20440
+ // types to avoid excessive fan out. In deferred (and thus possibly circular) locations we limit the traversal to
20441
+ // four levels of depth.
20442
+ function someContainsMarkerType(types: readonly Type[] | undefined, maxDepth = 4) {
20443
+ return some(types, t => containsMarkerType(t, maxDepth));
20444
+ }
20445
+
20446
+ function containsMarkerType(type: Type, maxDepth: number): boolean {
20447
+ return maxDepth > 0 && (
20448
+ type.flags & TypeFlags.TypeParameter ? type === markerSubType || type === markerSubType || type === markerOtherType :
20449
+ type.aliasSymbol ? someContainsMarkerType(type.aliasTypeArguments, maxDepth) :
20450
+ type.flags & TypeFlags.Object ? objectTypeContainsMarkerType(type as ObjectType, maxDepth) :
20451
+ type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) && !(type.flags & TypeFlags.EnumLiteral) ? someContainsMarkerType((type as UnionOrIntersectionType | TemplateLiteralType).types, maxDepth) :
20452
+ type.flags & (TypeFlags.Index | TypeFlags.StringMapping) ? containsMarkerType((type as IndexType | StringMappingType).type, maxDepth) :
20453
+ false);
20454
+ }
20455
+
20456
+ function objectTypeContainsMarkerType(type: ObjectType, maxDepth: number): boolean {
20457
+ const objectFlags = getObjectFlags(type);
20458
+ if (objectFlags & ObjectFlags.Reference) {
20459
+ return someContainsMarkerType(getTypeArguments(type as TypeReference), maxDepth - ((type as TypeReference).node ? 1 : 0));
20460
+ }
20461
+ if (objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral) {
20462
+ const resolved = resolveStructuredTypeMembers(type);
20463
+ return some(resolved.properties, prop => containsMarkerType(getTypeOfSymbol(prop), maxDepth - 1)) ||
20464
+ some(resolved.callSignatures, sig => signatureContainsMarkerType(sig, maxDepth)) ||
20465
+ some(resolved.constructSignatures, sig => signatureContainsMarkerType(sig, maxDepth)) ||
20466
+ some(resolved.indexInfos, info => containsMarkerType(info.type, maxDepth - 1));
20467
+ }
20468
+ if (objectFlags & ObjectFlags.Mapped) {
20469
+ return containsMarkerType(getConstraintTypeFromMappedType(type as MappedType), maxDepth - 1) ||
20470
+ containsMarkerType(getTemplateTypeFromMappedType(type as MappedType), maxDepth - 1);
20471
+ }
20472
+ return false;
20473
+ }
20474
+
20475
+ function signatureContainsMarkerType(sig: Signature, maxDepth: number): boolean {
20476
+ return some(sig.parameters, param => containsMarkerType(getTypeOfSymbol(param), maxDepth - 1)) ||
20477
+ containsMarkerType(getReturnTypeOfSignature(sig), maxDepth - 1);
20478
+ }
20479
+
20430
20480
// Return true if the given type reference has a 'void' type argument for a covariant type parameter.
20431
20481
// See comment at call in recursiveTypeRelatedTo for when this case matters.
20432
20482
function hasCovariantVoidArgument(typeArguments: readonly Type[], variances: VarianceFlags[]): boolean {
0 commit comments