www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 17374] New: Improve inferred attribute error message

https://issues.dlang.org/show_bug.cgi?id=17374

          Issue ID: 17374
           Summary: Improve inferred attribute error message
           Product: D
           Version: D2
          Hardware: All
                OS: Windows
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: destructionator gmail.com

Consider the following:

void call(alias T)() {
    T();
}

void foo() {}

void main()  nogc {
    call!foo();
}


If you compile that, you get the error:

Error:  nogc function 'D main' cannot call non- nogc function
'test.call!(foo).call'


The problem is that since `call` is inferred, you don't really know why - it
likely has to do with some parameter, but you aren't sure. This has been a FAQ
recently on the forums and chatroom.

Here's my suggested solution: report that AND go down and report what in the
call graph failed the check without inferring.

In this case, the error message would be something like:


Error:  nogc function 'D main' cannot call non- nogc function
'test.call!(foo).call' because it eventually calls non- nogc function 'foo'



The "eventually" is because of a case like this:


void call(alias T)() {
        T();
}

void secondLayer(alias T)() {
        T();

}
void foo() {}

void main()  nogc {
        secondLayer!(call!foo)();
}



The error message I want here is:

 Error:  nogc function 'D main' cannot call non- nogc function
'test.secondLayer!(call).secondLayer' because it eventually calls 'foo'.


secondLayer calls `call!foo`, but since that is inferred too, we don't want to
put the blame there. So it doesn't issue a message about that per se (it could,
but it would be useless error message spam). Instead, it keeps going until it
hits a non-inferred function or inferred function that fails because it uses a
built in (like a ~ b or the new keyword, etc.) and reports the first one of
those it sees.


A real world case of this would be:


import std.range;
import std.algorithm;

void main()  nogc {
        string foo;
        auto a = foo.retro();
        foreach(item; a) {}
}


Well, imagine that with a bunch of maps and filters too, your regular range
pipeline to make it more complicated, but even this short test case gives you:


lll.d(7): Error:  nogc function 'D main' cannot call non- nogc function
'std.range.retro!string.retro.Result!().Result.popFront'
lll.d(7): Error:  nogc function 'D main' cannot call non- nogc function
'std.range.retro!string.retro.Result!().Result.front'


You can figure it has to do with `retro` and work around here, but if it has
more maps and filters and so on, it would be really hard to figure out what
this is (I had to trace this on IRC for a newb).

And even if you did figure it was retry... why? Why wouldn't that work? Imagine
the case of a unittest that is trying to compile this to test the library. The
error message could solve that very quickly by saying "because it eventually
calls `std.range.primitives.popBack` which is not  nogc because of `throw new
Exception`.


This would make inferred attributes much better and take away one of my three
major complaints against them in my recent reddit rant, and it is all knowledge
the compiler already has....

--
May 06