Stream: beginners

Topic: If expr and List.drop


view this post on Zulip Audrey Gao (Apr 04 2023 at 05:57):

I wondered what was the reason that the first expression worked while the second one received an error . image.png

view this post on Zulip Brendan Hansknecht (Apr 04 2023 at 06:21):

I think it is a bug in the wasm dev backend.

view this post on Zulip Brendan Hansknecht (Apr 04 2023 at 06:24):

Interesting that changing from List.dropAt x 0 to List.dropFirst x fixes it.

EDIT: This is actually extra confusing cause List.dropFirst is defined as:

dropFirst = \list ->
    List.dropAt list 0

view this post on Zulip Brendan Hansknecht (Apr 04 2023 at 06:26):

Also, I get a slightly different error, which might be useful as context for someone: JsValue(CompileError: wasm validation error: at offset 18988: popping value from empty stack)

view this post on Zulip Richard Feldman (Apr 04 2023 at 11:32):

:thinking: this works for me in roc repl on the command line

view this post on Zulip Richard Feldman (Apr 04 2023 at 11:33):

so yeah, probably a bug in the wasm dev backend

view this post on Zulip Richard Feldman (Apr 04 2023 at 11:33):

but I agree that I'm not sure what it would be, given how dropFirst is defined :sweat_smile:

view this post on Zulip Brendan Hansknecht (Apr 04 2023 at 14:51):

My gut feeling is it is somehow refcount/memory related. Maybe even a bug related to freeing a seamless slice, but that is definitely guessing.

view this post on Zulip Audrey Gao (Apr 05 2023 at 05:02):

Thanks for the information!

view this post on Zulip Brian Carroll (Apr 05 2023 at 20:05):

OK this is weird. The following tests passes for the Wasm backend if I insert it into gen_list.rs
And remember that tests are wrapped in a main function in the same way as REPL inputs are.

#[test]
fn zulip_issue() {
    assert_evals_to!(
        r#"
        x = [1,2,3]
        tl = List.dropAt x 0
        if Bool.true then [] else tl
        "#,
        RocList::empty(),
        RocList<i64>
    )
}

view this post on Zulip Brian Carroll (Apr 05 2023 at 20:07):

Also if I print out the IR after refcount insertion, this is what I get

procedure : `#UserApp.main` List I64
procedure = `#UserApp.main` ():
    let `#UserApp.x` : List I64 = Array [1i64, 2i64, 3i64];
    let `#UserApp.6` : U32 = 0i64;
    let `#UserApp.tl` : List I64 = CallByName `List.dropAt` `#UserApp.x` `#UserApp.6`;
    let `#UserApp.4` : Int1 = CallByName `Bool.true`;
    if `#UserApp.4` then
        dec `#UserApp.tl`;
        let `#UserApp.5` : List I64 = Array [];
        ret `#UserApp.5`;
    else
        ret `#UserApp.tl`;

procedure : `List.dropAt` List I64
procedure = `List.dropAt` (`#Attr.#arg1`: List I64, `#Attr.#arg2`: U32):
    let `List.494` : List I64 = lowlevel ListDropAt `#Attr.#arg1` `#Attr.#arg2`;
    ret `List.494`;

procedure : `Bool.true` Int1
procedure = `Bool.true` ():
    let `Bool.23` : Int1 = true;
    ret `Bool.23`;

view this post on Zulip Brian Carroll (Apr 05 2023 at 20:08):

There's just one decrement in the then branch

view this post on Zulip Brian Carroll (Apr 05 2023 at 20:10):

Flipping the if branches around moves the decrement to the branch that's not taken

view this post on Zulip Brian Carroll (Apr 05 2023 at 20:24):

OK I managed to extract a .wasm file from the browser.
The wasm instruction stream is invalid at the point where it calls the refcount decrement.

view this post on Zulip Brian Carroll (Apr 05 2023 at 20:58):

OK I figured out what's wrong. The backend tries to keep track of what's on the Wasm stack machine at each point in the program. In this example, our model of the stack machine goes wrong and we end up generating invalid Wasm instructions! This is the hardest part of the wasm backend. :sweating:


Last updated: Jul 05 2025 at 12:14 UTC