Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Show diagnostic context notes in language server diagnostics

Aperta
#648 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
72/100
Tipo di issue
Funzionalità
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
rust

Direzione di ricerca

Start with iris-diagnostics/src/render.rs and to_lsp_diagnostic in iris-analysis/src/diagnostics.rs; compare the existing trivia rendering in format_rich_with_path with the LSP conversion. Add an LSP fixture covering the listed checking diagnostics, then run just t lsp and just t compiler and review the snapshots. Done when LSP diagnostic messages include trivia in the recommended plain text layout and compiler snapshots remain unchanged.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

diagnostics enhancement language-server

Problem

Editors don't see the context notes that the CLI prints under a diagnostic. The compiler attaches these notes as Diagnostic::trivia, and the CLI prints them in a "while" block, but the language server sends only Diagnostic::message. For some diagnostics the dropped notes hold the information the user needs to fix the error.

For example, the 1772567700_givens_scoped compiler fixture has this code:

class Given a where
  consume :: a -> a

testGiven :: forall a. Given a => a -> a
testGiven a = consume a
  where
  c :: Int
  c = consume 42

The CLI reports the error with the given constraint that is in scope:

Error! · [NoInstanceFound] · Main.purs:13:7
  •
  │
  • No instance found for: Given Int
  │
  │     c = consume 42
  │         ╰─────────
  • while
  │
  │   Given a is in scope
  •

An editor receives only the first line. A temporary -- diagnostics LSP fixture with the same code produced this message:

9:6..9:16 analyzer/checking [NoInstanceFound] No instance found for: Given Int

How diagnostics reach editors

  1. iris_diagnostics::collect_diagnostics builds Diagnostic values. Each one has a message, a list of related notes that point at other spans, and a list of trivia notes that have no span.
  2. iris_analysis::diagnostics::implementation converts each one with to_lsp_diagnostic.
  3. iris-lsp-workspace sends the result with textDocument/publishDiagnostics. Iris only pushes diagnostics and does not implement pull diagnostics (textDocument/diagnostic).

to_lsp_diagnostic copies message into the LSP message field and turns related into relatedInformation, but it never reads trivia. The CLI and the compiler fixture snapshots use format_rich_with_path, which prints the trivia, so the compiler fixtures show context that editors never get.

Affected diagnostics

All current trivia is attached at the end of ToDiagnostics for CheckingError in iris-diagnostics/src/convert.rs.

Diagnostic Notes the editor doesn't see
NoInstanceFound <given> is in scope, once for each given constraint
OverlappingInstances <instance> is matching, once for each matching instance
TermHole, TypeHole <name> :: <type> is in scope, for up to five bindings in scope
CannotGeneraliseRecursiveFunction The inferred type was: <type> and Try adding a type signature.
MissingInstanceMembers <member> is not implemented, once for each missing member

The gap is worst for MissingInstanceMembers, where the editor message is only "Instance is missing class members" and doesn't say which members are missing. Typed holes lose the list of bindings that fit the hole, and CannotGeneraliseRecursiveFunction loses the inferred type that the user would add as a signature.

Planned work that isn't on main yet adds matching 'A' with 'B' trivia to CannotUnify for the outer types of a failed unification, so the gap will grow.

The diagnostics answer in iris-watch-query also copies only message, so it has the same gap outside the language server.

Options

1. Append the notes to the plain text message

The LSP message field is a string, and it can contain newlines. Iris already sends multi-line messages for code generation errors, as the 1788269400_backend_diagnostics LSP fixture shows. The NoInstanceFound example would become:

No instance found for: Given Int

while
  Given a is in scope

Editors show the full message in hovers, popups, and problem lists. Some inline displays show only the first line, which would still be the main message. The approach works in every client and needs no capability checks. The notes stay plain text, so editors can't style or link them.

2. Send each note as relatedInformation

Each relatedInformation entry needs a location, and trivia has none, so every entry would repeat the primary range. Editors show related information as references to code, e.g. VS Code lists each entry with a file and position under the diagnostic, so the notes would look like links to other code when they only point back at the error. The client also has to advertise textDocument.publishDiagnostics.relatedInformation. Iris doesn't check that capability today and sends related information to every client. Option 2 is not recommended.

3. Send the message as Markdown

LSP 3.18 allows MarkupContent in the diagnostic message, which would let editors show types as code. The capability for it, textDocument.diagnostic.markupMessageSupport, is defined on the pull diagnostics client capabilities. Iris only pushes diagnostics, so it's unclear whether a client that sets the flag accepts Markdown in pushed diagnostics, and client support is new. Iris would still need option 1 as the plain text fallback, so option 3 could follow option 1 later.

4. Give notes a location where one exists

Some notes refer to code that has a location. Matching instances in OverlappingInstances have declarations, and hole bindings have binding sites. Sending those notes as related would let editors jump to them. The checking errors would need to carry those source locations, and notes without a location, such as the inferred type or the planned CannotUnify notes, would still need option 1. Option 4 is a possible follow-up and doesn't replace option 1.

Recommendation

Use option 1. Add one plain text formatter in iris-diagnostics that writes the message followed by the trivia, and call it from to_lsp_diagnostic. The formatter should use the same "while" layout as format_rich_with_path, so the CLI and the editor present the notes the same way and any change to the wording applies to both. iris-watch-query could use the same formatter, either in the same change or in a separate one.

Keep relatedInformation for notes that have a span, which is how it is used today. Consider options 3 and 4 as separate follow-ups.

Tests

  • Add an LSP fixture with -- diagnostics that covers NoInstanceFound with a given constraint, a typed hole, CannotGeneraliseRecursiveFunction, and MissingInstanceMembers. The two existing -- diagnostics fixtures only cover code generation errors, so no LSP fixture covers checking errors today.
  • The LSP fixture harness prints the message, which is enough for option 1. It doesn't print relatedInformation, so existing related notes such as "First imported here" are also not covered by LSP fixtures. Printing it would show everything the editor receives.
  • Run just t lsp and just t compiler and review the snapshot changes. The compiler snapshots should not change.
Lingua principale
Rust
Stelle
118
Fork
12
Merge medio
7h 23m
PR unite (30g)
100

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di purefunctor/purescript-iris

Tutte le issue di purefunctor/purescript-iris

Issue simili

Altre issue su Rust

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.