Issue 22981 - Another forward reference bug involving a string mixin
Summary: Another forward reference bug involving a string mixin
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P3 normal
Assignee: No Owner
URL:
Keywords: pull, rejects-valid
Depends on:
Blocks:
 
Reported: 2022-04-04 07:42 UTC by Max Samukha
Modified: 2023-01-19 11:39 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Max Samukha 2022-04-04 07:42:17 UTC
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";
}
Comment 1 Max Samukha 2022-04-04 07:49:39 UTC
(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
Comment 2 Max Samukha 2022-04-04 07:51:16 UTC
> 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";
}
Comment 3 Max Samukha 2022-04-04 07:59:49 UTC
(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
Comment 4 basile-z 2022-04-30 08:28:44 UTC
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.
Comment 5 Max Samukha 2022-04-30 16:04:29 UTC
(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()
{
}
Comment 6 basile-z 2022-04-30 16:15:40 UTC
(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`
Comment 7 basile-z 2022-04-30 16:22:39 UTC
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.
Comment 8 basile-z 2022-04-30 16:25:34 UTC
(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";
}
```
Comment 9 basile-z 2022-04-30 16:29:22 UTC
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`
Comment 10 basile-z 2022-04-30 16:36:50 UTC
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
Comment 11 Max Samukha 2022-04-30 17:27:44 UTC
(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.
Comment 12 Max Samukha 2022-04-30 17:31:15 UTC
(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.
Comment 13 basile-z 2022-04-30 23:37:59 UTC
alright, I'll open another one ;)
Comment 14 Max Samukha 2022-05-01 07:49:57 UTC
(In reply to Basile-z from comment #13)
> alright, I'll open another one ;)

Great, thanks!
Comment 15 Dlang Bot 2023-01-16 01:26:08 UTC
@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