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

hasMember fails to recognize member (interaction with mixin template) #19495

Open
dlangBugzillaToGithub opened this issue Oct 12, 2018 · 3 comments
Labels

Comments

@dlangBugzillaToGithub
Copy link

Luís Marques (@luismarques) reported this on 2018-10-12T13:59:40Z

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

CC List

  • Boris Carvajal
  • Eduard Staniloiu

Description

In the code quoted below, there is an inconsistency between these two lines:

    pragma(msg, P.ElementType);
    static assert(hasMember!(P, "ElementType"));

The pragma correctly prints the P.ElementType, but the hasMember assert fails. The interaction with the mixin template suggests this might be a compiler bug, but for now I'm only marking this as a Phobos bug. A workaround would be appreciated.

--

import std.traits;

void main()
{
    alias V = Vec!Bool;
    alias P = Port!(V);
    pragma(msg, P.ElementType);
    static assert(hasMember!(P, "ElementType"));
}

mixin template SignalOps()
{
    static if(hasMember!(typeof(this), "ElementType")) { }
}

struct Bool {}

struct Port(SomeSignal)
{
    mixin SignalOps;

    static if(hasMember!(SomeSignal, "ElementType"))
        alias ElementType = SomeSignal.ElementType;
}

struct Vec(SomeSignal)
{
    alias ElementType = SomeSignal;
}
@dlangBugzillaToGithub
Copy link
Author

edi33416 commented on 2018-11-28T10:12:54Z

This is most definitely a compiler bug which seems to be related/triggered my the template mixin, as `std.traits.hasMember` only calls the equivalent `__traits(hasMember, T, memberName)` compiler trait.

As a workaround, you can use
static assert(__traits(hasMember, P, "ElementType")); // passes


Also, weirdly enough, swapping the mixin instantiation with the `static if` block in `Port`, will pass the initial assert

```
struct Port(SomeSignal)
{
    static if(hasMember!(SomeSignal, "ElementType"))
        alias ElementType = SomeSignal.ElementType;

    mixin SignalOps;
}

void main()
{
    ...
    static assert(hasMember!(P, "ElementType")); // OK
    static assert(__traits(hasMember, P, "ElementType")); // OK
}
```

You can check this on https://run.dlang.io/is/6aXcGq

@dlangBugzillaToGithub
Copy link
Author

edi33416 commented on 2018-11-28T11:47:36Z

What is even weirder, if you define your own `hasMember` wrapper, that works just fine with the initial definition of Port

```
enum hasM(T, string name) = __traits(hasMember, T, name);

static assert(hasM!(P, "ElementType")); // ok
```

As reflected by https://run.dlang.io/is/pKYL9B

@dlangBugzillaToGithub
Copy link
Author

boris2.9 commented on 2021-03-21T11:11:49Z

There are 2 issues here:

1) Currently, DMD can't see forward references that are declared inside subsequent declaration scopes (things like 'static if' or 'static foreach'), this is hard to solve because the compiler could jump to a later scope looking for what it needs but that scope could also need something from the previous, a chicken and egg problem.

2) Template instances are cached, if the first instance of 'hasMember!(S, ElementType")' evaluates to false, it will always return false.

Code:
---
enum hasM(T, string name) = __traits(hasMember, T, name);
  
struct S
{
    // ElementType is not yet defined so it evaluates to false and the
    // pragma(hasM) below will print false.
    // Commenting out this 'static if' will make the pragma(hasM) print true
    // because the three pragmas are evaluated much later than 'struct S'.
    static if(hasM!(S, "ElementType")) { }

    static if(1)
        alias ElementType = int;
}

void main()
{
    pragma(msg, S.ElementType); // int
    pragma(msg, hasM!(S, "ElementType")); // depends on the first instantiation
    pragma(msg, __traits(hasMember, S, "ElementType"));  // true
}
---

@thewilsonator thewilsonator added the Feature:traits Relating to __traits label Dec 14, 2024
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

2 participants