in packages/jsii-diff/lib/type-analysis.ts [14:100]
export function isSuperType(
a: reflect.TypeReference,
b: reflect.TypeReference,
updatedSystem: reflect.TypeSystem,
): Analysis {
if (a.void || b.void) {
throw new Error('isSuperType() does not handle voids');
}
if (a.isAny) {
return { success: true };
}
if (a.primitive !== undefined) {
if (a.primitive === b.primitive) {
return { success: true };
}
return failure(`${b.toString()} is not assignable to ${a.toString()}`);
}
if (a.arrayOfType !== undefined) {
// Arrays are covariant
if (b.arrayOfType === undefined) {
return failure(`${b.toString()} is not an array type`);
}
return prependReason(
isSuperType(a.arrayOfType, b.arrayOfType, updatedSystem),
`${b.toString()} is not assignable to ${a.toString()}`,
);
}
if (a.mapOfType !== undefined) {
// Maps are covariant (are they?)
if (b.mapOfType === undefined) {
return failure(`${b.toString()} is not a map type`);
}
return prependReason(
isSuperType(a.mapOfType, b.mapOfType, updatedSystem),
`${b.toString()} is not assignable to ${a.toString()}`,
);
}
// Every element of B can be assigned to A
if (b.unionOfTypes !== undefined) {
const analyses = b.unionOfTypes.map((bbb) =>
isSuperType(a, bbb, updatedSystem),
);
if (analyses.every((x) => x.success)) {
return { success: true };
}
return failure(
`some of ${b.toString()} are not assignable to ${a.toString()}`,
...flatMap(analyses, (x) => (x.success ? [] : x.reasons)),
);
}
// There should be an element of A which can accept all of B
if (a.unionOfTypes !== undefined) {
const analyses = a.unionOfTypes.map((aaa) =>
isSuperType(aaa, b, updatedSystem),
);
if (analyses.some((x) => x.success)) {
return { success: true };
}
return failure(
`none of ${b.toString()} are assignable to ${a.toString()}`,
...flatMap(analyses, (x) => (x.success ? [] : x.reasons)),
);
}
// We have two named types, recursion might happen so protect against it.
try {
// For named types, we'll always do a nominal typing relationship.
// That is, if in the updated typesystem someone were to use the type name
// from the old assembly, do they have a typing relationship that's accepted
// by a nominal type system. (That check also rules out enums)
const nominalCheck = isNominalSuperType(a, b, updatedSystem);
if (nominalCheck.success === false) {
return nominalCheck;
}
// At this point, the only thing left to do is recurse into the structs.
// We used to do that here, but we don't anymore; structs check themselves
// for structural weakening/strengthening.
return { success: true };
} catch (e: any) {
return failure(e.message);
}
}