I'm not entirely sure how to interpret the following error. I'll include the whole file for context but it isn't completely tidy
RBTree.Node({left: RBTree.Node({colour: R} as left_data)} as parent_data) => {
uneq_right = RBTree.Node(
{colour: R, left: left_data.right, key: parent_data.key, value: parent_data.value, right: parent_data.right}
)
uneq_right->eqL().apply(|new_right| {
new_parent = RBTree.Node({colour: B, left: left_data.left, key: left_data.key, value: left_data.value, right: new_right})
new_parent
})
}
Error:
-- TYPE MISMATCH ---------------------------------
The first argument being passed to this function has the wrong type:
┌─ RBTree.roc:343:21
│
343 │ uneq_right->eqL().apply(|new_right| {
│ ^^^^^^^^^^
This argument has the type:
RBTree(k, v)
But eqL needs the first argument to be:
RBTree(k, v)
eqL:
eqL : RBTree(k, v) -> Intermediate(RBTree(k, v))
There's also the following error
-- TYPE MISMATCH ---------------------------------
The first argument being passed to this function has the wrong type:
┌─ RBTree.roc:408:49
│
408 │ (new_right, {key, value}) = inner->delMin()
│ ^^^^^
This argument has the type:
{ colour: [B, R], key: k, left: RBTree(k, v), right: Error, value: v }
But delMin needs the first argument to be:
RBTree.Inner(k, v)
which is precisely the alias given by RBTree.Inner (the type of the payload of the Node):
Inner(k, v) : {
colour: [R, B],
left: RBTree(k, v),
key: k,
value: v,
right: RBTree(k, v)
}
Wondering if this has something to do with #beginners > Type module which depends on a type defined within? given the kind of recursive reference to RBTree(k, v) from RBTree.Inner(k, v)
Forgot to say this was with roc built from source but a couple days ago, I'll try again with tip if anything has changed.
These look like compiler bugs to me... I think the compiler is assigning different internal identities to structurally-identical recursive nominal types. I'll see if I can produce a min repro.
yeah it is, I'm looking into it!
@Jonathan I think as a workaround, you can add a type annotation to delete:
delete : RBTree(k, v), k -> RBTree(k, v) where [
k.is_eq: k, k -> Bool,
k.is_lt: k, k -> Bool,
k.is_gt: k, k -> Bool,
]
delete = |tree, query| { ... }
(actually, strictly speaking you only need is_lt and is_eq constraints there)
Issue filed at #9491
From the best I could minimize, it looks like when a parametric recursive nominal type is destructured in one helper and then passed into a separate self-recursive function, Roc reports a bogus RBTree(k) vs RBTree(k) mismatch even though both types are identical.
Richard Feldman said:
delete : RBTree(k, v), k -> RBTree(k, v) where [ k.is_eq: k, k -> Bool, k.is_lt: k, k -> Bool, k.is_gt: k, k -> Bool, ]
This got it working!
x = RBTree.empty()
x2 = x.insert(1, "Hello")
.insert(2, "World!")
.insert(3, "Nothin!")
.delete(3)
print!(x2.pairs())
roc main.roc --no-cache
[(1.0, "Hello"), (2.0, "world!")]
(I still feel like being able to alias common combinations like is_eq, is_lt, is_gt into Cmp(k) or Ord(k) or hasCmp(k) etc would be quite useful)
yeah I have a design for that but haven't implemented it, in part because I actually have personally been a fan of writing them out because of how explicit they are :smile:
but we can always add that capability in the future
That makes sense, whilst it does add a bit more line noise for me with repeated patterns, it's the kind of thing a good lsp code action (or agent I guess) will write.
Ian McLerran said:
Issue filed at #9491
One thing I've been meaning to ask, which relates to one of the changes that removes type parameters in this issue: can I create an alias inside a module that refers to the module's introduced type parameters? Eg
MyMod(a) := ...
and inside
MTry : Try(MyMod(a), err)
I think at some point roc check passed this.
Didn't work now :) nvm
I've identified the issue here, working on a fix!
have a fix up here: https://github.com/roc-lang/roc/pull/9512
Last updated: Jun 16 2026 at 16:19 UTC