Skip to content

Commit e9ccb16

Browse files
committed
Eliminate redundant exploration in type inference
1 parent 687ab54 commit e9ccb16

File tree

1 file changed

+20
-17
lines changed

1 file changed

+20
-17
lines changed

src/compiler/checker.ts

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10096,21 +10096,29 @@ namespace ts {
1009610096
inferTypes(context.signature.typeParameters, context.inferences, originalSource, originalTarget);
1009710097
}
1009810098

10099+
function getSymbolForInference(type: Type) {
10100+
// Exclude the static side of classes since it shares its symbol with the instance side which leads
10101+
// to false positives.
10102+
return type.flags & TypeFlags.Object && !(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class) ? type.symbol : undefined;
10103+
}
10104+
1009910105
function inferTypes(typeVariables: TypeVariable[], typeInferences: TypeInferences[], originalSource: Type, originalTarget: Type) {
10100-
let sourceStack: Type[];
10101-
let targetStack: Type[];
10106+
let stack: Type[];
1010210107
let depth = 0;
1010310108
let inferiority = 0;
1010410109
const visited = createMap<boolean>();
1010510110
inferFromTypes(originalSource, originalTarget);
1010610111

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;
10112+
function isInstantiationInProcess(type: Type) {
10113+
const symbol = getSymbolForInference(type);
10114+
if (symbol) {
10115+
for (let i = 0; i < depth; i++) {
10116+
const t = stack[i];
10117+
if (getSymbolForInference(t) === symbol) {
10118+
return true;
10119+
}
1011110120
}
1011210121
}
10113-
return false;
1011410122
}
1011510123

1011610124
function inferFromTypes(source: Type, target: Type) {
@@ -10240,23 +10248,18 @@ namespace ts {
1024010248
else {
1024110249
source = getApparentType(source);
1024210250
if (source.flags & TypeFlags.Object) {
10243-
if (isInProcess(source, target)) {
10244-
return;
10245-
}
10246-
if (isDeeplyNestedType(source, sourceStack, depth) && isDeeplyNestedType(target, targetStack, depth)) {
10251+
// If we are already processing another target type with the same associated symbol (such as
10252+
// an instantiation of the same generic type), we do not explore this target as it would yield
10253+
// no further inferences.
10254+
if (isInstantiationInProcess(target)) {
1024710255
return;
1024810256
}
1024910257
const key = source.id + "," + target.id;
1025010258
if (visited.get(key)) {
1025110259
return;
1025210260
}
1025310261
visited.set(key, true);
10254-
if (depth === 0) {
10255-
sourceStack = [];
10256-
targetStack = [];
10257-
}
10258-
sourceStack[depth] = source;
10259-
targetStack[depth] = target;
10262+
(stack || (stack = []))[depth] = target;
1026010263
depth++;
1026110264
inferFromObjectTypes(source, target);
1026210265
depth--;

0 commit comments

Comments
 (0)