Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 9df07a8

Browse filesBrowse files
committed
Less expensive and corrected check for broadest equivalent keys
1 parent 5f37d89 commit 9df07a8
Copy full SHA for 9df07a8

File tree

Expand file treeCollapse file tree

1 file changed

+41
-35
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+41
-35
lines changed

‎src/compiler/checker.ts

Copy file name to clipboardExpand all lines: src/compiler/checker.ts
+41-35Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17770,7 +17770,7 @@ namespace ts {
1777017770
if (source.flags & TypeFlags.Singleton) return true;
1777117771
}
1777217772
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
17773-
const related = relation.get(getRelationKey(source, target, IntersectionState.None, relation));
17773+
const related = relation.get(getRelationKey(source, target, IntersectionState.None, relation, /*ignoreConstraints*/ false));
1777417774
if (related !== undefined) {
1777517775
return !!(related & RelationComparisonResult.Succeeded);
1777617776
}
@@ -18670,7 +18670,8 @@ namespace ts {
1867018670
if (overflow) {
1867118671
return Ternary.False;
1867218672
}
18673-
const id = getRelationKey(source, target, intersectionState | (inPropertyCheck ? IntersectionState.InPropertyCheck : 0), relation);
18673+
const keyIntersectionState = intersectionState | (inPropertyCheck ? IntersectionState.InPropertyCheck : 0);
18674+
const id = getRelationKey(source, target, keyIntersectionState, relation, /*ingnoreConstraints*/ false);
1867418675
const entry = relation.get(id);
1867518676
if (entry !== undefined) {
1867618677
if (reportErrors && entry & RelationComparisonResult.Failed && !(entry & RelationComparisonResult.Reported)) {
@@ -18697,16 +18698,13 @@ namespace ts {
1869718698
targetStack = [];
1869818699
}
1869918700
else {
18700-
// generate a key where all type parameter id positions are replaced with unconstrained type parameter ids
18701-
// this isn't perfect - nested type references passed as type arguments will muck up the indexes and thus
18702-
// prevent finding matches- but it should hit up the common cases
18703-
const broadestEquivalentId = id.split(",").map(i => i.replace(/-\d+/g, (_match, offset: number) => {
18704-
const index = length(id.slice(0, offset).match(/[-=]/g) || undefined);
18705-
return `=${index}`;
18706-
})).join(",");
18701+
// A key that starts with "*" is an indication that we have type references that reference constrained
18702+
// type parameters. For such keys we also check against the key we would have gotten if all type parameters
18703+
// were unconstrained.
18704+
const broadestEquivalentId = id.startsWith("*") ? getRelationKey(source, target, keyIntersectionState, relation, /*ignoreConstraints*/ true) : undefined;
1870718705
for (let i = 0; i < maybeCount; i++) {
1870818706
// If source and target are already being compared, consider them related with assumptions
18709-
if (id === maybeKeys[i] || broadestEquivalentId === maybeKeys[i]) {
18707+
if (id === maybeKeys[i] || broadestEquivalentId && broadestEquivalentId === maybeKeys[i]) {
1871018708
return Ternary.Maybe;
1871118709
}
1871218710
}
@@ -20261,47 +20259,55 @@ namespace ts {
2026120259
return isNonDeferredTypeReference(type) && some(getTypeArguments(type), t => !!(t.flags & TypeFlags.TypeParameter) || isTypeReferenceWithGenericArguments(t));
2026220260
}
2026320261

20264-
/**
20265-
* getTypeReferenceId(A<T, number, U>) returns "111=0-12=1"
20266-
* where A.id=111 and number.id=12
20267-
*/
20268-
function getTypeReferenceId(type: TypeReference, typeParameters: Type[], depth = 0) {
20269-
let result = "" + type.target.id;
20270-
for (const t of getTypeArguments(type)) {
20271-
if (isUnconstrainedTypeParameter(t)) {
20272-
let index = typeParameters.indexOf(t);
20273-
if (index < 0) {
20274-
index = typeParameters.length;
20275-
typeParameters.push(t);
20262+
function getGenericTypeReferenceRelationKey(source: TypeReference, target: TypeReference, postFix: string, ignoreConstraints: boolean) {
20263+
const typeParameters: Type[] = [];
20264+
let constraintMarker = "";
20265+
const sourceId = getTypeReferenceId(source, 0);
20266+
const targetId = getTypeReferenceId(target, 0);
20267+
return `${constraintMarker}${sourceId},${targetId}${postFix}`;
20268+
// getTypeReferenceId(A<T, number, U>) returns "111=0-12=1"
20269+
// where A.id=111 and number.id=12
20270+
function getTypeReferenceId(type: TypeReference, depth = 0) {
20271+
let result = "" + type.target.id;
20272+
for (const t of getTypeArguments(type)) {
20273+
if (t.flags & TypeFlags.TypeParameter) {
20274+
if (ignoreConstraints || isUnconstrainedTypeParameter(t)) {
20275+
let index = typeParameters.indexOf(t);
20276+
if (index < 0) {
20277+
index = typeParameters.length;
20278+
typeParameters.push(t);
20279+
}
20280+
result += "=" + index;
20281+
continue;
20282+
}
20283+
// We mark type references that reference constrained type parameters such that we know to obtain
20284+
// and look for a "broadest equivalent key" in the cache.
20285+
constraintMarker = "*";
20286+
}
20287+
else if (depth < 4 && isTypeReferenceWithGenericArguments(t)) {
20288+
result += "<" + getTypeReferenceId(t as TypeReference, depth + 1) + ">";
20289+
continue;
2027620290
}
20277-
result += "=" + index;
20278-
}
20279-
else if (depth < 4 && isTypeReferenceWithGenericArguments(t)) {
20280-
result += "<" + getTypeReferenceId(t as TypeReference, typeParameters, depth + 1) + ">";
20281-
}
20282-
else {
2028320291
result += "-" + t.id;
2028420292
}
20293+
return result;
2028520294
}
20286-
return result;
2028720295
}
2028820296

2028920297
/**
2029020298
* To improve caching, the relation key for two generic types uses the target's id plus ids of the type parameters.
2029120299
* For other cases, the types ids are used.
2029220300
*/
20293-
function getRelationKey(source: Type, target: Type, intersectionState: IntersectionState, relation: ESMap<string, RelationComparisonResult>) {
20301+
function getRelationKey(source: Type, target: Type, intersectionState: IntersectionState, relation: ESMap<string, RelationComparisonResult>, ignoreConstraints: boolean) {
2029420302
if (relation === identityRelation && source.id > target.id) {
2029520303
const temp = source;
2029620304
source = target;
2029720305
target = temp;
2029820306
}
2029920307
const postFix = intersectionState ? ":" + intersectionState : "";
20300-
if (isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target)) {
20301-
const typeParameters: Type[] = [];
20302-
return getTypeReferenceId(source as TypeReference, typeParameters) + "," + getTypeReferenceId(target as TypeReference, typeParameters) + postFix;
20303-
}
20304-
return source.id + "," + target.id + postFix;
20308+
return isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target) ?
20309+
getGenericTypeReferenceRelationKey(source as TypeReference, target as TypeReference, postFix, ignoreConstraints) :
20310+
`${source.id},${target.id}${postFix}`;
2030520311
}
2030620312

2030720313
// Invoke the callback for each underlying property symbol of the given symbol and return the first

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.