UNPKG

typir

Version:

General purpose type checking library

102 lines 4.22 kB
/****************************************************************************** * 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