Stream: compiler development

Topic: Glue platform [] bugs


view this post on Zulip Sven van Caem (Sep 23 2024 at 13:13):

Hi! I've been poking around the glue platform, seeing what shapes it outputs for given types required in platform.roc. I've noticed some cases where it incorrectly handles [] type variables. I thought I remembered some discussion on this already, but I haven't been able to find it again in Zulip, nor in GitHub issues, so I thought I'd post my findings here.

The type [Always U32, Never []] gets turned into the following shape by the glue platform: (TagUnion (Enumeration {name: "U1", size: 4, tags: ["Always", "Never"]})). It seems something about the prescence of the [] type is causing it to discard all the tag unions payloads, when it should discard just the Never tag. The same happens if a tag has a unbound type variable payload, which should have outright crashed.

Just a [] on its own turns into the shape (TagUnion (NonRecursive {discriminantOffset: 0, discriminantSize: 1, name: "U1", tags: []})), even though EmptyTagUnion is available.

Lastly, since the Result type seems to be special-cased, I tried Result U32 [], which surprisingly resulted in the shape (Num U32). Layout-wise, this is correct, though I would have expected TagUnion (SingleTagStruct _)instead.

At least for the first two, all signs point to tag unions being reported as Enumeration tag unions by the glue platform where they shouldn't. Poking around in the platform code, it seems to only turn LayoutRepr::Builtin(Builtin::Int(_)) and LayoutRepr::Builtin(Builtin::Bool) into Enumerations. If the problem were in the platform, I would expect to see it erroneously turn a LayoutRepr::Union(_) into an Enumeration. This means there's either something else going wrong in the platform I haven't spotted yet, or the problem was already present in mono. If it's the latter, I'd be way out of my depth at the moment.

Any thoughts on what to do with this from here?

view this post on Zulip Anton (Sep 23 2024 at 17:10):

I think @Brendan Hansknecht looked into a similar issue before

view this post on Zulip Luke Boswell (Sep 23 2024 at 21:47):

Really cool that you're finding these issues.

view this post on Zulip Brendan Hansknecht (Sep 24 2024 at 03:57):

I have guesses, but mostly hope it is just a rust side roc glue issue and not a true compiler issue.

view this post on Zulip Brendan Hansknecht (Sep 24 2024 at 03:57):

I would start by digging into the rust side of the glue crate

view this post on Zulip Sven van Caem (Sep 24 2024 at 11:58):

Fair, I'll see if I can verify which side the problem is coming from

view this post on Zulip Sven van Caem (Sep 30 2024 at 08:35):

I believe I've found the problem!

It has to do with enumerations and single tag unions with an integer payload having the same mono representation. When deciding on what shape to report a tag union as, the glue platform first checks the amount of tags it has. If it's exactly one, it figures it's dealing with a single tag struct, and reports it accordingly. If there's more than one, it takes the mono representation of the tag union and works backwards from there. Specifically, if it then sees mono representing what it knows is a tag union with more than one variant as an integer, it figures it must be dealing with an Enumeration.

This hits an edge case with the [Always U32, Never []] type. The glue platform sees it has two tags in it, so it already decides this can't be a single tag union. When mono correctly eliminates the Never tag, it sees the tag union only has one tag left with an integer payload, and correctly represents it as just the integer payload. The platform then sees a multi-tag union represented as an integer, and decides it must be the Enumeration [Always, Never].

Happily, this means this is isn't a mono bug after all!

view this post on Zulip Sven van Caem (Sep 30 2024 at 10:52):

Looking into it some more, I believe it'd be possible to fix this inside the glue platform. Every time it tries to report the shape of a tag union, it could recursively check each payload for if it is unconstructable if:
1) it is an empty tag union
2) it is a tag union that only contains tags with unconstructable payloads,
3) it is a record with an empty tag union value.

I can't say this feels like the most elegant possible solution, as mono must be already doing some of this checking itself but discards it by the time it reaches the glue platform, but I think I've got a shot at making it work. Should I give it a go or make an issue for someone else to find a more elegant solution?

view this post on Zulip Richard Feldman (Sep 30 2024 at 11:49):

I'd say go for it, but if it starts feeling like too big of a tangent, put it back for some other time :big_smile:

view this post on Zulip Sven van Caem (Oct 02 2024 at 13:58):

There seem to be two methods (on the UnionLabels type) for retrieving the types of tag union payloads: variables() and iter_from_subs(). I wonder what the difference is between these two, and what the Subs type is?

view this post on Zulip Richard Feldman (Oct 02 2024 at 13:58):

@Folkert de Vries might know?

view this post on Zulip Folkert de Vries (Oct 03 2024 at 08:05):

well, Subs is short for (type) substitutions. It is whatis known as a union-find data structure, that we use to resolve the sort of "well a is equal to, but b is equal to c, so a should be equal to c" kind of question

view this post on Zulip Sven van Caem (Oct 03 2024 at 08:18):

Gotcha. I think I've found the answer to my other question just now. It seems .variables() just retuns slices of indices into the Subs data structure which you can then retrieve the Variables from yourself, while .iter_from_subs() indexes into Subs for you. Kind of obvious looking at it now, guess I just needed fresh eyes!


Last updated: Jul 06 2025 at 12:14 UTC