diff --git a/crates/core/src/types.rs b/crates/core/src/types.rs index a0862f5e8..5aaa71607 100644 --- a/crates/core/src/types.rs +++ b/crates/core/src/types.rs @@ -30,6 +30,9 @@ pub struct TypeInfo { /// Whether this type (transitively) has a list (or string). pub has_list: bool, + /// Whether this type (transitively) has a tuple. + pub has_tuple: bool, + /// Whether this type (transitively) has a resource (or handle). pub has_resource: bool, @@ -46,6 +49,7 @@ impl std::ops::BitOrAssign for TypeInfo { self.owned |= rhs.owned; self.error |= rhs.error; self.has_list |= rhs.has_list; + self.has_tuple |= rhs.has_tuple; self.has_resource |= rhs.has_resource; self.has_borrow_handle |= rhs.has_borrow_handle; self.has_own_handle |= rhs.has_own_handle; @@ -171,6 +175,7 @@ impl Types { for ty in t.types.iter() { info |= self.type_info(resolve, ty); } + info.has_tuple = true; } TypeDefKind::Flags(_) => {} TypeDefKind::Enum(_) => {} diff --git a/crates/rust/src/bindgen.rs b/crates/rust/src/bindgen.rs index 1e9dc9ff1..e0b21f4dc 100644 --- a/crates/rust/src/bindgen.rs +++ b/crates/rust/src/bindgen.rs @@ -292,7 +292,12 @@ impl Bindgen for FunctionBindgen<'_, '_> { return false; } match ty { - Type::Id(id) => !self.gen.gen.types.get(*id).has_resource, + // Note that tuples in Rust are not ABI-compatible with component + // model tuples, so those are exempted here from canonical lists. + Type::Id(id) => { + let info = self.gen.gen.types.get(*id); + !info.has_resource && !info.has_tuple + } _ => true, } } diff --git a/tests/runtime/lists.rs b/tests/runtime/lists.rs index 114ff1724..f5761ccfc 100644 --- a/tests/runtime/lists.rs +++ b/tests/runtime/lists.rs @@ -47,6 +47,10 @@ impl test::lists::test::Host for MyImports { assert_eq!(ptr[1][0], "baz"); } + fn list_param5(&mut self, ptr: Vec<(u8, u32, u8)>) { + assert_eq!(ptr, [(1, 2, 3), (4, 5, 6)]); + } + fn list_result(&mut self) -> Vec { vec![1, 2, 3, 4, 5] } diff --git a/tests/runtime/lists/wasm.c b/tests/runtime/lists/wasm.c index 253dc586d..7787984a1 100644 --- a/tests/runtime/lists/wasm.c +++ b/tests/runtime/lists/wasm.c @@ -78,6 +78,20 @@ void exports_lists_test_imports() { test_lists_test_list_param4(&a); } + { + lists_tuple3_u8_u32_u8_t data[2]; + data[0].f0 = 1; + data[0].f1 = 2; + data[0].f2 = 3; + data[1].f0 = 4; + data[1].f1 = 5; + data[1].f2 = 6; + lists_list_tuple3_u8_u32_u8_t a; + a.len = 2; + a.ptr = data; + test_lists_test_list_param5(&a); + } + { lists_list_u8_t a; test_lists_test_list_result(&a); @@ -301,6 +315,17 @@ void exports_test_lists_test_list_param4(lists_list_list_string_t *a) { lists_list_list_string_free(a); } +void exports_test_lists_test_list_param5(lists_list_tuple3_u8_u32_u8_t *a) { + assert(a->len == 2); + assert(a->ptr[0].f0 == 1); + assert(a->ptr[0].f1 == 2); + assert(a->ptr[0].f2 == 3); + assert(a->ptr[1].f0 == 4); + assert(a->ptr[1].f1 == 5); + assert(a->ptr[1].f2 == 6); + lists_list_tuple3_u8_u32_u8_free(a); +} + void exports_test_lists_test_list_result(lists_list_u8_t *ret0) { ret0->ptr = (uint8_t *) malloc(5); ret0->len = 5; diff --git a/tests/runtime/lists/wasm.cs b/tests/runtime/lists/wasm.cs index adefc9577..fd929c7ba 100644 --- a/tests/runtime/lists/wasm.cs +++ b/tests/runtime/lists/wasm.cs @@ -18,7 +18,7 @@ public static void TestImports() TestInterop.EmptyListParam(new byte[0]); TestInterop.EmptyStringParam(""); - + { byte[] result = TestInterop.EmptyListResult(); Debug.Assert(result.Length == 0); @@ -62,7 +62,7 @@ public static void TestImports() Console.WriteLine(result); Debug.Assert(result == "hello!"); } - + { List result = TestInterop.ListResult3(); Debug.Assert(result.Count() == 2); @@ -103,7 +103,7 @@ public static void TestImports() Debug.Assert(u.Length == 2, $"u.Length {u.Length}"); Debug.Assert(u[0] == ushort.MinValue, $"u[0] == {u[0]}"); Debug.Assert(u[1] == ushort.MaxValue, $"u[1] == {u[1]}"); - + Debug.Assert(s.Length == 2); Console.WriteLine(s[0]); Console.WriteLine(s[1]); @@ -112,7 +112,7 @@ public static void TestImports() { var (u, s) = TestInterop.ListMinmax32( - new uint[] { uint.MinValue, uint.MaxValue }, + new uint[] { uint.MinValue, uint.MaxValue }, new int[] { int.MinValue, int.MaxValue } ); @@ -130,7 +130,7 @@ public static void TestImports() Debug.Assert(s.Length == 2 && s[0] == long.MinValue && s[1] == long.MaxValue); } - + { var (u, s) = TestInterop.ListMinmaxFloat( new float[] { @@ -220,6 +220,17 @@ public static void ListParam4(List> a) Debug.Assert(a[1][0].Equals("baz")); } + public static void ListParam5(List<(byte, uint, byte)> a) + { + Debug.Assert(a.Count() == 2); + Debug.Assert(a[0].Item1 == 1); + Debug.Assert(a[0].Item2 == 2); + Debug.Assert(a[0].Item3 == 3); + Debug.Assert(a[1].Item1 == 4); + Debug.Assert(a[1].Item2 == 5); + Debug.Assert(a[1].Item3 == 6); + } + public static byte[] ListResult() { return new byte[] { (byte)1, (byte)2, (byte)3, (byte)4, (byte)5 }; diff --git a/tests/runtime/lists/wasm.go b/tests/runtime/lists/wasm.go index d4f96a15b..119b3d0f2 100644 --- a/tests/runtime/lists/wasm.go +++ b/tests/runtime/lists/wasm.go @@ -200,6 +200,18 @@ func (i ListImpl) ListParam4(a [][]string) { } } +func (i ListImpl) ListParam5(a []ExportsTestListsTestTuple3U8U32U8T) { + if len(a) != 2 { + panic("ListParam5") + } + if a[0].F0 != 1 || a[0].F1 != 2 || a[0].F2 != 3 { + panic("ListParam5") + } + if a[1].F0 != 4 || a[1].F1 != 5 || a[1].F2 != 6 { + panic("ListParam5") + } +} + func (i ListImpl) ListResult() []uint8 { return []uint8{1, 2, 3, 4, 5} } diff --git a/tests/runtime/lists/wasm.rs b/tests/runtime/lists/wasm.rs index 8107eab29..d13eb5c58 100644 --- a/tests/runtime/lists/wasm.rs +++ b/tests/runtime/lists/wasm.rs @@ -28,6 +28,7 @@ impl Guest for Component { vec!["foo".to_owned(), "bar".to_owned()], vec!["baz".to_owned()], ]); + list_param5(&[(1, 2, 3), (4, 5, 6)]); assert_eq!(list_result(), [1, 2, 3, 4, 5]); assert_eq!(list_result2(), "hello!"); assert_eq!(list_result3(), ["hello,", "world!"]); @@ -109,6 +110,10 @@ impl exports::test::lists::test::Guest for Component { assert_eq!(ptr[1][0], "baz"); } + fn list_param5(ptr: Vec<(u8, u32, u8)>) { + assert_eq!(ptr, [(1, 2, 3), (4, 5, 6)]); + } + fn list_result() -> Vec { vec![1, 2, 3, 4, 5] } diff --git a/tests/runtime/lists/wit_exports_test_lists_TestImpl.java b/tests/runtime/lists/wit_exports_test_lists_TestImpl.java index 492760aa8..58ad90677 100644 --- a/tests/runtime/lists/wit_exports_test_lists_TestImpl.java +++ b/tests/runtime/lists/wit_exports_test_lists_TestImpl.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import wit.worlds.Lists.Tuple2; +import wit.worlds.Lists.Tuple3; public class TestImpl { public static void emptyListParam(byte[] a) { @@ -52,6 +53,16 @@ public static void listParam4(ArrayList> a) { expect(a.get(1).get(0).equals("baz")); } + public static void listParam5(ArrayList> a) { + expect(a.size() == 2); + expect(a.get(0).f0 == 1); + expect(a.get(0).f1 == 2); + expect(a.get(0).f2 == 3); + expect(a.get(1).f0 == 4); + expect(a.get(1).f1 == 5); + expect(a.get(1).f2 == 6); + } + public static byte[] listResult() { return new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5 }; } diff --git a/tests/runtime/lists/world.wit b/tests/runtime/lists/world.wit index 3be347a41..4e5730875 100644 --- a/tests/runtime/lists/world.wit +++ b/tests/runtime/lists/world.wit @@ -10,6 +10,7 @@ interface test { list-param2: func(a: string); list-param3: func(a: list); list-param4: func(a: list>); + list-param5: func(a: list>); list-result: func() -> list; list-result2: func() -> string; list-result3: func() -> list;