Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate compilation breaks hasElaborateDestructor with recursive type #19509

Open
dlangBugzillaToGithub opened this issue Nov 16, 2018 · 0 comments
Labels

Comments

@dlangBugzillaToGithub
Copy link

Atila Neves (@atilaneves) reported this on 2018-11-16T10:53:36Z

Transferred from https://issues.dlang.org/show_bug.cgi?id=19407

CC List

  • Paul Backus

Description

The code below compiles fine together but fails when compiled separately:

--------
// app.d
import type;
--------

---------
// type.d
import std.meta;
import std.traits;

struct Sum(Types...) if(Types.length > 0) {
    union {
        static foreach(i, T; Types) {
            import std.conv: text;
            mixin(`T value` ~ i.text ~ `;`);
        }
    }

    static if(anySatisfy!(hasElaborateDestructor, Types)) {

    }
}

alias Type = Sum!(Pointer, Bool);

struct Bool{}
struct Pointer{
    Type* pointee;
}
---------

% dmd -c app.d
/usr/include/dlang/dmd/std/traits.d(2678): Error: unable to determine fields of Pointer because of forward references
/usr/include/dlang/dmd/std/traits.d(3760): Error: template instance `std.traits.FieldTypeTuple!(Pointer)` error instantiating
/usr/include/dlang/dmd/std/meta.d(887):        instantiated from here: F!(Pointer)
/usr/include/dlang/dmd/std/meta.d(892):        instantiated from here: anySatisfy!(hasElaborateDestructor, Pointer)
type.d(12):        instantiated from here: anySatisfy!(hasElaborateDestructor, Pointer, Bool)
type.d(17):        instantiated from here: Sum!(Pointer, Bool)


The error messages seems to suggest that it's impossible to use `Fields!Pointer` but if the `static if` is removed and a `pragma(msg, Fields!Pointer)` is added it works fine.

It seems to be a bizarre interaction between separate compilation, `anySatisfy` and `hasElaborateDestructor`. Notably, just trying to call `hasElaborateDestructor!Pointer` fails with the same error messages.

It's possible to write a new version of `hasElaborateDestructor` that can be used on `Pointer`:

---------
template sumtypeHasElaborateDestructor(S)
{
    import std.meta : anySatisfy;
    import std.traits: hasMember, Fields, isStaticArray, Fields;

    static if (isStaticArray!S && S.length)
    {
        enum bool sumtypeHasElaborateDestructor = sumtypeHasElaborateDestructor!(typeof(S.init[0]));
    }
    else static if (is(S == struct))
    {
        alias fields = Fields!S;

        template foo(int index = fields.length - 1) {
            static if(index == 0)
                enum foo = .sumtypeHasElaborateDestructor!(fields[0]);
            else
                enum foo = .sumtypeHasElaborateDestructor!(fields[index]) || foo!(index -1);
        }

        enum sumtypeHasElaborateDestructor = hasMember!(S, "__dtor")
            || .sumtypeAnySatisfy!(.sumtypeHasElaborateDestructor, fields);
        //|| foo!();
            //|| anySatisfy!(.sumtypeHasElaborateDestructor, Fields!S);
    }
    else
    {
        enum bool sumtypeHasElaborateDestructor = false;
    }
}

template sumtypeAnySatisfy(alias F, T...) {
    template helper(int index) {
        static if(index == 0)
            enum helper = F!(T[0]);
        else
            enum helper = F!(T[index]) || helper!(index -1);
    }

    static if(T.length == 0)
        enum sumtypeAnySatisfy = false;
    else
        enum sumtypeAnySatisfy = helper!(T.length - 1);
}
---------

And `sumtypeHasElaborateDestuctor!Pointer` compiles. But... `sumtypeAnySatisfy!(sumtypeHasElaborateDestructor, Types)` fails again with the same error messages as the standard Phobos versions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant