Skip to content

Commit 84f7afd

Browse files
committed
Handle special case of 'void' type arguments for covariant type parameters
1 parent b58e0fb commit 84f7afd

File tree

1 file changed

+20
-6
lines changed

1 file changed

+20
-6
lines changed

src/compiler/checker.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9422,10 +9422,13 @@ namespace ts {
94229422
return result;
94239423
}
94249424
// The type arguments did not relate appropriately, but it may be because getVariances was
9425-
// invoked recursively and returned emptyArray (in which case typeArgumentsRelatedTo defaults
9426-
// to covariance for all type arguments). In that case we need to contine with a structural
9427-
// comparison. Otherwise, we know for certain the instantiations aren't related.
9428-
if (variances !== emptyArray) {
9425+
// invoked recursively and returned emptyArray (in which case typeArgumentsRelatedTo defaulted
9426+
// to covariance for all type arguments). It might also be the case that the target type has a
9427+
// 'void' type argument for a covariant type parameter that is only used in return positions
9428+
// within the generic type (in which case any type argument is permitted on the source side).
9429+
// In those cases we proceed with a structural comparison. Otherwise, we know for certain the
9430+
// instantiations aren't related and we can return here.
9431+
if (variances !== emptyArray && !hasCovariantVoidArgument(<TypeReference>target, variances)) {
94299432
return Ternary.False;
94309433
}
94319434
}
@@ -9839,7 +9842,7 @@ namespace ts {
98399842
}
98409843

98419844
function getVarianceType(type: GenericType, source: TypeParameter, target: Type) {
9842-
return createTypeReference(type, map(type.typeParameters, t => t === source ? target: t));
9845+
return createTypeReference(type, map(type.typeParameters, t => t === source ? target : t));
98439846
}
98449847

98459848
// Return an array containing the variance of each type parameter. The variance is effectively
@@ -9848,7 +9851,7 @@ namespace ts {
98489851
// instantiations of the generic type for type arguments with known relations. Note that the
98499852
// function returns the emptyArray singleton to signal that it has been invoked recursively for
98509853
// the given generic type.
9851-
function getVariances(type: GenericType) {
9854+
function getVariances(type: GenericType): Variance[] {
98529855
const typeParameters = type.typeParameters || emptyArray;
98539856
let variances = type.variances;
98549857
if (!variances) {
@@ -9883,6 +9886,17 @@ namespace ts {
98839886
return variances;
98849887
}
98859888

9889+
// Return true if the given type reference has a 'void' type argument for a covariant type parameter.
9890+
// See comment at call in recursiveTypeRelatedTo for when this case matters.
9891+
function hasCovariantVoidArgument(type: TypeReference, variances: Variance[]): boolean {
9892+
for (let i = 0; i < variances.length; i++) {
9893+
if (variances[i] === Variance.Covariant && type.typeArguments[i].flags & TypeFlags.Void) {
9894+
return true;
9895+
}
9896+
}
9897+
return false;
9898+
}
9899+
98869900
function isUnconstrainedTypeParameter(type: Type) {
98879901
return type.flags & TypeFlags.TypeParameter && !getConstraintFromTypeParameter(<TypeParameter>type);
98889902
}

0 commit comments

Comments
 (0)