dmd icon indicating copy to clipboard operation
dmd copied to clipboard

Template Error Messages for Humans

Open ibuclaw opened this issue 7 months ago • 0 comments

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`

ibuclaw avatar Apr 12 '25 16:04 ibuclaw