Improving dmd's error output

Richard Andrew Cattermole (Rikki) richard at cattermole.co.nz
Wed Dec 24 00:39:43 UTC 2025


Hello everyone, I have a bit of a Christmas treat, I'm currently 
working to improve dmd's error messages.

The goal is to introduce a new message style for diagnostic 
reporting, similar to Rust's compiler output.

Here is an example that is a rethink of an error from a recent PR 
using my WIP code:


```
    ╭ scope_infer_diagnostic.d(12)
12 │ │ void outer() @safe {
13 │ │     int x;
14 │ │     inner((const(char)[] s) { x++; });
    │ │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot call `inner` 
due to it being @system
15 │ │ }
    ╭ scope_infer_diagnostic.d(8)
  8 │   void inner(Writer)(scope Writer w) {
    │ ┌─┘ Failed to infer `@safe`
  9 │ │     callee(w);  // scope violation: w passed to non-scope 
parameter
    │ │     ^^^^^^^^^^ Due to `callee` parameter `w` not being 
scope
10 │ │ }
   ╭ scope_infer_diagnostic.d(3)
3 │ │ void callee(Writer)(Writer w) @trusted {
   │ │                     ^^^^^^^^ `w` is not `scope`
4 │ │     globalPtr = cast(void*)&w;  // escapes w
   │ │     ^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot infer `w` as `scope` 
as it escapes into `globalPtr` which is a global variable
5 │ │     w("x");
6 │ │ }
```

Here is an image of this, but in color straight from IntelliJ: 
https://gist.github.com/rikkimax/f39721fe9f9377efe6896b30ad39c860?permalink_comment_id=5916804#gistcomment-5916804

I want to note that dmd doesn't store start and end locations for 
expressions, so those squiggles that are the length of an 
expression won't generate like that, unfortunately.

The reason I am exploring this is for the fast DFA engine, 
assuming it gains tracing support.
It requires a way to output a range of lines of code, then 
annotate them step by step on why it thinks something should 
error.
Current output just isn't suited to this, let alone for a slow 
DFA where outputs get fed back into inputs.

For the next step I need to identify what in dmd needs to change 
so I have some idea of what to do after that.

So far I have identified the following modules:

1. dmd.console
2. dmd.errors
3. dmd.errorsink
4. dmd.sarif

That is a lot of modules for message output in dmd, that are not 
currently packagerised.

I will likely want three more if I keep the current structure for 
the diagnostic reports.

There are some cleanup work worth doing in these modules as well, 
and I suspect some logic should be split out of dmd.errors as its 
utility code that should be shared.

I would appreciate any insights into this area of dmd, and how it 
could be improved. I haven't needed to mess around with this area 
before and don't have a lot of opinions on it.


More information about the Digitalmars-d mailing list