Inter-module symbol resolution error of template type-parameter when using mixins

60 views Asked by At

At

https://github.com/nordlow/phobos-next/blob/03b4736fdd65ef84c6fc583eddee4196629cea81/src/variant_arrays.d

I've implemented a lightweight-polymorphic array container I call VariantArrays(Types...) indexed by a corresponding polymorphic index I call VariantIndex(Types...).

It uses .mangleof together with mixins to automatically infer the definition (including its name) of each array store for each element type in Types. The element types are passed in the template parameter Types to the two templated structs mentioned above.

Everything works except for when I try to instantiate VariantArrays from within a module other than variant_arrays.d. For instance, if I try to use it in another module containing

unittest
{
    struct S { int x; }
    import variant_arrays : VariantArrays;
    VariantArrays!S a;
}

I get the error

variant_arrays.d-mixin-130(130,1): Error: undefined identifier `S`
foo.d(5,5): Error: template instance variant_arrays.VariantArrays!(S) error instantiating

In other words, the symbol S cannot be resolved in the scope of VariantArrays eventhough it's feed as a template parameter.

Is there a way around this problem?

Posted also here: http://forum.dlang.org/post/[email protected]

Here follows the definition of variant_arrays.d (excluding unittests):

/** Polymorphic index into an element in `VariantArrays`. */
private struct VariantIndex(Types...)
{
    import std.meta : staticIndexOf;
private:
    alias Kind = ubyte;              // kind code
    alias Size = size_t;             // size type

    import bit_traits : bitsNeeded;

    /// Number of bits needed to represent kind.
    enum kindBits = bitsNeeded!(Types.length);

    /// Get number kind of kind type `SomeKind`.
    enum nrOfKind(SomeKind) = staticIndexOf!(SomeKind, Types); // TODO cast to ubyte if Types.length is <= 256

    /// Is `true` iff an index to a `SomeKind`-kind can be stored.
    enum canReferTo(SomeKind) = nrOfKind!SomeKind >= 0;

    /// Construct.
    this(Kind kind, Size index) // TODO can ctor inferred by bitfields?
    {
        _kindNr = kind;
        _index = index;
    }

    import std.bitmanip : bitfields;
    mixin(bitfields!(Size, "_index", 8*Size.sizeof - kindBits,
                     Kind, "_kindNr", kindBits));
}

/** Stores set of variants.

    Enables lightweight storage of polymorphic objects.

    Each element is indexed by a corresponding `VariantIndex`.
 */
private struct VariantArrays(Types...)
{
    alias Index = VariantIndex!Types;

    import basic_copyable_array : CopyableArray;

    /// Returns: array type (as a string) of `Type`.
    private static immutable(string) arrayTypeString(Type)()
    {
        return `CopyableArray!(` ~ Type.stringof ~ `)`;
    }

    /// Returns: array instance (as a strinng) storing `Type`.
    private static immutable(string) arrayInstanceString(Type)()
    {
        return `_values` ~ Type.mangleof;
    }

    /** Insert `value` at back.
     */
    pragma(inline)                             // DMD cannot inline
    Index insertBack(SomeKind)(SomeKind value) // TODO add array type overload
        if (Index.canReferTo!SomeKind)
    {
        mixin(`alias arrayInstance = ` ~ arrayInstanceString!SomeKind ~ `;`);
        const currentIndex = arrayInstance.length;
        arrayInstance.insertBack(value);
        return Index(Index.nrOfKind!SomeKind,
                     currentIndex);
    }
    alias put = insertBack;     // polymorphic `OutputRange` support

    /// Get reference to element of type `SomeKind` at `index`.
    scope ref inout(SomeKind) at(SomeKind)(in size_t index) inout return
        if (Index.canReferTo!SomeKind)
    {
        mixin(`return ` ~ arrayInstanceString!SomeKind ~ `[index];`);
    }

    /// Peek at element of type `SomeKind` at `index`.
    scope inout(SomeKind)* peek(SomeKind)(in Index index) inout return @system
        if (Index.canReferTo!SomeKind)
    {
        if (Index.nrOfKind!SomeKind == index._kindNr)
        {
            return &at!SomeKind(index._index);
        }
        else
        {
            return null;
        }
    }

private:
    // TODO this fails:
    mixin({
            string s = "";
            foreach (Type; Types)
            {
                s ~= arrayTypeString!Type ~ ` ` ~ arrayInstanceString!Type ~ `;`;
            }
            return s;
        }());
}
0

There are 0 answers