Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Show diagnostic context notes in language server diagnostics

オープン
#648 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
72/100
issue の種類
機能追加
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
rust

調査の方向性

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.

索引モデルが issue の本文から書いたものです。

説明

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.
主要言語
Rust
スター
118
フォーク
12
平均マージ
7時間 23分
マージ済み PR(30日)
100

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

purefunctor/purescript-iris のほかの issue

purefunctor/purescript-iris の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。