typir
Version:
General purpose type checking library
102 lines • 4.22 kB
JavaScript
/******************************************************************************
* Copyright 2024 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import { isSpecificTypirProblem } from '../utils/utils-definitions.js';
import { isTypeEdge } from '../graph/type-edge.js';
import { assertUnreachable } from '../utils/utils.js';
export const TypeEqualityProblem = 'TypeEqualityProblem';
export function isTypeEqualityProblem(problem) {
return isSpecificTypirProblem(problem, TypeEqualityProblem);
}
export class DefaultTypeEquality {
constructor(services) {
this.typeRelationships = services.caching.TypeRelationships;
}
areTypesEqual(type1, type2) {
return this.getTypeEqualityProblem(type1, type2) === undefined;
}
getTypeEqualityProblem(type1, type2) {
var _a;
const cache = this.typeRelationships;
const linkData = cache.getRelationshipBidirectional(type1, type2, EqualityEdge);
const equalityCaching = (_a = linkData === null || linkData === void 0 ? void 0 : linkData.cachingInformation) !== null && _a !== void 0 ? _a : 'UNKNOWN';
function save(equalityCaching, error) {
const newEdge = {
$relation: EqualityEdge,
from: type1,
to: type2,
cachingInformation: 'LINK_EXISTS',
error,
};
cache.setOrUpdateBidirectionalRelationship(newEdge, equalityCaching);
}
// skip recursive checking
if (equalityCaching === 'PENDING') {
/** 'undefined' should be correct here ...
* - since this relationship will be checked earlier/higher/upper in the call stack again
* - since this values is not cached and therefore NOT reused in the earlier call! */
return undefined;
}
// the result is already known
if (equalityCaching === 'LINK_EXISTS') {
return undefined;
}
if (equalityCaching === 'NO_LINK') {
return {
$problem: TypeEqualityProblem,
type1,
type2,
subProblems: (linkData === null || linkData === void 0 ? void 0 : linkData.error) ? [linkData.error] : [],
};
}
// do the expensive calculation now
if (equalityCaching === 'UNKNOWN') {
// mark the current relationship as PENDING to detect and resolve cycling checks
save('PENDING', undefined);
// do the actual calculation
const result = this.calculateEquality(type1, type2);
// this allows to cache results (and to re-set the PENDING state)
if (result === undefined) {
save('LINK_EXISTS', undefined);
}
else {
save('NO_LINK', result);
}
return result;
}
assertUnreachable(equalityCaching);
}
calculateEquality(type1, type2) {
if (type1 === type2) {
return undefined;
}
if (type1.getIdentifier() === type2.getIdentifier()) { // this works, since identifiers are unique!
return undefined;
}
// use the type-specific logic
// ask the 1st type
const result1 = type1.analyzeTypeEqualityProblems(type2);
if (result1.length <= 0) {
return undefined;
}
// ask the 2nd type
const result2 = type2.analyzeTypeEqualityProblems(type1);
if (result2.length <= 0) {
return undefined;
}
// both types reported, that they are diffferent
return {
$problem: TypeEqualityProblem,
type1,
type2,
subProblems: [...result1, ...result2] // return the equality problems of both types
};
}
}
export const EqualityEdge = 'EqualityEdge';
export function isEqualityEdge(edge) {
return isTypeEdge(edge) && edge.$relation === EqualityEdge;
}
//# sourceMappingURL=equality.js.map