Hi, i was messing about with databases and recursive html generation and ren into a weird bug.
roc dev
results in
thread 'main' panicked at 'Error in alias analysis: error in module ModName("UserApp"), function definition FuncName("\x11\x00\x00\x00\x04\x00\x00\x00*;j\xa0}\xf7\xe1\xf1"), definition of value binding ValueId(6): could not find func in module ModName("UserApp") with name FuncName("\x14\x00\x00\x00\x01\x00\x00\x00\xe5\x96\x8d\x14@\xd2\xe7\xc3")', crates/compiler/gen_llvm/src/llvm/build.rs:5779:19
roc dev --dev
results in
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', crates/compiler/mono/src/code_gen_help/mod.rs:587:86
ass.si/gitea/skovir2 the problematic part seems to be getPostReply
, tho i haven't been able to create the minimum example
Thanks for the help
The class of bugs Error in alias analysis
are usually pretty hairy. If you are able to isolate and minimise the bug to file an issue that would be helpful. When I usually get this bug, I generally find a workaround by changing the types or finding a bug in my code somewhere. Another potential solution is to try and remove the type annotations and see if that helps. Sorry I'm not being more helpful.
I was able to remove it for some builds, by adding the annotation.
I'll work on the distillation tomorrow. I just wished, that this was a known problem, so that I needn't be the one reporting it. :)
It is kinda a class of issues :oh_no:. So multiple variants to be reported to help fix root causes.
Not to speculate too much, but this looks like a memory corruption in rust land
What makes you think that?
Brendan Hansknecht said:
What makes you think that?
The first error message seems to report not finding a wierd function name, that contains non ascii bytes
FuncName("\x11\x00\x00\x00\x04\x00\x00\x00*;j\xa0}\xf7\xe1\xf1")
I think it may just be printing an integer as a string. Need to double check though.
app "test"
packages {
pf: "https://github.com/roc-lang/basic-webserver/releases/download/0.3.0/gJOTXTeR3CD4zCbRqK7olo4edxQvW5u3xGL-8SSxDcY.tar.br",
}
imports [
pf.Task,
pf.SQLite3,
]
provides [main] to pf
getPostReply = \_postID ->
postRez <- SQLite3.execute {
path: "skovir.db",
query: "select * from posts",
bindings: [],
} |> Task.attempt
Task.ok postRez
main = \_req ->
out <- getPostReply "1" |> Task.attempt
Task.ok { body: Inspect.toStr out |> Str.toUtf8, status: 200, headers: [] }
This is the smallest I can get it, while still keeping the bug
Tho it seems to be a different bug. Am I writing illegal roc?
I wouldnt say illegal, the compiler should give a nice error instead of crashing.
The Task.attempt parts dont look right to me. I'm away from my computer but can give an example later.
Luke can probably explain why this is happening, but if you change it to unwrap the Task.attempt before wrapping it in a Task.ok a second time, that seems to fix it. The compiler reasons for why are beyond me though.
app "test"
packages {
pf: "https://github.com/roc-lang/basic-webserver/releases/download/0.3.0/gJOTXTeR3CD4zCbRqK7olo4edxQvW5u3xGL-8SSxDcY.tar.br",
}
imports [
pf.Task,
pf.SQLite3,
]
provides [main] to pf
getPostReply = \_postID ->
postRez <- SQLite3.execute {
path: "skovir.db",
query: "select * from posts",
bindings: [],
}
|> Task.attempt
# Task.ok postRez
when postRez is
Ok result ->
Task.ok result
Err err ->
Task.err err
main = \_req ->
out <- getPostReply "1" |> Task.attempt
Task.ok { body: Inspect.toStr out |> Str.toUtf8, status: 200, headers: [] }
Thats changing the type tho. From _ -> Task (Result (List (List SqliteValue)) Error) []
To _ -> Task (List (List SqliteValue)) Error
Could complex task values be the issue?
I think the Task.attempt requires you to handle the backpassed Task with a function that transforms the Result into a task.
The definition according to https://roc-lang.github.io/basic-webserver/Task/#attempt is attempt : Task a b, (Result a b -> Task c d) -> Task c d
I think if you rewrote the code like this without the syntax sugar it might be more clear that the second argument isn't matching the expected definition for Task.attempt's second argument.
Task.attempt (SQLite3.execute {
path: "skovir.db",
query: "select * from posts",
bindings: [],
}) (\postRez -> Task.ok postRez)
Not sure if I said that clearly or not.
Could it be that the return type of Task.ok : a -> Task a *
doesn't unify with Task (Result ...) []
specifically the error return types?
Yeah, so if I change it to this it is also happy.
getPostReply = \_postID ->
postRez <- SQLite3.execute {
path: "skovir.db",
query: "select * from posts",
bindings: [],
} |> Task.attempt
Task.ok postRez
main = \_req ->
out <- getPostReply "1" |> Task.await
Task.ok { body: Inspect.toStr out |> Str.toUtf8, status: 200, headers: [] }
So the second Task.attempt
changed to Task.await
. I think this works because now we are not trying to unwrap an *
error... (probably butchered that explanation) and so the compiler can complete its analysis.
At least this is my totally uninformed mental model. To find out what is actually going on we probably need to follow it through the compiler with some dbg!
statements, or consult Ayaz who is familiar with the type analysis. Maybe the checkmate program could help here?
Jeffrey Mudge said:
I think the Task.attempt requires you to handle the backpassed Task with a function that transforms the Result into a task.
The definition according to https://roc-lang.github.io/basic-webserver/Task/#attempt isattempt : Task a b, (Result a b -> Task c d) -> Task c d
I think if you rewrote the code like this without the syntax sugar it might be more clear that the second argument isn't matching the expected definition for Task.attempt's second argument.
Task.attempt (SQLite3.execute { path: "skovir.db", query: "select * from posts", bindings: [], }) (\postRez -> Task.ok postRez)
I'm, sorry, I'm not sure if I'm misreading this, but it seems to me, like this is correct.
The Result is passed into the second argument, so the signature must be at least:
Result a b -> _
and then i return a Task.ok with a value, meaning that i create the following type signature
Result (List (List SqlValue)) Error -> Task (Result (List (List SqlValue))) []
which fits into Result a b -> Task c d
Luke Boswell said:
Yeah, so if I change it to this it is also happy.
getPostReply = \_postID -> postRez <- SQLite3.execute { path: "skovir.db", query: "select * from posts", bindings: [], } |> Task.attempt Task.ok postRez main = \_req -> out <- getPostReply "1" |> Task.await Task.ok { body: Inspect.toStr out |> Str.toUtf8, status: 200, headers: [] }
This is great news! Now i can try to work around the issue. I thought I was gonna have to go back to zig. :)
@Ayaz Hafiz, sorry for the ping, but after messing about for a day, I still have no idea how to even approach writing a bug report about this. For clarity This is the permalink to the problematic file. With the following function seemingly being responsible for the crash:
getPostReply : I64, Num * -> Task.Task (List Html.Node) _
getPostReply = \postID, limit ->
if limit > 0 then
postRez <- dbWrap "select (post_id, post_date, post_content, quoting_post_id) from posts where quoting_post_id = :postid" [{ name: ":postid", value: Num.toStr postID }] |> Task.attempt
posts = postRez |> Result.withDefault [] |> List.map postFromList
posts
|> List.map
(\el ->
recurse <- getPostReply el.id (limit - 1) |> Task.attempt
Html.div [] [
Html.text "$(Inspect.toStr el)",
Html.div [] (recurse |> Result.withDefault []),
]
|> Task.ok
)
|> seq
else
Task.ok []
Thanks in advance
Don’t worry too much about filing a bug report, we know about this class of issues. Are you able to find a workaround to unlock yourself?
Not really. Currently my best workaround is to just load the whole database into ram
Alright. It might take me a couple days, but I’ll try to take a look at
your application and see if I can find a workaround. We have some ideas
about how to resolve these types of bugs in the short term.
Much appreciated, tho if a fix is too difficult I'd settle for a brief explanation of this class of issues.
I'm following this with some interest, as I'm currently trying to workaround a similar issue in my Roc project. If anyone has general tips for finding workarounds in these cases that'd be super helpful! I've tried unwrapping and rewrapping a task involved but that didn't make a difference in my case.
@Adrian when I have had these issues my solution has been to explicitly annotate everything and then work backwards, normally I find it's a weird type error, or there isn't enough information for the compiler to properly infer everything
This sadly didn't work for me (maybe I didn't annotate enough; no true Scotsman). In general i find the bug to pop up when copying Task.seq from basic-cli
to basic-webserver
(could be due to suppressing errors)
Ahh I might actually have an answer for you now. For me this happens when I create certain type aliases.
If I make an opaque type and then make an alias of that opaque type I get that compiler error. My solution is to remove all type aliases that are just aliases of opaque types and write them online instead.
I don't remember writing any explicit type aliases for my case
This issue is being discussed in many places, so I thing closing this and pointing everyone to github.com/roc-lang/#5701 would be the most productive
Last updated: Jul 05 2025 at 12:14 UTC