Stream: beginners

Topic: ✔ strange type mismatch


view this post on Zulip johan alley (Oct 06 2026 at 11:41):

I'm getting this error:

── ✗ type mismatch ────────────────────────────────────────── src/main.roc:9:5

This ? may return early with a type that doesn't match the function body.

Stdout.line!("Hello,World!")?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If this Try is an Err, then the ? after it immediately returns an Err whose
payload has this type:

    [StdoutErr(Str)]

Returning an Err with that type only works if the function itself returns a Try
with a compatible error type, but this function's return type is:

    Try({}, [Exit(I32), StdoutErr(Str)])

Hint: The error types from all ? operators and the function body must be
compatible, since any of them could be the actual return value.

and I cant figure out what it means. The types look compatible. Is it a bug?
I also cant figure out how to replicate it in a minimal setup

view this post on Zulip Luke Boswell (Oct 06 2026 at 12:26):

Which platform are you using?

view this post on Zulip Luke Boswell (Oct 06 2026 at 12:26):

What is the type annotation for the platforms Stdout.line!?

view this post on Zulip johan alley (Oct 06 2026 at 12:37):

Which platform are you using?

My own
Was trying to make a raylib one but I was getting errors, so I started over and was trying to just remake the zig template platform first to have a reference while learning how to make a platform.

What is the type annotation for the platforms Stdout.line!?

Host.roc:

Host := [].{
    stderr_line! : Str => Try({}, [StderrErr(Str)])
    stdin_line! : {} => Try(Str, [StdinErr(Str)])
    stdout_line! : Str => Try({}, [StdoutErr(Str)])
}

Stdout.roc:

import Host

Stdout := [].{
    line! : Str => Try({}, [StdoutErr(Str)])
    line! = Host.stdout_line!
}

main.roc:

app [main!] { roc: "nightly-2026-10-04-130536d", pf: platform "platform/main.roc" }

import pf.Stdout

main! : List(Str) => Try({}, [Exit(I32), StdoutErr(Str)])
main! = |_args| {
    Stdout.line!("Hello,World!")?
    Ok({})
}

view this post on Zulip Luke Boswell (Oct 06 2026 at 12:41):

@Jared Ramirez is this a bug?

I feel like this should work, but I might be tired and missing something obvious here.

view this post on Zulip Luke Boswell (Oct 06 2026 at 12:42):

Does it work if you use main! : List(Str) => Try({}, _) i.e. add a _ type hole instead?

view this post on Zulip Jared Ramirez (Oct 06 2026 at 12:47):

yup, this is a known issue! currently polarity does not apply to host functions return types (ie returned tag unions are not implicitly opened), because the host ABI contract requires a closed union exactly

to fix, i believe we will need to implement an implicit remapping when you use a host function like this, along the lines of an implicit match to instantiate it as open

view this post on Zulip johan alley (Oct 06 2026 at 12:47):

Does it work if you use main! : List(Str) => Try({}, _) i.e. add a _ type hole instead?

── ✗ type mismatch ──────────────────────────────────────────── src/main.roc:7:9

The platform requires  main!  to have a specific type.

main! = |_args| {
        ^^^^^^^

Here it has the type:

    List(Str) => Try({}, [StdoutErr(Str)])

But the platform requires:

    List(Str) => Try({}, [Exit(I32)])
The requirement is declared here:

requires {} { main! : List(Str) => Try({}, [Exit(I32), ..]) }
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

view this post on Zulip johan alley (Oct 06 2026 at 12:49):

yup, this is a known issue! currently polarity does not apply to host functions return types

ok I understand what is happening then. Just need to make a wrapper then.
Thanks for the help!

view this post on Zulip Notification Bot (Oct 06 2026 at 12:54):

johan alley has marked this topic as resolved.

view this post on Zulip Richard Feldman (Oct 06 2026 at 13:22):

I think it's fine if platform authors remap explicitly

view this post on Zulip Richard Feldman (Oct 06 2026 at 13:23):

@Jared Ramirez I'm not sure if we should remap automatically :sweat_smile:

view this post on Zulip Jared Ramirez (Oct 06 2026 at 13:45):

yeah fair, if we don't tho, we should try to improve the error message at least!

view this post on Zulip Jared Ramirez (Oct 06 2026 at 13:46):

@johan alley would you mind making a ticket for that with your example above?

view this post on Zulip johan alley (Oct 06 2026 at 13:53):

I'm not sure if we should remap automatically

@Richard Feldman why though? I expect most of the platform functions I make wont need a wrapper (other than to avoid this issue)

view this post on Zulip Richard Feldman (Oct 06 2026 at 14:52):

short answer is that we've found a number of scenarios where re-mapping is something we could do...but there consistently end up being pitfalls during implementation, and it's still not clear to me that it's a good idea to hide such a significant cost as a (potentially large) match


Last updated: Oct 15 2026 at 17:56 UTC