Skip to content

Commit

Permalink
Merge pull request #17984 from Microsoft/typeReferenceRelations
Browse files Browse the repository at this point in the history
Recursive-related-check generic type references based on the id of their targets and type arguments
  • Loading branch information
sandersn authored Aug 23, 2017
2 parents deaddb5 + f30931c commit 2b9aba4
Show file tree
Hide file tree
Showing 4 changed files with 1,428 additions and 9 deletions.
52 changes: 49 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8810,8 +8810,7 @@ namespace ts {
return true;
}
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
const id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id;
const related = relation.get(id);
const related = relation.get(getRelationKey(source, target, relation));
if (related !== undefined) {
return related === RelationComparisonResult.Succeeded;
}
Expand Down Expand Up @@ -9212,7 +9211,7 @@ namespace ts {
if (overflow) {
return Ternary.False;
}
const id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id;
const id = getRelationKey(source, target, relation);
const related = relation.get(id);
if (related !== undefined) {
if (reportErrors && related === RelationComparisonResult.Failed) {
Expand Down Expand Up @@ -9777,6 +9776,53 @@ namespace ts {
}
}

function isUnconstrainedTypeParameter(type: Type) {
return type.flags & TypeFlags.TypeParameter && !getConstraintFromTypeParameter(<TypeParameter>type);
}

function isTypeReferenceWithGenericArguments(type: Type) {
return getObjectFlags(type) & ObjectFlags.Reference && some((<TypeReference>type).typeArguments, isUnconstrainedTypeParameter);
}

/**
* getTypeReferenceId(A<T, number, U>) returns "111=0-12=1"
* where A.id=111 and number.id=12
*/
function getTypeReferenceId(type: TypeReference, typeParameters: Type[]) {
let result = "" + type.target.id;
for (const t of type.typeArguments) {
if (isUnconstrainedTypeParameter(t)) {
let index = indexOf(typeParameters, t);
if (index < 0) {
index = typeParameters.length;
typeParameters.push(t);
}
result += "=" + index;
}
else {
result += "-" + t.id;
}
}
return result;
}

/**
* To improve caching, the relation key for two generic types uses the target's id plus ids of the type parameters.
* For other cases, the types ids are used.
*/
function getRelationKey(source: Type, target: Type, relation: Map<RelationComparisonResult>) {
if (relation === identityRelation && source.id > target.id) {
const temp = source;
source = target;
target = temp;
}
if (isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target)) {
const typeParameters: Type[] = [];
return getTypeReferenceId(<TypeReference>source, typeParameters) + "," + getTypeReferenceId(<TypeReference>target, typeParameters);
}
return source.id + "," + target.id;
}

// Invoke the callback for each underlying property symbol of the given symbol and return the first
// value that isn't undefined.
function forEachProperty<T>(prop: Symbol, callback: (p: Symbol) => T): T {
Expand Down
Loading

0 comments on commit 2b9aba4

Please sign in to comment.