Skip to content

Commit e7f5c96

Browse files
weswighamsandersn
authored andcommitted
cache relationships, needs work on preserving diagnostic output
1 parent 3eaadc6 commit e7f5c96

File tree

1 file changed

+57
-13
lines changed

1 file changed

+57
-13
lines changed

src/compiler/checker.ts

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -469,10 +469,25 @@ namespace ts {
469469
};
470470

471471
const subtypeRelation = createMap<RelationComparisonResult>();
472+
const subtypeRelationErrors = createMap<DiagnosticMessageChain>();
472473
const assignableRelation = createMap<RelationComparisonResult>();
474+
const assignableRelationErrors = createMap<DiagnosticMessageChain>();
473475
const comparableRelation = createMap<RelationComparisonResult>();
476+
const comparableRelationErrors = createMap<DiagnosticMessageChain>();
474477
const identityRelation = createMap<RelationComparisonResult>();
478+
const identityRelationErrors = createMap<DiagnosticMessageChain>();
475479
const enumRelation = createMap<boolean>();
480+
const enumRelationErrors = createMap<DiagnosticMessageChain>();
481+
482+
function getErrorCache(relation: Map<RelationComparisonResult> | Map<boolean>) {
483+
switch (true) {
484+
case relation === subtypeRelation: return subtypeRelationErrors;
485+
case relation === assignableRelation: return assignableRelationErrors;
486+
case relation === comparableRelation: return comparableRelationErrors;
487+
case relation === identityRelation: return identityRelationErrors;
488+
case relation === enumRelation: return enumRelationErrors;
489+
}
490+
}
476491

477492
// This is for caching the result of getSymbolDisplayBuilder. Do not access directly.
478493
let _displayBuilder: SymbolDisplayBuilder;
@@ -8918,6 +8933,17 @@ namespace ts {
89188933
* * Ternary.False if they are not related.
89198934
*/
89208935
function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage): Ternary {
8936+
const comparisonId = comparisonTypeId(source, target);
8937+
const cachedResult = fetchRelationResult(comparisonId);
8938+
if (cachedResult !== undefined) {
8939+
if (reportErrors && cachedResult === Ternary.False) {
8940+
const cachedChain = getErrorCache(relation).get(comparisonId);
8941+
if (cachedChain) {
8942+
errorInfo = concatenateDiagnosticMessageChains(errorInfo, cachedChain);
8943+
}
8944+
}
8945+
return cachedResult;
8946+
}
89218947
if (source.flags & TypeFlags.StringOrNumberLiteral && source.flags & TypeFlags.FreshLiteral) {
89228948
source = (<LiteralType>source).regularType;
89238949
}
@@ -9028,6 +9054,14 @@ namespace ts {
90289054
}
90299055
reportRelationError(headMessage, source, target);
90309056
}
9057+
9058+
if (fetchRelationResult(comparisonId) === undefined) {
9059+
relation.set(comparisonId, result ? RelationComparisonResult.Succeeded : reportErrors ? RelationComparisonResult.FailedAndReported : RelationComparisonResult.Failed);
9060+
if (reportErrors && errorInfo) {
9061+
getErrorCache(relation).set(comparisonId, errorInfo);
9062+
}
9063+
}
9064+
90319065
return result;
90329066
}
90339067

@@ -9190,6 +9224,24 @@ namespace ts {
91909224
return result;
91919225
}
91929226

9227+
function comparisonTypeId(source: Type, target: Type) {
9228+
return relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id;
9229+
}
9230+
9231+
function fetchRelationResult(id: string, reportErrors?: boolean): Ternary | undefined {
9232+
const related = relation.get(id);
9233+
if (related !== undefined) {
9234+
if (reportErrors && related === RelationComparisonResult.Failed) {
9235+
// We are elaborating errors and the cached result is an unreported failure. Record the result as a reported
9236+
// failure and continue computing the relation such that errors get reported.
9237+
relation.set(id, RelationComparisonResult.FailedAndReported);
9238+
}
9239+
else {
9240+
return related === RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
9241+
}
9242+
}
9243+
}
9244+
91939245
// Determine if possibly recursive types are related. First, check if the result is already available in the global cache.
91949246
// Second, check if we have already started a comparison of the given two types in which case we assume the result to be true.
91959247
// Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are
@@ -9208,7 +9260,7 @@ namespace ts {
92089260
// this is a copy of the normal code! It can probably be merged somehow.
92099261
const src = (source as TypeReference).target;
92109262
const trg = (target as TypeReference).target;
9211-
const id = relation !== identityRelation || src.id < trg.id ? src.id + "," + trg.id : trg.id + "," + src.id;
9263+
const id = comparisonTypeId(src, trg);
92129264
if (!maybeReferenceKeys) {
92139265
maybeReferenceKeys = [];
92149266
}
@@ -9223,19 +9275,11 @@ namespace ts {
92239275
maybeReferenceCount++;
92249276
}
92259277

9226-
const id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id;
9227-
const related = relation.get(id);
9228-
if (related !== undefined) {
9229-
if (reportErrors && related === RelationComparisonResult.Failed) {
9230-
// We are elaborating errors and the cached result is an unreported failure. Record the result as a reported
9231-
// failure and continue computing the relation such that errors get reported.
9232-
relation.set(id, RelationComparisonResult.FailedAndReported);
9233-
}
9234-
else {
9235-
return related === RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
9236-
}
9278+
const id = comparisonTypeId(source, target);
9279+
const cachedResult = fetchRelationResult(id);
9280+
if (cachedResult !== undefined) {
9281+
return cachedResult;
92379282
}
9238-
92399283
if (!maybeKeys) {
92409284
maybeKeys = [];
92419285
sourceStack = [];

0 commit comments

Comments
 (0)