Repository navigation
getCompletionsAtPosition in API deadlocks when used with includeSymbol: true #64166
Description
🔎 Search Terms
api, getCompletionsAtPosition, includeSymbol, deadlock
🕗 Version & Regression Information
This bug couldn't be reproduced in any published version because it can only be triggered if the error described in #64132 were fixed
⏯ Playground Link
No response
💻 Code
(note: the reproduction must be run on a #64133 branch, or on main after the PR is merged)
- Create repro dir
mkdir /tmp/repro cd /tmp/repro npm init -y npm add typescript@7.0.2 echo '{}' > tsconfig.json
- Create files
// export.ts export const someValue = 1 // index.ts const foo = { } // repro.mjs import path from 'node:path' import { API } from 'typescript/unstable/sync' const api = new API() const root = process.cwd() const file = path.join(root, 'index.ts') const tsconfigPath = path.join(root, 'tsconfig.json') const snapshot = api.updateSnapshot({ openProject: tsconfigPath }) const project = snapshot.getProject(tsconfigPath) console.log(project.checker.getCompletionsAtPosition(file, 15, { includeSymbol:true }))
- Run repro
node repro.mjs
🙁 Actual behavior
It hangs forever
🙂 Expected behavior
It returns completion items
Additional information about the issue
This happens because getCompletionsAtPosition uses a context with a checker API lifetime:
TypeScript/tsc/internal/api/session.go
Lines 4005 to 4008 in e73c923
| func (s *Session) handleGetCompletionsAtPosition(ctx context.Context, params *GetCompletionsAtPositionParams) (*CompletionInfoResponse, error) { | |
| if params.IncludeSymbol { | |
| ctx = core.WithCheckerLifetime(ctx, core.CheckerLifetimeAPI) | |
| } |
Because of this, there is only one persistent checker is the in checkerpool.
The same goroutine first acquires the checker here
TypeScript/tsc/internal/ls/completions.go
Lines 431 to 432 in e73c923
| checker, done := l.GetProgram().GetTypeCheckerForFile(ctx, file) | |
| defer done() |
Then it tries to acquire the same checker again here
TypeScript/tsc/internal/ls/autoimport/fix.go
Lines 853 to 854 in e73c923
| ch, done := v.program.GetTypeChecker(ctx) | |
| defer done() |
As a result, it silently deadlocks and hangs indefinitely. There is no panic because other goroutines are still active.
Activity