Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrap native map to work around 2**24 element limit #50310

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
82 changes: 61 additions & 21 deletions src/compiler/checker.ts
Expand Up @@ -1042,12 +1042,52 @@ namespace ts {
let _jsxNamespace: __String;
let _jsxFactoryEntity: EntityName | undefined;

const subtypeRelation = new Map<string, RelationComparisonResult>();
const strictSubtypeRelation = new Map<string, RelationComparisonResult>();
const assignableRelation = new Map<string, RelationComparisonResult>();
const comparableRelation = new Map<string, RelationComparisonResult>();
const identityRelation = new Map<string, RelationComparisonResult>();
const enumRelation = new Map<string, RelationComparisonResult>();
class InfiniMap<K, V> {
private next?: InfiniMap<K, V>;
private inner: ESMap<K, V>;
constructor() {
this.inner = new Map();
}
get(key: K): V | undefined {
return this.inner.has(key) ? this.inner.get(key) : this.next?.get(key);
}
set(key: K, value: V): this {
if (this.inner.size > ((2 ** 24) - 1)) {
this.next ||= new InfiniMap();
this.next.set(key, value);
weswigham marked this conversation as resolved.
Show resolved Hide resolved
}
else {
this.inner.set(key, value);
}
return this;
}
has(key: K): boolean {
return this.inner.has(key) || !!this.next?.has(key);
}
clear(): void {
this.inner.clear();
this.next?.clear();
this.next = undefined;
}
delete(key: K): boolean {
return this.inner.delete(key) || !!this.next?.delete(key);
}
forEach(callbackfn: (value: V, key: K, map: InfiniMap<K, V>) => void): void {
this.inner.forEach((v, k) => callbackfn(v, k, this));
this.next?.forEach((v, k) => callbackfn(v, k, this));
}
get size(): number {
return this.inner.size + (this.next?.size || 0);
}
}

type RelationCache = InfiniMap<string, RelationComparisonResult>;
const subtypeRelation = new InfiniMap<string, RelationComparisonResult>();
const strictSubtypeRelation = new InfiniMap<string, RelationComparisonResult>();
const assignableRelation = new InfiniMap<string, RelationComparisonResult>();
const comparableRelation = new InfiniMap<string, RelationComparisonResult>();
const identityRelation = new InfiniMap<string, RelationComparisonResult>();
const enumRelation = new InfiniMap<string, RelationComparisonResult>();

const builtinGlobals = createSymbolTable();
builtinGlobals.set(undefinedSymbol.escapedName, undefinedSymbol);
Expand Down Expand Up @@ -17583,7 +17623,7 @@ namespace ts {
function checkTypeRelatedToAndOptionallyElaborate(
source: Type,
target: Type,
relation: ESMap<string, RelationComparisonResult>,
relation: RelationCache,
errorNode: Node | undefined,
expr: Expression | undefined,
headMessage: DiagnosticMessage | undefined,
Expand All @@ -17605,7 +17645,7 @@ namespace ts {
node: Expression | undefined,
source: Type,
target: Type,
relation: ESMap<string, RelationComparisonResult>,
relation: RelationCache,
headMessage: DiagnosticMessage | undefined,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined
Expand Down Expand Up @@ -17642,7 +17682,7 @@ namespace ts {
node: Expression,
source: Type,
target: Type,
relation: ESMap<string, RelationComparisonResult>,
relation: RelationCache,
headMessage: DiagnosticMessage | undefined,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined
Expand Down Expand Up @@ -17671,7 +17711,7 @@ namespace ts {
node: ArrowFunction,
source: Type,
target: Type,
relation: ESMap<string, RelationComparisonResult>,
relation: RelationCache,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined
): boolean {
Expand Down Expand Up @@ -17758,7 +17798,7 @@ namespace ts {
iterator: ElaborationIterator,
source: Type,
target: Type,
relation: ESMap<string, RelationComparisonResult>,
relation: RelationCache,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined
) {
Expand Down Expand Up @@ -17876,7 +17916,7 @@ namespace ts {
node: JsxAttributes,
source: Type,
target: Type,
relation: ESMap<string, RelationComparisonResult>,
relation: RelationCache,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined
) {
Expand Down Expand Up @@ -17977,7 +18017,7 @@ namespace ts {
node: ArrayLiteralExpression,
source: Type,
target: Type,
relation: ESMap<string, RelationComparisonResult>,
relation: RelationCache,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined
) {
Expand Down Expand Up @@ -18030,7 +18070,7 @@ namespace ts {
node: ObjectLiteralExpression,
source: Type,
target: Type,
relation: ESMap<string, RelationComparisonResult>,
relation: RelationCache,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined
) {
Expand Down Expand Up @@ -18334,7 +18374,7 @@ namespace ts {
return true;
}

function isSimpleTypeRelatedTo(source: Type, target: Type, relation: ESMap<string, RelationComparisonResult>, errorReporter?: ErrorReporter) {
function isSimpleTypeRelatedTo(source: Type, target: Type, relation: RelationCache, errorReporter?: ErrorReporter) {
const s = source.flags;
const t = target.flags;
if (t & TypeFlags.AnyOrUnknown || s & TypeFlags.Never || source === wildcardType) return true;
Expand Down Expand Up @@ -18375,7 +18415,7 @@ namespace ts {
return false;
}

function isTypeRelatedTo(source: Type, target: Type, relation: ESMap<string, RelationComparisonResult>) {
function isTypeRelatedTo(source: Type, target: Type, relation: RelationCache) {
if (isFreshLiteralType(source)) {
source = (source as FreshableType).regularType;
}
Expand Down Expand Up @@ -18452,7 +18492,7 @@ namespace ts {
function checkTypeRelatedTo(
source: Type,
target: Type,
relation: ESMap<string, RelationComparisonResult>,
relation: RelationCache,
errorNode: Node | undefined,
headMessage?: DiagnosticMessage,
containingMessageChain?: () => DiagnosticMessageChain | undefined,
Expand Down Expand Up @@ -20991,7 +21031,7 @@ namespace ts {
* To improve caching, the relation key for two generic types uses the target's id plus ids of the type parameters.
* For other cases, the types ids are used.
*/
function getRelationKey(source: Type, target: Type, intersectionState: IntersectionState, relation: ESMap<string, RelationComparisonResult>, ignoreConstraints: boolean) {
function getRelationKey(source: Type, target: Type, intersectionState: IntersectionState, relation: RelationCache, ignoreConstraints: boolean) {
if (relation === identityRelation && source.id > target.id) {
const temp = source;
source = target;
Expand Down Expand Up @@ -30384,7 +30424,7 @@ namespace ts {
function checkApplicableSignatureForJsxOpeningLikeElement(
node: JsxOpeningLikeElement,
signature: Signature,
relation: ESMap<string, RelationComparisonResult>,
relation: RelationCache,
checkMode: CheckMode,
reportErrors: boolean,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
Expand Down Expand Up @@ -30487,7 +30527,7 @@ namespace ts {
node: CallLikeExpression,
args: readonly Expression[],
signature: Signature,
relation: ESMap<string, RelationComparisonResult>,
relation: RelationCache,
checkMode: CheckMode,
reportErrors: boolean,
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
Expand Down Expand Up @@ -31051,7 +31091,7 @@ namespace ts {
candidateForTypeArgumentError = oldCandidateForTypeArgumentError;
}

function chooseOverload(candidates: Signature[], relation: ESMap<string, RelationComparisonResult>, isSingleNonGenericCandidate: boolean, signatureHelpTrailingComma = false) {
function chooseOverload(candidates: Signature[], relation: RelationCache, isSingleNonGenericCandidate: boolean, signatureHelpTrailingComma = false) {
candidatesForArgumentError = undefined;
candidateForArgumentArityError = undefined;
candidateForTypeArgumentError = undefined;
Expand Down