Comment #0 by destructionator — 2023-11-29T01:42:05Z
This worked fine on dmd 2.098 (my mainline LTS version) but ceased working some time between that and 2.105 (I don't feel like doing a bisect tonight):
```
void main() {
ref int alol();
typeof(&alol) dg;
int a;
dg = delegate ref() { return a; };
dg() = 5;
assert(a == 5);
}
```
me@arsd:~/test$ dmd-2098 refdg
me@arsd:~/test$ ./refdg # compiles and passes assert
me@arsd:~/test$ dmd-master refdg
refdg.d(5): Error: cannot implicitly convert expression `__dgliteral4` of type
int delegate() pure nothrow @nogc ref @safe` to `int delegate() ref`
refdg.d(5): Error: cannot implicitly convert expression `__dgliteral4` of type
int delegate() pure nothrow @nogc ref @safe` to `int delegate() ref`
Fails on the new dmd. If you write out all the attributes on the dg type:
```
void main() {
ref int alol() @safe @nogc nothrow pure;
typeof(&alol) dg;
int a;
dg = delegate ref() { return a; };
dg() = 5;
assert(a == 5);
}
```
Compiles and runs successfully on both old and new dmd.
Comment #1 by snarwin+bugzilla — 2023-11-29T02:09:44Z
Introduced by DMD PR 14142:
https://issues.dlang.org/show_bug.cgi?id=24265
Looks like maybe this isn't a behavioral bug, but a bad error message: the actual problem is that `ref int delegate() return` does not convert to `ref int delegate()`, but the compiler does not print the `return` attribute when printing the delegate's type.
Comment #2 by snarwin+bugzilla — 2023-11-29T02:10:08Z
Comment #3 by destructionator — 2023-11-29T02:21:27Z
OK, yeah, I suspected it might have to do with the return thing, but weird that adding the explicit attributes made it work.
I'm ok reclassifying this as a diagnostic bug. I'll at least add the keyword.
Comment #4 by snarwin+bugzilla — 2023-11-29T20:07:24Z
Looks like this only happens when the return attribute is inferred.
---
void test()
{
int a;
ref int f();
ref int g() return;
ref int h() => a; // return inferred
typeof(&f) dg;
dg = &g; // line 9
dg = &h; // line 10
}
---
Output:
---
bug.d(9): Error: cannot implicitly convert expression `&g` of type `int delegate() ref return` to `int delegate() ref`
bug.d(10): Error: cannot implicitly convert expression `&h` of type `int delegate() pure nothrow @nogc ref @safe` to `int delegate() ref`
---
Comment #5 by snarwin+bugzilla — 2023-11-29T20:40:49Z
Correction, it's not a diagnostic problem--the types are printed differently because they are actually considered different by the compiler. For example, this:
---
void test()
{
int local;
ref int explicit() pure nothrow @nogc @safe return;
ref int inferred() pure nothrow @nogc @safe => local;
static assert(is(typeof(&explicit) == typeof(&inferred)));
}
---
...fails with the following output:
---
bug.d(7): Error: static assert: `is(int delegate() pure nothrow @nogc ref return @safe == int delegate() pure nothrow @nogc ref @safe)` is false
---
The return attribute is not printed because it is genuinely not being inferred, probably due to issue 22977.
Comment #6 by snarwin+bugzilla — 2023-11-29T21:06:26Z
The bug *is* related to dropping function attributes during implicit conversion, and it only affects a delegate whose type is inferred from the type of a delegate literal:
---
void test()
{
int local;
auto inferred = delegate ref int() => local;
ref int fun() pure nothrow @nogc @safe;
static assert(is(typeof(inferred) == typeof(&fun)));
typeof(&fun) explicit = inferred;
ref int f();
typeof(&f) dg;
dg = &fun; // ok
dg = explicit; // ok
dg = inferred; // error
}
---
Output:
---
bug.d(17): Error: cannot implicitly convert expression `inferred` of type `int delegate() pure nothrow @nogc ref @safe` to `int delegate() ref`
---
Somehow, the compiler is ending up with two internal representations of the "same" delegate type, and only one of them can implicitly convert to the unannotated version.
Comment #7 by robert.schadek — 2024-12-13T19:32:03Z