@@ -10917,6 +10917,7 @@ namespace ts {
10917
10917
return {
10918
10918
typeParameter,
10919
10919
candidates: undefined,
10920
+ contraCandidates: undefined,
10920
10921
inferredType: undefined,
10921
10922
priority: undefined,
10922
10923
topLevel: true,
@@ -10928,6 +10929,7 @@ namespace ts {
10928
10929
return {
10929
10930
typeParameter: inference.typeParameter,
10930
10931
candidates: inference.candidates && inference.candidates.slice(),
10932
+ contraCandidates: inference.contraCandidates && inference.contraCandidates.slice(),
10931
10933
inferredType: inference.inferredType,
10932
10934
priority: inference.priority,
10933
10935
topLevel: inference.topLevel,
@@ -11041,6 +11043,7 @@ namespace ts {
11041
11043
function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) {
11042
11044
let symbolStack: Symbol[];
11043
11045
let visited: Map<boolean>;
11046
+ let contravariant = false;
11044
11047
inferFromTypes(originalSource, originalTarget);
11045
11048
11046
11049
function inferFromTypes(source: Type, target: Type) {
@@ -11108,18 +11111,20 @@ namespace ts {
11108
11111
const inference = getInferenceInfoForType(target);
11109
11112
if (inference) {
11110
11113
if (!inference.isFixed) {
11111
- // We give lowest priority to inferences of implicitNeverType (which is used as the
11112
- // element type for empty array literals). Thus, inferences from empty array literals
11113
- // only matter when no other inferences are made.
11114
- const p = priority | (source === implicitNeverType ? InferencePriority.NeverType : 0);
11115
- if (!inference.candidates || p < inference.priority) {
11116
- inference.candidates = [source];
11117
- inference.priority = p;
11114
+ if (inference.priority === undefined || priority < inference.priority) {
11115
+ inference.candidates = undefined;
11116
+ inference.contraCandidates = undefined;
11117
+ inference.priority = priority;
11118
11118
}
11119
- else if (p === inference.priority) {
11120
- inference.candidates.push(source);
11119
+ if (priority === inference.priority) {
11120
+ if (contravariant) {
11121
+ inference.contraCandidates = append(inference.contraCandidates, source);
11122
+ }
11123
+ else {
11124
+ inference.candidates = append(inference.candidates, source);
11125
+ }
11121
11126
}
11122
- if (!(p & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, <TypeParameter>target)) {
11127
+ if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, <TypeParameter>target)) {
11123
11128
inference.topLevel = false;
11124
11129
}
11125
11130
}
@@ -11142,15 +11147,15 @@ namespace ts {
11142
11147
}
11143
11148
}
11144
11149
else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) {
11145
- priority ^= InferencePriority.Contravariant ;
11150
+ contravariant = !contravariant ;
11146
11151
inferFromTypes((<IndexType>source).type, (<IndexType>target).type);
11147
- priority ^= InferencePriority.Contravariant ;
11152
+ contravariant = !contravariant ;
11148
11153
}
11149
11154
else if ((isLiteralType(source) || source.flags & TypeFlags.String) && target.flags & TypeFlags.Index) {
11150
11155
const empty = createEmptyObjectTypeFromStringLiteral(source);
11151
- priority ^= InferencePriority.Contravariant ;
11156
+ contravariant = !contravariant ;
11152
11157
inferFromTypes(empty, (target as IndexType).type);
11153
- priority ^= InferencePriority.Contravariant ;
11158
+ contravariant = !contravariant ;
11154
11159
}
11155
11160
else if (source.flags & TypeFlags.IndexedAccess && target.flags & TypeFlags.IndexedAccess) {
11156
11161
inferFromTypes((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType);
@@ -11219,9 +11224,9 @@ namespace ts {
11219
11224
11220
11225
function inferFromContravariantTypes(source: Type, target: Type) {
11221
11226
if (strictFunctionTypes) {
11222
- priority ^= InferencePriority.Contravariant ;
11227
+ contravariant = !contravariant ;
11223
11228
inferFromTypes(source, target);
11224
- priority ^= InferencePriority.Contravariant ;
11229
+ contravariant = !contravariant ;
11225
11230
}
11226
11231
else {
11227
11232
inferFromTypes(source, target);
@@ -11400,10 +11405,19 @@ namespace ts {
11400
11405
// If all inferences were made from contravariant positions, infer a common subtype. Otherwise, if
11401
11406
// union types were requested or if all inferences were made from the return type position, infer a
11402
11407
// union type. Otherwise, infer a common supertype.
11403
- const unwidenedType = inference.priority & InferencePriority.Contravariant ? getCommonSubtype(baseCandidates) :
11404
- context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.ReturnType ? getUnionType(baseCandidates, UnionReduction.Subtype) :
11408
+ const unwidenedType = context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.ReturnType ?
11409
+ getUnionType(baseCandidates, UnionReduction.Subtype) :
11405
11410
getCommonSupertype(baseCandidates);
11406
11411
inferredType = getWidenedType(unwidenedType);
11412
+ // If we have inferred 'never' but have contravariant candidates. To get a more specific type we
11413
+ // infer from the contravariant candidates instead.
11414
+ if (inferredType.flags & TypeFlags.Never && inference.contraCandidates) {
11415
+ inferredType = getCommonSubtype(inference.contraCandidates);
11416
+ }
11417
+ }
11418
+ else if (inference.contraCandidates) {
11419
+ // We only have contravariant inferences, infer the best common subtype of those
11420
+ inferredType = getCommonSubtype(inference.contraCandidates);
11407
11421
}
11408
11422
else if (context.flags & InferenceFlags.NoDefault) {
11409
11423
// We use silentNeverType as the wildcard that signals no inferences.
0 commit comments