Skip to content

Commit 19f259b

Browse files
authored
Fix mismatched tuple ABIs in Rust (#1113)
* Fix mismatched tuple ABIs in Rust This fixes the mistaken assumption that the tuple ABI in Rust is the same as the component model ABI and generates different code for lifting/lowering lists. Closes #1112 * Attempt a java test * Add a go test * Fix java test * Attempt to write C#
1 parent 898b833 commit 19f259b

File tree

9 files changed

+85
-6
lines changed

9 files changed

+85
-6
lines changed

crates/core/src/types.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ pub struct TypeInfo {
3030
/// Whether this type (transitively) has a list (or string).
3131
pub has_list: bool,
3232

33+
/// Whether this type (transitively) has a tuple.
34+
pub has_tuple: bool,
35+
3336
/// Whether this type (transitively) has a resource (or handle).
3437
pub has_resource: bool,
3538

@@ -46,6 +49,7 @@ impl std::ops::BitOrAssign for TypeInfo {
4649
self.owned |= rhs.owned;
4750
self.error |= rhs.error;
4851
self.has_list |= rhs.has_list;
52+
self.has_tuple |= rhs.has_tuple;
4953
self.has_resource |= rhs.has_resource;
5054
self.has_borrow_handle |= rhs.has_borrow_handle;
5155
self.has_own_handle |= rhs.has_own_handle;
@@ -171,6 +175,7 @@ impl Types {
171175
for ty in t.types.iter() {
172176
info |= self.type_info(resolve, ty);
173177
}
178+
info.has_tuple = true;
174179
}
175180
TypeDefKind::Flags(_) => {}
176181
TypeDefKind::Enum(_) => {}

crates/rust/src/bindgen.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,12 @@ impl Bindgen for FunctionBindgen<'_, '_> {
292292
return false;
293293
}
294294
match ty {
295-
Type::Id(id) => !self.gen.gen.types.get(*id).has_resource,
295+
// Note that tuples in Rust are not ABI-compatible with component
296+
// model tuples, so those are exempted here from canonical lists.
297+
Type::Id(id) => {
298+
let info = self.gen.gen.types.get(*id);
299+
!info.has_resource && !info.has_tuple
300+
}
296301
_ => true,
297302
}
298303
}

tests/runtime/lists.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ impl test::lists::test::Host for MyImports {
4747
assert_eq!(ptr[1][0], "baz");
4848
}
4949

50+
fn list_param5(&mut self, ptr: Vec<(u8, u32, u8)>) {
51+
assert_eq!(ptr, [(1, 2, 3), (4, 5, 6)]);
52+
}
53+
5054
fn list_result(&mut self) -> Vec<u8> {
5155
vec![1, 2, 3, 4, 5]
5256
}

tests/runtime/lists/wasm.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,20 @@ void exports_lists_test_imports() {
7878
test_lists_test_list_param4(&a);
7979
}
8080

81+
{
82+
lists_tuple3_u8_u32_u8_t data[2];
83+
data[0].f0 = 1;
84+
data[0].f1 = 2;
85+
data[0].f2 = 3;
86+
data[1].f0 = 4;
87+
data[1].f1 = 5;
88+
data[1].f2 = 6;
89+
lists_list_tuple3_u8_u32_u8_t a;
90+
a.len = 2;
91+
a.ptr = data;
92+
test_lists_test_list_param5(&a);
93+
}
94+
8195
{
8296
lists_list_u8_t a;
8397
test_lists_test_list_result(&a);
@@ -301,6 +315,17 @@ void exports_test_lists_test_list_param4(lists_list_list_string_t *a) {
301315
lists_list_list_string_free(a);
302316
}
303317

318+
void exports_test_lists_test_list_param5(lists_list_tuple3_u8_u32_u8_t *a) {
319+
assert(a->len == 2);
320+
assert(a->ptr[0].f0 == 1);
321+
assert(a->ptr[0].f1 == 2);
322+
assert(a->ptr[0].f2 == 3);
323+
assert(a->ptr[1].f0 == 4);
324+
assert(a->ptr[1].f1 == 5);
325+
assert(a->ptr[1].f2 == 6);
326+
lists_list_tuple3_u8_u32_u8_free(a);
327+
}
328+
304329
void exports_test_lists_test_list_result(lists_list_u8_t *ret0) {
305330
ret0->ptr = (uint8_t *) malloc(5);
306331
ret0->len = 5;

tests/runtime/lists/wasm.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public static void TestImports()
1818

1919
TestInterop.EmptyListParam(new byte[0]);
2020
TestInterop.EmptyStringParam("");
21-
21+
2222
{
2323
byte[] result = TestInterop.EmptyListResult();
2424
Debug.Assert(result.Length == 0);
@@ -62,7 +62,7 @@ public static void TestImports()
6262
Console.WriteLine(result);
6363
Debug.Assert(result == "hello!");
6464
}
65-
65+
6666
{
6767
List<String> result = TestInterop.ListResult3();
6868
Debug.Assert(result.Count() == 2);
@@ -103,7 +103,7 @@ public static void TestImports()
103103
Debug.Assert(u.Length == 2, $"u.Length {u.Length}");
104104
Debug.Assert(u[0] == ushort.MinValue, $"u[0] == {u[0]}");
105105
Debug.Assert(u[1] == ushort.MaxValue, $"u[1] == {u[1]}");
106-
106+
107107
Debug.Assert(s.Length == 2);
108108
Console.WriteLine(s[0]);
109109
Console.WriteLine(s[1]);
@@ -112,7 +112,7 @@ public static void TestImports()
112112

113113
{
114114
var (u, s) = TestInterop.ListMinmax32(
115-
new uint[] { uint.MinValue, uint.MaxValue },
115+
new uint[] { uint.MinValue, uint.MaxValue },
116116
new int[] { int.MinValue, int.MaxValue }
117117
);
118118

@@ -130,7 +130,7 @@ public static void TestImports()
130130

131131
Debug.Assert(s.Length == 2 && s[0] == long.MinValue && s[1] == long.MaxValue);
132132
}
133-
133+
134134
{
135135
var (u, s) = TestInterop.ListMinmaxFloat(
136136
new float[] {
@@ -220,6 +220,17 @@ public static void ListParam4(List<List<String>> a)
220220
Debug.Assert(a[1][0].Equals("baz"));
221221
}
222222

223+
public static void ListParam5(List<(byte, uint, byte)> a)
224+
{
225+
Debug.Assert(a.Count() == 2);
226+
Debug.Assert(a[0].Item1 == 1);
227+
Debug.Assert(a[0].Item2 == 2);
228+
Debug.Assert(a[0].Item3 == 3);
229+
Debug.Assert(a[1].Item1 == 4);
230+
Debug.Assert(a[1].Item2 == 5);
231+
Debug.Assert(a[1].Item3 == 6);
232+
}
233+
223234
public static byte[] ListResult()
224235
{
225236
return new byte[] { (byte)1, (byte)2, (byte)3, (byte)4, (byte)5 };

tests/runtime/lists/wasm.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,18 @@ func (i ListImpl) ListParam4(a [][]string) {
200200
}
201201
}
202202

203+
func (i ListImpl) ListParam5(a []ExportsTestListsTestTuple3U8U32U8T) {
204+
if len(a) != 2 {
205+
panic("ListParam5")
206+
}
207+
if a[0].F0 != 1 || a[0].F1 != 2 || a[0].F2 != 3 {
208+
panic("ListParam5")
209+
}
210+
if a[1].F0 != 4 || a[1].F1 != 5 || a[1].F2 != 6 {
211+
panic("ListParam5")
212+
}
213+
}
214+
203215
func (i ListImpl) ListResult() []uint8 {
204216
return []uint8{1, 2, 3, 4, 5}
205217
}

tests/runtime/lists/wasm.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ impl Guest for Component {
2828
vec!["foo".to_owned(), "bar".to_owned()],
2929
vec!["baz".to_owned()],
3030
]);
31+
list_param5(&[(1, 2, 3), (4, 5, 6)]);
3132
assert_eq!(list_result(), [1, 2, 3, 4, 5]);
3233
assert_eq!(list_result2(), "hello!");
3334
assert_eq!(list_result3(), ["hello,", "world!"]);
@@ -109,6 +110,10 @@ impl exports::test::lists::test::Guest for Component {
109110
assert_eq!(ptr[1][0], "baz");
110111
}
111112

113+
fn list_param5(ptr: Vec<(u8, u32, u8)>) {
114+
assert_eq!(ptr, [(1, 2, 3), (4, 5, 6)]);
115+
}
116+
112117
fn list_result() -> Vec<u8> {
113118
vec![1, 2, 3, 4, 5]
114119
}

tests/runtime/lists/wit_exports_test_lists_TestImpl.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.ArrayList;
66

77
import wit.worlds.Lists.Tuple2;
8+
import wit.worlds.Lists.Tuple3;
89

910
public class TestImpl {
1011
public static void emptyListParam(byte[] a) {
@@ -52,6 +53,16 @@ public static void listParam4(ArrayList<ArrayList<String>> a) {
5253
expect(a.get(1).get(0).equals("baz"));
5354
}
5455

56+
public static void listParam5(ArrayList<Tuple3<Byte, Integer, Byte>> a) {
57+
expect(a.size() == 2);
58+
expect(a.get(0).f0 == 1);
59+
expect(a.get(0).f1 == 2);
60+
expect(a.get(0).f2 == 3);
61+
expect(a.get(1).f0 == 4);
62+
expect(a.get(1).f1 == 5);
63+
expect(a.get(1).f2 == 6);
64+
}
65+
5566
public static byte[] listResult() {
5667
return new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5 };
5768
}

tests/runtime/lists/world.wit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ interface test {
1010
list-param2: func(a: string);
1111
list-param3: func(a: list<string>);
1212
list-param4: func(a: list<list<string>>);
13+
list-param5: func(a: list<tuple<u8, u32, u8>>);
1314
list-result: func() -> list<u8>;
1415
list-result2: func() -> string;
1516
list-result3: func() -> list<string>;

0 commit comments

Comments
 (0)