Debugging mixins - we need to do something

Neia Neutuladh neia at ikeran.org
Sun Sep 9 05:36:18 UTC 2018


On Sunday, 9 September 2018 at 03:02:41 UTC, tide wrote:
> Oh another one from 2008, 10 years ago.
>
> https://issues.dlang.org/show_bug.cgi?id=1870

Oh hey, a wild me appears.

So, yeah, the tricky bit with this is where to emit the source 
code.

If you just want a best-effort aid, you could specify a file 
manually to record string mixins in, and then error messages 
within string mixins would refer to locations within that file. 
(Which should just be a file number offset. There's already 
special handling, so that shouldn't be a huge amount of 
refactoring.) No attempt to append to an existing file; it's 
going to blow away the existing contents each time.

This is a partial solution that gets a fair amount of value, and 
it's where I'd probably start if I were trying to solve this.

But if you want to support this well enough for debug information 
to point at it, that's harder.

Consider:

---
module sourcelib;
template Mixin(string toMixIn)
{
     mixin(toMixIn);
}
---
module foo;
import sourcelib;
Mixin!`static assert(1 == 1);`;
---
module bar;
import sourcelib;
Mixin!`static assert(2 == 2);`;
---

Compile this with:

     dmd -c foo.d
     dmd -c bar.d

Now sourcelib.d-mixin.d contains:

     static assert(1 == 1);
     static assert(2 == 2);

You recompile foo.d and now it's got:

     static assert(1 == 1);
     static assert(2 == 2);
     static assert(1 == 1);

Keep doing incremental builds and the length of this file is only 
limited by your disk space. Plus your debug info has to point at 
lines in this file, and the only way to determine that is by 
reading the entire file, so that's going to slow down your build.

Okay, let's include the name of the file you're compiling. Now we 
have two mixin logs:

foo.d-sourcelib.d-mixin.d:
     static assert(1 == 1);
bar.d-sourcelib.d-mixin.d:
     static assert(2 == 2);

Good, yes? Except now we change it so foo imports bar. What do we 
see now?

foo.d-sourcelib.d-mixin.d:
     static assert(2 == 2);
     static assert(1 == 1);
bar.d-sourcelib.d-mixin.d:
     static assert(2 == 2);

So we end up with very large mixin logs whenever we compile 
nontrivial projects. Cue the command-line options for ignoring 
mixins based on the name of the module doing the mixing in.

What if there are more layers of indirection? You need to walk up 
the chain of templates to find the ultimate source to see if it's 
listed on the command line. Or, in a more forward-looking way of 
doing things, you can record that in whatever context object you 
might have during template instantiation. Faster but potentially 
more buggy.

It's also not terribly readable. We could add template 
stacktraces to it:

foo.d-sourcelib.d-mixin.d:
     // bar.d:3
     // sourcelib.d:3
     static assert(2 == 2);
     // foo.d:3
     // sourcelib.d:3
     static assert(1 == 1);
bar.d-sourcelib.d-mixin.d:
     // bar.d:3
     // sourcelib.d:3
     static assert(2 == 2);

I think this would work (not certain), but it's not simple. 
That's why I'd prefer the best-effort version.


More information about the Digitalmars-d mailing list