Thread overview
[Issue 24265] ref delegate no longer implicitly converts to unannotated type
Nov 29, 2023
Paul Backus
Nov 29, 2023
Paul Backus
Nov 29, 2023
Adam D. Ruppe
Nov 29, 2023
Paul Backus
Nov 29, 2023
Paul Backus
[Issue 24265] ref delegate literal no longer implicitly converts to unannotated type
Nov 29, 2023
Paul Backus
November 29, 2023
https://issues.dlang.org/show_bug.cgi?id=24265

Paul Backus <snarwin+bugzilla@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |snarwin+bugzilla@gmail.com

--- Comment #1 from Paul Backus <snarwin+bugzilla@gmail.com> ---
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.

--
November 29, 2023
https://issues.dlang.org/show_bug.cgi?id=24265

--- Comment #2 from Paul Backus <snarwin+bugzilla@gmail.com> ---
Oops, pasted the wrong link; the introducing PR is here:

https://github.com/dlang/dmd/pull/14142

--
November 29, 2023
https://issues.dlang.org/show_bug.cgi?id=24265

Adam D. Ruppe <destructionator@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |diagnostic

--- Comment #3 from Adam D. Ruppe <destructionator@gmail.com> ---
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.

--
November 29, 2023
https://issues.dlang.org/show_bug.cgi?id=24265

--- Comment #4 from Paul Backus <snarwin+bugzilla@gmail.com> ---
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`
---

--
November 29, 2023
https://issues.dlang.org/show_bug.cgi?id=24265

Paul Backus <snarwin+bugzilla@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|diagnostic                  |

--- Comment #5 from Paul Backus <snarwin+bugzilla@gmail.com> ---
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.

--
November 29, 2023
https://issues.dlang.org/show_bug.cgi?id=24265

Paul Backus <snarwin+bugzilla@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Summary|ref delegate no longer      |ref delegate literal no
                   |implicitly converts to      |longer implicitly converts
                   |unannotated type            |to unannotated type

--- Comment #6 from Paul Backus <snarwin+bugzilla@gmail.com> ---
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.

--