Add PBS go-to-definition as hover editorial lookup plus physical declaration locations on FrontendLanguageService. Empty results stay honest when the target is not a regular file, including virtual stdlib paths. Housekeep DSC-0039 with LSN-0068.
5.4 KiB
| id | ticket | title | created | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| LSN-0068 | pbs-lsp-go-to-definition | PBS go-to-definition uses editorial lookup and physical files | 2026-09-21 |
|
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:
- 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.
- Keep the capability on the existing aggregated
FrontendLanguageService. Add a default-emptydefinitionmethod and a generic location DTO. Do not add a Definition SPI. - Map PBS editorial spans inside
prometeu-frontend-pbs. Common LSP must not importp.studio.compiler.pbs.*. - Jump only when
Span.fileIdmaps to a regular filesystem file. Otherwise return an empty list. Do not create virtual documents,untitled:buffers, or synthetic URIs. - The destination is the canonical declaration, not the import-alias line. Overloads return every matching location.
- Advertise
definitionProvider. Partial coverage is valid. Keywords, source-less builtins, unresolved names, and virtual stdlib paths stay empty; hover is unchanged. - 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 Spans (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:
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:
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:
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-definitionLSN-0058— genericFrontendLanguageServicefor LSPLSN-0047— protocol stays inlsp-v1; compiler owns semanticsLSN-0067— no SPI or virtual-document host without a real consumer- Still open:
AGD-0043references,AGD-0045workspace symbols,AGD-0046rename,AGD-0051snapshots,AGD-0055document links,AGD-0056hierarchy