Skip to content

Single-expression only type predicates #57552

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

Conversation

RyanCavanaugh
Copy link
Member

Variant on #57465 with tighter rules for inference:

  • Must have exactly one parameter
  • Must be an expression-bodied function, or have a body consisting of a single return with expression
  • May be a getter

Hoping this gets perf cost down to ~0% while still getting ~all of the value

@typescript-bot typescript-bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Feb 26, 2024
@RyanCavanaugh
Copy link
Member Author

@typescript-bot perf test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 26, 2024

Heya @RyanCavanaugh, I've started to run the regular perf test suite on this PR at 4970249. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

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

Here they are:

tsc

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Angular - node (v18.15.0, x64)
Memory used 295,641k (± 0.01%) 295,676k (± 0.01%) ~ 295,649k 295,722k p=0.127 n=6
Parse Time 2.67s (± 0.31%) 2.66s (± 0.24%) ~ 2.65s 2.67s p=0.177 n=6
Bind Time 0.83s (± 0.98%) 0.83s (± 1.25%) ~ 0.81s 0.84s p=0.270 n=6
Check Time 8.24s (± 0.42%) 8.26s (± 0.28%) ~ 8.22s 8.29s p=0.376 n=6
Emit Time 7.11s (± 0.27%) 7.11s (± 0.32%) ~ 7.07s 7.13s p=0.742 n=6
Total Time 18.85s (± 0.27%) 18.85s (± 0.16%) ~ 18.81s 18.89s p=1.000 n=6
Compiler-Unions - node (v18.15.0, x64)
Memory used 194,509k (± 1.66%) 194,105k (± 1.56%) ~ 192,114k 198,053k p=0.378 n=6
Parse Time 1.35s (± 0.98%) 1.36s (± 0.76%) ~ 1.35s 1.38s p=0.181 n=6
Bind Time 0.72s (± 0.00%) 0.72s (± 0.00%) ~ 0.72s 0.72s p=1.000 n=6
Check Time 9.35s (± 0.26%) 9.55s (± 0.63%) +0.20s (+ 2.12%) 9.49s 9.65s p=0.005 n=6
Emit Time 2.63s (± 0.42%) 2.63s (± 0.52%) ~ 2.62s 2.65s p=0.498 n=6
Total Time 14.05s (± 0.21%) 14.27s (± 0.43%) +0.22s (+ 1.54%) 14.20s 14.35s p=0.005 n=6
Monaco - node (v18.15.0, x64)
Memory used 347,486k (± 0.00%) 347,498k (± 0.00%) ~ 347,487k 347,522k p=0.261 n=6
Parse Time 2.48s (± 0.51%) 2.49s (± 0.42%) ~ 2.47s 2.50s p=0.615 n=6
Bind Time 0.93s (± 0.44%) 0.93s (± 0.56%) ~ 0.92s 0.93s p=0.595 n=6
Check Time 6.95s (± 0.30%) 6.98s (± 0.27%) +0.03s (+ 0.48%) 6.95s 7.00s p=0.023 n=6
Emit Time 4.05s (± 0.31%) 4.06s (± 0.62%) ~ 4.03s 4.10s p=0.805 n=6
Total Time 14.40s (± 0.29%) 14.45s (± 0.29%) ~ 14.37s 14.49s p=0.109 n=6
TFS - node (v18.15.0, x64)
Memory used 302,864k (± 0.01%) 302,833k (± 0.00%) -31k (- 0.01%) 302,820k 302,853k p=0.030 n=6
Parse Time 2.02s (± 0.68%) 2.02s (± 0.81%) ~ 2.00s 2.04s p=0.867 n=6
Bind Time 1.00s (± 1.36%) 1.00s (± 1.36%) ~ 0.99s 1.02s p=1.000 n=6
Check Time 6.34s (± 0.42%) 6.34s (± 0.39%) ~ 6.31s 6.37s p=0.936 n=6
Emit Time 3.59s (± 0.52%) 3.60s (± 0.32%) ~ 3.58s 3.61s p=0.625 n=6
Total Time 12.95s (± 0.37%) 12.96s (± 0.29%) ~ 12.90s 13.01s p=0.870 n=6
material-ui - node (v18.15.0, x64)
Memory used 511,289k (± 0.00%) 511,337k (± 0.02%) +49k (+ 0.01%) 511,297k 511,497k p=0.045 n=6
Parse Time 2.65s (± 0.46%) 2.66s (± 0.65%) ~ 2.63s 2.68s p=0.566 n=6
Bind Time 1.00s (± 1.17%) 0.98s (± 0.56%) ~ 0.98s 0.99s p=0.055 n=6
Check Time 17.24s (± 0.45%) 17.28s (± 0.40%) ~ 17.17s 17.38s p=0.199 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 20.89s (± 0.39%) 20.93s (± 0.30%) ~ 20.81s 20.98s p=0.336 n=6
mui-docs - node (v18.15.0, x64)
Memory used 2,294,941k (± 0.00%) 2,295,076k (± 0.00%) +135k (+ 0.01%) 2,294,960k 2,295,221k p=0.031 n=6
Parse Time 12.01s (± 0.84%) 11.98s (± 0.94%) ~ 11.87s 12.16s p=0.689 n=6
Bind Time 2.65s (± 0.44%) 2.63s (± 0.20%) -0.02s (- 0.57%) 2.63s 2.64s p=0.036 n=6
Check Time 101.96s (± 0.86%) 102.24s (± 0.64%) ~ 101.62s 102.98s p=0.809 n=6
Emit Time 0.32s (± 1.27%) 0.32s (± 0.00%) ~ 0.32s 0.32s p=0.405 n=6
Total Time 116.94s (± 0.82%) 117.17s (± 0.62%) ~ 116.44s 117.99s p=1.000 n=6
self-build-src - node (v18.15.0, x64)
Memory used 2,406,440k (± 0.02%) 2,408,093k (± 0.02%) +1,653k (+ 0.07%) 2,407,696k 2,409,191k p=0.005 n=6
Parse Time 5.05s (± 1.26%) 5.09s (± 0.41%) ~ 5.06s 5.11s p=0.295 n=6
Bind Time 1.89s (± 0.80%) 1.88s (± 0.64%) ~ 1.86s 1.89s p=0.218 n=6
Check Time 33.61s (± 0.28%) 33.67s (± 0.25%) ~ 33.58s 33.79s p=0.470 n=6
Emit Time 2.68s (± 0.93%) 2.69s (± 1.23%) ~ 2.65s 2.72s p=0.572 n=6
Total Time 43.25s (± 0.16%) 43.35s (± 0.24%) ~ 43.22s 43.51s p=0.066 n=6
self-compiler - node (v18.15.0, x64)
Memory used 419,202k (± 0.00%) 419,836k (± 0.01%) +634k (+ 0.15%) 419,783k 419,866k p=0.005 n=6
Parse Time 2.71s (± 2.66%) 2.77s (± 2.94%) ~ 2.66s 2.83s p=0.106 n=6
Bind Time 1.17s (± 6.74%) 1.12s (± 6.67%) ~ 1.07s 1.22s p=0.458 n=6
Check Time 15.25s (± 0.34%) 15.26s (± 0.24%) ~ 15.21s 15.29s p=0.627 n=6
Emit Time 1.14s (± 0.66%) 1.13s (± 0.91%) ~ 1.12s 1.15s p=0.351 n=6
Total Time 20.27s (± 0.36%) 20.29s (± 0.15%) ~ 20.25s 20.33s p=0.807 n=6
vscode - node (v18.15.0, x64)
Memory used 2,849,327k (± 0.00%) 2,849,871k (± 0.00%) +545k (+ 0.02%) 2,849,769k 2,849,962k p=0.005 n=6
Parse Time 10.77s (± 0.25%) 10.75s (± 0.21%) ~ 10.72s 10.79s p=0.284 n=6
Bind Time 3.43s (± 0.53%) 3.44s (± 0.34%) ~ 3.43s 3.46s p=0.133 n=6
Check Time 60.80s (± 0.69%) 60.75s (± 0.35%) ~ 60.56s 61.17s p=0.748 n=6
Emit Time 17.45s (±10.19%) 16.31s (± 0.97%) ~ 16.18s 16.51s p=0.229 n=6
Total Time 92.45s (± 2.27%) 91.24s (± 0.23%) ~ 91.01s 91.51s p=0.936 n=6
webpack - node (v18.15.0, x64)
Memory used 396,926k (± 0.01%) 396,983k (± 0.01%) ~ 396,928k 397,062k p=0.149 n=6
Parse Time 3.16s (± 0.91%) 3.17s (± 0.86%) ~ 3.13s 3.21s p=1.000 n=6
Bind Time 1.39s (± 1.08%) 1.40s (± 1.08%) ~ 1.37s 1.41s p=0.325 n=6
Check Time 14.08s (± 0.50%) 14.17s (± 0.40%) +0.09s (+ 0.65%) 14.13s 14.28s p=0.036 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 18.63s (± 0.36%) 18.73s (± 0.35%) +0.10s (+ 0.55%) 18.65s 18.83s p=0.037 n=6
xstate - node (v18.15.0, x64)
Memory used 513,417k (± 0.01%) 513,474k (± 0.01%) ~ 513,410k 513,546k p=0.066 n=6
Parse Time 3.27s (± 0.19%) 3.28s (± 0.30%) ~ 3.27s 3.29s p=0.151 n=6
Bind Time 1.54s (± 0.68%) 1.54s (± 0.49%) ~ 1.53s 1.55s p=0.611 n=6
Check Time 2.87s (± 0.68%) 2.89s (± 0.49%) ~ 2.87s 2.91s p=0.107 n=6
Emit Time 0.08s (± 4.99%) 0.07s (± 5.69%) 🟩-0.01s (-12.24%) 0.07s 0.08s p=0.008 n=6
Total Time 7.78s (± 0.39%) 7.79s (± 0.16%) ~ 7.78s 7.81s p=0.291 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Angular - node (v18.15.0, x64)
  • Compiler-Unions - node (v18.15.0, x64)
  • Monaco - node (v18.15.0, x64)
  • TFS - node (v18.15.0, x64)
  • material-ui - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

tsserver

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-UnionsTSServer - node (v18.15.0, x64)
Req 1 - updateOpen 2,354ms (± 0.76%) 2,370ms (± 0.67%) ~ 2,341ms 2,387ms p=0.173 n=6
Req 2 - geterr 5,500ms (± 1.15%) 5,634ms (± 1.41%) +135ms (+ 2.45%) 5,569ms 5,791ms p=0.020 n=6
Req 3 - references 325ms (± 0.99%) 324ms (± 0.72%) ~ 321ms 327ms p=0.565 n=6
Req 4 - navto 277ms (± 0.99%) 276ms (± 0.77%) ~ 274ms 279ms p=0.408 n=6
Req 5 - completionInfo count 1,357 (± 0.00%) 1,357 (± 0.00%) ~ 1,357 1,357 p=1.000 n=6
Req 5 - completionInfo 84ms (± 6.51%) 90ms (± 7.59%) ~ 82ms 96ms p=0.100 n=6
CompilerTSServer - node (v18.15.0, x64)
Req 1 - updateOpen 2,477ms (± 0.93%) 2,471ms (± 0.73%) ~ 2,442ms 2,488ms p=0.521 n=6
Req 2 - geterr 4,175ms (± 1.89%) 4,242ms (± 1.86%) ~ 4,162ms 4,318ms p=0.066 n=6
Req 3 - references 337ms (± 1.71%) 333ms (± 0.32%) ~ 331ms 334ms p=0.372 n=6
Req 4 - navto 284ms (± 0.14%) 285ms (± 0.41%) ~ 284ms 287ms p=0.087 n=6
Req 5 - completionInfo count 1,519 (± 0.00%) 1,519 (± 0.00%) ~ 1,519 1,519 p=1.000 n=6
Req 5 - completionInfo 85ms (± 6.44%) 81ms (± 7.48%) ~ 74ms 89ms p=0.168 n=6
xstateTSServer - node (v18.15.0, x64)
Req 1 - updateOpen 2,614ms (± 0.38%) 2,618ms (± 0.47%) ~ 2,605ms 2,636ms p=0.688 n=6
Req 2 - geterr 1,739ms (± 3.24%) 1,746ms (± 2.75%) ~ 1,690ms 1,800ms p=0.575 n=6
Req 3 - references 108ms (± 0.51%) 115ms (± 9.16%) ~ 106ms 128ms p=0.154 n=6
Req 4 - navto 371ms (± 0.37%) 371ms (± 0.93%) ~ 364ms 374ms p=1.000 n=6
Req 5 - completionInfo count 2,079 (± 0.00%) 2,079 (± 0.00%) ~ 2,079 2,079 p=1.000 n=6
Req 5 - completionInfo 311ms (± 1.42%) 310ms (± 2.21%) ~ 299ms 317ms p=0.809 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • CompilerTSServer - node (v18.15.0, x64)
  • Compiler-UnionsTSServer - node (v18.15.0, x64)
  • xstateTSServer - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

startup

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
tsc-startup - node (v18.15.0, x64)
Execution time 153.68ms (± 0.19%) 153.64ms (± 0.18%) ~ 152.40ms 157.38ms p=0.367 n=600
tsserver-startup - node (v18.15.0, x64)
Execution time 229.90ms (± 0.16%) 229.88ms (± 0.15%) ~ 228.59ms 234.43ms p=0.558 n=600
tsserverlibrary-startup - node (v18.15.0, x64)
Execution time 231.34ms (± 0.17%) 231.44ms (± 0.18%) +0.10ms (+ 0.04%) 229.81ms 236.99ms p=0.033 n=600
typescript-startup - node (v18.15.0, x64)
Execution time 231.07ms (± 0.18%) 231.23ms (± 0.20%) +0.15ms (+ 0.07%) 229.23ms 238.40ms p=0.000 n=600
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • tsc-startup - node (v18.15.0, x64)
  • tsserver-startup - node (v18.15.0, x64)
  • tsserverlibrary-startup - node (v18.15.0, x64)
  • typescript-startup - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Developer Information:

Download Benchmarks

@RyanCavanaugh
Copy link
Member Author

@typescript-bot perf test this faster

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 26, 2024

Heya @RyanCavanaugh, I've started to run the faster perf test suite on this PR at 29cdadc. You can monitor the build here.

Update: The results are in!

@danvk
Copy link
Contributor

danvk commented Feb 26, 2024

@RyanCavanaugh Happy to see this caught your interest 😊

My suspicion is that at least some of the slowdown in Compiler-Unions is due to the extra work that happens indirectly because of the new type guards themselves, rather than the direct new work of determining which functions are type guards.

I found this sort of "ablation test" useful in teasing these two apart:
danvk/TypeScript@infer-type-predicate-16069...danvk:TypeScript:ablation-2024-02-26

i.e. do all the work, but don't actually infer the type predicate.

With my PR as of last week I got results that made sense: ~4% slowdown on the PR, ~1.7% slowdown on the ablation → ~2.3% of the slowdown is due to more elaborate type checking.
With the latest version of my PR the results made less sense: ~1.8% slowdown vs. ~1.75% slowdown on the ablation → almost no slowdown is due to extra type checking? But it's inferring all the same type predicates… 🤷

@RyanCavanaugh
Copy link
Member Author

Not just from a perf perspective, but my current take (subject to additional thinking) is that this is also a correctness / DX improvement. Any function that does anything but the type guard itself is likely to either a) have additional constraints that mean it's not really a type guard or b) only appear to guard as a sort of side effect of implementation. But I want to think about that more

@typescript-bot
Copy link
Collaborator

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

Here they are:

tsc

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Angular - node (v18.15.0, x64)
Memory used 295,647k (± 0.01%) 295,682k (± 0.01%) +35k (+ 0.01%) 295,641k 295,712k p=0.031 n=6
Parse Time 2.67s (± 0.19%) 2.67s (± 0.47%) ~ 2.66s 2.69s p=0.931 n=6
Bind Time 0.84s (± 1.45%) 0.83s (± 0.62%) ~ 0.82s 0.83s p=0.142 n=6
Check Time 8.26s (± 0.35%) 8.25s (± 0.30%) ~ 8.22s 8.29s p=0.520 n=6
Emit Time 7.10s (± 0.45%) 7.10s (± 0.27%) ~ 7.07s 7.12s p=0.686 n=6
Total Time 18.86s (± 0.25%) 18.85s (± 0.16%) ~ 18.80s 18.88s p=0.466 n=6
Compiler-Unions - node (v18.15.0, x64)
Memory used 192,549k (± 1.25%) 194,066k (± 1.53%) +1,517k (+ 0.79%) 192,083k 197,930k p=0.031 n=6
Parse Time 1.35s (± 1.21%) 1.36s (± 2.39%) ~ 1.31s 1.39s p=0.747 n=6
Bind Time 0.72s (± 0.00%) 0.72s (± 0.00%) ~ 0.72s 0.72s p=1.000 n=6
Check Time 9.36s (± 0.43%) 9.55s (± 0.69%) +0.19s (+ 2.01%) 9.46s 9.63s p=0.005 n=6
Emit Time 2.62s (± 0.89%) 2.64s (± 0.69%) ~ 2.61s 2.66s p=0.144 n=6
Total Time 14.05s (± 0.42%) 14.27s (± 0.43%) +0.22s (+ 1.55%) 14.19s 14.35s p=0.005 n=6
Monaco - node (v18.15.0, x64)
Memory used 347,480k (± 0.00%) 347,500k (± 0.00%) +21k (+ 0.01%) 347,481k 347,520k p=0.045 n=6
Parse Time 2.48s (± 0.61%) 2.48s (± 0.67%) ~ 2.46s 2.51s p=0.568 n=6
Bind Time 0.93s (± 0.00%) 0.93s (± 0.44%) ~ 0.93s 0.94s p=0.405 n=6
Check Time 6.96s (± 0.29%) 7.00s (± 0.33%) +0.04s (+ 0.65%) 6.97s 7.03s p=0.012 n=6
Emit Time 4.07s (± 0.51%) 4.07s (± 0.37%) ~ 4.05s 4.09s p=1.000 n=6
Total Time 14.43s (± 0.27%) 14.48s (± 0.26%) ~ 14.41s 14.51s p=0.127 n=6
TFS - node (v18.15.0, x64)
Memory used 302,870k (± 0.00%) 302,837k (± 0.00%) -33k (- 0.01%) 302,818k 302,855k p=0.005 n=6
Parse Time 2.02s (± 0.79%) 2.01s (± 0.92%) ~ 1.99s 2.04s p=0.685 n=6
Bind Time 1.01s (± 1.32%) 1.00s (± 1.03%) ~ 0.99s 1.02s p=0.591 n=6
Check Time 6.35s (± 0.26%) 6.33s (± 0.50%) ~ 6.29s 6.38s p=0.330 n=6
Emit Time 3.60s (± 0.42%) 3.59s (± 0.33%) ~ 3.58s 3.61s p=0.804 n=6
Total Time 12.98s (± 0.13%) 12.95s (± 0.25%) ~ 12.89s 12.97s p=0.056 n=6
material-ui - node (v18.15.0, x64)
Memory used 511,316k (± 0.02%) 511,327k (± 0.01%) ~ 511,302k 511,402k p=0.128 n=6
Parse Time 2.66s (± 0.52%) 2.66s (± 0.39%) ~ 2.65s 2.68s p=0.391 n=6
Bind Time 1.00s (± 0.82%) 0.99s (± 0.76%) ~ 0.98s 1.00s p=0.206 n=6
Check Time 17.26s (± 0.25%) 17.26s (± 0.33%) ~ 17.20s 17.36s p=0.561 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 20.91s (± 0.25%) 20.92s (± 0.30%) ~ 20.84s 21.02s p=1.000 n=6
mui-docs - node (v18.15.0, x64)
Memory used 2,294,906k (± 0.00%) 2,295,113k (± 0.00%) +207k (+ 0.01%) 2,295,042k 2,295,186k p=0.005 n=6
Parse Time 11.96s (± 0.53%) 12.05s (± 1.34%) ~ 11.93s 12.37s p=0.261 n=6
Bind Time 2.64s (± 0.54%) 2.65s (± 0.37%) ~ 2.64s 2.66s p=0.315 n=6
Check Time 102.37s (± 0.64%) 101.48s (± 0.36%) -0.89s (- 0.87%) 100.86s 101.81s p=0.031 n=6
Emit Time 0.32s (± 1.27%) 0.32s (± 0.00%) ~ 0.32s 0.32s p=0.405 n=6
Total Time 117.29s (± 0.58%) 116.50s (± 0.20%) -0.79s (- 0.67%) 116.19s 116.77s p=0.031 n=6
self-build-src - node (v18.15.0, x64)
Memory used 2,405,992k (± 0.02%) 2,408,043k (± 0.02%) +2,051k (+ 0.09%) 2,407,279k 2,408,635k p=0.005 n=6
Parse Time 5.08s (± 0.46%) 5.07s (± 0.95%) ~ 5.02s 5.13s p=0.810 n=6
Bind Time 1.89s (± 0.65%) 1.88s (± 0.67%) ~ 1.87s 1.90s p=0.452 n=6
Check Time 33.66s (± 0.33%) 33.76s (± 0.42%) ~ 33.49s 33.86s p=0.173 n=6
Emit Time 2.68s (± 1.04%) 2.74s (± 0.78%) +0.06s (+ 2.05%) 2.71s 2.76s p=0.013 n=6
Total Time 43.33s (± 0.26%) 43.47s (± 0.29%) ~ 43.23s 43.58s p=0.093 n=6
self-compiler - node (v18.15.0, x64)
Memory used 419,236k (± 0.01%) 419,877k (± 0.01%) +641k (+ 0.15%) 419,821k 419,906k p=0.005 n=6
Parse Time 2.79s (± 2.68%) 2.81s (± 2.53%) ~ 2.67s 2.87s p=0.332 n=6
Bind Time 1.10s (± 5.91%) 1.10s (± 5.63%) ~ 1.07s 1.23s p=0.388 n=6
Check Time 15.23s (± 0.30%) 15.28s (± 0.18%) +0.05s (+ 0.31%) 15.25s 15.32s p=0.044 n=6
Emit Time 1.13s (± 0.91%) 1.14s (± 1.47%) ~ 1.12s 1.16s p=0.512 n=6
Total Time 20.25s (± 0.22%) 20.34s (± 0.15%) +0.08s (+ 0.40%) 20.29s 20.37s p=0.013 n=6
vscode - node (v18.15.0, x64)
Memory used 2,849,332k (± 0.00%) 2,849,902k (± 0.00%) +570k (+ 0.02%) 2,849,846k 2,849,995k p=0.005 n=6
Parse Time 10.74s (± 0.16%) 10.75s (± 0.33%) ~ 10.72s 10.81s p=0.392 n=6
Bind Time 3.43s (± 0.41%) 3.44s (± 0.84%) ~ 3.42s 3.50s p=0.413 n=6
Check Time 60.60s (± 0.30%) 60.87s (± 0.13%) +0.27s (+ 0.44%) 60.71s 60.93s p=0.010 n=6
Emit Time 16.24s (± 0.86%) 16.31s (± 0.62%) ~ 16.19s 16.44s p=0.470 n=6
Total Time 91.00s (± 0.32%) 91.38s (± 0.18%) +0.37s (+ 0.41%) 91.11s 91.59s p=0.031 n=6
webpack - node (v18.15.0, x64)
Memory used 396,876k (± 0.02%) 396,936k (± 0.01%) ~ 396,848k 396,978k p=0.173 n=6
Parse Time 3.16s (± 0.33%) 3.15s (± 0.58%) ~ 3.13s 3.17s p=0.192 n=6
Bind Time 1.39s (± 0.59%) 1.39s (± 0.29%) ~ 1.39s 1.40s p=0.584 n=6
Check Time 14.13s (± 0.40%) 14.12s (± 0.45%) ~ 14.06s 14.21s p=0.808 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 18.69s (± 0.29%) 18.66s (± 0.35%) ~ 18.59s 18.77s p=0.334 n=6
xstate - node (v18.15.0, x64)
Memory used 513,418k (± 0.01%) 513,469k (± 0.01%) ~ 513,413k 513,526k p=0.092 n=6
Parse Time 3.27s (± 0.25%) 3.27s (± 0.27%) ~ 3.26s 3.28s p=0.550 n=6
Bind Time 1.54s (± 0.26%) 1.54s (± 0.26%) ~ 1.54s 1.55s p=1.000 n=6
Check Time 2.88s (± 0.48%) 2.91s (± 0.71%) +0.03s (+ 0.98%) 2.88s 2.94s p=0.035 n=6
Emit Time 0.08s (± 0.00%) 0.07s (± 0.00%) 🟩-0.01s (-12.50%) 0.07s 0.07s p=0.001 n=6
Total Time 7.78s (± 0.15%) 7.80s (± 0.17%) ~ 7.78s 7.81s p=0.073 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Angular - node (v18.15.0, x64)
  • Compiler-Unions - node (v18.15.0, x64)
  • Monaco - node (v18.15.0, x64)
  • TFS - node (v18.15.0, x64)
  • material-ui - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Developer Information:

Download Benchmarks

@RyanCavanaugh
Copy link
Member Author

Newest commit no-ops the result as suggested above (for perf testing only)

@RyanCavanaugh
Copy link
Member Author

@typescript-bot perf test this faster

@typescript-bot
Copy link
Collaborator

typescript-bot commented Feb 26, 2024

Heya @RyanCavanaugh, I've started to run the faster perf test suite on this PR at 466e186. You can monitor the build here.

Update: The results are in!

@danvk
Copy link
Contributor

danvk commented Feb 26, 2024

Running the two versions against #54148 and tsc itself (self-check), this is the only dropped predicate that I see (in src/compiler/transformers/es2018.ts):

    function isSuperContainer(node: Node) {
        const kind = node.kind;
        return kind === SyntaxKind.ClassDeclaration
            || kind === SyntaxKind.Constructor
            || kind === SyntaxKind.MethodDeclaration
            || kind === SyntaxKind.GetAccessor
            || kind === SyntaxKind.SetAccessor;
    }

Definitely a legitimate inference, and maybe a little confusing that you'd change the return type by factoring out a local variable. But not a huge loss.

@typescript-bot
Copy link
Collaborator

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

Here they are:

tsc

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Angular - node (v18.15.0, x64)
Memory used 295,676k (± 0.01%) 295,699k (± 0.01%) ~ 295,663k 295,753k p=0.229 n=6
Parse Time 2.67s (± 0.39%) 2.67s (± 0.45%) ~ 2.66s 2.69s p=0.735 n=6
Bind Time 0.83s (± 1.25%) 0.83s (± 0.66%) ~ 0.82s 0.83s p=0.090 n=6
Check Time 8.28s (± 0.91%) 8.26s (± 0.30%) ~ 8.21s 8.28s p=0.746 n=6
Emit Time 7.12s (± 0.09%) 7.13s (± 0.88%) ~ 7.10s 7.26s p=0.096 n=6
Total Time 18.90s (± 0.42%) 18.88s (± 0.46%) ~ 18.80s 19.05s p=0.418 n=6
Compiler-Unions - node (v18.15.0, x64)
Memory used 192,452k (± 0.70%) 195,969k (± 1.54%) +3,517k (+ 1.83%) 192,049k 198,089k p=0.031 n=6
Parse Time 1.36s (± 0.98%) 1.36s (± 0.62%) ~ 1.34s 1.36s p=0.788 n=6
Bind Time 0.72s (± 0.00%) 0.72s (± 0.00%) ~ 0.72s 0.72s p=1.000 n=6
Check Time 9.35s (± 0.37%) 9.50s (± 0.32%) +0.16s (+ 1.66%) 9.47s 9.56s p=0.005 n=6
Emit Time 2.63s (± 0.93%) 2.59s (± 0.38%) -0.04s (- 1.46%) 2.58s 2.60s p=0.023 n=6
Total Time 14.05s (± 0.15%) 14.17s (± 0.25%) +0.11s (+ 0.79%) 14.13s 14.23s p=0.005 n=6
Monaco - node (v18.15.0, x64)
Memory used 347,468k (± 0.00%) 347,498k (± 0.00%) +30k (+ 0.01%) 347,489k 347,522k p=0.005 n=6
Parse Time 2.48s (± 0.54%) 2.48s (± 0.47%) ~ 2.46s 2.49s p=0.737 n=6
Bind Time 0.92s (± 0.59%) 0.93s (± 0.68%) ~ 0.92s 0.94s p=0.201 n=6
Check Time 6.95s (± 0.76%) 7.02s (± 0.72%) +0.07s (+ 0.98%) 6.97s 7.11s p=0.045 n=6
Emit Time 4.06s (± 0.51%) 4.05s (± 0.62%) ~ 4.01s 4.08s p=0.329 n=6
Total Time 14.42s (± 0.27%) 14.47s (± 0.40%) ~ 14.41s 14.57s p=0.091 n=6
TFS - node (v18.15.0, x64)
Memory used 302,878k (± 0.01%) 302,841k (± 0.00%) -37k (- 0.01%) 302,833k 302,854k p=0.005 n=6
Parse Time 2.01s (± 1.23%) 2.01s (± 0.51%) ~ 1.99s 2.02s p=0.808 n=6
Bind Time 1.01s (± 1.77%) 1.01s (± 1.03%) ~ 1.00s 1.03s p=0.462 n=6
Check Time 6.35s (± 0.45%) 6.31s (± 0.25%) ~ 6.29s 6.33s p=0.050 n=6
Emit Time 3.60s (± 0.49%) 3.60s (± 0.60%) ~ 3.57s 3.63s p=0.935 n=6
Total Time 12.96s (± 0.20%) 12.93s (± 0.25%) ~ 12.89s 12.98s p=0.091 n=6
material-ui - node (v18.15.0, x64)
Memory used 511,289k (± 0.00%) 511,314k (± 0.01%) ~ 511,267k 511,367k p=0.128 n=6
Parse Time 2.66s (± 0.61%) 2.65s (± 0.57%) ~ 2.63s 2.67s p=0.932 n=6
Bind Time 0.99s (± 0.41%) 1.00s (± 0.98%) ~ 0.99s 1.01s p=0.213 n=6
Check Time 17.26s (± 0.24%) 17.25s (± 0.15%) ~ 17.22s 17.29s p=0.747 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 20.91s (± 0.16%) 20.91s (± 0.20%) ~ 20.84s 20.97s p=0.685 n=6
mui-docs - node (v18.15.0, x64)
Memory used 2,294,911k (± 0.00%) 2,294,975k (± 0.00%) ~ 2,294,919k 2,295,053k p=0.471 n=6
Parse Time 11.97s (± 0.76%) 12.04s (± 0.89%) ~ 11.88s 12.18s p=0.173 n=6
Bind Time 2.64s (± 0.44%) 2.65s (± 0.48%) ~ 2.63s 2.66s p=0.281 n=6
Check Time 101.51s (± 0.75%) 101.71s (± 0.55%) ~ 101.00s 102.56s p=0.936 n=6
Emit Time 0.32s (± 1.28%) 0.32s (± 0.00%) ~ 0.32s 0.32s p=0.405 n=6
Total Time 116.44s (± 0.67%) 116.72s (± 0.55%) ~ 115.95s 117.69s p=0.748 n=6
self-build-src - node (v18.15.0, x64)
Memory used 2,406,811k (± 0.03%) 2,407,129k (± 0.03%) ~ 2,406,361k 2,407,787k p=0.298 n=6
Parse Time 5.09s (± 0.53%) 5.07s (± 0.94%) ~ 5.02s 5.13s p=0.574 n=6
Bind Time 1.88s (± 0.62%) 1.88s (± 0.34%) ~ 1.87s 1.89s p=1.000 n=6
Check Time 33.73s (± 0.45%) 33.95s (± 0.37%) +0.22s (+ 0.66%) 33.80s 34.12s p=0.031 n=6
Emit Time 2.67s (± 1.61%) 2.69s (± 1.43%) ~ 2.65s 2.76s p=0.688 n=6
Total Time 43.39s (± 0.40%) 43.60s (± 0.37%) ~ 43.37s 43.81s p=0.078 n=6
self-compiler - node (v18.15.0, x64)
Memory used 419,245k (± 0.01%) 419,651k (± 0.01%) +406k (+ 0.10%) 419,593k 419,718k p=0.005 n=6
Parse Time 2.81s (± 1.84%) 2.79s (± 3.15%) ~ 2.68s 2.88s p=0.872 n=6
Bind Time 1.10s (± 4.71%) 1.12s (± 7.02%) ~ 1.07s 1.23s p=0.730 n=6
Check Time 15.28s (± 0.55%) 15.32s (± 0.37%) ~ 15.24s 15.37s p=0.467 n=6
Emit Time 1.15s (± 1.82%) 1.14s (± 0.74%) ~ 1.13s 1.15s p=0.198 n=6
Total Time 20.33s (± 0.46%) 20.37s (± 0.31%) ~ 20.29s 20.45s p=0.689 n=6
vscode - node (v18.15.0, x64)
Memory used 2,849,402k (± 0.00%) 2,849,568k (± 0.00%) +167k (+ 0.01%) 2,849,440k 2,849,683k p=0.005 n=6
Parse Time 10.78s (± 0.37%) 10.75s (± 0.25%) ~ 10.70s 10.78s p=0.163 n=6
Bind Time 3.43s (± 0.50%) 3.43s (± 0.66%) ~ 3.41s 3.47s p=0.684 n=6
Check Time 60.73s (± 0.34%) 60.90s (± 0.44%) ~ 60.67s 61.38s p=0.471 n=6
Emit Time 16.32s (± 0.87%) 16.20s (± 0.44%) ~ 16.09s 16.31s p=0.173 n=6
Total Time 91.26s (± 0.25%) 91.27s (± 0.36%) ~ 91.01s 91.88s p=0.630 n=6
webpack - node (v18.15.0, x64)
Memory used 396,914k (± 0.01%) 396,955k (± 0.02%) ~ 396,862k 397,020k p=0.298 n=6
Parse Time 3.17s (± 0.50%) 3.15s (± 0.38%) ~ 3.14s 3.17s p=0.067 n=6
Bind Time 1.40s (± 0.78%) 1.38s (± 0.76%) -0.02s (- 1.07%) 1.37s 1.40s p=0.046 n=6
Check Time 14.09s (± 0.30%) 14.15s (± 0.22%) +0.06s (+ 0.44%) 14.11s 14.19s p=0.024 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 18.66s (± 0.27%) 18.69s (± 0.18%) ~ 18.66s 18.74s p=0.372 n=6
xstate - node (v18.15.0, x64)
Memory used 513,423k (± 0.01%) 513,471k (± 0.01%) ~ 513,430k 513,525k p=0.173 n=6
Parse Time 3.28s (± 0.23%) 3.27s (± 0.37%) ~ 3.26s 3.29s p=0.502 n=6
Bind Time 1.54s (± 0.26%) 1.54s (± 0.49%) ~ 1.53s 1.55s p=1.000 n=6
Check Time 2.87s (± 0.52%) 2.89s (± 0.62%) +0.02s (+ 0.81%) 2.86s 2.91s p=0.040 n=6
Emit Time 0.08s (± 0.00%) 0.07s (± 0.00%) 🟩-0.01s (-12.50%) 0.07s 0.07s p=0.001 n=6
Total Time 7.77s (± 0.19%) 7.79s (± 0.39%) ~ 7.74s 7.82s p=0.377 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Angular - node (v18.15.0, x64)
  • Compiler-Unions - node (v18.15.0, x64)
  • Monaco - node (v18.15.0, x64)
  • TFS - node (v18.15.0, x64)
  • material-ui - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Developer Information:

