Hi!
I'm trying to do day 1 of AoC 2025. I'm getting a compiler error that I really don't understand:
-- TYPE MISMATCH ---------------------------------
This expression is used in an unexpected way:
┌─ day01.roc:10:19
│
10 │ num = num_str.to_i32()?
│ ^^^^^^^
It has the type:
Str
But I expected it to be:
{ unknown: _field }
Found 1 error(s) and 0 warning(s) for day01.roc.
Roc crashed: non-exhaustive match
Here's my program:
app [main!] { pf: platform "https://github.com/lukewilliamboswell/roc-platform-template-zig/releases/download/0.3/98T93wthPgoBRLYtPTT4RBBsQunrfDG94gihPf1zYYmE.tar.zst" }
import pf.Stdout
parse_instruction = |chars| {
match chars {
[] => Err(ParsingError)
[c, ..rest] => {
num_str = Str.from_utf8(rest)?
num = num_str.to_i32()?
if c == 'L' { Ok(-num) } else { Ok(num) }
}
}
}
main! = |_args| {
res = parse_instruction("L12".to_utf8())
match res {
Ok(num) => {
Stdout.line!(num.to_str())
Ok({})
}
_ => Err(Exit(1))
}
}
I'll take a look
I got sidetracked by adding missing tests, I'm almost done though
Instead of num_str.to_i32() it needs to be I32.from_str(num_str).
I will make an issue for the bad error message
I've solved both parts of AoC 2025 Day 01 using the old compiler, then I ported the code as best I could to the new compiler, and roc check day01.roc says there are no errors, but I get a segfault at runtime. I tried to activate the ref counting logs as instructed by @Luke Boswell , but I'm not sure I did it correctly because I don't understand how I can use this output. Here's the full program:
app [main!] { pf: platform "https://github.com/lukewilliamboswell/roc-platform-template-zig/releases/download/0.3/98T93wthPgoBRLYtPTT4RBBsQunrfDG94gihPf1zYYmE.tar.zst" }
import pf.Stdout
data =
\\L50
\\L12
\\R13
\\L1
\\L5
\\R5
parse_instruction: List(U8) -> Try(I32, _)
parse_instruction = |chars| {
match chars {
[] => Err(ParsingError)
[c, .. as rest] => {
num_str = Str.from_utf8(rest)?
num = I32.from_str(num_str)?
if c == 'L' { Ok(-num) } else { Ok(num) }
}
}
}
count_zeroes_with_clicks: I32, I32 -> I32
count_zeroes_with_clicks = |pos, new_pos| {
div_floor = |i| {
if i < 0 { (i + 1) // 100 - 1 } else { i // 100 }
}
incr = (div_floor(new_pos) - div_floor(pos)).abs()
if new_pos < pos {
incr + (if new_pos % 100 == 0 { 1 } else { 0 }) - (if pos % 100 == 0 { 1 } else { 0 })
} else {
incr
}
}
compute_password: List(I32), I32, I32, Bool -> I32
compute_password = |instructions, pos, count, with_clicks| {
match instructions {
[] => count
[inst, .. as rest] => {
new_pos = pos + inst
new_count =
count
+
if with_clicks {
count_zeroes_with_clicks(pos, new_pos)
} else if new_pos % 100 == 0 {
1
} else {
0
}
rest->compute_password(new_pos, new_count, with_clicks)
}
}
}
map_try: List(a), (a -> Try(b, c)) -> Try(List(b), c)
map_try = |list, to_result_fun| {
list->walk_try(
[],
|state, elem| {
match to_result_fun(elem) {
Ok(ok) => Ok(state.append(ok))
Err(b) => Err(b)
}
}
)
}
walk_try: List(a), s, (s, a -> Try(s, c)) -> Try(s, c)
walk_try = |list, init, func| {
match list {
[] => { Ok(init) }
[val, .. as rest] => {
maybe_state = func(init, val)
match maybe_state {
Ok(state) => walk_try(rest, state, func)
Err(b) => Err(b)
}
}
}
}
main!: List(Str) => Try({ }, [Exit(I32)])
main! = |_args| {
lines_utf8 = data.split_on("\n").map(|s| s.to_utf8())
maybe_instructions = lines_utf8->map_try(parse_instruction)
match maybe_instructions {
Ok(instructions) => {
result1 = instructions->compute_password(50, 0, False)
Stdout.line!(result1.to_str())
result2 = instructions->compute_password(50, 0, True)
Stdout.line!(result2.to_str())
Ok({})
}
_ => {
Stdout.line!("Error")
Err(Exit(1))
}
}
}
Here's the output:
debug: [HOST] Building args...
debug: [ALLOC] ptr=0x1034c0008 size=40 align=8
debug: [ALLOC] ptr=0x1034e0008 size=137 align=8
debug: [HOST] args_list ptr=0x1034c0018 len=1
debug: [HOST] Calling roc__main_for_host...
error: Child process /Users/ageron/Library/Caches/roc/5931167c7313ef73dbb36e68e48b39cf/temp/roc-tmp-ZtoLGEfLd8V5hXupRG23Usp7b6PNT2Iz/roc_run_994723065 killed by signal: 11
error: Child process crashed with segmentation fault (SIGSEGV)
Thanks for your help.
I just updated to the latest compiler (compiled from source). Sadly, I'm getting the same issue as before: roc check day01.roc passes without any problem, but when I run roc day01.roc, I get zero output and the exit code is 139.
I tried compiling with zig build test -Dtrace-refcount, as instructed, but there were 4 errors during the build:
[...]
[REFCOUNT] DECREF closure struct fields=0
[REFCOUNT] DECREF closure DONE ptr=0x115060128
[REFCOUNT] DECREF layout.tag=5 ptr=0x1150600f0
[REFCOUNT] DECREF struct ptr=0x1150600f0 fields=3
␃
======================================
First difference occurs on line 1:
expected:
^ (end of string)
found:
[REFCOUNT] INCREF list (copyToPtr) ptr=0x14c060018 len=1 rc=1 slice=0 elems_rc=0
^ ('\x5b')
/opt/homebrew/Cellar/zig/0.15.2/lib/zig/std/testing.zig:673:9: 0x1001c30a3 in expectEqualStrings (fx_platform_test)
return error.TestExpectedEqual;
^
/Users/ageron/dev/software/roc/src/cli/test/fx_platform_test.zig:276:5: 0x1001c3ab7 in testRocTestSinglePass (fx_platform_test)
try testing.expectEqualStrings("", run_result.stderr);
^
/Users/ageron/dev/software/roc/src/cli/test/fx_platform_test.zig:290:5: 0x1001c5b1b in test.fx platform expect with numeric literal (dev backend) (fx_platform_test)
try testRocTestSinglePass("--opt=dev", "test/fx/expect_with_literal.roc");
^
error: while executing test 'fx_test_specs.test.find by path works', the following test command failed:
./.zig-cache/o/0f39b7360e6022731ad8853445efb7a7/fx_platform_test --cache-dir=./.zig-cache --seed=0x59791556 --listen=-
Build Summary: 111/114 steps succeeded; 1 failed; 3494/3510 tests passed; 12 skipped; 4 failed
test transitive failure
└─ tests_summary transitive failure
└─ run test fx_platform_test 49/58 passed, 4 failed, 5 skipped
error: the following build command failed with exit code 1:
.zig-cache/o/7f41ba9e64948bf84032de38cf4b09b4/build /opt/homebrew/Cellar/zig/0.15.2/bin/zig /opt/homebrew/Cellar/zig/0.15.2/lib/zig /Users/ageron/dev/software/roc .zig-cache /Users/ageron/.cache/zig --seed 0x59791556 -Ze417d1370ce16f8a test -Dtrace-refcount
That said, it looks like the compiler is built successfully. But the problem remains: roc check day01.roc succeeds but not roc day01.roc (error 139). Here's the output:
Should I just wait until the new compiler is more stable or is there something I can do to fix this? Thanks! :folded_hands:
I'd wait until it's more stable for this specific issue. Sorry
The dev backend has had a lot of love... but it's all sitting on a branch and not ready to land yet
I know we've been saying close or soon now for a while... but we literally find issues at the very last minute and they tend to be material and require fixing upstream.
Thanks @Luke Boswell , I can wait, no problem. Let me know if I can be of any help.
We have the "echo" platform up and running now which is designed for examples... if your interested someone needs to start tinkering with that and thinking about the exercism track again.
You can hit bugs with more complex apps ... but it should be pretty stable for simple things I think
$ cat test/echo/hello.roc
main! = |_args| {
echo!("Hello, World!")
Ok({})
}
$ roc test/echo/hello.roc
Hello, World!
It has a single effect that is imported by default echo! : Str => {}
and main is
main! : List(Str) => Try({}, [Exit(I8), ..])
Thanks. I'm surprised there's no need for an app section, and no import pf.echo!. Is echo the default platform?
Yeah, it's a default platform that is always available for the purpose of tutorials and teaching Roc
The idea of not having the app header or import statements, is that we can introduce those concepts later when onboarding people.
Cool, I like it!
Last updated: Apr 10 2026 at 12:38 UTC