Stream: contributing

Topic: LirCodeGen list


view this post on Zulip Norbert Hajagos (Mar 22 2026 at 09:24):

Hi! I'm stuck on implementing list_replace_unsafe in the new dev backend. It's done in the interpreter, but I can't really get a grip. I've been looking at other low level builtions, but just realized they aren't wired up to the builtins, so I cannot trust them being the right implementation. Do you have advice on what are the right lowlevel functions to look at as inspiration? Think I only have to do work ing the LirCodeGen's generateLowLevel 's big switch. The unique things of this builtin is that it returns a struct of {list, element}. I've based my work on list_set (uses wrapListReplace almost exactly how I'd need it) and list_split_first (returns a struct). I'm also interested how the refcounting should be handled in LirCodeGen. I see that in wrapListReplace, it is skipped compleatly, so I figured it's already accounted for by the ownership rules specified in LowLevel.zig?

I'm getting Evaluation error: error.RecordIndexOutOfBounds

view this post on Zulip Anton (Mar 23 2026 at 14:36):

Hi Norbert,
I have a couple of CI issues I need to look at first but I will come back to this after that's done.

view this post on Zulip Anton (Mar 24 2026 at 17:10):

I'm getting Evaluation error: error.RecordIndexOutOfBounds

Can you share your branch @Norbert Hajagos?

view this post on Zulip Norbert Hajagos (Mar 24 2026 at 21:11):

Here it is:
https://github.com/roc-lang/roc/tree/list-builtins
There is test/cli/list_replace.roc and test/snapshots/repl/list_replace.md you can use for the testing. I'm on NixOs, x86-64bit. I'm finishing the day, thank you for looking into it.

view this post on Zulip Anton (Mar 25 2026 at 17:54):

This is the core fix for the RecordIndexOutOfBounds:

+++ b/src/eval/interpreter.zig
@@ -2788,7 +2788,7 @@ pub const Interpreter = struct {
                 var dest = try self.pushRaw(record_layout, 0, result_rt_var);
                 var acc = try dest.asRecord(&self.runtime_layout_store);

-                const list_field_stack_val = try acc.getFieldByIndex(list_field.idx, list_arg.rt_var);
+                const list_field_stack_val = try acc.getFieldByName("list", list_arg.rt_var);
                 const list_ptr: *builtins.list.RocList = @ptrCast(@alignCast(list_field_stack_val.ptr.?));

                 if (self.runtime_layout_store.isZeroSized(list_info.elem_layout)) {
@@ -2802,7 +2802,7 @@ pub const Interpreter = struct {

                 // Get pointer space for the replaced item
                 const elem_rt_var = elt_arg.rt_var;
-                const prev_field_stack_val = try acc.getFieldByIndex(prev_field.idx, elem_rt_var);
+                const prev_field_stack_val = try acc.getFieldByName("prev", elem_rt_var);

Make sure to rebase on latest main too, that fixes problems that will cause zig build minici to fail otherwise.

view this post on Zulip Anton (Mar 25 2026 at 17:58):

I've based my work on list_set (uses wrapListReplace almost exactly how I'd need it) and list_split_first (returns a struct)

Yes, that is the way to go :)

view this post on Zulip Anton (Mar 25 2026 at 18:09):

In LirCodeGen.zig, everything in .list_replace_unsafe => { ... looks correct.

view this post on Zulip Anton (Mar 25 2026 at 18:16):

I'm also interested how the refcounting should be handled in LirCodeGen

Refcounting is handled by the ownership rules (see getArgOwnership in LowLevel.zig), not inside the wrapper.
The interpreter version does handle refcounting explicitly.

view this post on Zulip Norbert Hajagos (Mar 26 2026 at 13:07):

Thank you Anton! There's so much work being done by others that by the time I'm finished with my small changes, the ground has shifted from under me. But it's fun just reading others' code and figuring things out. Hope I can look at it this weekend, maybe even land it. I'll stick with implementing builtins for a while, so that Roc could collect the dividends from my initial learning investments. Would be a waste to stop here now :smile:


Last updated: Apr 10 2026 at 12:38 UTC