mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 03:23:08 -06:00
Stricter criteria for eliminating types in unions during inference
This commit is contained in:
parent
2a2866c3a9
commit
a81ce061de
@ -15486,8 +15486,7 @@ namespace ts {
|
||||
let visited: Map<number>;
|
||||
let bivariant = false;
|
||||
let propagationType: Type;
|
||||
let inferenceMatch = false;
|
||||
let inferenceIncomplete = false;
|
||||
let inferencePriority = InferencePriority.MaxValue;
|
||||
let allowComplexConstraintInference = true;
|
||||
inferFromTypes(originalSource, originalTarget);
|
||||
|
||||
@ -15600,7 +15599,7 @@ namespace ts {
|
||||
clearCachedInferences(inferences);
|
||||
}
|
||||
}
|
||||
inferenceMatch = true;
|
||||
inferencePriority = Math.min(inferencePriority, priority);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
@ -15694,19 +15693,15 @@ namespace ts {
|
||||
const key = source.id + "," + target.id;
|
||||
const status = visited && visited.get(key);
|
||||
if (status !== undefined) {
|
||||
if (status & 1) inferenceMatch = true;
|
||||
if (status & 2) inferenceIncomplete = true;
|
||||
inferencePriority = Math.min(inferencePriority, status);
|
||||
return;
|
||||
}
|
||||
(visited || (visited = createMap<number>())).set(key, 0);
|
||||
const saveInferenceMatch = inferenceMatch;
|
||||
const saveInferenceIncomplete = inferenceIncomplete;
|
||||
inferenceMatch = false;
|
||||
inferenceIncomplete = false;
|
||||
(visited || (visited = createMap<number>())).set(key, -1);
|
||||
const saveInferencePriority = inferencePriority;
|
||||
inferencePriority = InferencePriority.MaxValue;
|
||||
action(source, target);
|
||||
visited.set(key, (inferenceMatch ? 1 : 0) | (inferenceIncomplete ? 2 : 0));
|
||||
inferenceMatch = inferenceMatch || saveInferenceMatch;
|
||||
inferenceIncomplete = inferenceIncomplete || saveInferenceIncomplete;
|
||||
visited.set(key, inferencePriority);
|
||||
inferencePriority = Math.min(inferencePriority, saveInferencePriority);
|
||||
}
|
||||
|
||||
function inferFromMatchingType(source: Type, targets: Type[], matches: (s: Type, t: Type) => boolean) {
|
||||
@ -15778,10 +15773,11 @@ namespace ts {
|
||||
let nakedTypeVariable: Type | undefined;
|
||||
const sources = source.flags & TypeFlags.Union ? (<UnionType>source).types : [source];
|
||||
const matched = new Array<boolean>(sources.length);
|
||||
const saveInferenceIncomplete = inferenceIncomplete;
|
||||
inferenceIncomplete = false;
|
||||
let inferenceCircularity = false;
|
||||
// First infer to types that are not naked type variables. For each source type we
|
||||
// track whether inferences were made from that particular type to some target.
|
||||
// track whether inferences were made from that particular type to some target with
|
||||
// equal priority (i.e. of equal quality) to what we would infer for a naked type
|
||||
// parameter.
|
||||
for (const t of targets) {
|
||||
if (getInferenceInfoForType(t)) {
|
||||
nakedTypeVariable = t;
|
||||
@ -15789,20 +15785,20 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < sources.length; i++) {
|
||||
const saveInferenceMatch = inferenceMatch;
|
||||
inferenceMatch = false;
|
||||
const saveInferencePriority = inferencePriority;
|
||||
inferencePriority = InferencePriority.MaxValue;
|
||||
inferFromTypes(sources[i], t);
|
||||
if (inferenceMatch) matched[i] = true;
|
||||
inferenceMatch = inferenceMatch || saveInferenceMatch;
|
||||
if (inferencePriority === priority) matched[i] = true;
|
||||
inferenceCircularity = inferenceCircularity || inferencePriority < 0;
|
||||
inferencePriority = Math.min(inferencePriority, saveInferencePriority);
|
||||
}
|
||||
}
|
||||
}
|
||||
const inferenceComplete = !inferenceIncomplete;
|
||||
inferenceIncomplete = inferenceIncomplete || saveInferenceIncomplete;
|
||||
// If the target has a single naked type variable and inference completed (meaning we
|
||||
// explored the types fully), create a union of the source types from which no inferences
|
||||
// have been made so far and infer from that union to the naked type variable.
|
||||
if (typeVariableCount === 1 && inferenceComplete) {
|
||||
// If the target has a single naked type variable and no inference circularities were
|
||||
// encountered above (meaning we explored the types fully), create a union of the source
|
||||
// types from which no inferences have been made so far and infer from that union to the
|
||||
// naked type variable.
|
||||
if (typeVariableCount === 1 && !inferenceCircularity) {
|
||||
const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s);
|
||||
if (unmatched.length) {
|
||||
inferFromTypes(getUnionType(unmatched), nakedTypeVariable!);
|
||||
@ -15905,7 +15901,7 @@ namespace ts {
|
||||
const symbol = isNonConstructorObject ? target.symbol : undefined;
|
||||
if (symbol) {
|
||||
if (contains(symbolStack, symbol)) {
|
||||
inferenceIncomplete = true;
|
||||
inferencePriority = -1;
|
||||
return;
|
||||
}
|
||||
(symbolStack || (symbolStack = [])).push(symbol);
|
||||
|
||||
@ -4471,6 +4471,7 @@ namespace ts {
|
||||
LiteralKeyof = 1 << 5, // Inference made from a string literal to a keyof T
|
||||
NoConstraints = 1 << 6, // Don't infer from constraints of instantiable types
|
||||
AlwaysStrict = 1 << 7, // Always use strict rules for contravariant inferences
|
||||
MaxValue = 1 << 8, // Seed for inference priority tracking
|
||||
|
||||
PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user