@@ -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