Skip to content

[Bug] wasm-gc: "Invalid stub type" for closure parameters containing String or Array in FFI stubs #1131

@bikallem

Description

@bikallem

Description

When a wasm-gc FFI stub function takes a closure (function type) as a parameter, the compiler rejects closures whose internal signature contains String, Array[T], or enum types with error [4042] Invalid stub type.

Closures passed to FFI stubs should be treated as opaque externref values on wasm-gc, regardless of their internal type signatures. The closure's parameter/return types are a MoonBit-level concern and should not affect the wasm import signature — the closure itself is just an externref.

Closures that work: those containing only #external types (externref) or wasm value types (Int, Double, UInt, etc.)

Closures that fail: those containing String, Array[T], or enum types as parameters or return types

Minimal Reproduction

moon.mod.json:

{
  "name": "blem/closure-stub-bug",
  "version": "0.1.0",
  "moonc-opt": "v0.8.1"
}

moon.pkg.json:

{
  "is-main": true,
  "supported-targets": ["wasm-gc"]
}

main.mbt:

#external
pub type Event

#external
pub type EventListener

// --- These work (externref or wasm value types inside closure) ---

fn ok_externref(callback : (Event) -> Unit) -> EventListener = "m" "a"
fn ok_no_args(callback : () -> Unit) -> EventListener = "m" "b"
fn ok_int(callback : (Int) -> Unit) -> EventListener = "m" "c"
fn ok_double(callback : (Double) -> Unit) -> EventListener = "m" "d"
fn ok_ret_externref(callback : (Event) -> Event) -> EventListener = "m" "e"

// --- These fail with [4042] "Invalid stub type" ---

fn fail_string_param(callback : (String) -> Unit) -> EventListener = "m" "f"
fn fail_string_return(callback : (Event) -> String) -> EventListener = "m" "g"
fn fail_array_param(callback : (Array[Event]) -> Unit) -> EventListener = "m" "h"

fn main {
  ignore(ok_externref)
  ignore(ok_no_args)
  ignore(ok_int)
  ignore(ok_double)
  ignore(ok_ret_externref)
  ignore(fail_string_param)
  ignore(fail_string_return)
  ignore(fail_array_param)
}

Actual behavior

$ moon build --target wasm-gc

Error: [4042]
 fn fail_string_param(callback : (String) -> Unit) -> EventListener = "m" "f"
                                 ────────┬───────
                                         ╰───────── Invalid stub type.

Error: [4042]
 fn fail_string_return(callback : (Event) -> String) -> EventListener = "m" "g"
                                  ────────┬────────
                                          ╰────────── Invalid stub type.

Error: [4042]
 fn fail_array_param(callback : (Array[Event]) -> Unit) -> EventListener = "m" "h"
                                ───────────┬──────────
                                           ╰──────────── Invalid stub type.

Expected behavior

All FFI stubs should compile successfully. The closure parameter is an externref on wasm-gc regardless of its internal type signature.

Environment

  • moonc -v: v0.8.1+bd827dc85 (2026-02-09)
  • moon version: moon 0.1.20260209 (b129ae2 2026-02-09)
  • OS: Linux 6.18.7-arch1-1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions