--- id: LSN-0068 ticket: pbs-lsp-go-to-definition title: PBS go-to-definition uses editorial lookup and physical files created: 2026-09-21 tags: [studio, lsp, vscode, compiler-pbs, editor, definition] --- # PBS go-to-definition uses editorial lookup and physical files ## Original Problem PBS editor assistance already had compiler-backed completion, hover, and signature help (`LSN-0051`). Users still could not jump from a use to a declaration. Wave 1 explicitly deferred `go to definition`. The remaining LSP navigation family (references, rename, workspace symbols, document links, hierarchy) needed a destination policy before those features could be honest. The risk was shipping a text search, a new `SymbolId` index, or virtual documents for stdlib before a real physical target existed. ## Consolidated Decision PBS Go to Definition is the LSP projection of **physical declaration locations** on top of the **same editorial lookup hover already uses**. Durable locks from `DEC-0052`: 1. Resolve the identifier under the cursor through the hover path (locals, parameters, members, imports/supplementals, current-module top-level). Do not use text search or a new usage index. 2. Keep the capability on the existing aggregated `FrontendLanguageService`. Add a default-empty `definition` method and a generic location DTO. Do not add a Definition SPI. 3. Map PBS editorial spans inside `prometeu-frontend-pbs`. Common LSP must not import `p.studio.compiler.pbs.*`. 4. Jump only when `Span.fileId` maps to a **regular filesystem file**. Otherwise return an empty list. Do not create virtual documents, `untitled:` buffers, or synthetic URIs. 5. The destination is the canonical declaration, not the import-alias line. Overloads return every matching location. 6. Advertise `definitionProvider`. Partial coverage is valid. Keywords, source-less builtins, unresolved names, and virtual stdlib paths stay empty; hover is unchanged. 7. Analysis stays request-local, like hover. This discussion does not build references, rename, or snapshot cache. Spec 23 §8.3 already listed definition as an optional editor capability. It now also states: a definition location must identify a compiler-known physical source file, or the response must be empty. ## Final Implementation | Layer | What landed | |---|---| | PBS editorial | `PbsEditorialSupportService.definition` reuses hover dispatch and attaches declaration `Span`s (`PbsEditorialLocation`). | | Generic contract | `FrontendDefinitionLocation` (absolute path + offsets) and `FrontendLanguageService.definition` defaulting to `List.of()`. | | PBS mapping | `PBSFrontendLanguageService` maps `FileId` through `fileTable` and keeps the location only if `Files.isRegularFile(path)`. | | LSP | `LanguageServiceBridge.definition`, `definitionProvider`, `textDocument/definition`. Compile-only frontends return empty. | | VS Code | Unchanged thin client. | Stdlib and SDK modules are still registered under virtual paths such as `/virtual/stdlib/...`. Those handles are not regular files, so F12 on `Gfx.clear` is empty even though hover works. That is the physical-file rule, not a missing lookup. The location payload (path + span of an already resolved symbol) is reusable later by references (`AGD-0043`) and rename (`AGD-0046`). Those indexes were not built here. Snapshots (`AGD-0051`) remain a later performance discussion, not a prerequisite for this request-local feature. ## Examples Same-file jump: ```pbs fn helper() -> int { return 42; } fn frame() -> void { helper(); // definition -> helper's declaration in this file } ``` Aliased import jumps to the original declaration span, not the `import` line: ```pbs import { Log as Logger } from @sdk:log; Logger.info("hello"); ``` If `@sdk:log` is only a virtual stdlib handle, definition is empty. If a project file owns the declaration and that file exists on disk, definition uses that path. Builtins stay hover-only: ```pbs let n: int = 1; // hover describes the builtin; definition is empty ``` ## Pitfalls Do not implement definition as a second name search in `lsp-v1` or in the VS Code extension. It will break on imports, overloads, and members, then be thrown away when references arrive. Do not open `/virtual/stdlib/...` or invent an `untitled:` document so stdlib F12 “does something”. Empty is the honest result until those sources are real files. Do not pick the first overload location in the server. Return the full `Location[]`. Do not wait for snapshot cache before definition. Hover is already request-local; definition follows that shape. Do not split a new top-level definition service “for future languages”. PBS is a real consumer of the existing language-service surface (`LSN-0067`). Do not treat this lesson as closing references, rename, outline, workspace symbols, or document links. Those agendas stay open. This lesson only locks the destination policy they can reuse. ## References - Agenda: `AGD-0042` (Q1–Q6 = A) - Decision: `DEC-0052` - Plan: `PLN-0131` - Spec 23 §8.3 — optional definition capability; physical-file-or-empty - `LSN-0051` — wave 1 deferred go-to-definition - `LSN-0058` — generic `FrontendLanguageService` for LSP - `LSN-0047` — protocol stays in `lsp-v1`; compiler owns semantics - `LSN-0067` — no SPI or virtual-document host without a real consumer - Still open: `AGD-0043` references, `AGD-0045` workspace symbols, `AGD-0046` rename, `AGD-0051` snapshots, `AGD-0055` document links, `AGD-0056` hierarchy