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

traits parent does not work on eponymous templates #18873

Open
dlangBugzillaToGithub opened this issue Aug 24, 2014 · 5 comments
Open

traits parent does not work on eponymous templates #18873

dlangBugzillaToGithub opened this issue Aug 24, 2014 · 5 comments
Labels

Comments

@dlangBugzillaToGithub
Copy link

Ellery Newcomer reported this on 2014-08-24T18:11:39Z

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

CC List

  • Adam D. Ruppe
  • Mike Franklin

Description

Passing an instantiated eponymous function template to __traits(parent,) yields a symbol that points to the function passed in. In G in the following code, I'm seeing this behavior:

  f       __traits(parent, f)
------  ----------------------
a              tok
b!int.c        __T1bTiZ
t!int          t


code:

import  std.typetuple;

int a(int i) {
    return i;
}

template b(T) {
    int c(T t) {
        return 1;
    }
}

int t(T)(T g) {
    return 1;
}

template G(alias f) {
    static assert(is(typeof(f) == function));
    pragma(msg, __traits(identifier, f));
    alias Parent = TypeTuple!(__traits(parent, f))[0];
    pragma(msg, __traits(identifier, Parent));
    static assert(!is(typeof(Parent) == typeof(f)), "I'm my own parent?");
}

void main(){
    alias y = G!(a);
    alias z = G!(t!int); // fails in here
}
@dlangBugzillaToGithub
Copy link
Author

slavo5150 commented on 2015-01-25T05:55:55Z

Looks like this might be the same as Issue 12496

@dlangBugzillaToGithub
Copy link
Author

b2.temp commented on 2016-11-05T16:16:38Z

=========
import std.meta;

template Parent(T)
{
    alias Parent = AliasSeq!(__traits(parent, T))[0];
}

unittest
{
    class A(T){}
    static assert(A!int.stringof != Parent!(A!int).stringof);
�}
=========

yields: Error: static assert  ("A!int" != "A!int") is false


the longer form

=========
import std.meta;

template Parent(T)
{
    alias Parent = AliasSeq!(__traits(parent, T))[0];
}

unittest
{
    template B(T){class B{}}
    alias T = B!int;
    static assert(is(T));
    static assert(T.stringof != Parent!T.stringof);
}
=========

yields: Error: static assert  ("B!int" != "B!int") is false

�too.

@dlangBugzillaToGithub
Copy link
Author

b2.temp commented on 2016-11-05T18:06:52Z

Strangely enough this bug can lead to think that we can detect an eponymous template:

==========
template isTemplateInstance(alias T : Base!Args, alias Base, Args...)
{
    enum isTemplateInstance = is(typeof(T));
}

template isTemplateInstance(T : Base!Args, alias Base, Args...)
{
    enum isTemplateInstance = is(T);
}

template isTemplateInstance(T)
{
    enum isTemplateInstance = false;
}

template isTemplateInstance(alias T)
{
    enum isTemplateInstance = isTemplateInstance!(typeof(T));
}

template isEponymousTemplate(T)
{
    static if (is(T == class) || is(T == interface) || is(T == struct) || is(T == union))
    {
        enum p = __traits(parent, T).stringof == T.stringof;
        enum isEponymousTemplate = p && isTemplateInstance!T;
    }
    else
        enum isEponymousTemplate = false;
}

unittest
{
    class A(T){}
    struct B(T){}
    static assert(isEponymousTemplate!(A!int));
    static assert(isEponymousTemplate!(B!int));
    static assert(!isEponymousTemplate!int);
    template C(T)
    {
        class C{}
    }
    static assert(isEponymousTemplate!(C!int));
}

unittest
{
    template A(T)
    {
        class A{}
    }
    static assert(isEponymousTemplate!(A!int));

    template B(T)
    {
        class A{}
    }
    static assert(!isEponymousTemplate!(B!int.A));

    class C(T){}
    static assert(!isEponymousTemplate!int);

    A!int a;
    static assert(isEponymousTemplate!a);
}
==========

Indeed we can detect it but we can't get the parent !
What's happen is that "isEponymousTemplate" yield true for an eponymous template because the template itself points to its argument !

@dlangBugzillaToGithub
Copy link
Author

slavo5150 commented on 2018-01-29T07:51:05Z

(In reply to Basile B. from comment #2)
> =========
> import std.meta;
> 
> template Parent(T)
> {
>     alias Parent = AliasSeq!(__traits(parent, T))[0];
> }
> 
> unittest
> {
>     class A(T){}
>     static assert(A!int.stringof != Parent!(A!int).stringof);
> }
> =========
> 
> yields: Error: static assert  ("A!int" != "A!int") is false
> 
> 
> the longer form
> 
> =========
> import std.meta;
> 
> template Parent(T)
> {
>     alias Parent = AliasSeq!(__traits(parent, T))[0];
> }
> 
> unittest
> {
>     template B(T){class B{}}
>     alias T = B!int;
>     static assert(is(T));
>     static assert(T.stringof != Parent!T.stringof);
> }
> =========
> 
> yields: Error: static assert  ("B!int" != "B!int") is false

These two tests now pass in v2.078.1

@dlangBugzillaToGithub
Copy link
Author

destructionator commented on 2020-05-24T17:24:28Z

Here's something related I just came upon:

template wrap(string foo) {
        enum wrap = foo;
}
pragma(msg, __traits(parent, wrap!"lol")); // says lol
pragma(msg, __traits(parent, __traits(parent, wrap!"lol"))); // says argument "lol" has no parent


So in the first one, it appears it evaluates to the outer template which is then instantly evaluated back to the enum literal. Then the second one sees the literal and says literals have no parents.

Quite bizarre indeed.

@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