Stream: bugs

Topic: Type checking with question mark operator ? and branching


view this post on Zulip Matthieu Pizenberg (Dec 02 2025 at 19:33):

Type checking is failing with this example. Am I missing something or is this a bug?

get_greeting : {} -> Try(Str, _)
get_greeting = |{}| {
    match 0 {
        0 => Try.Ok(List.first(["hello"])?),
        _ => Err(Impossible)
    }
}

main! = || {
    Stdout.line!(get_greeting({}).ok_or("Error!"))
}

I get the following error message:

This expression is used in an unexpected way:
   ┌─ test/fx/question_mark_operator_branching.roc:10:5
   │
10 │     match 0 {
11 │         0 => Try.Ok(List.first(["hello"])?),
12 │         _ => Err(Impossible)
13 │     }

It has the type:
    Try(Str, [Impossible, .._others])

But the type annotation says it should have the type:
    Try(Str, [ListWasEmpty])

view this post on Zulip Richard Feldman (Dec 02 2025 at 20:27):

seems like a bug, I'll look into it!

view this post on Zulip Matthieu Pizenberg (Dec 02 2025 at 20:29):

maybe an even simpler test with "if" branching is possible. I haven’t checked if it’s "match" specific or reproducible with branching in general.

view this post on Zulip Richard Feldman (Dec 02 2025 at 20:33):

it's that we don't have polarity yet (cc @Jared Ramirez, not sure if you've started on that yet!) so it's treating [ListWasEmpty] from List.first as a closed union

view this post on Zulip Richard Feldman (Dec 02 2025 at 20:33):

I can manually annotate all the builtins as open and it should fix it

view this post on Zulip Richard Feldman (Dec 02 2025 at 20:34):

and then can put them back to the current signatures after we add polarity to the type-checker

view this post on Zulip Matthieu Pizenberg (Dec 02 2025 at 20:40):

Meanwhile, I’m just going to do a double match to make the type checker happy. Now I’m getting this for my program. Not sure where to start looking at. Any suggestions?

❯ roc day02.roc

Roc crashed: e_closure: failed to resolve capture value

view this post on Zulip Hardy (Dec 02 2025 at 20:57):

I have also seen the "e_closure" problem. It occured to me when i tried following:

    for line in test_input.split_on("\n") {
        if line.starts_with("L") {
            val = I64.from_str(line.drop_prefix("L"))
            dbg val
        }
    }

After peeking at your solution i got around that one by moving the line.drop_prefix("L") before the if. So my guess would be that there is some problem using a value in an inner scope which is already captured in an outer scope or something. Not sure how properly describe it.

view this post on Zulip Richard Feldman (Dec 02 2025 at 21:30):

can you give me a .roc file to repro?

view this post on Zulip Richard Feldman (Dec 02 2025 at 21:30):

doesn't need to be minimal, just something where I can run roc and reproduce it

view this post on Zulip Matthieu Pizenberg (Dec 02 2025 at 21:30):

yep, exactly what I was preparing

view this post on Zulip Matthieu Pizenberg (Dec 02 2025 at 21:34):

https://github.com/roc-lang/roc/issues/8547

view this post on Zulip Matthieu Pizenberg (Dec 02 2025 at 21:35):

Don’t know if Claude root cause analysis is correct, but I figured I’d leave it there for you to judge.

view this post on Zulip Richard Feldman (Dec 02 2025 at 21:48):

thanks! the original error in this thread is fixed now btw

view this post on Zulip Edwin Santos (Dec 03 2025 at 01:25):

Matthieu Pizenberg said:

Meanwhile, I’m just going to do a double match to make the type checker happy. Now I’m getting this for my program. Not sure where to start looking at. Any suggestions?

❯ roc day02.roc

Roc crashed: e_closure: failed to resolve capture value

I've also been having this issue with closures, got it with this sample program:

main! = |args| {
    identity = |a| a
    init_try : Try(U32, [SomeError, ..others])
    init_try = Err(SomeError)
    final_try = match init_try {
            Ok(ok) => Ok(ok)
            Err(e) => Err(identity(e))
    }
    was_an_error = Try.is_err(final_try)

    Stdout.line!("final_try is an error: ${was_an_error}")
    Ok({})

}

# Error: Roc crashed: e_closure: failed to resolve capture value

I tried with Strings and numerics and without type signatures they would crash, with type signatures they can succeed. But when using a Try type this always fails, with or without a type signature or changing the error type to something like [..others] or just SomeError. I also swapped Err(SomeError) with Ok(30) and still get the closure error. Was trying to get a closure like |_| Exit(101) going.

view this post on Zulip Richard Feldman (Dec 03 2025 at 02:45):

@Edwin Santos @Matthieu Pizenberg this is fixed now!

view this post on Zulip Jared Ramirez (Dec 03 2025 at 02:47):

Richard Feldman said:

it's that we don't have polarity yet (cc Jared Ramirez, not sure if you've started on that yet!) so it's treating [ListWasEmpty] from List.first as a closed union

i have polarity partially implemented, but there’s still a bit of work until its ready to go

view this post on Zulip Richard Feldman (Dec 03 2025 at 02:47):

yeah no rush! modifying the types in Builtin.roc to make the tag unions expicitly open fixed it


Last updated: Dec 21 2025 at 12:15 UTC