www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 12287] New: infinite loop on std.traits.moduleName on templated struct member

reply d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287

           Summary: infinite loop on std.traits.moduleName on templated
                    struct member
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: major
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: oivind.loe gmail.com


--- Comment #0 from Řivind <oivind.loe gmail.com> 2014-03-02 12:55:35 PST ---
Compile of the following code never completes. If the struct is not a template,
the behavior is as expected. Don't know if this is a DMD or Phobos issue.
Running on 2.065.0


import std.stdio;
import std.traits;

struct X(T) {
    T i;
}

void main(){

    writeln(moduleName!((X!int).i));

}

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 02 2014
next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287


Vladimir Panteleev <thecybershadow gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |thecybershadow gmail.com


--- Comment #1 from Vladimir Panteleev <thecybershadow gmail.com> 2014-03-02
23:20:31 EET ---
It looks like the underlying problem is that the parent of a template instance
is the template instance itself.

Reduced:

struct X(T) { }

alias Xi = X!int;

static assert(!__traits(isSame, Xi, __traits(parent, Xi)));

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #2 from Vladimir Panteleev <thecybershadow gmail.com> 2014-03-02
23:42:03 EET ---
I think this only applies to eponymous templates. The parent of the member is
the struct declaration, the parent of which is the template instance. But when
referring to the template instance of an eponymous template, it is "converted"
to the symbol it wraps (the struct declaration), so it never exits the cycle.

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287


Vladimir Panteleev <thecybershadow gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |pull


--- Comment #3 from Vladimir Panteleev <thecybershadow gmail.com> 2014-03-02
23:58:21 EET ---
https://github.com/D-Programming-Language/dmd/pull/3346

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #4 from Kenji Hara <k.hara.pg gmail.com> 2014-03-02 18:19:10 PST ---
(In reply to comment #2)
 I think this only applies to eponymous templates. The parent of the member is
 the struct declaration, the parent of which is the template instance. But when
 referring to the template instance of an eponymous template, it is "converted"
 to the symbol it wraps (the struct declaration), so it never exits the cycle.

No, this is a Phobos bug. I think it's not good to add a special case in __traits(parent) for eponymous templates. -- Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #5 from Vladimir Panteleev <thecybershadow gmail.com> 2014-03-03
04:21:23 EET ---
(In reply to comment #4)
 No, this is a Phobos bug. I think it's not good to add a special case in
 __traits(parent) for eponymous templates.

How can you fix it in Phobos, if it is not possible to get the parent of an eponymous template? -- Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #6 from Kenji Hara <k.hara.pg gmail.com> 2014-03-02 18:33:03 PST ---
(In reply to comment #5)
 (In reply to comment #4)
 No, this is a Phobos bug. I think it's not good to add a special case in
 __traits(parent) for eponymous templates.

How can you fix it in Phobos, if it is not possible to get the parent of an eponymous template?

https://github.com/D-Programming-Language/phobos/pull/1978 -- Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #7 from Vladimir Panteleev <thecybershadow gmail.com> 2014-03-03
04:34:43 EET ---
OK, so you pattern-match the template.

But I don't think this is a good solution, because any recursive use of
__traits(parent) will need to take care of this special case. It goes against
the principle of least surprise.

What are your arguments against a compiler change?

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #8 from Kenji Hara <k.hara.pg gmail.com> 2014-03-02 18:46:53 PST ---
(In reply to comment #7)
 OK, so you pattern-match the template.
 
 But I don't think this is a good solution, because any recursive use of
 __traits(parent) will need to take care of this special case. It goes against
 the principle of least surprise.
 
 What are your arguments against a compiler change?

Because your compiler change will make some part of the internal structure of the template instantiation invisible. Any compiler-side special handlings are unavoidable behavior for the all language users. So I'm afraid that your change might become harmful blocker for some users. -- Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #9 from Vladimir Panteleev <thecybershadow gmail.com> 2014-03-03
04:49:01 EET ---
(In reply to comment #8)
 Because your compiler change will make some part of the internal structure of
 the template instantiation invisible. 

I don't understand. Why? Before my patch: __traits(parent, X!foo) is the same symbol as X!foo. It did not reveal any internal structure at all, the result was completely useless. After my patch, it produces the result that a casual user may expect from an eponymous template, especially when declared like struct S(Args) {...} -- Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #10 from Kenji Hara <k.hara.pg gmail.com> 2014-03-02 19:00:17 PST
---
(In reply to comment #9)
 (In reply to comment #8)
 Because your compiler change will make some part of the internal structure of
 the template instantiation invisible. 

I don't understand. Why? Before my patch: __traits(parent, X!foo) is the same symbol as X!foo. It did not reveal any internal structure at all, the result was completely useless.

Internally X!foo is exactly same as X!foo.X. So __traits(parent, X!foo) will return the parent of the instantiated type X - that is the TemplateInstance 'X!foo'. They are completely different objects. But, latter semantic analysis will translate X!foo to X!foo.X again. The behavior is not directly related to the __traits(parent) behavior.
 After my patch, it produces the result that a casual user may expect from an
 eponymous template, especially when declared like struct S(Args) {...}

I think it's not consistent behavior in generic case. For example: template S(T) { struct S {} int x; static assert(__traits(isSame, __traits(parent, S), __traits(parent, x))); } alias s = S!int; Your change will break this case. -- Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #11 from Vladimir Panteleev <thecybershadow gmail.com> 2014-03-03
05:03:05 EET ---
(In reply to comment #10)
 But, latter semantic analysis will translate X!foo to X!foo.X again. The
 behavior is not directly related to the __traits(parent) behavior.

The __traits code runs semantic on its result immediately after calculating the parent. So "later" here means "immediately after".
 I think it's not consistent behavior in generic case. For example:
 
 template S(T)
 {
     struct S {}
 
     int x;
     static assert(__traits(isSame, __traits(parent, S),
                                    __traits(parent, x)));
 }
 alias s = S!int;
 
 Your change will break this case.

I think that makes no sense. In the same spirit, you could argue that since the parent of x is struct S, then x is a member of struct S. -- Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #12 from Vladimir Panteleev <thecybershadow gmail.com> 2014-03-03
05:14:12 EET ---
(In reply to comment #10)
 template S(T)
 {
     struct S {}
 
     int x;
     static assert(__traits(isSame, __traits(parent, S),
                                    __traits(parent, x)));
 }
 alias s = S!int;
 
 Your change will break this case.

I've amended my pull so that it does not break this case. Now the parent of any member of an eponymous template is the template instantiation's parent, not just the eponymous member. BTW, why is the parent of a template instantiation not the template declaration? Right now it goes right to the module. I think going through the declaration would be more logical. -- Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #13 from Kenji Hara <k.hara.pg gmail.com> 2014-03-02 19:41:13 PST
---
(In reply to comment #11)
 The __traits code runs semantic on its result immediately after calculating the
 parent. So "later" here means "immediately after".

The semantic will return ScopeExp, and it still contain the TemplateInstance object. So you are misunderstanding.
 I think that makes no sense. In the same spirit, you could argue that since the
 parent of x is struct S, then x is a member of struct S.

I don't understand what you saying. The parent of struct S and variable x is the template instance S!int. There's nothing else. -- Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #14 from Vladimir Panteleev <thecybershadow gmail.com> 2014-03-03
05:53:28 EET ---
(In reply to comment #13)
 The semantic will return ScopeExp, and it still contain the TemplateInstance
 object. So you are misunderstanding.

I just checked again with a debugger and this is not what I am seeing. The returned expression is a TypeExp, with the type being the TypeStruct pointing at the struct of course.
 I don't understand what you saying. The parent of struct S and variable x is
 the template instance S!int. There's nothing else.

Maybe I am wrong but from looking at what is going on with a debugger I don't see that happening. But even if you are right, isn't the correct fix to move the replacing of the template instance with the eponymous member so that it doesn't happen with chained __traits(parent)? Your library solution is a crutch; I don't think there should ever be a case where __traits(parent) enters an infinite loop. -- Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #15 from Kenji Hara <k.hara.pg gmail.com> 2014-03-02 20:35:34 PST
---
(In reply to comment #14)
 (In reply to comment #13)
 The semantic will return ScopeExp, and it still contain the TemplateInstance
 object. So you are misunderstanding.

I just checked again with a debugger and this is not what I am seeing. The returned expression is a TypeExp, with the type being the TypeStruct pointing at the struct of course.
 I don't understand what you saying. The parent of struct S and variable x is
 the template instance S!int. There's nothing else.

Maybe I am wrong but from looking at what is going on with a debugger I don't see that happening.

Ah, I was wrong. Indeed __traits(parent) will return TypeExp for the instantiated type of the eponymous template.
 But even if you are right, isn't the correct fix to move the replacing of the
 template instance with the eponymous member so that it doesn't happen with
 chained __traits(parent)?
 
 Your library solution is a crutch; I don't think there should ever be a case
 where __traits(parent) enters an infinite loop.

I think the library solution is far better than the hack for __traits(parent). In other word, the infinite loop is the expected behavior with 2.065 Phobos code. -- Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #16 from Vladimir Panteleev <thecybershadow gmail.com> 2014-03-03
06:50:26 EET ---
I use __traits(parent) in my code as well. Just because you added the crutch to
one of the uses of __traits(parent) in the standard library doesn't mean that
the problem is fixed for everyone. Every user who uses __traits(parent)
recursively directly will need to implement this crutch as well, and they will
find out about this by having their compiler CRASH or HANG during certain
parameters to their templates! I don't understand how you can think that this
is acceptable. Unless I am missing something, the advantages of the solution
you presented clearly do not outweigh the disadvantages. If you still think
your solution is better, please clearly list its advantages and why you think
it stands up to my criticism.

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #17 from Vladimir Panteleev <thecybershadow gmail.com> 2014-03-03
07:00:55 EET ---
If we are to go with a library solution, then parentOf needs to be made public,
documented, and advocated in favor of the __traits primitive. And the
documentation of the __traits primitive needs to be updated to say that it is
unreliable as in certain cases it returns the symbol itself rather than its
parent. (What a mess.)

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 02 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287



--- Comment #18 from github-bugzilla puremagic.com 2014-03-09 23:01:19 PDT ---
Commits pushed to master at https://github.com/D-Programming-Language/phobos

https://github.com/D-Programming-Language/phobos/commit/a4aa5d8a15ed48f17ec4e70151faddcd886f7b89
fix Issue 12287 - infinite loop on std.traits.moduleName on templated struct
member

https://github.com/D-Programming-Language/phobos/commit/b0aabc6c9328ee2a83a0cdb3863d55ba7ee71342
Merge pull request #1978 from 9rnsr/fix12287

Issue 12287 - infinite loop on std.traits.moduleName on templated struct member

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 09 2014
prev sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12287


Andrei Alexandrescu <andrei erdani.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |andrei erdani.com
         Resolution|                            |FIXED


-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 09 2014