Merge pull request #15863 from Microsoft/fixRedundantTypeInference
Eliminate redundant work in type inference
This commit is contained in:
commit
2a9a6e821f
1 changed files with 21 additions and 29 deletions
|
@ -10097,22 +10097,11 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
function inferTypes(typeVariables: TypeVariable[], typeInferences: TypeInferences[], originalSource: Type, originalTarget: Type) {
|
function inferTypes(typeVariables: TypeVariable[], typeInferences: TypeInferences[], originalSource: Type, originalTarget: Type) {
|
||||||
let sourceStack: Type[];
|
let symbolStack: Symbol[];
|
||||||
let targetStack: Type[];
|
let visited: Map<boolean>;
|
||||||
let depth = 0;
|
|
||||||
let inferiority = 0;
|
let inferiority = 0;
|
||||||
const visited = createMap<boolean>();
|
|
||||||
inferFromTypes(originalSource, originalTarget);
|
inferFromTypes(originalSource, originalTarget);
|
||||||
|
|
||||||
function isInProcess(source: Type, target: Type) {
|
|
||||||
for (let i = 0; i < depth; i++) {
|
|
||||||
if (source === sourceStack[i] && target === targetStack[i]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function inferFromTypes(source: Type, target: Type) {
|
function inferFromTypes(source: Type, target: Type) {
|
||||||
if (!couldContainTypeVariables(target)) {
|
if (!couldContainTypeVariables(target)) {
|
||||||
return;
|
return;
|
||||||
|
@ -10240,26 +10229,29 @@ namespace ts {
|
||||||
else {
|
else {
|
||||||
source = getApparentType(source);
|
source = getApparentType(source);
|
||||||
if (source.flags & TypeFlags.Object) {
|
if (source.flags & TypeFlags.Object) {
|
||||||
if (isInProcess(source, target)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isDeeplyNestedType(source, sourceStack, depth) && isDeeplyNestedType(target, targetStack, depth)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const key = source.id + "," + target.id;
|
const key = source.id + "," + target.id;
|
||||||
if (visited.get(key)) {
|
if (visited && visited.get(key)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
visited.set(key, true);
|
(visited || (visited = createMap<boolean>())).set(key, true);
|
||||||
if (depth === 0) {
|
// If we are already processing another target type with the same associated symbol (such as
|
||||||
sourceStack = [];
|
// an instantiation of the same generic type), we do not explore this target as it would yield
|
||||||
targetStack = [];
|
// no further inferences. We exclude the static side of classes from this check since it shares
|
||||||
|
// its symbol with the instance side which would lead to false positives.
|
||||||
|
const isNonConstructorObject = target.flags & TypeFlags.Object &&
|
||||||
|
!(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class);
|
||||||
|
const symbol = isNonConstructorObject ? target.symbol : undefined;
|
||||||
|
if (symbol) {
|
||||||
|
if (contains(symbolStack, symbol)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(symbolStack || (symbolStack = [])).push(symbol);
|
||||||
|
inferFromObjectTypes(source, target);
|
||||||
|
symbolStack.pop();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
inferFromObjectTypes(source, target);
|
||||||
}
|
}
|
||||||
sourceStack[depth] = source;
|
|
||||||
targetStack[depth] = target;
|
|
||||||
depth++;
|
|
||||||
inferFromObjectTypes(source, target);
|
|
||||||
depth--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue