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

Exhaustive case completion for switch statements #50996

Merged
merged 27 commits into from
Dec 2, 2022
Merged

Conversation

gabritto
Copy link
Member

@gabritto gabritto commented Sep 29, 2022

This PR aims to add an exhaustive case completion in the completions provided inside a switch statement.
The exhaustive case completion aims to provide all the possible case clauses that are not already present in the switch statement.
The completion is also only provided if the switch expression has a type that is a union of literal types, because that's when it's likely a user might want an exhaustive case list in their switch statement, and that's when we can offer the list of cases based on the type.

Basic examples

enum E {
    A = 0,
    B = "B",
    C = "C",
}
declare const e: E;
switch (e) {
    |
}

becomes:

switch (e) {
    case E.A:
    case E.B:
    case E.C:
}

when the case completion is accepted, and

declare const kind: "x" | "y";
switch (kind) {
    |
}

becomes

switch (kind) {
    case "x":
    case "y":
}

Open items

  • The preview text on vscode shows the wrong indentation. Is this something vscode can fix? Or should we fix it? How does it work in other editors (e.g. vim, emacs)?

  • Tab stops: should we add tab stops after each case clause? If so, should the tab stops be on the same line as the case, or on the next line?

@typescript-bot typescript-bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Sep 29, 2022
@gabritto gabritto changed the title Gabritto/switchsnippet Exhaustive case completion for switch statements Nov 10, 2022
@@ -22698,35 +22695,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
* @param text a valid bigint string excluding a trailing `n`, but including a possible prefix `-`. Use `isValidBigIntString(text, roundTripOnly)` before calling this function.
*/
function parseBigIntLiteralType(text: string) {
const negative = text.startsWith("-");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this into a new function in utilities.

@@ -6881,10 +6881,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (isSingleOrDoubleQuote(firstChar) && some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) {
return factory.createStringLiteral(getSpecifierForModuleSymbol(symbol, context));
}
const canUsePropertyAccess = firstChar === CharacterCodes.hash ?
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also moved this into a new function in utilities.

@gabritto gabritto marked this pull request as ready for review November 11, 2022 00:21
@gabritto
Copy link
Member Author

@typescript-bot perf test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 11, 2022

Heya @gabritto, I've started to run the perf test suite on this PR at 97dcf69. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

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

Here they are:

Compiler

Comparison Report - main..50996
Metric main 50996 Delta Best Worst
Angular - node (v18.10.0, x64)
Memory used 341,171k (± 0.02%) 341,168k (± 0.01%) -3k (- 0.00%) 341,101k 341,258k
Parse Time 1.57s (± 1.10%) 1.56s (± 1.04%) -0.01s (- 0.45%) 1.52s 1.59s
Bind Time 0.54s (± 1.30%) 0.54s (± 1.27%) -0.01s (- 0.92%) 0.52s 0.55s
Check Time 4.03s (± 0.80%) 4.02s (± 0.67%) -0.01s (- 0.20%) 3.99s 4.12s
Emit Time 4.31s (± 1.44%) 4.30s (± 1.33%) -0.01s (- 0.16%) 4.18s 4.43s
Total Time 10.44s (± 0.87%) 10.42s (± 0.76%) -0.02s (- 0.21%) 10.23s 10.61s
Compiler-Unions - node (v18.10.0, x64)
Memory used 189,949k (± 0.65%) 188,257k (± 1.07%) -1,692k (- 0.89%) 184,898k 190,570k
Parse Time 0.61s (± 1.73%) 0.62s (± 1.13%) +0.00s (+ 0.65%) 0.60s 0.63s
Bind Time 0.33s (± 1.45%) 0.33s (± 1.95%) +0.00s (+ 1.53%) 0.32s 0.35s
Check Time 5.00s (± 0.90%) 4.99s (± 1.11%) -0.01s (- 0.22%) 4.89s 5.10s
Emit Time 1.52s (± 0.54%) 1.54s (± 0.76%) +0.01s (+ 0.85%) 1.50s 1.55s
Total Time 7.46s (± 0.72%) 7.47s (± 0.85%) +0.01s (+ 0.15%) 7.34s 7.60s
Monaco - node (v18.10.0, x64)
Memory used 320,471k (± 0.02%) 320,479k (± 0.02%) +8k (+ 0.00%) 320,396k 320,664k
Parse Time 1.16s (± 1.31%) 1.16s (± 1.40%) +0.01s (+ 0.60%) 1.14s 1.21s
Bind Time 0.49s (± 1.06%) 0.49s (± 1.33%) -0.00s (- 0.20%) 0.47s 0.50s
Check Time 3.86s (± 0.80%) 3.87s (± 0.34%) +0.01s (+ 0.31%) 3.85s 3.91s
Emit Time 2.26s (± 1.50%) 2.27s (± 0.72%) +0.01s (+ 0.66%) 2.24s 2.32s
Total Time 7.76s (± 0.73%) 7.79s (± 0.44%) +0.03s (+ 0.41%) 7.75s 7.89s
TFS - node (v18.10.0, x64)
Memory used 283,117k (± 0.15%) 283,289k (± 0.19%) +172k (+ 0.06%) 282,836k 284,807k
Parse Time 0.96s (± 0.98%) 0.97s (± 1.19%) +0.00s (+ 0.42%) 0.95s 0.99s
Bind Time 0.45s (± 5.85%) 0.48s (± 9.67%) +0.03s (+ 6.49%) 0.43s 0.58s
Check Time 3.80s (± 0.82%) 3.80s (± 0.63%) -0.00s (- 0.05%) 3.75s 3.85s
Emit Time 2.22s (± 1.35%) 2.20s (± 1.00%) -0.02s (- 1.04%) 2.15s 2.25s
Total Time 7.43s (± 0.85%) 7.44s (± 0.76%) +0.00s (+ 0.07%) 7.33s 7.54s
material-ui - node (v18.10.0, x64)
Memory used 435,954k (± 0.01%) 435,980k (± 0.01%) +26k (+ 0.01%) 435,907k 436,171k
Parse Time 1.34s (± 0.94%) 1.34s (± 0.94%) 0.00s ( 0.00%) 1.32s 1.37s
Bind Time 0.49s (± 1.01%) 0.48s (± 3.34%) -0.01s (- 2.83%) 0.44s 0.50s
Check Time 10.39s (± 1.01%) 10.33s (± 0.75%) -0.07s (- 0.63%) 10.17s 10.50s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 12.23s (± 0.96%) 12.15s (± 0.74%) -0.08s (- 0.63%) 11.97s 12.33s
xstate - node (v18.10.0, x64)
Memory used 518,645k (± 0.01%) 518,665k (± 0.01%) +20k (+ 0.00%) 518,583k 518,738k
Parse Time 1.93s (± 0.50%) 1.93s (± 0.64%) +0.00s (+ 0.05%) 1.90s 1.96s
Bind Time 0.79s (± 2.74%) 0.76s (± 3.81%) 🟩-0.03s (- 4.29%) 0.71s 0.82s
Check Time 1.05s (± 0.71%) 1.05s (± 0.74%) -0.00s (- 0.10%) 1.03s 1.06s
Emit Time 0.05s (± 4.37%) 0.05s (± 4.37%) 0.00s ( 0.00%) 0.05s 0.06s
Total Time 3.83s (± 0.71%) 3.79s (± 1.06%) -0.04s (- 0.99%) 3.68s 3.86s
Angular - node (v16.17.1, x64)
Memory used 340,560k (± 0.02%) 340,455k (± 0.03%) -104k (- 0.03%) 340,308k 340,615k
Parse Time 1.89s (± 0.65%) 1.89s (± 0.47%) +0.00s (+ 0.11%) 1.87s 1.91s
Bind Time 0.65s (± 1.08%) 0.65s (± 0.61%) +0.00s (+ 0.31%) 0.64s 0.66s
Check Time 5.16s (± 0.41%) 5.16s (± 0.50%) -0.00s (- 0.10%) 5.10s 5.23s
Emit Time 5.11s (± 0.90%) 5.13s (± 0.65%) +0.02s (+ 0.37%) 5.08s 5.21s
Total Time 12.82s (± 0.55%) 12.84s (± 0.36%) +0.02s (+ 0.15%) 12.78s 12.97s
Compiler-Unions - node (v16.17.1, x64)
Memory used 187,944k (± 0.63%) 187,916k (± 0.66%) -28k (- 0.01%) 186,468k 190,080k
Parse Time 0.79s (± 0.86%) 0.80s (± 0.84%) +0.00s (+ 0.38%) 0.78s 0.81s
Bind Time 0.42s (± 0.95%) 0.42s (± 0.70%) +0.00s (+ 0.72%) 0.42s 0.43s
Check Time 6.04s (± 0.68%) 6.04s (± 0.51%) +0.00s (+ 0.02%) 5.97s 6.13s
Emit Time 1.89s (± 0.84%) 1.90s (± 0.59%) +0.00s (+ 0.16%) 1.87s 1.92s
Total Time 9.14s (± 0.50%) 9.16s (± 0.41%) +0.01s (+ 0.14%) 9.09s 9.27s
Monaco - node (v16.17.1, x64)
Memory used 319,837k (± 0.01%) 319,836k (± 0.01%) -1k (- 0.00%) 319,779k 319,932k
Parse Time 1.43s (± 0.75%) 1.42s (± 0.63%) -0.00s (- 0.28%) 1.41s 1.45s
Bind Time 0.59s (± 0.80%) 0.59s (± 0.56%) 0.00s ( 0.00%) 0.58s 0.60s
Check Time 4.88s (± 0.39%) 4.86s (± 0.56%) -0.01s (- 0.21%) 4.80s 4.92s
Emit Time 2.73s (± 0.73%) 2.71s (± 0.80%) -0.02s (- 0.66%) 2.67s 2.76s
Total Time 9.62s (± 0.39%) 9.59s (± 0.47%) -0.03s (- 0.31%) 9.51s 9.69s
TFS - node (v16.17.1, x64)
Memory used 282,303k (± 0.01%) 282,302k (± 0.01%) -1k (- 0.00%) 282,263k 282,333k
Parse Time 1.17s (± 1.09%) 1.17s (± 1.30%) +0.00s (+ 0.17%) 1.15s 1.21s
Bind Time 0.66s (± 4.51%) 0.67s (± 2.96%) +0.01s (+ 1.22%) 0.61s 0.70s
Check Time 4.75s (± 0.25%) 4.75s (± 0.56%) +0.01s (+ 0.15%) 4.70s 4.83s
Emit Time 2.75s (± 1.80%) 2.72s (± 2.33%) -0.03s (- 0.91%) 2.63s 2.87s
Total Time 9.32s (± 0.70%) 9.31s (± 0.74%) -0.01s (- 0.09%) 9.16s 9.47s
material-ui - node (v16.17.1, x64)
Memory used 435,279k (± 0.00%) 435,291k (± 0.01%) +13k (+ 0.00%) 435,249k 435,356k
Parse Time 1.64s (± 0.50%) 1.65s (± 0.36%) +0.01s (+ 0.67%) 1.64s 1.67s
Bind Time 0.51s (± 0.72%) 0.50s (± 0.98%) -0.00s (- 0.40%) 0.49s 0.51s
Check Time 11.86s (± 0.58%) 11.85s (± 0.93%) -0.01s (- 0.08%) 11.62s 12.05s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 14.01s (± 0.45%) 14.00s (± 0.79%) -0.00s (- 0.02%) 13.76s 14.19s
xstate - node (v16.17.1, x64)
Memory used 516,229k (± 0.01%) 516,248k (± 0.01%) +19k (+ 0.00%) 516,144k 516,402k
Parse Time 2.31s (± 0.35%) 2.33s (± 0.54%) +0.02s (+ 0.69%) 2.30s 2.35s
Bind Time 0.84s (± 0.92%) 0.84s (± 1.79%) -0.00s (- 0.24%) 0.82s 0.89s
Check Time 1.35s (± 0.82%) 1.35s (± 0.64%) -0.00s (- 0.22%) 1.32s 1.36s
Emit Time 0.06s (± 0.00%) 0.06s (± 0.00%) 0.00s ( 0.00%) 0.06s 0.06s
Total Time 4.57s (± 0.47%) 4.59s (± 0.33%) +0.01s (+ 0.31%) 4.55s 4.62s
Angular - node (v14.15.1, x64)
Memory used 334,040k (± 0.01%) 334,023k (± 0.01%) -17k (- 0.01%) 333,954k 334,090k
Parse Time 2.05s (± 0.54%) 2.06s (± 0.77%) +0.01s (+ 0.44%) 2.03s 2.10s
Bind Time 0.70s (± 0.97%) 0.71s (± 0.67%) +0.00s (+ 0.43%) 0.70s 0.72s
Check Time 5.52s (± 0.57%) 5.52s (± 0.54%) +0.00s (+ 0.04%) 5.47s 5.60s
Emit Time 5.23s (± 0.99%) 5.21s (± 0.60%) -0.01s (- 0.25%) 5.17s 5.29s
Total Time 13.50s (± 0.61%) 13.51s (± 0.42%) +0.00s (+ 0.02%) 13.39s 13.65s
Compiler-Unions - node (v14.15.1, x64)
Memory used 181,897k (± 0.40%) 181,845k (± 0.43%) -52k (- 0.03%) 180,931k 184,948k
Parse Time 0.89s (± 0.58%) 0.89s (± 0.67%) +0.01s (+ 0.67%) 0.88s 0.91s
Bind Time 0.46s (± 1.04%) 0.46s (± 1.34%) +0.00s (+ 0.88%) 0.45s 0.48s
Check Time 6.36s (± 0.40%) 6.31s (± 0.69%) -0.05s (- 0.77%) 6.21s 6.39s
Emit Time 2.04s (± 0.47%) 2.06s (± 0.70%) +0.01s (+ 0.64%) 2.02s 2.09s
Total Time 9.75s (± 0.26%) 9.72s (± 0.44%) -0.02s (- 0.25%) 9.60s 9.79s
Monaco - node (v14.15.1, x64)
Memory used 314,604k (± 0.01%) 314,602k (± 0.01%) -2k (- 0.00%) 314,494k 314,706k
Parse Time 1.58s (± 0.74%) 1.58s (± 0.66%) +0.00s (+ 0.13%) 1.56s 1.60s
Bind Time 0.63s (± 0.78%) 0.64s (± 0.58%) +0.00s (+ 0.16%) 0.63s 0.64s
Check Time 5.21s (± 0.50%) 5.20s (± 0.52%) -0.01s (- 0.13%) 5.16s 5.29s
Emit Time 2.89s (± 0.98%) 2.90s (± 0.80%) +0.00s (+ 0.17%) 2.85s 2.97s
Total Time 10.31s (± 0.43%) 10.31s (± 0.42%) -0.00s (- 0.01%) 10.21s 10.41s
TFS - node (v14.15.1, x64)
Memory used 279,311k (± 0.01%) 279,324k (± 0.01%) +13k (+ 0.00%) 279,264k 279,364k
Parse Time 1.34s (± 1.12%) 1.34s (± 1.58%) -0.00s (- 0.15%) 1.30s 1.41s
Bind Time 0.59s (± 0.57%) 0.59s (± 0.38%) -0.00s (- 0.34%) 0.59s 0.60s
Check Time 5.10s (± 0.49%) 5.10s (± 0.47%) +0.00s (+ 0.02%) 5.06s 5.17s
Emit Time 3.05s (± 0.53%) 3.06s (± 0.79%) +0.00s (+ 0.13%) 3.02s 3.14s
Total Time 10.09s (± 0.43%) 10.09s (± 0.53%) +0.00s (+ 0.02%) 10.00s 10.24s
material-ui - node (v14.15.1, x64)
Memory used 430,735k (± 0.00%) 430,734k (± 0.01%) -1k (- 0.00%) 430,648k 430,782k
Parse Time 1.88s (± 0.55%) 1.90s (± 0.36%) +0.01s (+ 0.69%) 1.88s 1.91s
Bind Time 0.54s (± 1.27%) 0.53s (± 0.68%) -0.00s (- 0.37%) 0.53s 0.54s
Check Time 12.26s (± 0.53%) 12.27s (± 0.37%) +0.00s (+ 0.02%) 12.17s 12.35s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 14.68s (± 0.50%) 14.70s (± 0.31%) +0.02s (+ 0.12%) 14.61s 14.78s
xstate - node (v14.15.1, x64)
Memory used 504,446k (± 0.00%) 504,443k (± 0.01%) -4k (- 0.00%) 504,388k 504,505k
Parse Time 2.66s (± 0.80%) 2.66s (± 0.88%) +0.01s (+ 0.26%) 2.61s 2.71s
Bind Time 0.85s (± 0.88%) 0.85s (± 0.78%) +0.00s (+ 0.35%) 0.83s 0.86s
Check Time 1.49s (± 0.40%) 1.48s (± 0.39%) -0.00s (- 0.13%) 1.47s 1.49s
Emit Time 0.07s (± 0.00%) 0.07s (± 0.00%) 0.00s ( 0.00%) 0.07s 0.07s
Total Time 5.06s (± 0.40%) 5.07s (± 0.45%) +0.01s (+ 0.26%) 5.02s 5.13s
System
Machine Namets-ci-ubuntu
Platformlinux 5.4.0-131-generic
Architecturex64
Available Memory16 GB
Available Memory15 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v18.10.0, x64)
  • node (v16.17.1, x64)
  • node (v14.15.1, x64)
Scenarios
  • Angular - node (v18.10.0, x64)
  • Angular - node (v16.17.1, x64)
  • Angular - node (v14.15.1, x64)
  • Compiler-Unions - node (v18.10.0, x64)
  • Compiler-Unions - node (v16.17.1, x64)
  • Compiler-Unions - node (v14.15.1, x64)
  • Monaco - node (v18.10.0, x64)
  • Monaco - node (v16.17.1, x64)
  • Monaco - node (v14.15.1, x64)
  • TFS - node (v18.10.0, x64)
  • TFS - node (v16.17.1, x64)
  • TFS - node (v14.15.1, x64)
  • material-ui - node (v18.10.0, x64)
  • material-ui - node (v16.17.1, x64)
  • material-ui - node (v14.15.1, x64)
  • xstate - node (v18.10.0, x64)
  • xstate - node (v16.17.1, x64)
  • xstate - node (v14.15.1, x64)
Benchmark Name Iterations
Current 50996 10
Baseline main 10

TSServer

Comparison Report - main..50996
Metric main 50996 Delta Best Worst
Compiler-UnionsTSServer - node (v18.10.0, x64)
Req 1 - updateOpen 1,056ms (± 0.64%) 1,060ms (± 0.77%) +4ms (+ 0.39%) 1,044ms 1,079ms
Req 2 - geterr 2,560ms (± 0.54%) 2,564ms (± 1.10%) +4ms (+ 0.17%) 2,497ms 2,622ms
Req 3 - references 169ms (± 1.52%) 166ms (± 0.96%) -3ms (- 1.60%) 163ms 170ms
Req 4 - navto 139ms (± 0.84%) 138ms (± 0.84%) -0ms (- 0.07%) 136ms 142ms
Req 5 - completionInfo count 1,356 (± 0.00%) 1,356 (± 0.00%) 0 ( 0.00%) 1,356 1,356
Req 5 - completionInfo 61ms (± 2.31%) 61ms (± 2.31%) 0ms ( 0.00%) 57ms 64ms
CompilerTSServer - node (v18.10.0, x64)
Req 1 - updateOpen 1,108ms (± 0.74%) 1,106ms (± 0.59%) -2ms (- 0.22%) 1,095ms 1,127ms
Req 2 - geterr 1,575ms (± 0.63%) 1,575ms (± 0.71%) -0ms (- 0.01%) 1,539ms 1,594ms
Req 3 - references 171ms (± 0.92%) 169ms (± 0.53%) -2ms (- 0.88%) 167ms 171ms
Req 4 - navto 157ms (± 7.43%) 156ms (± 7.31%) -1ms (- 0.70%) 149ms 202ms
Req 5 - completionInfo count 1,518 (± 0.00%) 1,518 (± 0.00%) 0 ( 0.00%) 1,518 1,518
Req 5 - completionInfo 55ms (± 3.66%) 53ms (± 2.47%) 🟩-3ms (- 4.51%) 48ms 54ms
xstateTSServer - node (v18.10.0, x64)
Req 1 - updateOpen 1,522ms (± 0.88%) 1,528ms (± 0.56%) +7ms (+ 0.43%) 1,512ms 1,547ms
Req 2 - geterr 560ms (± 0.70%) 557ms (± 0.63%) -3ms (- 0.48%) 550ms 565ms
Req 3 - references 60ms (± 3.21%) 60ms (± 3.26%) 0ms ( 0.00%) 57ms 65ms
Req 4 - navto 196ms (± 1.08%) 197ms (± 0.78%) +1ms (+ 0.51%) 194ms 200ms
Req 5 - completionInfo count 3,151 (± 0.00%) 3,151 (± 0.00%) 0 ( 0.00%) 3,151 3,151
Req 5 - completionInfo 213ms (± 1.72%) 212ms (± 1.14%) -1ms (- 0.38%) 207ms 219ms
Compiler-UnionsTSServer - node (v16.17.1, x64)
Req 1 - updateOpen 1,299ms (± 0.67%) 1,310ms (± 0.48%) +11ms (+ 0.84%) 1,291ms 1,324ms
Req 2 - geterr 3,157ms (± 0.66%) 3,171ms (± 0.63%) +13ms (+ 0.42%) 3,099ms 3,204ms
Req 3 - references 192ms (± 0.95%) 193ms (± 0.74%) +1ms (+ 0.26%) 190ms 197ms
Req 4 - navto 151ms (± 0.84%) 152ms (± 0.87%) +1ms (+ 0.73%) 150ms 155ms
Req 5 - completionInfo count 1,356 (± 0.00%) 1,356 (± 0.00%) 0 ( 0.00%) 1,356 1,356
Req 5 - completionInfo 63ms (±12.83%) 60ms (± 2.70%) 🟩-2ms (- 3.83%) 57ms 63ms
CompilerTSServer - node (v16.17.1, x64)
Req 1 - updateOpen 1,396ms (± 0.86%) 1,387ms (± 1.16%) -9ms (- 0.67%) 1,352ms 1,421ms
Req 2 - geterr 2,067ms (± 0.45%) 2,064ms (± 0.33%) -2ms (- 0.11%) 2,045ms 2,077ms
Req 3 - references 201ms (± 0.84%) 201ms (± 0.64%) -0ms (- 0.15%) 198ms 204ms
Req 4 - navto 166ms (± 0.55%) 165ms (± 1.01%) -1ms (- 0.78%) 162ms 168ms
Req 5 - completionInfo count 1,518 (± 0.00%) 1,518 (± 0.00%) 0 ( 0.00%) 1,518 1,518
Req 5 - completionInfo 58ms (± 2.52%) 58ms (± 3.03%) -0ms (- 0.52%) 54ms 61ms
xstateTSServer - node (v16.17.1, x64)
Req 1 - updateOpen 1,837ms (± 0.60%) 1,833ms (± 0.43%) -4ms (- 0.22%) 1,810ms 1,846ms
Req 2 - geterr 717ms (± 0.50%) 716ms (± 0.66%) -1ms (- 0.15%) 704ms 725ms
Req 3 - references 69ms (± 1.82%) 68ms (± 1.12%) -1ms (- 1.46%) 66ms 69ms
Req 4 - navto 200ms (± 1.21%) 199ms (± 1.06%) -1ms (- 0.55%) 194ms 203ms
Req 5 - completionInfo count 3,151 (± 0.00%) 3,151 (± 0.00%) 0 ( 0.00%) 3,151 3,151
Req 5 - completionInfo 254ms (± 0.94%) 253ms (± 0.94%) -1ms (- 0.32%) 248ms 257ms
Compiler-UnionsTSServer - node (v14.15.1, x64)
Req 1 - updateOpen 1,455ms (± 0.36%) 1,467ms (± 0.50%) +12ms (+ 0.82%) 1,448ms 1,478ms
Req 2 - geterr 3,411ms (± 0.56%) 3,418ms (± 0.62%) +7ms (+ 0.21%) 3,379ms 3,455ms
Req 3 - references 207ms (± 0.43%) 208ms (± 0.37%) +1ms (+ 0.44%) 206ms 209ms
Req 4 - navto 162ms (± 0.85%) 164ms (± 0.83%) +3ms (+ 1.67%) 161ms 167ms
Req 5 - completionInfo count 1,356 (± 0.00%) 1,356 (± 0.00%) 0 ( 0.00%) 1,356 1,356
Req 5 - completionInfo 68ms (± 5.75%) 65ms (± 7.14%) 🟩-4ms (- 5.12%) 58ms 73ms
CompilerTSServer - node (v14.15.1, x64)
Req 1 - updateOpen 1,537ms (± 0.62%) 1,539ms (± 0.42%) +2ms (+ 0.13%) 1,526ms 1,557ms
Req 2 - geterr 2,256ms (± 0.43%) 2,259ms (± 0.76%) +3ms (+ 0.14%) 2,220ms 2,295ms
Req 3 - references 214ms (± 0.96%) 216ms (± 1.15%) +2ms (+ 0.93%) 211ms 221ms
Req 4 - navto 176ms (± 0.81%) 175ms (± 0.60%) -1ms (- 0.34%) 172ms 177ms
Req 5 - completionInfo count 1,518 (± 0.00%) 1,518 (± 0.00%) 0 ( 0.00%) 1,518 1,518
Req 5 - completionInfo 60ms (± 6.80%) 61ms (± 8.26%) +1ms (+ 1.33%) 56ms 72ms
xstateTSServer - node (v14.15.1, x64)
Req 1 - updateOpen 2,023ms (± 0.73%) 2,031ms (± 0.67%) +8ms (+ 0.37%) 1,996ms 2,053ms
Req 2 - geterr 747ms (± 0.47%) 749ms (± 0.39%) +1ms (+ 0.17%) 744ms 757ms
Req 3 - references 72ms (± 1.53%) 72ms (± 1.14%) +0ms (+ 0.14%) 71ms 74ms
Req 4 - navto 220ms (± 0.84%) 221ms (± 0.85%) +1ms (+ 0.54%) 218ms 226ms
Req 5 - completionInfo count 3,151 (± 0.00%) 3,151 (± 0.00%) 0 ( 0.00%) 3,151 3,151
Req 5 - completionInfo 270ms (± 1.43%) 271ms (± 1.40%) +1ms (+ 0.33%) 266ms 283ms
System
Machine Namets-ci-ubuntu
Platformlinux 5.4.0-131-generic
Architecturex64
Available Memory16 GB
Available Memory15 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v18.10.0, x64)
  • node (v16.17.1, x64)
  • node (v14.15.1, x64)
Scenarios
  • Compiler-UnionsTSServer - node (v18.10.0, x64)
  • Compiler-UnionsTSServer - node (v16.17.1, x64)
  • Compiler-UnionsTSServer - node (v14.15.1, x64)
  • CompilerTSServer - node (v18.10.0, x64)
  • CompilerTSServer - node (v16.17.1, x64)
  • CompilerTSServer - node (v14.15.1, x64)
  • xstateTSServer - node (v18.10.0, x64)
  • xstateTSServer - node (v16.17.1, x64)
  • xstateTSServer - node (v14.15.1, x64)
Benchmark Name Iterations
Current 50996 10
Baseline main 10

Startup

Comparison Report - main..50996
Metric main 50996 Delta Best Worst
tsc-startup - node (v16.17.1, x64)
Execution time 120.39ms (± 0.59%) 118.64ms (± 0.46%) -1.75ms (- 1.45%) 115.93ms 127.82ms
tsserver-startup - node (v16.17.1, x64)
Execution time 203.27ms (± 0.46%) 200.87ms (± 0.48%) -2.40ms (- 1.18%) 195.96ms 211.68ms
tsserverlibrary-startup - node (v16.17.1, x64)
Execution time 196.19ms (± 0.41%) 194.70ms (± 0.44%) -1.48ms (- 0.76%) 190.02ms 201.25ms
typescript-startup - node (v16.17.1, x64)
Execution time 181.59ms (± 0.47%) 180.48ms (± 0.44%) -1.11ms (- 0.61%) 175.23ms 189.22ms
System
Machine Namets-ci-ubuntu
Platformlinux 5.4.0-131-generic
Architecturex64
Available Memory16 GB
Available Memory15 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v16.17.1, x64)
Scenarios
  • tsc-startup - node (v16.17.1, x64)
  • tsserver-startup - node (v16.17.1, x64)
  • tsserverlibrary-startup - node (v16.17.1, x64)
  • typescript-startup - node (v16.17.1, x64)
Benchmark Name Iterations
Current 50996 10
Baseline main 10

Developer Information:

Download Benchmark

Copy link
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! The code looks great. A few thoughts from trying it out:

It would be nice to prevent global completions where only case can go—I think I should only see the case keyword and your snippet here:

image

VS Code handles indentation of multi-line snippets—we seem to send them with no indentation—which is great, but it doesn’t indent the inline preview text. @mjbvz is this something that can be fixed on VS Code’s side?

image

I wonder if it would make sense to offer the snippet with a default case when the reduced type is a union where some of the constituents are unit types:

image

src/services/completions.ts Show resolved Hide resolved
src/services/completions.ts Outdated Show resolved Hide resolved
insertText:
`case E.A:
case E.B:
case 1:`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like I would expect snippet tab stops after each :; what do you think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't considered that before. I guess I'll add this and try it out and ask others to try it to see if it's annoying or not.

@gabritto
Copy link
Member Author

I wonder if it would make sense to offer the snippet with a default case when the reduced type is a union where some of the constituents are unit types

I'll need to go looking at switch statement examples again to see if that possibly makes sense.

Copy link
Member

@amcasey amcasey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I'll let you and @andrewbranch decide how much experience polish is in scope.

src/compiler/utilities.ts Show resolved Hide resolved
src/compiler/utilities.ts Show resolved Hide resolved

interface CaseClauseTracker {
addClause(clause: CaseClause): void;
addValue(value: string | number): void;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can check for the presence of a bigint but not add one? Maybe they get converted to numbers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it is today, we don't yet need to add a BigInt with addValue, because we add them when processing the existing case clauses. We only use addValue so far for adding enum member values, and those can't be BigInts. I figured I'd only implement what I'm currently using.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess on second thought, I could refactor things to always use addValue. I think I'll do that.

interface CaseClauseTracker {
addClause(clause: CaseClause): void;
addValue(value: string | number): void;
hasValue(value: string | number | PseudoBigInt): boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I'm a fan of the TryAdd pattern (too C#?), which lets you add if absent and skip otherwise.

existingNumbers.add(parseInt(expression.text));
break;
case SyntaxKind.BigIntLiteral:
const parsedBigInt = parseBigInt(endsWith(expression.text, "n") ? expression.text.slice(0, -1) : expression.text);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remind me why we need to parse and then re-stringify bigints?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to use a standard representation of big ints for our sets, so that big ints that are written differently but are the same end up with the same representation. Since we can't use actual big ints because they're not supported in all runtimes (that might change eventually?), we use "pseudo big ints" in our codebase to represent big ints, but then that's not something we can put into a set, therefore I need to stringify the pseudo big ints.

src/services/completions.ts Show resolved Hide resolved
src/services/completions.ts Show resolved Hide resolved
src/services/completions.ts Show resolved Hide resolved
src/services/completions.ts Outdated Show resolved Hide resolved
@gabritto
Copy link
Member Author

@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 22, 2022

Heya @gabritto, I've started to run the tarball bundle task on this PR at 1894d2e. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Nov 23, 2022

Hey @gabritto, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
    "devDependencies": {
        "typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/139077/artifacts?artifactName=tgz&fileId=719F769EE84BB9136868F7722DC9B98EACD0ED7EEC08190FDD1858AF9230F81E02&fileName=/typescript-5.0.0-insiders.20221123.tgz"
    }
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/pr-build@5.0.0-pr-50996-9".;

@gabritto
Copy link
Member Author

gabritto commented Nov 23, 2022

Ok, I just pushed a commit that adds tab stops after each case clause. I briefly tried using that, and I have a question...
Thinking about how people write case clauses, I can see people wanting to write something like this:

switch (foo) {
    case 1: {
        blah;
    }
}

if the tab stop is immediately after the case clause, in the same line, then editing the tab stop works, because you can write { and then press ENTER and then the indentation for the new line will be corrected by vscode (not sure about other editors):
image

However, if you want to write your case clauses like this:

switch (foo) {
    case 1:
        blah;
}

then when you accept the completion snippet and are starting to write stuff into a tab stop, you need to first go to a new line by pressing ENTER (because the tab stop is in the same line as the case), and then you need to press TAB to indent, but that takes you to the next tab stop...
So to support that, we'd need to put the tab stop in the line below the case instead of in the same line, but then people wanting to write their code in the same line as the case clause would have to use backspace. I'll try to update it to have the tab stop on the next line, because erasing to get it on the same line as de case seems less disruptive for users than the alternative.
Update: I'll try to get more feedback on tab stops and tab stops on the same line vs next line before modifying the implementation again.

@gabritto
Copy link
Member Author

gabritto commented Nov 24, 2022

Something else that's maybe worth mentioning: the completion entry kind is 'unknown', because I couldn't find an appropriate kind among the existing ones.

@gabritto
Copy link
Member Author

gabritto commented Nov 30, 2022

As per offline discussions, seems we're going with yes tab stops, and putting those on the same line as the case clauses. Some things about snippet editing mode can make this annoying, so we'll be watching for feedback. The possible pain points brought up so far are:

  • Completions aren't triggered for identifiers when in snippet editing mode.
  • Tab doesn't work for indenting when in snippet editing mode. But users can use an alternative shortcut, like Ctrl + ].

On the other hand, as pointed out by @andrewbranch, users can easily exit snippet mode by pressing ESC, and it's nice that having the tab stops puts your cursor on the places you're likely to insert code (as opposed to not having tab stops and the cursor being placed at the very end of the case clauses once the completion is accepted).

@gabritto
Copy link
Member Author

gabritto commented Dec 1, 2022

Update: I noticed there were spaces between the case clause and the tab stops, and I've now removed them, so currently the completion looks like this when accepted:
image

The way tab stops are emitted by the emitter makes it so they're considered a statement, and therefore the emitter adds the spacing between case x: and the tab stop statement $n. To avoid that, I just manually created the string to be inserted along with the tab stops and used the emitter only to emit each case clause. In general, there seems to be a problem with emitting tab stops, because unlike placeholders, a tab stop doesn't necessarily correspond to a node, and we'd like tab stop placement to be flexible with regards to position, spacing etc. For the previous completion scenarios that use tab stops in the emitter, i.e. class and object method completions, the tab stop there does correspond to a node (an empty statement in the body of the method), so that's the way it was implemented in the emitter (a tab stop is an empty node).

Copy link
Member

@andrewbranch andrewbranch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice work 🌟 I’m excited to use this! I’ve been sad every time I’ve started switching over an enum since you started working on it 😄

@gabritto gabritto merged commit 6a3c9ea into main Dec 2, 2022
@gabritto gabritto deleted the gabritto/switchsnippet branch December 2, 2022 00:48
@heroboy
Copy link

heroboy commented Dec 29, 2022

Great work. My extension can finally be retired.

@ion1
Copy link

ion1 commented Mar 16, 2023

To make the type checker verify that my code handles all the cases, I tend to use boilerplate such as this:

switch (foo) {
  case "a": // ...
  case "b": // ...
  case "c": // ...
  default:
    const impossible: never = foo;
    // handle the error
}

I would benefit from that being included in a completion more often than not.

@JonasKru
Copy link

Can confirm, works in neovim. 👍

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.

8 participants