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.

Reply via email to