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

Flatten immediately nested conditional types in the false position #36583

Merged
merged 7 commits into from
Mar 16, 2020

Conversation

ahejlsberg
Copy link
Member

@ahejlsberg ahejlsberg commented Feb 3, 2020

With this PR we flatten immediately nested conditional types in the false position, effectively treating types of the form

type Foo<...> =
    A extends B ? X :
    C extends D ? Y :
    E extends F ? Z :
    ...;

as a single construct for purposes of resolution. This should meaningfully improve the cost of resolving such types, plus it means they aren't subject to the instatiation depth limiter (they basically count as a single level).

Fixes #28663.

@ajafff
Copy link
Contributor

ajafff commented Feb 3, 2020

I'm pretty sure we have bug for this somewhere

#28663

@weswigham
Copy link
Member

I've thrown up #36584 as a much simpler alternative - there's no hard syntactic requirements (so it will take effect much more often than this change), it doesn't contort conditional instantiation with an inner loop, and allows the same usecases. In the cases where we would flatten here, we already don't create anything intermediate that isn't used to determine simplifyability (at least once distributivity is handled/bailed appropriately); so beyond acting as a trampoline to reduce stack depth in certain scenarios, I don't think the extra structure here serves much purpose, other than to greatly complicate the code. Ergo, I think the onus is really on this change to demonstrate a case where the extra structure actually saves us from a pathological performance cliff.

@ahejlsberg
Copy link
Member Author

@weswigham Beyond fixing the depth limiter issue on large conditional types, the PR makes resolution faster by virtue of its shortened code path and reduces memory consumption by not storing resolved types in the caches associated with the each nested type's ConditionalRoot. The effects are not dramatic, but every little bit counts. I disagree that the loop greatly complicates the code. I think it is perfectly meaningful to think of a series of immediately nested conditionals as a single construct, and the loop reflects that.

@weswigham
Copy link
Member

