Skip to content

Extra long code compilation whitch finished with "memory leak" report after ~20min #42937

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

Closed
mixalbl4-127 opened this issue Feb 24, 2021 · 3 comments · Fixed by #43973
Closed
Assignees
Labels
Domain: Declaration Emit The issue relates to the emission of d.ts files Domain: Performance Reports of unusually slow behavior Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status.

Comments

@mixalbl4-127
Copy link

mixalbl4-127 commented Feb 24, 2021

This issue started here: TypeStrong/fork-ts-checker-webpack-plugin#569

Current behavior

Make file: Api.ts

/* eslint-disable */
/* tslint:disable */
import { HttpClient } from "./http-client";

export class Api<SecurityDataType = unknown> {
  constructor(private http: HttpClient<SecurityDataType>) {}

    abc1 = () => this.http.request();
    abc2 = () => this.http.request();
    abc3 = () => this.http.request();
}

and http-client.ts

/* eslint-disable */
/* tslint:disable */

/** Overrided Promise type. Needs for additional typings of `.catch` callback */
type TPromise<ResolveType, RejectType = any> = Omit<Promise<ResolveType>, "then" | "catch"> & {
  then<TResult1 = ResolveType, TResult2 = never>(
    onfulfilled?: ((value: ResolveType) => TResult1 | PromiseLike<TResult1>) | undefined | null,
    onrejected?: ((reason: RejectType) => TResult2 | PromiseLike<TResult2>) | undefined | null,
  ): TPromise<TResult1 | TResult2, RejectType>;
  catch<TResult = never>(
    onrejected?: ((reason: RejectType) => TResult | PromiseLike<TResult>) | undefined | null,
  ): TPromise<ResolveType | TResult, RejectType>;
};

export interface HttpResponse<D extends unknown, E extends unknown = unknown> extends Response {
  data: D;
  error: E;
}

export class HttpClient<SecurityDataType = unknown> {
  public request = <T = any, E = any>(): TPromise<HttpResponse<T, E>> => {
    return '' as any;
  };
}

try to compile, you will see that "Issues checking in progress..." process take extra long time ~15 sec.
I dont know why, but if you Copy-Paste http-client.ts to Api.ts directly this check take <1 sec.

This files make this lib https://github.com/acacode/swagger-typescript-api with ~1000 this.http.request, and each this.http.request() took ~7 sec of checking. When I do this in intel i7 CPU, after ~30 min of compiling I got error about memory leak.

Video: https://user-images.githubusercontent.com/3511307/108701953-4a842480-7511-11eb-9924-7f3c0c60acd0.mp4

Environment

  • fork-ts-checker-webpack-plugin: 6.1.0
  • typescript: 3.9.9
  • eslint: 6.8.0
  • webpack: 4.46.0
  • os: Linux mint 18.3 KDE

Tested on latest typescript 4.2.2 - same result.

Same with tsc --watch --noEmit.

Video: https://user-images.githubusercontent.com/3511307/108986783-2eac8a00-769b-11eb-9f9e-27f914830c8d.mp4

@sheetalkamat
Copy link
Member

sheetalkamat commented Apr 27, 2021

This is issue with declaration emit and repros if you run
tsc --d api.ts

Results in:

Api.ts:8:5 - error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.

8     abc1 = () => this.http.request();
      ~~~~

Api.ts:9:5 - error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.

9     abc2 = () => this.http.request();
      ~~~~

Api.ts:10:5 - error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.

10     abc3 = () => this.http.request();
       ~~~~

Api.ts:11:3 - error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.

11   abc4 = () => this.http.request();
     ~~~~


Found 4 errors.

Files:                           7
Lines of Library:            24662
Lines of Definitions:            0
Lines of TypeScript:            36
Lines of JavaScript:             0
Lines of JSON:                   0
Lines of Other:                  0
Nodes of Library:           110877
Nodes of Definitions:            0
Nodes of TypeScript:           238
Nodes of JavaScript:             0
Nodes of JSON:                   0
Nodes of Other:                  0
Identifiers:                 40393
Symbols:                     45782
Types:                       55882
Instantiations:             144834
Memory used:               256134K
Assignability cache size:     3097
Identity cache size:             0
Subtype cache size:              0
Strict subtype cache size:       0
I/O Read time:               0.01s
Parse time:                  0.40s
ResolveModule time:          0.00s
Program time:                0.41s
Bind time:                   0.18s
Check time:                  0.88s
transformTime time:         30.48s
commentTime time:            0.00s
I/O Write time:              0.01s
printTime time:             30.50s
Emit time:                  30.50s
Total time:                 31.98s

@weswigham
Copy link
Member

My initial takes just looking at the example: TPromise being private means we have to print it back structurally when referenced outside that file. TPromise is rather large and complicated, so that probably doesn't help, since every member you're specifying is of a TPromise type. exporting it probably gets the performance under control (I haven't validated this hypothesis yet, I just think it's likely).

@weswigham
Copy link
Member

Yeah, my initial guess was spot on - TPromise not being exported means we have to print the type of this.http.request() structurally; except that structure is self-recursive, so we have to keep printing it until we hit our depth limit (5) and issue a truncation error (as you can see when declaration emit is on) - this takes a long time, because in generating that truncated type we have to calculate (and recalculate, since, as I've mentioned elsewhere, there's no caching of any kind for symbol visibility) visibility for every type listed in the structure. For context, the (truncated) structural type of the expression doesn't even fit on one screen:
image
because the TPromise type expands so much. So yes, the quick fix for y'all is to export TPromise. #30979 would be the ideal fix from us, I think, since then we could quickly and easily serialize the type without iterating to a depth limiter. In lieu of that, #43973 offers an improvement by way of adding a dumb cache into symbol visibility lookups, which is enough to bring the example runtime down from 20s to 7s on my machine. To bring it down more (which I do think would be possible), I think we'd need a smarter cache, or just more optimized symbol visibility lookup.

@weswigham weswigham added the Domain: Performance Reports of unusually slow behavior label May 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Domain: Declaration Emit The issue relates to the emission of d.ts files Domain: Performance Reports of unusually slow behavior Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants