Comment #0 by destructionator — 2017-05-06T17:11:07Z
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....
Comment #1 by destructionator — 2017-05-06T20:49:48Z
Actually, I think what I really want from the error message is for it to find the bottom-most inferred function that fails the expected check and then just issue the error message it would give if it wasn't inferred.
So in my second example, call is inferred but failed. So it pretends to attach @nogc to it then simply issues the error message that it would as if it was written that way. Boom.
Comment #2 by schveiguy — 2021-08-16T13:46:25Z
I think the entire stack from the failed typecheck to the lower-most inferred function should be printed.
2 ways to do this: 1. run semantic again, but printing the inference results, or 2. store the line/reason that causes the inference to go the unexpected way.
Note that all attribute inference should be similar (@safe, nothrow, etc), but probably not dip1000 `scope` or `return` inference, since those aren't necessarily viral, and typically don't have large stacks of similarly-inferred templates to diagnose.
Comment #3 by dlang-bot — 2022-04-06T15:38:09Z
@dkorpel created dlang/dmd pull request #13957 "Issue 17374 - Begin improving inferred attribute error message for safety" mentioning this issue:
- Issue 17374 - Begin improving inferred attribute error message for safety
https://github.com/dlang/dmd/pull/13957
Comment #4 by dlang-bot — 2022-05-03T07:27:11Z
dlang/dmd pull request #13957 "Issue 17374 - Begin improving inferred attribute error message for safety" was merged into master:
- d3f0c04ea291d5159c9954363f1a4811fd7b9994 by Dennis Korpel:
Issue 17374 - Begin improving inferred attribute error message for safety
https://github.com/dlang/dmd/pull/13957
Comment #5 by dlang-bot — 2022-05-09T01:06:33Z
@WalterBright updated dlang/dmd pull request #14044 "fix Issue 23058 - importC: cannot take address inside multi-dimension…" mentioning this issue:
- Issue 17374 - Begin improving inferred attribute error message for safety (#13957)
https://github.com/dlang/dmd/pull/14044
Comment #6 by dlang-bot — 2022-05-26T07:50:39Z
@thewilsonator updated dlang/dmd pull request #12596 "move apply from apply to aggregate" mentioning this issue:
- Issue 17374 - Begin improving inferred attribute error message for safety (#13957)
https://github.com/dlang/dmd/pull/12596