Merge pull request #15863 from Microsoft/fixRedundantTypeInference

Eliminate redundant work in type inference
This commit is contained in:
Anders Hejlsberg 2017-05-16 09:34:31 -07:00 committed by GitHub
commit 2a9a6e821f

View file

@ -10097,22 +10097,11 @@ namespace ts {
}
function inferTypes(typeVariables: TypeVariable[], typeInferences: TypeInferences[], originalSource: Type, originalTarget: Type) {
let sourceStack: Type[];
let targetStack: Type[];
let depth = 0;
let symbolStack: Symbol[];
let visited: Map<boolean>;
let inferiority = 0;
const visited = createMap<boolean>();
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) {
if (!couldContainTypeVariables(target)) {
return;
@ -10240,26 +10229,29 @@ namespace ts {
else {
source = getApparentType(source);
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;
if (visited.get(key)) {
if (visited && visited.get(key)) {
return;
}
visited.set(key, true);
if (depth === 0) {
sourceStack = [];
targetStack = [];
(visited || (visited = createMap<boolean>())).set(key, true);
// If we are already processing another target type with the same associated symbol (such as
// an instantiation of the same generic type), we do not explore this target as it would yield
// 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--;
}
}
}