Skip to content

Commit 966a5a8

Browse files
committed
Add fallback when both co- and contra-variant inferences exist
1 parent eb014a2 commit 966a5a8

File tree

1 file changed

+19
-16
lines changed

1 file changed

+19
-16
lines changed

src/compiler/checker.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25154,22 +25154,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2515425154
const inference = context.inferences[index];
2515525155
if (!inference.inferredType) {
2515625156
let inferredType: Type | undefined;
25157-
const signature = context.signature;
25158-
if (signature) {
25159-
const inferredCovariantType = inference.candidates ? getCovariantInference(inference, signature) : undefined;
25160-
if (inference.contraCandidates) {
25161-
// If we have both co- and contra-variant inferences, we use the co-variant inference if it is not 'never',
25162-
// it is a subtype of some contra-variant inference, and no other type parameter is constrained to this type
25163-
// parameter and has inferences that would conflict. Otherwise, we use the contra-variant inference.
25164-
const useCovariantType = inferredCovariantType && !(inferredCovariantType.flags & TypeFlags.Never) &&
25157+
let fallbackType: Type | undefined;
25158+
if (context.signature) {
25159+
const inferredCovariantType = inference.candidates ? getCovariantInference(inference, context.signature) : undefined;
25160+
const inferredContravariantType = inference.contraCandidates ? getContravariantInference(inference) : undefined;
25161+
if (inferredCovariantType || inferredContravariantType) {
25162+
// If we have both co- and contra-variant inferences, we prefer the co-variant inference if it is not 'never',
25163+
// all co-variant inferences are subtypes of it (i.e. it isn't one of a conflicting set of candidates), it is
25164+
// a subtype of some contra-variant inference, and no other type parameter is constrained to this type parameter
25165+
// and has inferences that would conflict. Otherwise, we prefer the contra-variant inference.
25166+
const preferCovariantType = inferredCovariantType && (!inferredContravariantType ||
25167+
!(inferredCovariantType.flags & TypeFlags.Never) &&
25168+
every(inference.candidates, t => isTypeSubtypeOf(t, inferredCovariantType)) &&
2516525169
some(inference.contraCandidates, t => isTypeSubtypeOf(inferredCovariantType, t)) &&
25166-
every(context.inferences, other =>
25167-
other !== inference && getConstraintOfTypeParameter(other.typeParameter) !== inference.typeParameter ||
25168-
every(other.candidates, t => isTypeSubtypeOf(t, inferredCovariantType)));
25169-
inferredType = useCovariantType ? inferredCovariantType : getContravariantInference(inference);
25170-
}
25171-
else if (inferredCovariantType) {
25172-
inferredType = inferredCovariantType;
25170+
every(context.inferences, other => other === inference ||
25171+
getConstraintOfTypeParameter(other.typeParameter) !== inference.typeParameter ||
25172+
every(other.candidates, t => isTypeSubtypeOf(t, inferredCovariantType))));
25173+
inferredType = preferCovariantType ? inferredCovariantType : inferredContravariantType;
25174+
fallbackType = preferCovariantType ? inferredContravariantType : inferredCovariantType;
2517325175
}
2517425176
else if (context.flags & InferenceFlags.NoDefault) {
2517525177
// We use silentNeverType as the wildcard that signals no inferences.
@@ -25199,7 +25201,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2519925201
if (constraint) {
2520025202
const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper);
2520125203
if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) {
25202-
inference.inferredType = inferredType = instantiatedConstraint;
25204+
// If the fallback type satisfies the constraint, we pick it. Otherwise, we pick the constraint.
25205+
inference.inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint;
2520325206
}
2520425207
}
2520525208
}

0 commit comments

Comments
 (0)