Skip to content

error trying to import generic arrayref functions with concrete array types #12200

@michaelficarra

Description

@michaelficarra

Test Case

#[test]
fn test_arrayref() -> Result<(), Box<dyn std::error::Error>> {
    let module_a = wat::parse_str(r#"
        (module
            (func (export "len") (param $a arrayref) (result i32)
                (array.len (local.get $a))
            )
        )
    "#)?;
    let module_b = wat::parse_str(r#"
        (module
            (type $concrete_array (array (mut i32)))
            (import "module_a" "len" (func $len (param (ref null $concrete_array)) (result i32)))
            (func (export "use_len") (result i32)
                (call $len
                    (array.new_fixed $concrete_array 3
                        (i32.const 1)
                        (i32.const 2)
                        (i32.const 3)
                    )
                )
            )
        )
    "#)?;

    let mut config = wasmtime::Config::new();
    config.wasm_gc(true);
    config.wasm_function_references(true);
    let engine = wasmtime::Engine::new(&config)?;
    let mut store = wasmtime::Store::new(&engine, ());

    let module_a = wasmtime::Module::from_binary(&engine, &module_a)?;
    let module_b = wasmtime::Module::from_binary(&engine, &module_b)?;

    let empty_imports = vec![];
    let instance_a = wasmtime::Instance::new(&mut store, &module_a, &empty_imports)?;
    let exports_a = instance_a.exports(&mut store).collect::<Vec<_>>();

    let mut positional_imports = vec![];
    for import in module_b.imports() {
        let export = exports_a.iter().find(|e| e.name() == import.name()).unwrap();
        positional_imports.push(export.clone().into_extern());
    }
    let instance_b = wasmtime::Instance::new(&mut store, &module_b, &positional_imports)?;

    let use_len = instance_b.get_typed_func::<(), i32>(&mut store, "use_len")?;
    let result = use_len.call(&mut store, ())?;
    assert_eq!(result, 3);

    Ok(())
}

or, if you prefer to use Linker instead of manually wiring up the imports, this should be equivalent:

#[test]
fn test_arrayref() -> Result<(), Box<dyn std::error::Error>> {
    let module_a = wat::parse_str(r#"
        (module
            (func (export "len") (param $a arrayref) (result i32)
                (array.len (local.get $a))
            )
        )
    "#)?;
    let module_b = wat::parse_str(r#"
        (module
            (type $concrete_array (array (mut i32)))
            (import "module_a" "len" (func $len (param (ref null $concrete_array)) (result i32)))
            (func (export "use_len") (result i32)
                (call $len
                    (array.new_fixed $concrete_array 3
                        (i32.const 1)
                        (i32.const 2)
                        (i32.const 3)
                    )
                )
            )
        )
    "#)?;

    let mut config = wasmtime::Config::new();
    config.wasm_gc(true);
    config.wasm_function_references(true);
    let engine = wasmtime::Engine::new(&config)?;
    let mut store = wasmtime::Store::new(&engine, ());

    let module_a = wasmtime::Module::from_binary(&engine, &module_a)?;
    let module_b = wasmtime::Module::from_binary(&engine, &module_b)?;
    
    let mut linker = wasmtime::Linker::new(&engine);
    linker.module(&mut store, "module_a", &module_a)?;
    linker.module(&mut store, "module_b", &module_b)?;

    let instance_b = linker.instantiate(&mut store, &module_b)?;
    let use_len = instance_b.get_typed_func::<(), i32>(&mut store, "use_len")?;
    let result = use_len.call(&mut store, ())?;
    assert_eq!(result, 3);

    Ok(())
}

Steps to Reproduce

  • Run the test.

Expected Results

I expect the wasm to validate and run. I expect the Rust assertion assert_eq!(result, 3); to then pass.

Actual Results

---- test::manual::test_arrayref stdout ----
Error: incompatible import type for `module_a::len`

Caused by:
    types incompatible: expected type `(func (param (ref null array (engine 2))) (result i32))`, found type `(func (param (ref null array)) (result i32))`

If you remove the import and replace the function call (call $len) with the array.len instruction, it works.

Versions and Environment

Wasmtime version or commit: 40.0.0

Operating system: Darwin L6QHWH6D3R 24.5.0 Darwin Kernel Version 24.5.0: Tue Apr 22 19:54:29 PDT 2025; root:xnu-11417.121.6~2/RELEASE_ARM64_T6030 arm64 arm Darwin

Architecture: arm64

Extra Info

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIncorrect behavior in the current implementation that needs fixingwasm-proposal:gcIssues with the implementation of the gc wasm proposal

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions