@@ -15486,8 +15486,7 @@ namespace ts {
15486
15486
let visited: Map<number>;
15487
15487
let bivariant = false;
15488
15488
let propagationType: Type;
15489
- let inferenceMatch = false;
15490
- let inferenceIncomplete = false;
15489
+ let inferencePriority = InferencePriority.MaxValue;
15491
15490
let allowComplexConstraintInference = true;
15492
15491
inferFromTypes(originalSource, originalTarget);
15493
15492
@@ -15600,7 +15599,7 @@ namespace ts {
15600
15599
clearCachedInferences(inferences);
15601
15600
}
15602
15601
}
15603
- inferenceMatch = true ;
15602
+ inferencePriority = Math.min(inferencePriority, priority) ;
15604
15603
return;
15605
15604
}
15606
15605
else {
@@ -15694,19 +15693,15 @@ namespace ts {
15694
15693
const key = source.id + "," + target.id;
15695
15694
const status = visited && visited.get(key);
15696
15695
if (status !== undefined) {
15697
- if (status & 1) inferenceMatch = true;
15698
- if (status & 2) inferenceIncomplete = true;
15696
+ inferencePriority = Math.min(inferencePriority, status);
15699
15697
return;
15700
15698
}
15701
- (visited || (visited = createMap<number>())).set(key, 0);
15702
- const saveInferenceMatch = inferenceMatch;
15703
- const saveInferenceIncomplete = inferenceIncomplete;
15704
- inferenceMatch = false;
15705
- inferenceIncomplete = false;
15699
+ (visited || (visited = createMap<number>())).set(key, -1);
15700
+ const saveInferencePriority = inferencePriority;
15701
+ inferencePriority = InferencePriority.MaxValue;
15706
15702
action(source, target);
15707
- visited.set(key, (inferenceMatch ? 1 : 0) | (inferenceIncomplete ? 2 : 0));
15708
- inferenceMatch = inferenceMatch || saveInferenceMatch;
15709
- inferenceIncomplete = inferenceIncomplete || saveInferenceIncomplete;
15703
+ visited.set(key, inferencePriority);
15704
+ inferencePriority = Math.min(inferencePriority, saveInferencePriority);
15710
15705
}
15711
15706
15712
15707
function inferFromMatchingType(source: Type, targets: Type[], matches: (s: Type, t: Type) => boolean) {
@@ -15778,31 +15773,32 @@ namespace ts {
15778
15773
let nakedTypeVariable: Type | undefined;
15779
15774
const sources = source.flags & TypeFlags.Union ? (<UnionType>source).types : [source];
15780
15775
const matched = new Array<boolean>(sources.length);
15781
- const saveInferenceIncomplete = inferenceIncomplete;
15782
- inferenceIncomplete = false;
15776
+ let inferenceCircularity = false;
15783
15777
// First infer to types that are not naked type variables. For each source type we
15784
- // track whether inferences were made from that particular type to some target.
15778
+ // track whether inferences were made from that particular type to some target with
15779
+ // equal priority (i.e. of equal quality) to what we would infer for a naked type
15780
+ // parameter.
15785
15781
for (const t of targets) {
15786
15782
if (getInferenceInfoForType(t)) {
15787
15783
nakedTypeVariable = t;
15788
15784
typeVariableCount++;
15789
15785
}
15790
15786
else {
15791
15787
for (let i = 0; i < sources.length; i++) {
15792
- const saveInferenceMatch = inferenceMatch ;
15793
- inferenceMatch = false ;
15788
+ const saveInferencePriority = inferencePriority ;
15789
+ inferencePriority = InferencePriority.MaxValue ;
15794
15790
inferFromTypes(sources[i], t);
15795
- if (inferenceMatch) matched[i] = true;
15796
- inferenceMatch = inferenceMatch || saveInferenceMatch;
15791
+ if (inferencePriority === priority) matched[i] = true;
15792
+ inferenceCircularity = inferenceCircularity || inferencePriority < 0;
15793
+ inferencePriority = Math.min(inferencePriority, saveInferencePriority);
15797
15794
}
15798
15795
}
15799
15796
}
15800
- const inferenceComplete = !inferenceIncomplete;
15801
- inferenceIncomplete = inferenceIncomplete || saveInferenceIncomplete;
15802
- // If the target has a single naked type variable and inference completed (meaning we
15803
- // explored the types fully), create a union of the source types from which no inferences
15804
- // have been made so far and infer from that union to the naked type variable.
15805
- if (typeVariableCount === 1 && inferenceComplete) {
15797
+ // If the target has a single naked type variable and no inference circularities were
15798
+ // encountered above (meaning we explored the types fully), create a union of the source
15799
+ // types from which no inferences have been made so far and infer from that union to the
15800
+ // naked type variable.
15801
+ if (typeVariableCount === 1 && !inferenceCircularity) {
15806
15802
const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s);
15807
15803
if (unmatched.length) {
15808
15804
inferFromTypes(getUnionType(unmatched), nakedTypeVariable!);
@@ -15905,7 +15901,7 @@ namespace ts {
15905
15901
const symbol = isNonConstructorObject ? target.symbol : undefined;
15906
15902
if (symbol) {
15907
15903
if (contains(symbolStack, symbol)) {
15908
- inferenceIncomplete = true ;
15904
+ inferencePriority = -1 ;
15909
15905
return;
15910
15906
}
15911
15907
(symbolStack || (symbolStack = [])).push(symbol);
0 commit comments