Skip to content

Commit 2a9a6e8

Browse files
authored
Merge pull request #15863 from Microsoft/fixRedundantTypeInference
Eliminate redundant work in type inference
2 parents d51e467 + ed1a6c1 commit 2a9a6e8

File tree

1 file changed

+21
-29
lines changed

1 file changed

+21
-29
lines changed

src/compiler/checker.ts

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10097,22 +10097,11 @@ namespace ts {
1009710097
}
1009810098

1009910099
function inferTypes(typeVariables: TypeVariable[], typeInferences: TypeInferences[], originalSource: Type, originalTarget: Type) {
10100-
let sourceStack: Type[];
10101-
let targetStack: Type[];
10102-
let depth = 0;
10100+
let symbolStack: Symbol[];
10101+
let visited: Map<boolean>;
1010310102
let inferiority = 0;
10104-
const visited = createMap<boolean>();
1010510103
inferFromTypes(originalSource, originalTarget);
1010610104

10107-
function isInProcess(source: Type, target: Type) {
10108-
for (let i = 0; i < depth; i++) {
10109-
if (source === sourceStack[i] && target === targetStack[i]) {
10110-
return true;
10111-
}
10112-
}
10113-
return false;
10114-
}
10115-
1011610105
function inferFromTypes(source: Type, target: Type) {
1011710106
if (!couldContainTypeVariables(target)) {
1011810107
return;
@@ -10240,26 +10229,29 @@ namespace ts {
1024010229
else {
1024110230
source = getApparentType(source);
1024210231
if (source.flags & TypeFlags.Object) {
10243-
if (isInProcess(source, target)) {
10244-
return;
10245-
}
10246-
if (isDeeplyNestedType(source, sourceStack, depth) && isDeeplyNestedType(target, targetStack, depth)) {
10247-
return;
10248-
}
1024910232
const key = source.id + "," + target.id;
10250-
if (visited.get(key)) {
10233+
if (visited && visited.get(key)) {
1025110234
return;
1025210235
}
10253-
visited.set(key, true);
10254-
if (depth === 0) {
10255-
sourceStack = [];
10256-
targetStack = [];
10236+
(visited || (visited = createMap<boolean>())).set(key, true);
10237+
// If we are already processing another target type with the same associated symbol (such as
10238+
// an instantiation of the same generic type), we do not explore this target as it would yield
10239+
// no further inferences. We exclude the static side of classes from this check since it shares
10240+
// its symbol with the instance side which would lead to false positives.
10241+
const isNonConstructorObject = target.flags & TypeFlags.Object &&
10242+
!(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class);
10243+
const symbol = isNonConstructorObject ? target.symbol : undefined;
10244+
if (symbol) {
10245+
if (contains(symbolStack, symbol)) {
10246+
return;
10247+
}
10248+
(symbolStack || (symbolStack = [])).push(symbol);
10249+
inferFromObjectTypes(source, target);
10250+
symbolStack.pop();
10251+
}
10252+
else {
10253+
inferFromObjectTypes(source, target);
1025710254
}
10258-
sourceStack[depth] = source;
10259-
targetStack[depth] = target;
10260-
depth++;
10261-
inferFromObjectTypes(source, target);
10262-
depth--;
1026310255
}
1026410256
}
1026510257
}

0 commit comments

Comments
 (0)