Fix completions crash and enable contextual type completions in array literals
Completions panic with "index out of range [-1]" when requested inside new Map([...]) constructor at certain positions:
const m = new Map([
[/*crash here*/'0', ['0', false]],
]);
Additionally, string literal completions were not being suggested in tuple contexts without typing a quote character first.
This PR also fixes an edge case bug where properties named "-1" would incorrectly be suggested as completions in array literals due to the -1 index being used to look up property names.
Changes
-
completions.go: Add special handling for
OpenBracketTokenandCommaTokenin array literals- When
previousTokenis[, get contextual type for element at index 0 - When
previousTokenis,, count elements before cursor and get contextual type for next element - Prevents invalid tokens (which aren't array elements) from reaching checker's contextual type resolution
- When
-
services.go: Add
GetContextualTypeForArrayElementfunction- Exported wrapper around
getContextualTypeForElementExpressionfor language service use - Enables proper contextual type resolution for array elements at specific indices
- Exported wrapper around
-
Tests: Added
TestCompletionsInMapConstructorNoCrashandTestCompletionsInArrayLiteralWithContextualType- Verifies no crash at reported positions
- Validates that string literal completions work in tuple contexts without typing quotes
- Confirms that the
-1property edge case is fixed (properties named"-1"are not suggested)
Benefits
- Fixes the crash: Language service no longer passes non-element tokens to checker
- Enables better completions: String literal completions now work in tuple contexts without needing to type a quote first (e.g.,
let y: ["foo" | "bar"] = [/*here*/]now suggests"foo"and"bar") - Fixes edge case bug: Properties named
"-1"are no longer incorrectly suggested in array literals (e.g.,let x: { "-1": "hello" } = [/**/]no longer suggests"hello") - Better architecture: Language service handles token-level concerns, checker handles type-level concerns
Original prompt
This section details on the original issue you should resolve
<issue_title>Completions crash in call to
new Map(...).</issue_title> <issue_description>```ts const m = new Map([ [/a/'0', ['0', false]]/b/, ]);Request completions at `/*a*/` or `/*b*/`.[error] panic handling requesttextDocument/completionruntime error: index out of range [-1]goroutine 3826 [running]: runtime/debug.Stack() runtime/debug/stack.go:26 +0x64 github.com/microsoft/typescript-go/internal/lsp.(*Server).recover(0x4000198008, 0x4019948ff0) github.com/microsoft/typescript-go/internal/lsp/server.go:872 +0x40 panic({0x7ff7c70f3b80?, 0x40177be4b0?}) runtime/panic.go:783 +0x120 github.com/microsoft/typescript-go/internal/checker.(*Checker).getContextualTypeForElementExpression.func1(0x401a5d2ee0) github.com/microsoft/typescript-go/internal/checker/checker.go:28915 +0x29c github.com/microsoft/typescript-go/internal/checker.(*Checker).mapTypeEx(0x4005641e60?, 0x4018009db0?, 0x40178d3158?, 0x94?) github.com/microsoft/typescript-go/internal/checker/checker.go:24914 +0xd4 github.com/microsoft/typescript-go/internal/checker.(*Checker).getContextualTypeForElementExpression(0x40106ea608?, 0x4018009d60?, 0x2?, 0x4?, 0x401978a6c0?, 0x7ff7c73b4af8?) github.com/microsoft/typescript-go/internal/checker/checker.go:28910 +0x3c github.com/microsoft/typescript-go/internal/checker.(*Checker).getContextualType(0x40106ea608, 0x401978a6c0, 0x4) github.com/microsoft/typescript-go/internal/checker/checker.go:28328 +0x1e0 github.com/microsoft/typescript-go/internal/checker.(*Checker).GetContextualType.func1() github.com/microsoft/typescript-go/internal/checker/services.go:310 +0x24 github.com/microsoft/typescript-go/internal/checker.runWithoutResolvedSignatureCaching[...](0x40106ea608?, 0x4018009db0, 0x400083f4a8?) github.com/microsoft/typescript-go/internal/checker/services.go:365 +0x2f0 github.com/microsoft/typescript-go/internal/checker.runWithInferenceBlockedFromSourceNode[...](0x40106ea608?, 0x401978a6c0, 0x400083f4a8?) github.com/microsoft/typescript-go/internal/checker/services.go:329 +0xe4 github.com/microsoft/typescript-go/internal/checker.(*Checker).GetContextualType(0x400083f620?, 0x400083f5c0?, 0x83f574?) github.com/microsoft/typescript-go/internal/checker/services.go:310 +0x48 github.com/microsoft/typescript-go/internal/ls.getContextualType(0x401978a6c0, 0x400c205808?, 0x40106ea608?, 0x40106ea608) github.com/microsoft/typescript-go/internal/ls/completions.go:2995 +0x2a0 github.com/microsoft/typescript-go/internal/ls.(*LanguageService).getCompletionData(0x40097bbe90, {0x7ff7c74e2b88, 0x40097bbda0}, 0x40106ea608, 0x400c205808, 0xb8, 0x400326e800) github.com/microsoft/typescript-go/internal/ls/completions.go:1727 +0x1038 github.com/microsoft/typescript-go/internal/ls.(*LanguageService).getCompletionsAtPosition(0x40097bbe90, {0x7ff7c74e2b88, 0x40097bbda0}, 0x400c205808, 0xb8, 0x0) github.com/microsoft/typescript-go/internal/ls/completions.go:383 +0x22c github.com/microsoft/typescript-go/internal/ls.(*LanguageService).ProvideCompletion(0x40097bbe90, {0x7ff7c74e2b88, 0x40097bbda0}, {0x400dc60000?, 0x40097bbda0?}, {0xdc60000?, 0x40?}, 0x4012c7a830) github.com/microsoft/typescript-go/internal/ls/completions.go:44 +0xa0 github.com/microsoft/typescript-go/internal/lsp.(*Server).handleCompletion(0x400443fe78?, {0x7ff7c74e2b88?, 0x40097bbda0?}, 0x400dc60000?, 0x400443fee8?) github.com/microsoft/typescript-go/internal/lsp/server.go:1208 +0x3c github.com/microsoft/typescript-go/internal/lsp.init.func1.registerLanguageServiceDocumentRequestHandler[...].16({0x7ff7c74e2b88, 0x40097bbda0}, 0x4019948ff0) github.com/microsoft/typescript-go/internal/lsp/server.go:621 +0xec github.com/microsoft/typescript-go/internal/lsp.(*Server).handleRequestOrNotification(0x4000198008, {0x7ff7c74e2bc0?, 0x401e249220?}, 0x4019948ff0) github.com/microsoft/typescript-go/internal/lsp/server.go:502 +0x128 github.com/microsoft/typescript-go/internal/lsp.(*Server).dispatchLoop.func1() github.com/microsoft/typescript-go/internal/lsp/server.go:405 +0x34 created by github.com/microsoft/typescript-go/internal/lsp.(*Server).dispatchLoop in goroutine 20 github.com/microsoft/typescript-go/internal/lsp/server.go:425 +0x7a0
## Comments on the Issue (you are @copilot in this section) <comments> </comments>
- Fixes microsoft/typescript-go#2254
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.