import { Type } from "./Type"; export const UNKNOWN_SIZE = "unknown"; export type ArraySize = typeof UNKNOWN_SIZE | number; export class ArrayType extends Type { constructor(readonly elementsType: Type, readonly size: ArraySize, readonly isIncompleteArrayInitializer: boolean = false) { super() } override get isArrayType(): boolean { return true; } override equals(otherType: Type): boolean { if (otherType instanceof ArrayType) { const sizesMatch = this.size === otherType.size || this.size === UNKNOWN_SIZE || otherType.size == UNKNOWN_SIZE; return sizesMatch && this.elementsType.equals(otherType.elementsType); } else { return false; } } override isAssignableTo(otherType: Type): boolean { if (otherType instanceof ArrayType) { if (this.elementsType.isAssignableTo(otherType.elementsType)) { if (this.isIncompleteArrayInitializer) { return otherType.size == UNKNOWN_SIZE || (this.size != UNKNOWN_SIZE && otherType.size >= this.size); } else { //return otherType.size == UNKNOWN_SIZE || (this.size != UNKNOWN_SIZE && otherType.size == this.size); // Except for array initializers, the size of the arrays is ignored. The size annotation is part of the array type only to construct new arrays on declaration without calling a constructor explicitly return true; } } else { return false; } } else { return false; } } override toString(): string { if (this.size == UNKNOWN_SIZE) { return `${this.elementsType.toString()}[?]`; } else if(this.isIncompleteArrayInitializer) { return `${this.elementsType.toString()}[>=${this.size}]`; } else { return `${this.elementsType.toString()}[${this.size}]`; } } }