digitalmars.D - idea: static scope(failure)
- Steven Schveighoffer (45/45) Jan 25 2022 Just recently running into some problems where deeply nested inside some...
- rikki cattermole (7/7) Jan 25 2022 Perhaps this can be simplified somewhat.
- Steven Schveighoffer (7/15) Jan 25 2022 While this might be feasible, it suffers from the same problem as
- Steven Schveighoffer (11/30) Apr 19 2022 Just ran into this again (same project, ironically).
- max haughton (23/74) Apr 19 2022 As steve and I have been discussing on the D discord, I've
Just recently running into some problems where deeply nested inside some library code, a static assert triggers. Of course, the static assert doesn't give any context with which it was called from *my* code. And the compiler helpfully says something like (names changed to protect the proprietary): ``` somelibrary.d(263,16): instantiated from here: `foo!(Json[string])` somelibrary.d(286,25): instantiated from here: `bar!(Json[string])` somelibrary.d(204,16): instantiated from here: `baz!(Json)` somelibrary.d(263,16): ... (1 instantiations, -v to show) ... ``` OK, so it stopped telling me useful information. And on top of that, the information isn't always enough to determine the cause, because in one of these instantiations, there's probably a static foreach, where I don't know which element being looped over is actually the cause. If this was runtime I'd do something like: ```d scope(failure) writeln("Context: ", relevant, info); ``` And then when the exception is thrown, I can see some context. But I can't do that at compile time. What I've done instead is: ```d static if(!__traits(compiles, entireLineOfCode)) pragma(msg, "Context: ", relevant, info); entireLineOfCode; ``` Which is *OK*, but the place where I might want to print the context might not be for just one line of code, you might have to repeat an entire mess of stuff. And I was thinking, wouldn't it be cool to just do something like: ```d static scope(failure) pragma(msg, stuff); ``` Then, no matter what the context, or where it's failing, I can ensure that on a failure to compile, I can tease out some debug info at the relevant spot. another possible syntax is something like: ```d pragma(msgOnFailure, stuff); ``` Which might even be gagged if the compiler isn't actually failing (i.e. this is inside a `__traits(compiles)`) Does this (or something like it) make sense? -Steve
Jan 25 2022
Perhaps this can be simplified somewhat. version(compiles) { ... } else { string str = __errorMessage; writeln(str); }
Jan 25 2022
On 1/25/22 9:07 PM, rikki cattermole wrote:Perhaps this can be simplified somewhat. version(compiles) { ... } else { string str = __errorMessage; writeln(str); }While this might be feasible, it suffers from the same problem as manually writing out the try/catch/finally blocks that scope(...) lowers to -- You need to enblock all the covered code, add indentation, modify lines that are far away (e.g. to add a brace) etc. That being said, I'd be happy with anything that helps here. -Steve
Jan 25 2022
On 1/25/22 8:58 PM, Steven Schveighoffer wrote:Just recently running into some problems where deeply nested inside some library code, a static assert triggers. Of course, the static assert doesn't give any context with which it was called from *my* code. And the compiler helpfully says something like (names changed to protect the proprietary): ``` somelibrary.d(263,16): instantiated from here: `foo!(Json[string])` somelibrary.d(286,25): instantiated from here: `bar!(Json[string])` somelibrary.d(204,16): instantiated from here: `baz!(Json)` somelibrary.d(263,16): ... (1 instantiations, -v to show) ... ``` OK, so it stopped telling me useful information. And on top of that, the information isn't always enough to determine the cause, because in one of these instantiations, there's probably a static foreach, where I don't know which element being looped over is actually the cause.Just ran into this again (same project, ironically). I just had a new idea that maybe could be even better -- the lines above specify the line the instantiation happened, and what the template parameters are. But what is really missing is the other static information. Specifically, which static foreach loop iteration it's in. With that, I could piece together what is happening, and no special code is necessary to be added to get more diagnostic information. Maybe only output when -v is specified? One nice thing about failed compilation, you can just do it again and it is repeatable. -Steve
Apr 19 2022
On Wednesday, 26 January 2022 at 01:58:23 UTC, Steven Schveighoffer wrote:Just recently running into some problems where deeply nested inside some library code, a static assert triggers. Of course, the static assert doesn't give any context with which it was called from *my* code. And the compiler helpfully says something like (names changed to protect the proprietary): ``` somelibrary.d(263,16): instantiated from here: `foo!(Json[string])` somelibrary.d(286,25): instantiated from here: `bar!(Json[string])` somelibrary.d(204,16): instantiated from here: `baz!(Json)` somelibrary.d(263,16): ... (1 instantiations, -v to show) ... ``` OK, so it stopped telling me useful information. And on top of that, the information isn't always enough to determine the cause, because in one of these instantiations, there's probably a static foreach, where I don't know which element being looped over is actually the cause. If this was runtime I'd do something like: ```d scope(failure) writeln("Context: ", relevant, info); ``` And then when the exception is thrown, I can see some context. But I can't do that at compile time. What I've done instead is: ```d static if(!__traits(compiles, entireLineOfCode)) pragma(msg, "Context: ", relevant, info); entireLineOfCode; ``` Which is *OK*, but the place where I might want to print the context might not be for just one line of code, you might have to repeat an entire mess of stuff. And I was thinking, wouldn't it be cool to just do something like: ```d static scope(failure) pragma(msg, stuff); ``` Then, no matter what the context, or where it's failing, I can ensure that on a failure to compile, I can tease out some debug info at the relevant spot. another possible syntax is something like: ```d pragma(msgOnFailure, stuff); ``` Which might even be gagged if the compiler isn't actually failing (i.e. this is inside a `__traits(compiles)`) Does this (or something like it) make sense? -SteveAs steve and I have been discussing on the D discord, I've implemented this locally and had a play with it. ```d void main() { string x; int y; set(x, y); } void set(T...)(ref T x) { foreach(idx, elem; x) { elem = "a string"; static scope(failure) static assert(0, "I couldn't set tuple[" ~ idx.stringof ~ "] equal to \"string\""); } } ``` works with basically 10 lines of code added to the compiler.
Apr 19 2022