Spin-off from issue 16056.
dmd considers the two types to be equal:
----
alias A = immutable int* delegate();
alias B = immutable int* delegate() immutable;
static assert(is(A == B)); /* passes */
----
That's ok. But it treats them differently.
This is accepted with `-version=V1`, but it's rejected with `-version=V2`:
----
version (V1) alias T = immutable void delegate();
version (V2) alias T = immutable void delegate() immutable;
void main()
{
int x = 1;
T dg = { ++x; };
}
----
Both V1 and V2 should be rejected.
Furthermore, when you use both types, the first one determines how the second is treated.
This is accepted:
----
void main()
{
int x = 1;
immutable void delegate() dg1 = { ++x; };
immutable void delegate() immutable dg2 = { ++x; };
}
----
Swap the two delegates lines and both are rejected. Again, both variants should be rejected.
All this applies to const as well, of course.
Comment #1 by eyal.lotem — 2016-05-24T06:46:24Z
I think it makes sense for the types not to be considered equal.
(Head-mutable ptrs to immutable data exist, so why should delegates be inconsistent?)
Comment #2 by ag0aep6g — 2016-05-24T11:45:46Z
(In reply to Eyal Lotem from comment #1)
> I think it makes sense for the types not to be considered equal.
> (Head-mutable ptrs to immutable data exist, so why should delegates be
> inconsistent?)
A head mutable delegate would be `void delegate() immutable`, no? That is considered different from the two types this is about.
Comment #3 by k.hara.pg — 2016-06-02T15:23:26Z
From the type qualifier transitivity, immutable(int* delegate()) should be same with immutable(int* delegate() immutable).
The root problem is in dmd implementation, TypeNext.makeXXX functions. Fixing those implementation bugs is not difficult.
Comment #4 by timon.gehr — 2021-04-13T00:25:17Z
(In reply to Kenji Hara from comment #3)
> From the type qualifier transitivity, immutable(int* delegate()) should be
> same with immutable(int* delegate() immutable).
> ...
This does not follow from transitivity because the postfix `immutable` also annotates the implicit context parameter of the function pointer while the `immutable` qualifier on the delegate a priori does not.
If those two types are conflated this actually leads to type system unsoundness:
----
auto foo()pure{
int x;
return ()pure{ return x++; };
}
void main(){
immutable dg=foo(); // can convert to immutable as it's a strongly pure call
import std.stdio;
writeln(dg()," ",dg()); // 0 1, immutable context is modified
}
----
Comment #5 by robert.schadek — 2024-12-13T18:47:58Z