Bug 21285 – Delegate covariance broken between 2.092 and 2.094 (git master).
Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Linux
Creation time
2020-09-30T05:45:21Z
Last change time
2022-03-27T02:24:25Z
Keywords
pull, rejects-valid
Assigned to
No Owner
Creator
hsteoh
Comments
Comment #0 by hsteoh — 2020-09-30T05:45:21Z
Reduced code:
--------
void main()
{
string path;
int bank;
auto aa = [
"path": (string arg) {
path = arg;
},
"bank": (string arg) {
bank = 1;
throw new Exception("");
},
];
}
--------
DMD 2.094 output:
--------
/tmp/test.d(6): Error: cannot implicitly convert expression __lambda1 of type void delegate(string arg) pure nothrow @nogc @safe to void delegate(string) pure @safe
--------
Surely `void delegate(string) pure nothrow @nogc @safe` is implicitly convertible to `void delegate(string) pure @safe`? Since nothrow is covariant to (implicit) throwing, and @nogc is covariant to (implicit) allocating. In any case, it's a bug that the compiler is unable to find a common value type for the above AA literal, since the common type `void delegate(string)` exists and works for both cases.
Note that the same problem persists even if the AA's type is explicitly spelled out `void delegate(string)[string]`, so this is not directly related to type deduction of the AA, but rather is a failure to find a common type between the two values of the AA literal.
This code successfully compiled with DMD 2.092, so this represents a recent regression.
Comment #1 by hsteoh — 2020-09-30T13:10:43Z
Apparently caused by DMD pull #11292 (d08981bcd1bbc8f3b54beb750f6a90c18c3d006b).
Comment #2 by dlang-bot — 2020-10-01T10:32:57Z
@Biotronic created dlang/dmd pull request #11819 "Fix Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master)." fixing this issue:
- Fix Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master)
https://github.com/dlang/dmd/pull/11819
Comment #3 by dlang-bot — 2020-10-21T00:50:46Z
dlang/dmd pull request #11819 "Fix Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master)." was merged into stable:
- 7776770ae204589250a2cb689ea71ae5e0c2dd06 by Simen Kjærås:
Fix Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master)
https://github.com/dlang/dmd/pull/11819
Comment #4 by dlang-bot — 2020-11-16T00:10:08Z
dlang/dmd pull request #11961 "merge stable" was merged into master:
- 24fd470f46c74c8787b1b6ee7e66a9368cba4724 by Simen Kjærås:
Fix Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master)
https://github.com/dlang/dmd/pull/11961
Comment #5 by hsteoh — 2020-11-23T19:45:33Z
The problem has not been completely fixed. Just a slight refactoring and it fails again:
Code:
--------
int f(string s) { throw new Exception(""); }
void main()
{
string path;
int bank, preset;
void delegate(string value)[string] aa = [
"path": (string arg) {
path = arg;
},
"bank": (string arg) {
bank = f(arg);
},
"preset": (string arg) {
preset = f(arg);
},
];
}
--------
Compiler output:
--------
test.d(7): Error: cannot implicitly convert expression __lambda1 of type void delegate(string arg) pure nothrow @nogc @safe to void delegate(string arg) @system
--------
Oddly enough, replacing the `preset` line with `preset = 1;` makes the problem go away. Somehow the number of elements in the AA initializer changes compiler behaviour.
Expected behaviour: `pure nothrow @nogc @safe` ought to be covariant with `@system`. And this covariance should not vary with unrelated factors such as the number of elements in the AA initializer.
Comment #6 by pro.mathias.lang — 2020-12-28T04:56:24Z
Comment #7 by pro.mathias.lang — 2021-10-18T08:03:24Z
I looked a bit more into this. The issue is that `scope` is inferred on:
> "preset": (string arg) {
Which is wrong, but since the function is not `@safe`, it shouldn't matter.
However, DMD also does something very stupid: It tries to find a common type among all initializers without looking at the array type! This can be seen in the following code:
```
void main ()
{
void function()[] arr = [ &f1, &f2 ];
}
int f1 () { return 42; }
string f2 () { return "42"; }
```
Which errors out with:
```
cov.d(3): Error: incompatible types for `(& f1) : (& f2)`: `int function()` and `string function()`
```
Now there are maybe good reasons to reject this code (we got co and contravariance wrong in the past), but the fact that they error out between one another is just wrong.
What the FE essentially do is:
- Get all elements;
- Make an array of all those elements;
- Try to convert this array to the LHS array;
The stack trace I got while aborting on the above code was:
```
core.exception.AssertError@src/dmd/expression.d(4019): Assertion failure
----------------
??:? _d_assertp [0x10a86a91c]
src/dmd/dinifile.d:177 dmd.globals.MATCH dmd.expression.FuncExp.matchType(dmd.mtype.Type, dmd.dscope.Scope*, dmd.expression.FuncExp*, int) [0x10a6213c7]
src/dmd/dinifile.d:177 _ZN14implicitCastTo14ImplicitCastTo5visitEP7FuncExp [0x10a553de6]
src/dmd/dinifile.d:177 _ZN7FuncExp6acceptEP7Visitor [0x10a621535]
src/dmd/dinifile.d:177 dmd.expression.Expression dmd.dcast.implicitCastTo(dmd.expression.Expression, dmd.dscope.Scope*, dmd.mtype.Type) [0x10a5538c7]
src/dmd/dinifile.d:177 _ZN10Expression14implicitCastToEP5ScopeP4Type [0x10a6194d8]
src/dmd/dinifile.d:177 dmd.mtype.Type dmd.expressionsem.arrayExpressionToCommonType(dmd.dscope.Scope*, ref dmd.root.array.Array!(dmd.expression.Expression).Array) [0x10a62e240]
src/dmd/dinifile.d:177 _ZN25ExpressionSemanticVisitor5visitEP20AssocArrayLiteralExp [0x10a6330e1]
src/dmd/dinifile.d:177 _ZN20AssocArrayLiteralExp6acceptEP7Visitor [0x10a61ef15]
```
As can be seen, the error happens in a child of `arrayExpressionToCommonType`.
dlang/dmd pull request #13316 "Fix issue 21285 - Delegate covariance broken" was merged into stable:
- 2edb4df387b6767b1c7ad779fe9af1ce6bfe4d49 by dkorpel:
Fix issue 21285 - Delegate covariance broken
https://github.com/dlang/dmd/pull/13316
Comment #10 by hsteoh — 2022-03-08T18:01:44Z
Verified that it works on the original code I found this bug in. Thanks a bunch for the efforts!!
Comment #11 by dkorpel — 2022-03-08T19:29:09Z
(In reply to hsteoh from comment #10)
> Verified that it works on the original code I found this bug in. Thanks a
> bunch for the efforts!!
Glad to hear that. Unfortunately, the PR barely missed the v2.099.0 release, though it should be in v2.099.1.
Comment #12 by dlang-bot — 2022-03-27T02:24:25Z
dlang/dmd pull request #13892 "Merge stable into master" was merged into master:
- e80f99183cc23828ad5a2805759271501415640c by dkorpel:
Fix issue 21285 - Delegate covariance broken
https://github.com/dlang/dmd/pull/13892