Stream: contributing

Topic: Crash when comparing to a nested empty list of Str


view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 02:04):

The following code will crash when running roc test, but not when running roc check or build.

app "Roc_99_Problems"
    packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.5.0/Cufzl36_SnJ4QbOoEmiJ5dIpUxBvdB3NEySvuH82Wio.tar.br" }
    imports [pf.Stdout]
    provides [main] to pf

main =
    Stdout.line "Running `roc test` crashes this code"

fail : List Str -> List List Str
fail = \_list -> [[], []]
expect fail ["a","b"] == [["a"], ["b"]]

The crash looks like this:

thread 'main' panicked at 'Error in alias analysis: error in module ModName("UserApp"), function definition FuncName("\x11\x00\x00\x00\x01\x00\x00\x00\x87h\xb9Z\xedHc\x19"), definition of value binding ValueId(13): expected type '(heap_cell, bag<(heap_cell,)>)', found type '(heap_cell, bag<()>)'', crates/compiler/gen_llvm/src/llvm/build.rs:5744:19
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

The fail function is just a dummy implementation, but it is important that it returns a nested list of lists. Using a non-nested structure correctly fails the test, as expected. Using another type other than Str will also not crash and simply fail the test as expected.

I've tried a couple variations of this, including doing the== test without an expect, and that fails the exact same way, so I'd figure that the error is in the == implementation itself.

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 02:04):

Here is a full backtrace as well:

$ RUST_BACKTRACE=full roc test
thread 'main' panicked at 'Error in alias analysis: error in module ModName("UserApp"), function definition FuncName("\x11\x00\x00\x00\x01\x00\x00\x00\x87h\xb9Z\xedHc\x19"), definition of value binding ValueId(13): expected type '(heap_cell, bag<(heap_cell,)>)', found type '(heap_cell, bag<()>)'', crates/compiler/gen_llvm/src/llvm/build.rs:5744:19
stack backtrace:
   0:     0x55eab1fa62c1 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hbd7d55b7108d2ab8
   1:     0x55eab1fd3b8f - core::fmt::write::h6d54cd7c9e155ec5
   2:     0x55eab1fa1a21 - std::io::Write::write_fmt::h6a453a71c692f63b
   3:     0x55eab1fa60d5 - std::sys_common::backtrace::print::h4ddf81241a51b337
   4:     0x55eab1fa7757 - std::panicking::default_hook::{{closure}}::hff91f1f484ade5cd
   5:     0x55eab1fa7544 - std::panicking::default_hook::h21f14afd59f7aef9
   6:     0x55eab1fa7c0c - std::panicking::rust_panic_with_hook::h45f66047b14c555c
   7:     0x55eab1fa7b07 - std::panicking::begin_panic_handler::{{closure}}::h49d1a88ef0908eb4
   8:     0x55eab1fa66f6 - std::sys_common::backtrace::__rust_end_short_backtrace::hccebf9e57f8cc425
   9:     0x55eab1fa7852 - rust_begin_unwind
  10:     0x55eaaf3effd3 - core::panicking::panic_fmt::h54ec9d0e3180a83d
  11:     0x55eaaf6f3752 - roc_gen_llvm::llvm::build::build_procedures_help::h3bdbf853df53af30
  12:     0x55eaaf6ecb58 - roc_gen_llvm::llvm::build::build_procedures_expose_expects::h472e9cfdc7ef043d
  13:     0x55eaaf60b70d - roc_repl_expect::run::expect_mono_module_to_dylib::h1ae11cd75ea6252c
  14:     0x55eaaf5ea6c6 - roc_cli::test::h40d1fa4542d423a5
  15:     0x55eaaf4d627b - roc::main::h8c0286bbf2fcf86b
  16:     0x55eaaf4cb823 - std::sys_common::backtrace::__rust_begin_short_backtrace::ha2e31af2549d8703
  17:     0x55eaaf4cb8e3 - std::rt::lang_start::{{closure}}::h1a31ddf22b52a3d4
  18:     0x55eab1f98535 - std::rt::lang_start_internal::hf502095b101390bb
  19:     0x55eaaf4d84e5 - main
  20:     0x7fabc863dace - __libc_start_call_main
  21:     0x7fabc863db89 - __libc_start_main@@GLIBC_2.34
  22:     0x55eaaf4ca625 - _start
  23:                0x0 - <unknown>

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 02:21):

If you use that function in main instead of in the expect, will it fail with roc build?

Like use the expect as an if condition?

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 03:36):

Yes it also fails in that case

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 03:38):

main =
    val = fail ["a","b"]
    if val == [["a"], ["b"]] then
        Stdout.line "This will crash"
    else
        Stdout.line ""


fail : List Str -> List List Str
fail = \_list -> [[], []]

That code gives the same failure

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 04:26):

Cool that's what I expected. No idea why it is happening though. Probably need to dump the mono ir and investigate

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 04:26):

Out of curiosity does assigning the empty lists to a temporary fix the issue.

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 04:27):

Oh, also, just realized the type of failed is wrong

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 04:27):

The output needs parens

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 04:27):

Not sure if that is the issue, but another good test, make the output type List (List Str)

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 04:28):

With parens it doesn't crash

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 04:28):

Ah, so bad type and check failing to catch the type error, interesting

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 04:29):

So there should be a failure in the type checker thats not working

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 04:30):

What does the type checker think the type of List List Str is without the parens? That would be intresting to see.

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 04:31):

How would I dump the IR out of curiosity, I haven't done that yet, I have built the compiler from source if needed.

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 05:02):

if built from source, we have a few flags for dumping it a different stages.

In this case two interesting things to try:
ROC_PRINT_IR_AFTER_REFCOUNT=1 cargo run ...
And:
ROC_CHECK_MONO_IR=1 cargo run ...

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 05:54):

Here's what I got back from the after refcount IR

procedure : `#UserApp.3` {}
procedure = `#UserApp.3` ():
    let `#UserApp.17` : Str = "a";
    let `#UserApp.18` : Str = "b";
    let `#UserApp.13` : List Str = Array [`#UserApp.17`, `#UserApp.18`];
    let `#UserApp.7` : List List Str = CallByName `#UserApp.fail` `#UserApp.13`;
    let `#UserApp.12` : Str = "a";
    let `#UserApp.9` : List Str = Array [`#UserApp.12`];
    let `#UserApp.11` : Str = "b";
    let `#UserApp.10` : List Str = Array [`#UserApp.11`];
    let `#UserApp.8` : List List Str = Array [`#UserApp.9`, `#UserApp.10`];
    let `#UserApp.6` : Int1 = CallByName `Bool.structuralEq` `#UserApp.7` `#UserApp.8`;
    dec `#UserApp.8`;
    dec `#UserApp.7`;
    expect `#UserApp.6`;
    let `#UserApp.5` : {} = Struct {};
    ret `#UserApp.5`;

procedure : `Bool.structuralEq` Int1
procedure = `Bool.structuralEq` (`#Attr.#arg1`: List List Str, `#Attr.#arg2`: List List Str):
    let `Bool.23` : Int1 = lowlevel Eq `#Attr.#arg1` `#Attr.#arg2`;
    ret `Bool.23`;

procedure : `#UserApp.fail` List List Str
procedure = `#UserApp.fail` (`#UserApp.4`: List Str):
    dec `#UserApp.4`;
    let `#UserApp.15` : List [] = Array [];
    let `#UserApp.16` : List [] = Array [];
    let `#UserApp.14` : List List Str = Array [`#UserApp.15`, `#UserApp.16`];
    ret `#UserApp.14`;

thread 'main' panicked at 'Error in alias analysis: error in module ModName("UserApp"), function definition FuncName("\x11\x00\x00\x00\x01\x00\x00\x00\x87h\xb9Z\xedHc\x19"), definition of value binding ValueId(13): expected type '(heap_cell, bag<(heap_cell,)>)', found type '(heap_cell, bag<()>)'', crates/compiler/gen_llvm/src/llvm/build.rs:5744:19
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Not familiar with the IR but my first reading looks like it might be that the definitions UserApp.15 and UserApp.16 that cause problems. The type seems to be a List of empty lists.

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 06:00):

When I place the parens around the return type of fail to get the correct types the only meaningful diff is

<     let `#UserApp.15` : List [] = Array [];
<     let `#UserApp.16` : List [] = Array [];
---
>     let `#UserApp.15` : List Str = Array [];
>     let `#UserApp.16` : List Str = Array [];

Where the corrected types properly give List Str instead of this List [] type

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 06:01):

I'm not quite sure what List [] means as a type because I assumed [] is a value rather than a type.

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 06:12):

haha

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 06:12):

That looks very wrong

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 06:12):

@Ayaz Hafiz or @Folkert de Vries any ideas on this?

view this post on Zulip Ayaz Hafiz (Dec 19 2023 at 06:20):

Almost certainly List List Str is parsed as List (List) (Str) and that's an unhandled error not handled in the typechecker that produces an error type, and hence the error you see

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 06:25):

So the outer list receives two type parameters instead of one. Is the number of generic arguments passed to a type not checked?

view this post on Zulip Ayaz Hafiz (Dec 19 2023 at 06:30):

I would guess not given this

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 07:06):

Is there any type of existing/tracking issue for this I looked through the GirHub issues an could not find any related; would it be good to open up and issue and start looking into it?

view this post on Zulip Anton (Dec 19 2023 at 09:43):

Opening a new issue sounds good, can you also mention #6191 in the new issue? It's a similar error but with different types.

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 21:41):

Where would types get checked for having too many arguments in the compiler pipeline? (assuming that would be desired, it might not be for some reason I am unaware of).

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 21:54):

Also, some other strange behavior I've found while looking at this. The type Str Str seems to be valid according to the compiler:

main =
    weird : Str Str
    weird = "hello"
    Stdout.line weird

This compiles and prints hello, no errors. I am almost certain this is wrong, the type Str Str makes no sense. Doing this with a type alias, like:

MyStr a : Str a
main =
    weird : MyStr Str
    weird = "hello"
    Stdout.line weird

Also compiles and runs fine.

view this post on Zulip Lucas Culverhouse (Dec 19 2023 at 21:55):

This might be related, as it should be rejected due to the incorrect number of type parameters.

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 21:59):

Yeah, looks to be all the same root error

view this post on Zulip Anton (Dec 20 2023 at 09:58):

Where would types get checked for having too many arguments in the compiler pipeline

I don't know myself but I find the cursor.so editor useful to help me find stuff.


Last updated: Jul 06 2025 at 12:14 UTC