Skip to content

Commit 6da2625

Browse files
authored
Bail when comparing a specialized form of an already ongoing comparison (#42727)
* When structurally comparing similar types, check if we are already in the middle of a more general comparison of those same types * Do the same, but with only string manipulations
1 parent c117c26 commit 6da2625

5 files changed

+869
-2
lines changed

src/compiler/checker.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -17750,9 +17750,16 @@ namespace ts {
1775017750
targetStack = [];
1775117751
}
1775217752
else {
17753+
// generate a key where all type parameter id positions are replaced with unconstrained type parameter ids
17754+
// this isn't perfect - nested type references passed as type arguments will muck up the indexes and thus
17755+
// prevent finding matches- but it should hit up the common cases
17756+
const broadestEquivalentId = id.split(",").map(i => i.replace(/-\d+/g, (_match, offset: number) => {
17757+
const index = length(id.slice(0, offset).match(/[-=]/g) || undefined);
17758+
return `=${index}`;
17759+
})).join(",");
1775317760
for (let i = 0; i < maybeCount; i++) {
1775417761
// If source and target are already being compared, consider them related with assumptions
17755-
if (id === maybeKeys[i]) {
17762+
if (id === maybeKeys[i] || broadestEquivalentId === maybeKeys[i]) {
1775617763
return Ternary.Maybe;
1775717764
}
1775817765
}
@@ -19192,7 +19199,7 @@ namespace ts {
1919219199
}
1919319200

1919419201
function isTypeReferenceWithGenericArguments(type: Type): boolean {
19195-
return isNonDeferredTypeReference(type) && some(getTypeArguments(type), t => isUnconstrainedTypeParameter(t) || isTypeReferenceWithGenericArguments(t));
19202+
return isNonDeferredTypeReference(type) && some(getTypeArguments(type), t => !!(t.flags & TypeFlags.TypeParameter) || isTypeReferenceWithGenericArguments(t));
1919619203
}
1919719204

1919819205
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
//// [performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.ts]
2+
export declare type ThenArg<T> = T extends any ? any : T extends PromiseLike<infer U> ? U : T;
3+
4+
export interface InterfaceA<T> {
5+
filter(callback: (newValue: T, oldValue: T) => boolean): InterfaceA<T>;
6+
map<D>(callback: (value: T) => D): InterfaceA<D>;
7+
await<R extends ThenArg<T>>(): InterfaceA<R>;
8+
awaitLatest<R extends ThenArg<T>>(): InterfaceA<R>;
9+
awaitOrdered<R extends ThenArg<T>>(): InterfaceA<R>;
10+
awaitOrdered2<R extends ThenArg<T>>(): InterfaceA<R>;
11+
awaitOrdered3<R extends ThenArg<T>>(): InterfaceA<R>;
12+
awaitOrdered4<R extends ThenArg<T>>(): InterfaceA<R>;
13+
awaitOrdered5<R extends ThenArg<T>>(): InterfaceA<R>;
14+
awaitOrdered6<R extends ThenArg<T>>(): InterfaceA<R>;
15+
awaitOrdered7<R extends ThenArg<T>>(): InterfaceA<R>;
16+
awaitOrdered8<R extends ThenArg<T>>(): InterfaceA<R>;
17+
awaitOrdered9<R extends ThenArg<T>>(): InterfaceA<R>;
18+
}
19+
20+
export interface InterfaceB<T> extends InterfaceA<T> {
21+
map<D>(callback: (value: T) => D): InterfaceB<D>;
22+
await<R extends ThenArg<T>>(): InterfaceB<R>;
23+
awaitLatest<R extends ThenArg<T>>(): InterfaceB<R>;
24+
awaitOrdered<R extends ThenArg<T>>(): InterfaceB<R>;
25+
awaitOrdered2<R extends ThenArg<T>>(): InterfaceB<R>;
26+
awaitOrdered3<R extends ThenArg<T>>(): InterfaceB<R>;
27+
awaitOrdered4<R extends ThenArg<T>>(): InterfaceB<R>;
28+
awaitOrdered5<R extends ThenArg<T>>(): InterfaceB<R>;
29+
awaitOrdered6<R extends ThenArg<T>>(): InterfaceB<R>;
30+
awaitOrdered7<R extends ThenArg<T>>(): InterfaceB<R>;
31+
awaitOrdered8<R extends ThenArg<T>>(): InterfaceB<R>;
32+
awaitOrdered9<R extends ThenArg<T>>(): InterfaceB<R>;
33+
}
34+
35+
export class A<T> implements InterfaceB<T> {
36+
public filter(callback: (newValue: T, oldValue: T) => boolean): B<T> {
37+
return undefined as any;
38+
}
39+
40+
public map<D>(callback: (value: T) => D): B<D> {
41+
return undefined as any;
42+
}
43+
44+
public await<R extends ThenArg<T>>(): B<R> {
45+
return undefined as any;
46+
}
47+
48+
public awaitOrdered<R extends ThenArg<T>>(): B<R> {
49+
return undefined as any;
50+
}
51+
52+
public awaitOrdered2<R extends ThenArg<T>>(): B<R> {
53+
return undefined as any;
54+
}
55+
56+
public awaitOrdered3<R extends ThenArg<T>>(): B<R> {
57+
return undefined as any;
58+
}
59+
60+
public awaitOrdered4<R extends ThenArg<T>>(): B<R> {
61+
return undefined as any;
62+
}
63+
64+
public awaitOrdered5<R extends ThenArg<T>>(): B<R> {
65+
return undefined as any;
66+
}
67+
68+
public awaitOrdered6<R extends ThenArg<T>>(): B<R> {
69+
return undefined as any;
70+
}
71+
72+
public awaitOrdered7<R extends ThenArg<T>>(): B<R> {
73+
return undefined as any;
74+
}
75+
76+
public awaitOrdered8<R extends ThenArg<T>>(): B<R> {
77+
return undefined as any;
78+
}
79+
80+
public awaitOrdered9<R extends ThenArg<T>>(): B<R> {
81+
return undefined as any;
82+
}
83+
84+
public awaitLatest<R extends ThenArg<T>>(): B<R> {
85+
return undefined as any;
86+
}
87+
}
88+
89+
export class B<T> extends A<T> { }
90+
91+
//// [performanceComparisonOfStructurallyIdenticalInterfacesWithGenericSignatures.js]
92+
"use strict";
93+
var __extends = (this && this.__extends) || (function () {
94+
var extendStatics = function (d, b) {
95+
extendStatics = Object.setPrototypeOf ||
96+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
97+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
98+
return extendStatics(d, b);
99+
};
100+
return function (d, b) {
101+
if (typeof b !== "function" && b !== null)
102+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
103+
extendStatics(d, b);
104+
function __() { this.constructor = d; }
105+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
106+
};
107+
})();
108+
exports.__esModule = true;
109+
exports.B = exports.A = void 0;
110+
var A = /** @class */ (function () {
111+
function A() {
112+
}
113+
A.prototype.filter = function (callback) {
114+
return undefined;
115+
};
116+
A.prototype.map = function (callback) {
117+
return undefined;
118+
};
119+
A.prototype.await = function () {
120+
return undefined;
121+
};
122+
A.prototype.awaitOrdered = function () {
123+
return undefined;
124+
};
125+
A.prototype.awaitOrdered2 = function () {
126+
return undefined;
127+
};
128+
A.prototype.awaitOrdered3 = function () {
129+
return undefined;
130+
};
131+
A.prototype.awaitOrdered4 = function () {
132+
return undefined;
133+
};
134+
A.prototype.awaitOrdered5 = function () {
135+
return undefined;
136+
};
137+
A.prototype.awaitOrdered6 = function () {
138+
return undefined;
139+
};
140+
A.prototype.awaitOrdered7 = function () {
141+
return undefined;
142+
};
143+
A.prototype.awaitOrdered8 = function () {
144+
return undefined;
145+
};
146+
A.prototype.awaitOrdered9 = function () {
147+
return undefined;
148+
};
149+
A.prototype.awaitLatest = function () {
150+
return undefined;
151+
};
152+
return A;
153+
}());
154+
exports.A = A;
155+
var B = /** @class */ (function (_super) {
156+
__extends(B, _super);
157+
function B() {
158+
return _super !== null && _super.apply(this, arguments) || this;
159+
}
160+
return B;
161+
}(A));
162+
exports.B = B;

0 commit comments

Comments
 (0)