I think that unless this pattern is super-widespread (and it's not because we made it an error), it's really not worth giving this treatment to. I'd get giving this treatment to, like, nested object instantiation somehow, but syntactically nested conditionals are few and far between. There's a grand total of one type in the react .d.ts which would save one callstack depth for this. I feel a change like this change is just way too narrow to justify, at least without very concrete cases that it fixes and the effect it has on them.

@sandersn sandersn added the For Backlog Bug PRs that fix a backlog bug label Feb 20, 2020
@sandersn
Copy link
Member

I don't think this change is that complicated. Disregarding whitespace changes and new comments, it's the same length as #36584 -- about 10 lines.
Both solutions seem a bit ad-hoc to me, although special-casing immediately nested conditionals seems safer and more sensible than temporarily blinding the instantiation depth limiter. I agree that it needs a bit more justification, either:

  1. Example uses: (a) important packages with deeply immediately nested conditional types, or (b) a count of all immediately nested conditional types in some corpus like Definitely Typed or the user tests.
  2. Performance benefit: by measuring some important package (or packages) before and after the change.

@weswigham
Copy link
Member

@ahejlsberg I've finished merging #36584 into this PR, and also merged with master for you (it had conflicts). This should be good to go once CI checks all come back OK, so:

@typescript-bot test this
@typescript-bot user test this
@typescript-bot run dt
@typescript-bot perf test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 25, 2020

Heya @weswigham, I've started to run the parallelized community code test suite on this PR at e59c3e6. You can monitor the build here. It should now contribute to this PR's status checks.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 25, 2020

Heya @weswigham, I've started to run the extended test suite on this PR at e59c3e6. You can monitor the build here. It should now contribute to this PR's status checks.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 25, 2020

Heya @weswigham, I've started to run the parallelized Definitely Typed test suite on this PR at e59c3e6. You can monitor the build here. It should now contribute to this PR's status checks.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 25, 2020

Heya @weswigham, I've started to run the perf test suite on this PR at e59c3e6. You can monitor the build here. It should now contribute to this PR's status checks.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

@weswigham
The results of the perf run you requested are in!

Here they are:

Comparison Report - master..36583

Metric master 36583 Delta Best Worst
Angular - node (v10.16.3, x64)
Memory used 334,095k (± 0.04%) 333,539k (± 0.02%) -556k (- 0.17%) 333,407k 333,655k
Parse Time 1.62s (± 0.68%) 1.62s (± 0.55%) -0.01s (- 0.49%) 1.60s 1.64s
Bind Time 0.89s (± 1.18%) 0.89s (± 1.15%) +0.00s (+ 0.11%) 0.86s 0.91s
Check Time 4.69s (± 0.70%) 4.71s (± 0.70%) +0.02s (+ 0.32%) 4.65s 4.82s
Emit Time 5.24s (± 0.57%) 5.23s (± 0.65%) -0.01s (- 0.27%) 5.15s 5.32s
Total Time 12.45s (± 0.44%) 12.44s (± 0.52%) -0.01s (- 0.04%) 12.29s 12.60s
Monaco - node (v10.16.3, x64)
Memory used 335,211k (± 0.02%) 335,194k (± 0.02%) -18k (- 0.01%) 335,071k 335,272k
Parse Time 1.25s (± 0.98%) 1.25s (± 0.80%) +0.00s (+ 0.40%) 1.23s 1.27s
Bind Time 0.78s (± 1.00%) 0.78s (± 0.75%) -0.00s (- 0.26%) 0.77s 0.79s
Check Time 4.71s (± 0.88%) 4.71s (± 0.56%) +0.00s (+ 0.04%) 4.66s 4.75s
Emit Time 2.92s (± 0.55%) 2.91s (± 0.72%) -0.01s (- 0.45%) 2.87s 2.94s
Total Time 9.66s (± 0.67%) 9.65s (± 0.52%) -0.01s (- 0.10%) 9.56s 9.74s
TFS - node (v10.16.3, x64)
Memory used 299,331k (± 0.02%) 299,322k (± 0.02%) -9k (- 0.00%) 299,122k 299,468k
Parse Time 0.94s (± 0.59%) 0.95s (± 0.77%) +0.01s (+ 1.07%) 0.93s 0.96s
Bind Time 0.75s (± 0.80%) 0.74s (± 0.67%) -0.00s (- 0.00%) 0.74s 0.76s
Check Time 4.24s (± 0.56%) 4.27s (± 0.32%) +0.03s (+ 0.61%) 4.23s 4.29s
Emit Time 3.01s (± 0.77%) 3.03s (± 0.68%) +0.01s (+ 0.43%) 2.99s 3.08s
Total Time 8.94s (± 0.46%) 8.98s (± 0.40%) +0.05s (+ 0.53%) 8.93s 9.08s
Angular - node (v12.1.0, x64)
Memory used 309,750k (± 0.03%) 309,174k (± 0.02%) -576k (- 0.19%) 309,044k 309,264k
Parse Time 1.57s (± 0.64%) 1.57s (± 0.52%) -0.00s (- 0.19%) 1.55s 1.59s
Bind Time 0.87s (± 1.13%) 0.87s (± 0.89%) -0.00s (- 0.34%) 0.86s 0.89s
Check Time 4.59s (± 0.35%) 4.59s (± 0.51%) -0.00s (- 0.00%) 4.51s 4.62s
Emit Time 5.40s (± 0.75%) 5.41s (± 0.80%) +0.01s (+ 0.24%) 5.32s 5.52s
Total Time 12.43s (± 0.41%) 12.43s (± 0.48%) +0.00s (+ 0.02%) 12.28s 12.59s
Monaco - node (v12.1.0, x64)
Memory used 315,128k (± 0.02%) 315,042k (± 0.02%) -86k (- 0.03%) 314,869k 315,179k
Parse Time 1.20s (± 0.56%) 1.21s (± 0.96%) +0.00s (+ 0.33%) 1.18s 1.22s
Bind Time 0.75s (± 0.99%) 0.74s (± 0.54%) -0.01s (- 1.20%) 0.73s 0.75s
Check Time 4.54s (± 0.55%) 4.55s (± 0.64%) +0.01s (+ 0.20%) 4.49s 4.61s
Emit Time 2.95s (± 1.09%) 2.97s (± 1.34%) +0.01s (+ 0.44%) 2.91s 3.12s
Total Time 9.45s (± 0.61%) 9.47s (± 0.69%) +0.02s (+ 0.19%) 9.35s 9.68s
TFS - node (v12.1.0, x64)
Memory used 281,603k (± 0.02%) 281,634k (± 0.02%) +31k (+ 0.01%) 281,524k 281,751k
Parse Time 0.92s (± 0.81%) 0.92s (± 0.63%) -0.00s (- 0.00%) 0.91s 0.93s
Bind Time 0.71s (± 0.73%) 0.71s (± 0.94%) +0.00s (+ 0.14%) 0.70s 0.72s
Check Time 4.18s (± 0.45%) 4.18s (± 0.53%) -0.00s (- 0.05%) 4.13s 4.25s
Emit Time 3.05s (± 0.99%) 3.06s (± 1.30%) +0.01s (+ 0.49%) 2.98s 3.18s
Total Time 8.86s (± 0.58%) 8.88s (± 0.45%) +0.02s (+ 0.19%) 8.80s 8.99s
Angular - node (v8.9.0, x64)
Memory used 328,956k (± 0.02%) 328,449k (± 0.01%) -508k (- 0.15%) 328,352k 328,508k
Parse Time 2.10s (± 0.57%) 2.10s (± 0.53%) -0.00s (- 0.05%) 2.08s 2.13s
Bind Time 0.92s (± 1.03%) 0.92s (± 0.70%) +0.00s (+ 0.55%) 0.91s 0.94s
Check Time 5.47s (± 0.59%) 5.46s (± 0.71%) -0.01s (- 0.16%) 5.37s 5.55s
Emit Time 6.26s (± 0.98%) 6.22s (± 0.91%) -0.04s (- 0.64%) 6.14s 6.37s
Total Time 14.76s (± 0.50%) 14.71s (± 0.52%) -0.05s (- 0.30%) 14.60s 14.93s
Monaco - node (v8.9.0, x64)
Memory used 333,388k (± 0.02%) 333,429k (± 0.01%) +41k (+ 0.01%) 333,357k 333,505k
Parse Time 1.54s (± 0.32%) 1.53s (± 0.32%) -0.00s (- 0.13%) 1.52s 1.54s
Bind Time 0.91s (± 0.75%) 0.90s (± 0.68%) -0.01s (- 0.55%) 0.89s 0.91s
Check Time 5.38s (± 0.82%) 5.39s (± 0.76%) +0.01s (+ 0.28%) 5.30s 5.52s
Emit Time 3.55s (± 0.71%) 3.54s (± 0.35%) -0.01s (- 0.34%) 3.52s 3.57s
Total Time 11.37s (± 0.57%) 11.37s (± 0.44%) -0.00s (- 0.00%) 11.26s 11.52s
TFS - node (v8.9.0, x64)
Memory used 298,693k (± 0.01%) 298,703k (± 0.02%) +10k (+ 0.00%) 298,586k 298,813k
Parse Time 1.25s (± 0.48%) 1.25s (± 0.49%) -0.00s (- 0.32%) 1.24s 1.27s
Bind Time 0.75s (± 0.53%) 0.75s (± 0.99%) +0.00s (+ 0.53%) 0.74s 0.77s
Check Time 4.80s (± 0.51%) 4.83s (± 0.52%) +0.03s (+ 0.56%) 4.76s 4.86s
Emit Time 3.38s (± 0.72%) 3.39s (± 0.86%) +0.01s (+ 0.27%) 3.30s 3.44s
Total Time 10.18s (± 0.41%) 10.22s (± 0.44%) +0.04s (+ 0.38%) 10.10s 10.29s
Angular - node (v8.9.0, x86)
Memory used 188,662k (± 0.03%) 188,448k (± 0.02%) -214k (- 0.11%) 188,370k 188,521k
Parse Time 2.05s (± 0.59%) 2.06s (± 0.74%) +0.01s (+ 0.34%) 2.02s 2.09s
Bind Time 1.07s (± 0.47%) 1.07s (± 0.46%) +0.01s (+ 0.85%) 1.06s 1.08s
Check Time 5.01s (± 0.53%) 4.99s (± 0.51%) -0.01s (- 0.30%) 4.93s 5.05s
Emit Time 6.13s (± 0.89%) 6.17s (± 1.04%) +0.04s (+ 0.67%) 6.07s 6.35s
Total Time 14.25s (± 0.53%) 14.29s (± 0.61%) +0.05s (+ 0.34%) 14.12s 14.53s
Monaco - node (v8.9.0, x86)
Memory used 189,091k (± 0.01%) 189,118k (± 0.02%) +27k (+ 0.01%) 189,056k 189,225k
Parse Time 1.59s (± 1.00%) 1.59s (± 0.42%) -0.00s (- 0.13%) 1.58s 1.61s
Bind Time 0.77s (± 0.80%) 0.77s (± 0.91%) +0.00s (+ 0.26%) 0.76s 0.79s
Check Time 5.30s (± 2.36%) 5.36s (± 1.93%) +0.06s (+ 1.17%) 5.10s 5.53s
Emit Time 3.00s (± 4.15%) 2.99s (± 3.51%) -0.02s (- 0.53%) 2.83s 3.21s
Total Time 10.66s (± 0.48%) 10.71s (± 0.40%) +0.05s (+ 0.42%) 10.60s 10.80s
TFS - node (v8.9.0, x86)
Memory used 170,280k (± 0.01%) 170,286k (± 0.02%) +7k (+ 0.00%) 170,172k 170,379k
Parse Time 1.28s (± 1.16%) 1.27s (± 0.54%) -0.00s (- 0.23%) 1.26s 1.29s
Bind Time 0.71s (± 0.48%) 0.72s (± 0.83%) +0.00s (+ 0.42%) 0.71s 0.73s
Check Time 4.60s (± 1.01%) 4.59s (± 0.71%) -0.01s (- 0.11%) 4.52s 4.66s
Emit Time 2.97s (± 0.98%) 2.96s (± 0.79%) -0.01s (- 0.34%) 2.90s 3.01s
Total Time 9.55s (± 0.64%) 9.54s (± 0.41%) -0.01s (- 0.13%) 9.48s 9.67s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-166-generic
Architecturex64
Available Memory16 GB
Available Memory1 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v10.16.3, x64)
  • node (v12.1.0, x64)
  • node (v8.9.0, x64)
  • node (v8.9.0, x86)
Scenarios
  • Angular - node (v10.16.3, x64)
  • Angular - node (v12.1.0, x64)
  • Angular - node (v8.9.0, x64)
  • Angular - node (v8.9.0, x86)
  • Monaco - node (v10.16.3, x64)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v8.9.0, x64)
  • Monaco - node (v8.9.0, x86)
  • TFS - node (v10.16.3, x64)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v8.9.0, x64)
  • TFS - node (v8.9.0, x86)
Benchmark Name Iterations
Current 36583 10
Baseline master 10

@sandersn
Copy link
Member

sandersn commented Mar 2, 2020

@ahejlsberg This looks ready to merge, right?

@sandersn
Copy link
Member

@ahejlsberg can you update this PR and then merge it?

# Conflicts:
#	src/compiler/checker.ts
@sandersn sandersn merged commit 9120497 into master Mar 16, 2020
@weswigham weswigham deleted the nestedConditionalTypes branch June 16, 2022 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Backlog Bug PRs that fix a backlog bug
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Long conditional type resolves to any
5 participants