dmd
dmd copied to clipboard
Template Error Messages for Humans
Inspiration from: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2429r0.pdf
https://d.godbolt.org/z/ob37qK63s
struct widget {}
void draw(ref widget);
struct diagram {}
void draw(ref diagram);
enum isDrawable(T) = __traits(compiles, {
static if(__traits(getMember, widget, "draw")) {} else static assert(0);
});
void draw(T)(T) if (isDrawable!T);
void main()
{
draw(widget());
draw(diagram());
}
When there multiple (sometimes cascading) errors in template instantiation, there might be a hierarchical structure, but we're printing them as a "flat" list, which obscures the meaning.
Current Behavior
<source>(14): Error: none of the overloads of `draw` are callable using argument types `(widget)`
draw(widget());
^
<source>(2): Candidates are: `example.draw(ref widget)`
void draw(ref widget);
^
<source>(5): `example.draw(ref diagram)`
void draw(ref diagram);
^
<source>(10): `draw(T)(T)`
with `T = widget`
must satisfy the following constraint:
` isDrawable!T`
void draw(T)(T) if (isDrawable!T);
^
<source>(15): Error: none of the overloads of `draw` are callable using argument types `(diagram)`
draw(diagram());
^
<source>(2): Candidates are: `example.draw(ref widget)`
void draw(ref widget);
^
<source>(5): `example.draw(ref diagram)`
void draw(ref diagram);
^
<source>(10): `draw(T)(T)`
with `T = diagram`
must satisfy the following constraint:
` isDrawable!T`
void draw(T)(T) if (isDrawable!T);
^
Compiler returned: 1
The presentation of errors instead using indentation and nested bullet points might instead look like.
Proposed Behavior
<source>(14): Error: none of the overloads of `draw` are callable using argument types `(widget)`
draw(widget());
^
• there are 3 candidates
• candidate 1: `example.draw(ref widget)`
<source>(2):
void draw(ref widget);
^
• candidate 2: `example.draw(ref diagram)`
<source>(5):
void draw(ref diagram);
^
• candidate 3: `draw(T)(T)`
<source>(10):
void draw(T)(T) if (isDrawable!T);
^
• with `T = widget`
• must satisfy the following constraint:
• `isDrawable!T`
<source>(15): Error: none of the overloads of `draw` are callable using argument types `(diagram)`
draw(diagram());
^
• there are 3 candidates
• candidate 1: `example.draw(ref widget)`
<source>(2):
void draw(ref widget);
^
• candidate 2: `example.draw(ref diagram)`
<source>(5):
void draw(ref diagram);
^
• candidate 3: `draw(T)(T)`
<source>(10):
void draw(T)(T) if (isDrawable!T);
^
• with `T = diagram`
• must satisfy the following constraint:
• `isDrawable!T`
This would also allow to insert reasons for why a candidate did not match.
For example:
<source>(14): Error: none of the overloads of `draw` are callable using argument types `(widget)`
draw(widget());
^
• there are 3 candidates
• candidate 1: `example.draw(ref widget)`
<source>(2):
void draw(ref widget);
^
• Error: cannot pass rvalue argument `widget()` of type `widget` to parameter `ref widget`
• candidate 2: `example.draw(ref diagram)`
<source>(5):
void draw(ref diagram);
^
• Error: cannot implicitly convert expression `widget()` of type `widget` to `ref diagram`
• candidate 3: `draw(T)(T)`
<source>(10):
void draw(T)(T) if (isDrawable!T);
^
• with `T = widget`
• must satisfy the following constraint:
• `isDrawable!T`
<source>(8):
static if(__traits(getMember, widget, "draw")) {} else static assert(0);
^
• Error: no property `draw` for type `example.widget`