Skip to content

Commit 2b9aba4

Browse files
authored
Merge pull request #17984 from Microsoft/typeReferenceRelations
Recursive-related-check generic type references based on the id of their targets and type arguments
2 parents deaddb5 + f30931c commit 2b9aba4

File tree

4 files changed

+1428
-9
lines changed

4 files changed

+1428
-9
lines changed

src/compiler/checker.ts

+49-3
Original file line numberDiff line numberDiff line change
@@ -8810,8 +8810,7 @@ namespace ts {
88108810
return true;
88118811
}
88128812
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
8813-
const id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id;
8814-
const related = relation.get(id);
8813+
const related = relation.get(getRelationKey(source, target, relation));
88158814
if (related !== undefined) {
88168815
return related === RelationComparisonResult.Succeeded;
88178816
}
@@ -9212,7 +9211,7 @@ namespace ts {
92129211
if (overflow) {
92139212
return Ternary.False;
92149213
}
9215-
const id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id;
9214+
const id = getRelationKey(source, target, relation);
92169215
const related = relation.get(id);
92179216
if (related !== undefined) {
92189217
if (reportErrors && related === RelationComparisonResult.Failed) {
@@ -9777,6 +9776,53 @@ namespace ts {
97779776
}
97789777
}
97799778

9779+
function isUnconstrainedTypeParameter(type: Type) {
9780+
return type.flags & TypeFlags.TypeParameter && !getConstraintFromTypeParameter(<TypeParameter>type);
9781+
}
9782+
9783+
function isTypeReferenceWithGenericArguments(type: Type) {
9784+
return getObjectFlags(type) & ObjectFlags.Reference && some((<TypeReference>type).typeArguments, isUnconstrainedTypeParameter);
9785+
}
9786+
9787+
/**
9788+
* getTypeReferenceId(A<T, number, U>) returns "111=0-12=1"
9789+
* where A.id=111 and number.id=12
9790+
*/
9791+
function getTypeReferenceId(type: TypeReference, typeParameters: Type[]) {
9792+
let result = "" + type.target.id;
9793+
for (const t of type.typeArguments) {
9794+
if (isUnconstrainedTypeParameter(t)) {
9795+
let index = indexOf(typeParameters, t);
9796+
if (index < 0) {
9797+
index = typeParameters.length;
9798+
typeParameters.push(t);
9799+
}
9800+
result += "=" + index;
9801+
}
9802+
else {
9803+
result += "-" + t.id;
9804+
}
9805+
}
9806+
return result;
9807+
}
9808+
9809+
/**
9810+
* To improve caching, the relation key for two generic types uses the target's id plus ids of the type parameters.
9811+
* For other cases, the types ids are used.
9812+
*/
9813+
function getRelationKey(source: Type, target: Type, relation: Map<RelationComparisonResult>) {
9814+
if (relation === identityRelation && source.id > target.id) {
9815+
const temp = source;
9816+
source = target;
9817+
target = temp;
9818+
}
9819+
if (isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target)) {
9820+
const typeParameters: Type[] = [];
9821+
return getTypeReferenceId(<TypeReference>source, typeParameters) + "," + getTypeReferenceId(<TypeReference>target, typeParameters);
9822+
}
9823+
return source.id + "," + target.id;
9824+
}
9825+
97809826
// Invoke the callback for each underlying property symbol of the given symbol and return the first
97819827
// value that isn't undefined.
97829828
function forEachProperty<T>(prop: Symbol, callback: (p: Symbol) => T): T {

0 commit comments

Comments
 (0)