I'm looking into this issue, but can't figure out how to run the current version of checkmate
:thinking:
https://github.com/roc-lang/roc/issues/5678
I think you need to use the latest version, on this branch https://github.com/roc-lang/roc/tree/checkmate-ui-scaffold
Thanks for looking into the issue btw :)
For now, I am serving the checkmate UI (built once a day) at https://ayazhafiz.com/checkmate/
There are a bunch of missing pieces I want to clean up this week, but it should already be pretty usable (and hopefully much more useful for debugging types than anything we had before).
If you run into a typechecking bug and want to try to diagnose it, after minimizing, you can run a debug version of the compiler with ROC_CHECKMATE=1
set. That will spit out a JSON file of the form checkmate_<timestamp>.json
(maybe worth making the filename more customizable if someone wants an easy PR). You can then load them into the UI and investigate the unifications. Later this week I'm planning to add support for constraints, so you can see where in the source code a unification comes from.
@Ayaz Hafiz I've got another one for checkmate, :smiley: this issue is a minimal repro of the virtual dom issue
woo!
Btw @Luke Boswell Ive figured out the bug here, but fixing it requires a somewhat involved refactor so I hope to have a patch out tomorrow or after
Interested to know how you have found checkmate for debugging?
oh so huge
There's still some bugs (for example in the screenshot below the types at the top are missing), but scanning for "obvious" issues is very easy
For example, here it is clear to see that there is a function that after unification winds up with an empty lambda set - which should never happen! So that was the immediate give away of where to look for the problem.
Wow. This is pretty crazy. I'm realizing now we will have to lift canonicalization of annotations to happen after can of definitions, because canonicalized annotations need captures information
oh for lambda sets?
yeah
yeah now that you say it, it seems obvious in retrospect :sweat_smile:
Moreover we need to lift this to happen (or at least the injection of a lambda set into a type annotation) until after we have fixed the capture sets across all definitions, which we currently only do after all other canonicalization in one pass (to handle recursive defs, etc)
I think we need to figure out a plan here. As I see it, we have two options: (1) we can use a mutable cell to store the captures info in the type annotation, and expect that later the mutable cell will be fixed-up, or (2) we can move canonicalization of annotations to happen after all value canonicalization, including the captures fixing. I prefer (2) because this code is already not the easiest to reason about, and though two passes is annoying, it's likely not going to matter once we have a full SoA impl.
yeah I agree with (2) being the way to go
especially because we can incorporate this design constraint into the revamped design and minimize the cost then
:thinking: does it matter for constraint gen if we generate a constraint for the annotation first or the body first?
if not, we could potentially adjust the canonical IR to store the body first and then the annotation afterwards, right?
oh nm that wouldn't help because of the "must do a pass over all the bodies before starting on the annotations" need
I guess another idea would be to store captures in a side table and give them an ID, and then give the annotation and the body the same ID, then have the body actually populate it
which is similar to the Cell idea except you don't have to go back and fix it up later
constraint always happens after canonicalization
yeah that's the same as the mutable cell idea. which is only one pass but makes debugging harder :D
yeah maybe worth considering down the line, but not right now
This is a really frustrating change to make. I had to give up on the approach I was currently taking, I think part of the inconvenience is we have two separate IRs in the canonicalizer right now (SoA + classic AST). @Folkert de Vries do you have any existing plans to go full SoA in the can AST? If not I will do it. I really think we need to unify and simply the data structures significantly ASAP before fixing the more general issue here though.
I don't have plans (and probably would not get to it this year anyway). I think Richard has thoughts on this because it also has to integrate with the parser.
can we let the other one drift then? just come back and revisit it later?
We could but it's hard to do anything because half of the AST is in one, and half is in the other. we should consolidate them asap, I think
oh hm
I can work on that
or if you want to, go for it
I don't actually know what the current state of them is :sweat_smile:
Last updated: Jul 06 2025 at 12:14 UTC