A reduced test case: mixin ("enum E {", S.attr, "}"); struct S { E e; enum attr = "a"; } void main() { } onlineapp.d(7): Error: undefined identifier `E` The test case compiles if the enum is wrapped in a template: template E() { mixin ("enum E {", S.attr, "}"); } struct S { E!() e; enum attr = "a"; }
(In reply to Max Samukha from comment #0) > The test case compiles if the enum is wrapped in a template: However, it doesn't if the template instance is aliased: template E_() { mixin ("enum E_ {", S.attr, "}"); } alias E = E_!(); struct S { E e; enum attr = "a"; } onlineapp.d(12): Error: template instance `onlineapp.E_!()` is used as a type onlineapp.d(8): Error: template instance `onlineapp.E_!()` error instantiating
> However, it does if the template instance is aliased inside the type: template E_() { mixin ("enum E_ {", S.attr, "}"); } struct S { alias E = E_!(); E e; enum attr = "a"; }
(In reply to Max Samukha from comment #2) > > However, it does if the template instance is aliased inside the type: That wasn't supposed to be a quotation
I think that the compiler should perform a "pre-dsymbolsem" pass in aggregate decls, that pass would only target `enum` and other `static` declarations. That could kill the fake cycle on `E` and other similar bugs.
(In reply to Basile-z from comment #4) > I think that the compiler should perform a "pre-dsymbolsem" pass in > aggregate decls, that pass would only target `enum` and other `static` > declarations. > > That could kill the fake cycle on `E` and other similar bugs. I am not competent to comment on this. FWIW, attributes, which are conceptually similar to static members, don't have this issue: mixin ("enum E {", __traits(getAttributes, S)[0], "}"); @("a") struct S { E e; } void main() { }
(In reply to Max Samukha from comment #5) > I am not competent to comment on this. FWIW, attributes, which are > conceptually similar to static members, don't have this issue: > > mixin ("enum E {", __traits(getAttributes, S)[0], "}"); > > @("a") > struct S > { > E e; > } > > void main() > { > } Nah, attribs have the same problem, it's just that your test case does not reproduce it. For attribs this is more like ``` mixin ("enum E {", __traits(getAttributes, S)[0], "}"); @(S.a) struct S { E e; enum a = "dfgdf"; } void main() { } ``` output is then the same as the original test case, i.e > Error: undefined identifier `E`
In `S` the non static member `E e` create a cycle but actually with a pass dedicated to "static members - only" , the internal enum `S.a` would not require `S` semantic to be complete.
(In reply to Basile-z from comment #7) > In `S` the non static member `E e` create a cycle but actually with a pass > dedicated to "static members - only" , the internal enum `S.a` would not > require `S` semantic to be complete. reduced more ``` @(S.a) struct S { E e; enum a = "dfgdf"; } ```
even better ``` enum E { e1 = S.a } struct S { E e; enum a = "string"; } ``` > /tmp/temp_7F3BFB9249F0.d:6:14: Error: cannot implicitly convert expression `"string"` of type `string` to `int`
looks like enum being integral is assumed too early ;) for example if you change the infered type of S.a ``` enum E { e1 = S.a } struct S { E e; enum a = 123; // vs enum a = "string" } ``` no problems anymore
(In reply to Basile-z from comment #7) > In `S` the non static member `E e` create a cycle but actually with a pass > dedicated to "static members - only" , the internal enum `S.a` would not > require `S` semantic to be complete. Yes, I understand this. I meant UDAs are similar *in concept* to static members - they are things associated with the type's name but are not related to values of that type. Before D acquired proper UDAs, we used to emulate them with static fields and introspection.
(In reply to Basile-z from comment #10) > looks like enum being integral is assumed too early ;) > > for example if you change the infered type of S.a > > ``` > enum E { e1 = S.a } > > struct S > { > E e; > enum a = 123; // vs enum a = "string" > } > ``` > > no problems anymore Seems to be unrelated to the original issue. In the original test case, the enum is integral - it is the member's name that is mixed-in.
alright, I'll open another one ;)
(In reply to Basile-z from comment #13) > alright, I'll open another one ;) Great, thanks!
@ibuclaw created dlang/dmd pull request #14826 "dmd.aggregate: Define importAll override for AggregateDeclaration" fixing this issue: - fix Issue 22981 - Another forward reference bug involving a string mixin https://github.com/dlang/dmd/pull/14826