From 264b75b4885020ee90cc41c54117beb5b0d401cc Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 19 Sep 2018 15:26:53 -0700 Subject: [PATCH 1/3] Limit inference from apparent types to one level deep --- src/compiler/checker.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 34b72ab36f797..1059d8bd94f36 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13439,6 +13439,7 @@ namespace ts { let visited: Map; let contravariant = false; let propagationType: Type; + let top = true; inferFromTypes(originalSource, originalTarget); function inferFromTypes(source: Type, target: Type): void { @@ -13616,7 +13617,15 @@ namespace ts { // getApparentType can return _any_ type, since an indexed access or conditional may simplify to any other type. // If that occurs and it doesn't simplify to an object or intersection, we'll need to restart `inferFromTypes` // with the simplified source. - if (apparentSource !== source && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection))) { + if (apparentSource !== source && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection)) && top === true) { + // TODO: This `top` flag is a hack! This forbids inference from complex constraints within constraints! + // This isn't required algorithmically, but rather is used to lower the memory burden caused by performing inference + // that is _too good_ in projects with complicated constraints (eg, fp-ts). In such cases, if we did not limit ourselves + // here, we might produce more valid inferences for types, causing us to do more checks and perform more instantiations + // (in addition to the extra stack depth here) which, in turn, can push the already close process over its limit. + // TL;DR: If we ever become generally more memory efficienct (or our resource budget ever increases), we should just + // remove this `top` flag. + top = false; return inferFromTypes(apparentSource, target); } source = apparentSource; From d372f2cfc9c57c85eccfdd272b38f78b97f2fafc Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 19 Sep 2018 15:57:07 -0700 Subject: [PATCH 2/3] Rename marker & use booleanness not === --- src/compiler/checker.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1059d8bd94f36..b6dfe454e132a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13439,7 +13439,7 @@ namespace ts { let visited: Map; let contravariant = false; let propagationType: Type; - let top = true; + let allowComplexConstraintInference = true; inferFromTypes(originalSource, originalTarget); function inferFromTypes(source: Type, target: Type): void { @@ -13617,16 +13617,17 @@ namespace ts { // getApparentType can return _any_ type, since an indexed access or conditional may simplify to any other type. // If that occurs and it doesn't simplify to an object or intersection, we'll need to restart `inferFromTypes` // with the simplified source. - if (apparentSource !== source && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection)) && top === true) { - // TODO: This `top` flag is a hack! This forbids inference from complex constraints within constraints! + if (apparentSource !== source && allowComplexConstraintInference && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection))) { + // TODO: The `allowComplexConstraintInference` flag is a hack! This forbids inference from complex constraints within constraints! // This isn't required algorithmically, but rather is used to lower the memory burden caused by performing inference - // that is _too good_ in projects with complicated constraints (eg, fp-ts). In such cases, if we did not limit ourselves + // that is _too gooisTopLevelInExternalModuleAugmentationd_ in projects with complicated constraints (eg, fp-ts). In such cases, if we did not limit ourselves // here, we might produce more valid inferences for types, causing us to do more checks and perform more instantiations // (in addition to the extra stack depth here) which, in turn, can push the already close process over its limit. // TL;DR: If we ever become generally more memory efficienct (or our resource budget ever increases), we should just - // remove this `top` flag. - top = false; - return inferFromTypes(apparentSource, target); + // remove this `allowComplexConstraintInference` flag. + allowComplexConstraintInference = false; + inferFromTypes(apparentSource, target); + return; } source = apparentSource; } From 26295bed7cceac6b53461e68f0af61aa9b628d45 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 19 Sep 2018 16:00:27 -0700 Subject: [PATCH 3/3] Undo typo --- src/compiler/checker.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b6dfe454e132a..58717c941d932 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13620,14 +13620,13 @@ namespace ts { if (apparentSource !== source && allowComplexConstraintInference && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection))) { // TODO: The `allowComplexConstraintInference` flag is a hack! This forbids inference from complex constraints within constraints! // This isn't required algorithmically, but rather is used to lower the memory burden caused by performing inference - // that is _too gooisTopLevelInExternalModuleAugmentationd_ in projects with complicated constraints (eg, fp-ts). In such cases, if we did not limit ourselves + // that is _too good_ in projects with complicated constraints (eg, fp-ts). In such cases, if we did not limit ourselves // here, we might produce more valid inferences for types, causing us to do more checks and perform more instantiations // (in addition to the extra stack depth here) which, in turn, can push the already close process over its limit. // TL;DR: If we ever become generally more memory efficienct (or our resource budget ever increases), we should just // remove this `allowComplexConstraintInference` flag. allowComplexConstraintInference = false; - inferFromTypes(apparentSource, target); - return; + return inferFromTypes(apparentSource, target); } source = apparentSource; }