Issue 16058 - `immutable delegate()` and `immutable delegate() immutable` are considered equal but treated differently
Summary: `immutable delegate()` and `immutable delegate() immutable` are considered eq...
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: accepts-invalid
Depends on:
Blocks:
 
Reported: 2016-05-22 16:37 UTC by ag0aep6g
Modified: 2022-12-17 10:37 UTC (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description ag0aep6g 2016-05-22 16:37:04 UTC
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 Eyal Lotem 2016-05-24 06:46:24 UTC
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 ag0aep6g 2016-05-24 11:45:46 UTC
(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 Kenji Hara 2016-06-02 15:23:26 UTC
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 timon.gehr 2021-04-13 00:25:17 UTC
(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
}
----