Download Benchmarks

@bradzacher
Copy link
Contributor

bradzacher commented Feb 27, 2024

Definitely a legitimate inference, and maybe a little confusing that you'd change the return type by factoring out a local variable. But not a huge loss.

As I mentioned on twitter this feature is very similar to flow's %checks annotation.
It has the same limitation in that the function must only have the return statement because it essentially inlines the expression within the call site and statements can't be inlined in an expression.

From a DevX perspective it is super annoying because you can't do small stylistic refactors like you mentioned like extracting a variable. So you ended up doing stuff like chaining guard functions to work around the limitation.

function isBar(arg: Bar): %checks {
  return arg.type === 'bar';
}
function isFoo(arg: Foo): %checks {
  return isBar(arg.foo);
}

Though difference between the flow solution and this TS one was that flow requires an explicit %checks annotation on the return type so if you did something wrong like extract the variable you'd get a flow error. In contrast, as you said, TS being implicit means you will accidentally fall out of the implicit guard case and have no feedback to warn you of that fact.

There's probably some scope for a lint rule to catch it (though it'd be a first of its kind and I'm not sure if it's fully possible) but it'd be cool if TS had more advanced rules.

@danvk
Copy link
Contributor

danvk commented Feb 27, 2024

As I mentioned on twitter this feature is very similar to flow's %checks annotation.

A few thoughts on how this feature compares with %checks:

@RyanCavanaugh
Copy link
Member Author

From a DevX perspective it is super annoying because you can't do small stylistic refactors like you mentioned like extracting a variable. So you ended up doing stuff like chaining guard functions to work around the limitation.

I don't think TS really has this problem since you're not forced to infer the predicateness of the function; you can just write isBar(x: unknown): x is Bar.

@bradzacher
Copy link
Contributor

I don't think TS really has this problem since you're not forced to infer the predicateness of the function; you can just write isBar(x: unknown): x is Bar.

That's entirely true. FWIW flow also supports TS style type guard annotations now (but safer than TS cos flow validates the predicate matches the refinement).

The thing that I'd be scared about as a user is "actions at a distance". Eg the small refactor of one function causes type errors in other files.

Eg if your codebase relies upon inferred return types you could end up with a really spooky action at a distance as a refined variable changes type which changes the inferred return type of a function which causes a type error.
If that inferred return type function is in a library - it could instead mean an unintended breaking API change.

@RyanCavanaugh
Copy link
Member Author

The thing that I'd be scared about as a user is "actions at a distance". Eg the small refactor of one function causes type errors in other files.

That's a pretty good point and makes me think more about the expression vs declaration distinction -- function expressions are almost always "local", whereas declarations are much more likely to be exported with an inferred type. People might not realize they're exporting a type predicate and it might not be their intent.

@craigphicks
Copy link

craigphicks commented Mar 9, 2024

@bradzacher - There's probably some scope for a lint rule to catch it (though it'd be a first of its kind and I'm not sure if it's fully possible) but it'd be cool if TS had more advanced rules.

@RyanCavanaugh - People might not realize they're exporting a type predicate and it might not be their intent.

Suggestion 1

I hear Brad saying is that "inference" can be turned around to be a confirmation of the users declared typePredicate, to catch cases where a mismatch was not intended. Using it that way wouldn't cause the problem that Ryan mentions.

I also hear Brad saying use it only on special occasions, like a lint rule, avoiding the performance issue, at least while editing.

I wonder if this functionality (now purposed to be a typePredicate checker, as opposed to a silent inferr-er) would be hard to separate out as a separate API function for use by lint?

Yes, probably hard to separate it out from a whole compile. In that case how about adding a command line flag to allow a "super check", setting that flag to coincide with the occasions when lint would be used immediately before or afterwards anyway. A super check run could include typePredicate checking, and/or any similar expensive checking too expensive for a regular run.

Having to add @ts-ignore (or something) for a typePredicate that wasn't expected to pass the check would also be a useful form of documentation showing the users intention.

Suggestion 2

For some cases where the typePredicate would very be verbose/redundant, the user might prefer not to type it in. If there were some way in the server API to request an inferred type predicate (using the super check flag mentioned in 1?) then it could appear after is as an auto complete. That wouldn't be always, it would only happen when the cursor was positioned after is. Again, this would avoid the issue that Ryan mentions.


Maybe I should have posted this on #57465. I guess I'll double post it - I can always delete one later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants