Thread overview
[Issue 22010] Link error with mutually recursive SumType / struct with opEquals
Jun 09, 2021
João Lourenço
Jun 09, 2021
Vladimir Panteleev
Jun 09, 2021
João Lourenço
Jul 06, 2022
Mathias LANG
Dec 17, 2022
Iain Buclaw
June 09, 2021
https://issues.dlang.org/show_bug.cgi?id=22010

João Lourenço <jlourenco5691@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jlourenco5691@gmail.com

--- Comment #1 from João Lourenço <jlourenco5691@gmail.com> ---
I think this is because it uses `match` internally. You are passing a `const Ref!T` in your `opEquals` which makes its `TagTuple` a `const(TagTuple)`. When trying to match it won't be able to.

As a workaround fix, removing `const` from `opEquals` solves your issue.

Also, refactoring your `opEquals` to a template (to allow the program to compile), gives a more propper error when comparing the types:

```d
/+dub.sdl:
dependency "sumtype" version="~>1.1.1"
+/
import sumtype;

struct S { Ref!Node node; }
alias Node = SumType!S;

private struct Ref(T)
{
    private T* _ref_ptr;
    this(ref T value) { _ref_ptr = &value; } ///
    bool opEquals()(ref const Ref!T other) { return *_ref_ptr ==
*other._ref_ptr; }
}

void main()
{
    S s;
    assert(S.init == s);
}
```

Produces (tested with sumtype-1.1.1):
---
.dub/packages/sumtype-1.1.1/sumtype/src/sumtype.d(1718,13): Error: need `this`
for `tags` of type `ulong[2]`
.dub/packages/sumtype-1.1.1/sumtype/src/sumtype.d(1718,13): Error: need `this`
for `tags` of type `ulong[2]`
Error: `this` for `__invariant430` needs to be type `TagTuple` not type
`const(TagTuple)`
.dub/packages/sumtype-1.1.1/sumtype/src/sumtype.d(1828,4): Error: static
assert:  "`handlers[0]` of type `template` never matches"
.dub/packages/sumtype-1.1.1/sumtype/src/sumtype.d(1448,46):        instantiated
from here: `matchImpl!(const(SumType!(S)), const(SumType!(S)))`
.dub/packages/sumtype-1.1.1/sumtype/src/sumtype.d(578,31):        instantiated
from here: `match!(const(SumType!(S)), const(SumType!(S)))`
.dub/packages/sumtype-1.1.1/sumtype/src/sumtype.d(587,11):        instantiated
from here: `opEquals!(const(SumType!(S)), const(SumType!(S)))`
onlineapp.d(14,53):        instantiated from here: `opEquals!(SumType!(S),
const(SumType!(S)))`
onlineapp.d(10,9):        instantiated from here: `opEquals!()`
dmd failed with exit code 1.
---

This should work though.

--
June 09, 2021
https://issues.dlang.org/show_bug.cgi?id=22010

--- Comment #2 from Vladimir Panteleev <dlang-bugzilla@thecybershadow.net> ---
(In reply to João Lourenço from comment #1)
> I think this is because it uses `match` internally.

A link error like this should never happen no matter what the code does (unless it's something intentional like an extern declaration with no definition, of course.)

> As a workaround fix, removing `const` from `opEquals` solves your issue.

Thanks but this is a reduced example meant to illustrate the compiler bug.

--
June 09, 2021
https://issues.dlang.org/show_bug.cgi?id=22010

--- Comment #3 from João Lourenço <jlourenco5691@gmail.com> ---
(In reply to Vladimir Panteleev from comment #2)
> Thanks but this is a reduced example meant to illustrate the compiler bug.

Yes, I mislead the issue and thought it was about SumType itself.

--
July 06, 2022
https://issues.dlang.org/show_bug.cgi?id=22010

Mathias LANG <pro.mathias.lang@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |pro.mathias.lang@gmail.com

--- Comment #4 from Mathias LANG <pro.mathias.lang@gmail.com> ---
I believe I hit this issue as well. The key seems to be the mutual recursion.

In my case, the code is the following:
```
import std.sumtype;
import std.stdio;

alias ST = SumType!(int, long, Custom[]);

struct Custom
{
    int a;
    ST b;
}

void main ()
{
    const SumType!(int, long, Custom[]) st = [ Custom(42), Custom(69) ];
    version(all) writeln(st);
    assert(st.toString() == "NULL");
}
```

With this, I get a compiler error:
```
/usr/include/dmd/phobos/std/sumtype.d(1945): Error: need `this` for `tags` of
type `ulong[1]`
Error: `this` for `__invariant1322` needs to be type `TagTuple` not type
`const(TagTuple)`
/usr/include/dmd/phobos/std/sumtype.d(2102): Error: static assert:  "No
matching handler for types `(const(Custom[]))`"
/usr/include/dmd/phobos/std/sumtype.d(1662):        instantiated from here:
`matchImpl!(const(SumType!(int, long, Custom[])))`
/usr/include/dmd/phobos/std/sumtype.d(787):        instantiated from here:
`match!(const(SumType!(int, long, Custom[])))`
st.d(16):        instantiated from here: `toString!(const(SumType!(int, long,
Custom[])))`
```

Now if you remove the `writeln` in `version(all)`, you end up with:
```
ld: error: undefined symbol:
_D3std6format5write__T11formatValueTSQBj5array__T8AppenderTAyaZQoTAxS2st6CustomTaZQCiFKQBzKQzMKxSQDrQDq4spec__T10FormatSpecTaZQpZv
>>> referenced by st.d
>>>               st.o:(_D3std4conv__T5toStrTAyaTAxS2st6CustomZQzFQrZQy)
collect2: error: ld returned 1 exit status
Error: linker exited with status 1
```

Looking at SumType's code, it seems the instantiation of `formatValue` happens
here:
https://github.com/dlang/phobos/blob/dba1bbe271a9b2d7f24edeebbc77846e29904e41/std/sumtype.d#L807

--
December 17, 2022
https://issues.dlang.org/show_bug.cgi?id=22010

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Priority|P1                          |P3

--