Bug 24265 – ref delegate literal no longer implicitly converts to unannotated type

Status
NEW
Severity
regression
Priority
P3
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2023-11-29T01:42:05Z
Last change time
2024-12-13T19:32:03Z
Assigned to
No Owner
Creator
Adam D. Ruppe
Moved to GitHub: dmd#18201 →

Comments

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
Oops, pasted the wrong link; the introducing PR is here: https://github.com/dlang/dmd/pull/14142
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
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/18201 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB