-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Hitting TS Limits: "Max Call Stack Size Exceeded" #58439
Comments
While I think someone can take a look after the weekend, can you post any of the specific call stacks that you saw? |
StacktracesThe example from the repo:
From a previous odata2ts version (contained some bugs that have been resolved now). Also, this is directly from ts-morph trying to output js + dts
Using a private repo example
Using yet another private repo example
|
All those stacks are different which indicates they are (probably) seperate bugs. |
I tried to reproduce using the repo at https://github.com/texttechne/max-call-stack-size-exceeded, but the > max-call-stack-exceeded@1.0.0 generate
> odata2ts
Loaded config file: odata2ts.config.ts
---------------------------
Starting generation process. Service name "Dynamics"
Didn't find metadata file at: odata/dynamics.xml
Input source [odata/dynamics.xml] doesn't exist! |
Hi @ahejlsberg, so sorry to have messed up the example like this. Generation works now, but you don't need to generate the code. I've committed it directly under folder |
Ok, I can reproduce the issue. This looks to be a case of very deep type dependencies for which the compiler is attempting to compute variance information. For example, from top to bottom, each type below depends on the next type in the list, and it keeps going for >150 levels: FirmCustomFieldService<ClientType>
CustomFieldTypeService<ClientType>
FirmService<ClientType>
PartyService<ClientType>
DocumentTemplateService<ClientType>
PartyTypeService<ClientType>
LawsuitPartyTypeService<ClientType>
DepositionService<ClientType>
LawsuitPartyService<ClientType>
LawsuitService<ClientType>
AppointmentService<ClientType>
ADRService<ClientType>
ADRTypeService<ClientType>
LitigationService<ClientType>
LawsuitPhaseTypeService<ClientType>
AnswerEnlargementService<ClientType>
LawsuitPhaseDateService<ClientType>
ComplaintService<ClientType>
SubPhaseTypeService<ClientType>
DefendantLitigationAssnService<ClientType>
DefendantLawsuitPartyService<ClientType>
DepositionLitigationAssnService<ClientType>
LawsuitTypeService<ClientType>
TicklerTemplateService<ClientType>
AccountingSyncGLService<ClientType>
RoleTemplateService<ClientType>
CasePacerUserService<ClientType>
CaseMenuItemService<ClientType>
CaseMenuGroupService<ClientType>
CaseMenuTabService<ClientType>
CPDirectCaseProgressService<ClientType>
RecordFileService<ClientType>
RecordFolderService<ClientType>
RecordSubtypeService<ClientType>
IntakeClientLawsuitService<ClientType>
... Since variance computation is a recursive process, the deep dependencies eventually cause a stack overflow. I was going to suggest working around the problem using explicit variance annotations, but unfortunately the I'm not sure how important it is for these types to be generic. If the |
Thanks so much! Good to know what the actual problem is. I was definitely lost there... So I've tried out your suggestion to dispense with the Background For the Problematic Type ParameterThe generated OData client relies on an HTTP client which is configurable: Axios, Fetch, JQuery, ....roll your own. Each HTTP client comes with its very own configuration options. And each request should be configurable. Using the generic type here allows me to offer the correct typing for the configuration options: export abstract class EntitySetServiceV4<
ClientType extends ODataHttpClient,
T,
EditableT,
Q extends QueryObject,
EIdType
> {
public async query<ReturnType extends Partial<T> = T>(
queryFn?: (builder: ODataQueryBuilderV4<Q>, qObject: Q) => void,
requestConfig?: ODataHttpClientConfig<ClientType> // here the correct config object is inferred from the HTTPClient
): ODataResponse<ODataCollectionResponseV4<ReturnType>> {
// ....
}
} See source code I don't know how to define this differently... Is this a Bug?Let me ask naively: Do you think that's bad / imperformant code that I'm using here? Should I have known better? To ask the other way around: Do you accept this a TS bug? I think one can argue for both positions. However, I would argue for the latter one: That TS uses recursion to evaluate variance is an implementation detail that I, as end user, am not aware of & probably shouldn't be. Code that works perfectly fine in smaller examples, breaks for bigger code bases. But just my 2 cents... |
I think this can reasonably be called a design limitation. Technically, there's nothing wrong with your code, but the same can be said for code that, for example, nests You may want to experiment with adding |
Ok, I was afraid you would argue that way, unfortunately (for me) reasonable enough 😄 Before closing this issue: Do you see any problem with adding |
Finally found the time to toy around with variance annotations. After changing a certain implementation detail, I was able to annotate with This is the best result as I'm now able to compile even those large examples which in turn brings any bugs with my generator to light. But to be honest, that's more like trial and error for me than anything else. I think I got some hold of the variance topic in the meantime, but I fail to make the connection to my code. In the end I chose to annotate invariance... @ahejlsberg thank you so much for your analysis and all the right pointers! I was really lost there and needed help, which you provided brilliantly! |
🔎 Search Terms
"max call stack size"
Related Issues:
🕗 Version & Regression Information
⏯ Playground Link
https://github.com/texttechne/max-call-stack-size-exceeded
💻 Code
Unfortunately, it seems that this is a matter of complexity, so there's no "minimal" example.
However, I created a repo to reproduce this issue.
This bug occurs in connection with a generator (odata2ts) which creates an OData client out of metadata. As the metadata of the OData service represents an entity relationship model, there's also some form of recursion involved when entities have a bidirectional relationship to each other. However, this seems fine when the OData service in question is not that large.
The offending code examples:
And:
To be clear: The code itself works in smaller examples. However, at a certain point this code seems to hit the limits of TS...
I have an example in the repo where I could leave out the generation of either 1 or 2 and the error won't occur. There are other services where I would need to leave out both to prevent the error from ocurring.
🙁 Actual behavior
TS crashes with "RangeError: Maximum call stack size exceeded"
Unfortunately the stack trace changes from example to example, so please refer to the mentioned repo.
🙂 Expected behavior
It shouldn't crash
Additional information about the issue
To solve the issue for the odata2ts generator, I've decided to use
@ts-no-check
in every generated file. On the one hand, no consumer would like to type check generated code and it's hopefully a workaround.However, I've thought that this might serve as a nice repro case for the underlying issue.
The text was updated successfully, but these errors were encountered: