Repository: bytecodealliance/wasm-tools
Pull request #2108 (2025-03-20 16:22:40)

update async lift callback validation
As of the current spec, the callback function takes 3 parameters, not 4.


Patch:
diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs
index 9c44b0b3..13488d0f 100644
--- a/crates/wasmparser/src/validator/component.rs
+++ b/crates/wasmparser/src/validator/component.rs
@@ -2345,7 +2345,7 @@ impl ComponentState {
 
                             let ty = types[self.core_function_at(*idx, offset)?].unwrap_func();
 
-                            if ty.params() != [ValType::I32; 4] && ty.params() != [ValType::I32] {
+                            if ty.params() != [ValType::I32; 3] && ty.params() != [ValType::I32] {
                                 return Err(BinaryReaderError::new(
                                     "canonical option `callback` uses a core function with an incorrect signature",
                                     offset,
diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs
index a8288a22..0b8af565 100644
--- a/crates/wast/src/component/resolve.rs
+++ b/crates/wast/src/component/resolve.rs
@@ -841,7 +841,21 @@ impl<'a> Resolver<'a> {
                 target: AliasTarget::Outer {
                     outer: Index::Num(depth, span),
                     index: Index::Num(found, span),
-                    kind: ns.into(),
+                    kind: match ns {
+                        Ns::CoreModule => ComponentOuterAliasKind::CoreModule,
+                        Ns::CoreType => ComponentOuterAliasKind::CoreType,
+                        Ns::Type => ComponentOuterAliasKind::Type,
+                        Ns::Component => ComponentOuterAliasKind::Component,
+                        _ => {
+                            return Err(Error::new(
+                                span,
+                                format!(
+                                    "outer item `{}` is not a module, type, or component",
+                                    id.name(),
+                                ),
+                            ))
+                        }
+                    },
                 },
             };
             let local_index = self.current().register_alias(&alias)?;
@@ -1116,18 +1130,6 @@ impl From<Ns> for ComponentExportAliasKind {
     }
 }
 
-impl From<Ns> for ComponentOuterAliasKind {
-    fn from(ns: Ns) -> Self {
-        match ns {
-            Ns::CoreModule => Self::CoreModule,
-            Ns::CoreType => Self::CoreType,
-            Ns::Type => Self::Type,
-            Ns::Component => Self::Component,
-            _ => unreachable!("not an outer alias namespace"),
-        }
-    }
-}
-
 impl From<Ns> for core::ExportKind {
     fn from(ns: Ns) -> Self {
         match ns {
diff --git a/crates/wit-component/src/dummy.rs b/crates/wit-component/src/dummy.rs
index 9fd780fa..15636da9 100644
--- a/crates/wit-component/src/dummy.rs
+++ b/crates/wit-component/src/dummy.rs
@@ -341,7 +341,7 @@ fn push_func_export(
                 },
             );
             wat.push_str(&format!(
-                "(func (export \"{name}\") (param i32 i32 i32 i32) (result i32) unreachable)\n"
+                "(func (export \"{name}\") (param i32 i32 i32) (result i32) unreachable)\n"
             ));
         }
         ManglingAndAbi::Legacy(LiftLowerAbi::AsyncStackful) => {}
diff --git a/crates/wit-component/src/validation.rs b/crates/wit-component/src/validation.rs
index a0164550..037d48b7 100644
--- a/crates/wit-component/src/validation.rs
+++ b/crates/wit-component/src/validation.rs
@@ -1207,7 +1207,7 @@ impl ExportMap {
             if let Some((key, id, f)) = names.match_wit_export(suffix, resolve, world, exports) {
                 validate_func_sig(
                     full_name,
-                    &FuncType::new([ValType::I32; 4], [ValType::I32]),
+                    &FuncType::new([ValType::I32; 3], [ValType::I32]),
                     ty,
                 )?;
                 return Ok(Some(if id.is_some() {


Test patch:
diff --git a/crates/wit-component/tests/components/async-export-with-callback/component.wat b/crates/wit-component/tests/components/async-export-with-callback/component.wat
index 06476499..24886fec 100644
--- a/crates/wit-component/tests/components/async-export-with-callback/component.wat
+++ b/crates/wit-component/tests/components/async-export-with-callback/component.wat
@@ -1,7 +1,8 @@
 (component
   (core module (;0;)
     (type (;0;) (func (param i32 i32) (result i32)))
-    (type (;1;) (func (param i32 i32 i32 i32) (result i32)))
+    (type (;1;) (func (param i32 i32 i32) (result i32)))
+    (type (;2;) (func (param i32 i32 i32 i32) (result i32)))
     (memory (;0;) 1)
     (export "[async-lift]foo" (func 0))
     (export "[callback][async-lift]foo" (func 1))
@@ -12,16 +13,16 @@
     (func (;0;) (type 0) (param i32 i32) (result i32)
       unreachable
     )
-    (func (;1;) (type 1) (param i32 i32 i32 i32) (result i32)
+    (func (;1;) (type 1) (param i32 i32 i32) (result i32)
       unreachable
     )
     (func (;2;) (type 0) (param i32 i32) (result i32)
       unreachable
     )
-    (func (;3;) (type 1) (param i32 i32 i32 i32) (result i32)
+    (func (;3;) (type 1) (param i32 i32 i32) (result i32)
       unreachable
     )
-    (func (;4;) (type 1) (param i32 i32 i32 i32) (result i32)
+    (func (;4;) (type 2) (param i32 i32 i32 i32) (result i32)
       unreachable
     )
     (@producers
diff --git a/crates/wit-component/tests/components/async-export-with-callback/module.wat b/crates/wit-component/tests/components/async-export-with-callback/module.wat
index 868f9e80..d0145d68 100644
--- a/crates/wit-component/tests/components/async-export-with-callback/module.wat
+++ b/crates/wit-component/tests/components/async-export-with-callback/module.wat
@@ -1,8 +1,8 @@
 (module
   (func (export "[async-lift]foo") (param i32 i32) (result i32) unreachable)
-  (func (export "[callback][async-lift]foo") (param i32 i32 i32 i32) (result i32) unreachable)
+  (func (export "[callback][async-lift]foo") (param i32 i32 i32) (result i32) unreachable)
   (func (export "[async-lift]foo:foo/bar#foo") (param i32 i32) (result i32) unreachable)
-  (func (export "[callback][async-lift]foo:foo/bar#foo") (param i32 i32 i32 i32) (result i32) unreachable)
+  (func (export "[callback][async-lift]foo:foo/bar#foo") (param i32 i32 i32) (result i32) unreachable)
   (memory (export "memory") 1)
   (func (export "cabi_realloc") (param i32 i32 i32 i32) (result i32) unreachable)
 )
diff --git a/tests/cli/component-model-async/lift.wast b/tests/cli/component-model-async/lift.wast
index 165590f0..a37b1c8b 100644
--- a/tests/cli/component-model-async/lift.wast
+++ b/tests/cli/component-model-async/lift.wast
@@ -31,7 +31,7 @@
 ;; async lift; with callback
 (component
   (core module $m
-    (func (export "callback") (param i32 i32 i32 i32) (result i32) unreachable)
+    (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
     (func (export "foo") (param i32) (result i32) unreachable)
   )
   (core instance $i (instantiate $m))
@@ -45,7 +45,7 @@
 (assert_invalid
   (component
     (core module $m
-      (func (export "callback") (param i32 i32 f32 i32) (result i32) unreachable)
+      (func (export "callback") (param i32 f32 i32) (result i32) unreachable)
       (func (export "foo") (param i32) (result i32) unreachable)
     )
     (core instance $i (instantiate $m))
@@ -61,7 +61,7 @@
 (assert_invalid
   (component
     (core module $m
-      (func (export "callback") (param i32 i32 i32 i32) (result i32) unreachable)
+      (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
       (func (export "foo") (param i32) (result i32) unreachable)
       (func (export "post-return-foo") (param i32) unreachable)
     )
@@ -78,7 +78,7 @@
 (assert_invalid
   (component
     (core module $m
-      (func (export "callback") (param i32 i32 i32 i32) (result i32) unreachable)
+      (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
       (func (export "foo") (param i32 i32) (result i32) unreachable)
     )
     (core instance $i (instantiate $m))
@@ -109,7 +109,7 @@
 (assert_invalid
   (component
     (core module $m
-      (func (export "callback") (param i32 i32 i32 i32) (result i32) unreachable)
+      (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
       (func (export "foo") (param i32) (result i32) unreachable)
     )
     (core instance $i (instantiate $m))
diff --git a/tests/cli/component-model/invalid.wast b/tests/cli/component-model/invalid.wast
index 63d5dbc7..267b31f8 100644
--- a/tests/cli/component-model/invalid.wast
+++ b/tests/cli/component-model/invalid.wast
@@ -26,3 +26,9 @@
     "(alias outer $nonexistent $foo (type $foo))"
   )
   "outer component `nonexistent` not found")
+
+(assert_malformed
+  (component quote
+    "(import \"x\" (func $x))"
+    "(component (export \"x\" (func $x)))")
+  "outer item `x` is not a module, type, or component")
diff --git a/tests/snapshots/cli/component-model-async/lift.wast/2.print b/tests/snapshots/cli/component-model-async/lift.wast/2.print
index c56b1789..4a323d62 100644
--- a/tests/snapshots/cli/component-model-async/lift.wast/2.print
+++ b/tests/snapshots/cli/component-model-async/lift.wast/2.print
@@ -1,10 +1,10 @@
 (component
   (core module $m (;0;)
-    (type (;0;) (func (param i32 i32 i32 i32) (result i32)))
+    (type (;0;) (func (param i32 i32 i32) (result i32)))
     (type (;1;) (func (param i32) (result i32)))
     (export "callback" (func 0))
     (export "foo" (func 1))
-    (func (;0;) (type 0) (param i32 i32 i32 i32) (result i32)
+    (func (;0;) (type 0) (param i32 i32 i32) (result i32)
       unreachable
     )
     (func (;1;) (type 1) (param i32) (result i32)
diff --git a/tests/snapshots/cli/component-model/invalid.wast.json b/tests/snapshots/cli/component-model/invalid.wast.json
index 4c6a0819..207ab01c 100644
--- a/tests/snapshots/cli/component-model/invalid.wast.json
+++ b/tests/snapshots/cli/component-model/invalid.wast.json
@@ -28,6 +28,13 @@
       "filename": "invalid.3.wat",
       "module_type": "text",
       "text": "outer component `nonexistent` not found"
+    },
+    {
+      "type": "assert_malformed",
+      "line": 31,
+      "filename": "invalid.4.wat",
+      "module_type": "text",
+      "text": "outer item `x` is not a module, type, or component"
     }
   ]
 }
\ No newline at end of file