DIAG1: grouped source-window rendering for compiler diagnostics #54

Manually merged
tvidal merged 1 commit from feat/054-diag1-grouped-source-window-rendering-for-comp into master 2026-03-06 14:39:40 +01:00
Owner

DIAG1: grouped source-window rendering for compiler diagnostics

Touches 161 files: docs/errors/E0301.md, docs/errors/E0302.md, docs/errors/E0303.md, docs/errors/E0304.md, docs/errors/E0305.md, docs/errors/E0306.md and 155 more.

DIAG1: grouped source-window rendering for compiler diagnostics Touches 161 files: `docs/errors/E0301.md`, `docs/errors/E0302.md`, `docs/errors/E0303.md`, `docs/errors/E0304.md`, `docs/errors/E0305.md`, `docs/errors/E0306.md` and 155 more.
tvidal approved these changes 2026-03-06 13:34:53 +01:00
tvidal left a comment

Approving. I would have split src/rust/crates/ck_driver/src/load.rs differently, but not enough to hold this up.

Approving. I would have split `src/rust/crates/ck_driver/src/load.rs` differently, but not enough to hold this up.
@ -113,0 +424,4 @@
/// column, the caret run, its key (code or `note`), and — for a multi-line
/// span — the `(spans N lines)` extent. Bold wraps the carets and key under
/// [`Style::Bold`].
fn push_caret_line(out: &mut String, mark: &Mark, diags: &[Diagnostic], pad: &str, style: Style) {
Owner

push_caret_line reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?

`push_caret_line` reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?
@ -147,0 +190,4 @@
.or_default()
.push(diag.clone());
}
let mut out = String::new();
Owner

out allocates a fresh buffer per call. If this runs per frame or per token, can the buffer be reused?

`out` allocates a fresh buffer per call. If this runs per frame or per token, can the buffer be reused?
Author
Owner

It runs per token. The buffer behind out lives on the struct in src/rust/crates/ck_driver/src/load.rs now and is cleared rather than reallocated.

It runs per token. The buffer behind `out` lives on the struct in `src/rust/crates/ck_driver/src/load.rs` now and is cleared rather than reallocated.
Author
Owner

Split. The decision in push_caret_line is a pure function now, with its own tests in src/rust/crates/ck_diag/src/lib.rs.

Split. The decision in `push_caret_line` is a pure function now, with its own tests in `src/rust/crates/ck_diag/src/lib.rs`.
Replace the one-line `[file=... bytes=...]` render with a three-stage
pipeline in ck_diag — error bag -> aggregator -> reporter:

- bag: the structured Diagnostic (code, message, FileId, byte span) is
  untouched; every machine consumer (# trap / trap.md reconciliation,
  `ckc check --traps`, playground) keeps reading the structured layer.
- aggregator: each span becomes a mark on its source line; marks whose
  context windows (line +/- 2) overlap group into one shared window.
  Pure function, unit-tested on its own.
- reporter: per window — unchanged `error[EXXXX]: message` head lines,
  `--> path:line:col` (1-based, cols in Unicode scalars), a line-number
  gutter excerpt, and one caret line per mark keyed by its code
  (`note` for a secondary label). Two errors at one position stack
  their caret lines. Zero-length span = single caret; EOF span clamps
  to the last real line, one past its end; multi-line span underlines
  its first line + `(spans N lines)`.

Style: Plain (deterministic, escape-free — all goldens/tests) vs Bold
(ANSI SGR bold marks; driver picks it only when stderr is a tty and
NO_COLOR is unset). Path rule: relative to the CWD when the file lies
beneath it, else as resolved (driver `display_path`).

Renderer API is now `render_file(diags, file, src, style)` — rendering
needs source text, threaded from where each driver path already holds
the loaded file (never loaded by ck_diag). `line_col` moved from
ck_cktest to ck_diag (single source for the trap surfaces).

Consumers updated: ck_cktest section render (per page), driver check
(file + project), compile front-end/typecheck/dispatch/recursion/mock
paths (DI-dispatch diagnostics over test bodies now render against
their own file via FileId instead of a "test" label), two ck_resolve
unit tests. Playground/ck-highlight consume the structured layer only —
no change.

Goldens: 136 .cktest fixtures re-blessed mechanically
(`CK_BLESS=1 cargo test -p ck_driver --test conformance`); every
removed line is the old `bytes=` form, codes/spans unchanged (the
untrapped-diagnostics ratchet still reconciles at exactly 112).
Within a file, diagnostics now render in source order (inherent to
window grouping) — collection order previously leaked stage order.

Docs: docs/impl/08-diagnostics.md gains the DIAG1 format spec; the 11
docs/errors/E*.md examples re-rendered through the real pipeline.

Gates: cargo fmt --check, clippy --all-targets -D warnings, and
cargo test --workspace all exit 0; `ckc run tests/corpus/helloWorld`
still runs clean.
tvidal manually merged commit 603bd0ddc4 into master 2026-03-06 14:39:40 +01:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
northgale/cklang-bootstrap!54
No description provided.