@@ -8810,8 +8810,7 @@ namespace ts {
8810
8810
return true;
8811
8811
}
8812
8812
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));
8815
8814
if (related !== undefined) {
8816
8815
return related === RelationComparisonResult.Succeeded;
8817
8816
}
@@ -9212,7 +9211,7 @@ namespace ts {
9212
9211
if (overflow) {
9213
9212
return Ternary.False;
9214
9213
}
9215
- const id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id ;
9214
+ const id = getRelationKey( source, target, relation) ;
9216
9215
const related = relation.get(id);
9217
9216
if (related !== undefined) {
9218
9217
if (reportErrors && related === RelationComparisonResult.Failed) {
@@ -9777,6 +9776,53 @@ namespace ts {
9777
9776
}
9778
9777
}
9779
9778
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
+
9780
9826
// Invoke the callback for each underlying property symbol of the given symbol and return the first
9781
9827
// value that isn't undefined.
9782
9828
function forEachProperty<T>(prop: Symbol, callback: (p: Symbol) => T): T {
0 commit comments