Handle singleton records in erlang_to_fate #27

Merged
spivee merged 3 commits from singleton_records into master 2026-05-13 12:53:52 +09:00
Member

Sophia doesn't have a concept of singleton tuples, only empty tuples, and tuples of 2 or more elements. It does have a concept of singleton records, however, but instead of implementing these as FATE tuples, it simply leaves the inner value unwrapped in the FATE representation.

I noticed this and implemented it correctly in the Sophia parser and pretty printer, but this is also a case that needs to be implemented on the erlang side! Not hard to do, when turning maps to tuples, if there was only one element produced, we don't wrap it in {tuple, {Inner}}, and going back, we rewrap the FATE term in {tuple, {Inner}} before passing it to our normal record processing logic.

The error message that this case was producing was rather confusing, so I went and fixed that error message too, so instead of "Warning: Unimplemented type "Ping.state", using term as is: 0" it says "Warning: Could not coerce term into record type "Ping.state". Using term as is: 0".

Also while looking at errors in records I noticed that the pathy bit of the error doesn't tell you the name of the field, just what element in the tuple it was, and maybe people want to know the name of the field as well, so I added a little pass to throw that info in too.

Sophia doesn't have a concept of singleton tuples, only empty tuples, and tuples of 2 or more elements. It does have a concept of singleton records, however, but instead of implementing these as FATE tuples, it simply leaves the inner value unwrapped in the FATE representation. I noticed this and implemented it correctly in the Sophia parser and pretty printer, but this is also a case that needs to be implemented on the erlang side! Not hard to do, when turning maps to tuples, if there was only one element produced, we don't wrap it in {tuple, {Inner}}, and going back, we rewrap the FATE term in {tuple, {Inner}} before passing it to our normal record processing logic. The error message that this case was producing was rather confusing, so I went and fixed that error message too, so instead of "Warning: Unimplemented type "Ping.state", using term as is: 0" it says "Warning: Could not coerce term into record type "Ping.state". Using term as is: 0". Also while looking at errors in records I noticed that the pathy bit of the error doesn't tell you the name of the field, just what element in the tuple it was, and maybe people want to know the name of the field as well, so I added a little pass to throw that info in too.
spivee added 3 commits 2026-05-12 15:22:49 +09:00
I realized this case needed special handling in hz_sophia, but didn't
get around to covering it properly in the older hz_aaci analogues.

While I was at it, I went and improved the error paths for record elements.
This warning always confuses me. Usually it is a case I haven't actually implemented,
but I don't need the program to diagnose that for me, I need the program to tell me what the
type was, so that I can work out why it thinks it isn't implemented.

All three terms of the annotated type are relevant, but the annotated version can only differ from the normalized version if
it is a record or variant definition, so we special case those two just to communicate that the fact that it is *some* kind of record
did successfully pass through to the coerce logic, and otherwise we just try and print the opaque and normalized types faithfully.
I changed it from noting the index to just noting the field name, but
actually both pieces of information are important, since if there was
a type error, presumably the type information is actually wrong.

Now we put the index first, since that is the part of the FATE tuple
that failed, and then the field name that that would be if the type
information were correct, in case that is useful.
spivee requested review from zxq9 2026-05-12 15:22:49 +09:00
zxq9 approved these changes 2026-05-12 18:17:21 +09:00
zxq9 left a comment
Owner

Will this also need fixing in Sophia and/or FATE?

Will this also need fixing in Sophia and/or FATE?
Author
Member

No, fortunately, I found this issue on the Sophia side much earlier.
https://git.qpq.swiss/QPQ-AG/hakuzaru/src/branch/master/src/hz_sophia.erl#L1349-L1355

No, fortunately, I found this issue on the Sophia side much earlier. https://git.qpq.swiss/QPQ-AG/hakuzaru/src/branch/master/src/hz_sophia.erl#L1349-L1355
spivee merged commit ed252b4c06 into master 2026-05-13 12:53:52 +09:00
spivee deleted branch singleton_records 2026-05-13 12:53:52 +09:00
Sign in to join this conversation.