Skip to content

Commit 0b19bc3

Browse files
authored
Fix generated bindings for list-of-borrows (#670)
This commit fixes an issue for imported functions taking `list<borrow<T>>` arguments. Previously they were erroneously passed through as lists-of-pointers and now they're correctly mapped to list-of-handle-indexes in the ABI. This required rejiggering a bit how types are generated and what's considered owned when, namely requiring that all own handles use `Vec<T>` at the boundary since they need to take ownership.
1 parent f6004cd commit 0b19bc3

File tree

2 files changed

+46
-19
lines changed

2 files changed

+46
-19
lines changed

crates/rust-lib/src/lib.rs

+39-18
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,9 @@ pub trait RustGenerator<'a> {
337337
// If the type recursively owns data and it's a
338338
// variant/record/list, then we need to place the
339339
// lifetime parameter on the type as well.
340-
if (info.has_list || info.has_borrow_handle) && needs_generics(self.resolve(), &ty.kind)
340+
if (info.has_list || info.has_borrow_handle)
341+
&& !info.has_own_handle
342+
&& needs_generics(self.resolve(), &ty.kind)
341343
{
342344
self.print_generics(lt);
343345
}
@@ -470,6 +472,11 @@ pub trait RustGenerator<'a> {
470472
} else {
471473
mode
472474
};
475+
// Lists with `own` handles must always be owned
476+
let mode = match *ty {
477+
Type::Id(id) if self.info(id).has_own_handle => TypeMode::Owned,
478+
_ => mode,
479+
};
473480
match mode {
474481
TypeMode::AllBorrowed(lt) => {
475482
self.print_borrowed_slice(false, ty, lt, next_mode);
@@ -529,21 +536,29 @@ pub trait RustGenerator<'a> {
529536

530537
fn modes_of(&self, ty: TypeId) -> Vec<(String, TypeMode)> {
531538
let info = self.info(ty);
539+
// If this type isn't actually used, no need to generate it.
532540
if !info.owned && !info.borrowed {
533541
return Vec::new();
534542
}
535543
let mut result = Vec::new();
536-
let first_mode =
537-
if info.owned || !info.borrowed || matches!(self.ownership(), Ownership::Owning) {
538-
if info.has_borrow_handle {
539-
TypeMode::HandlesBorrowed("'a")
540-
} else {
541-
TypeMode::Owned
542-
}
544+
545+
// Prioritize generating an "owned" type. This is done to simplify
546+
// generated bindings by default. Borrowed handles always use a borrow,
547+
// however.
548+
let first_mode = if info.owned
549+
|| !info.borrowed
550+
|| matches!(self.ownership(), Ownership::Owning)
551+
|| info.has_own_handle
552+
{
553+
if info.has_borrow_handle {
554+
TypeMode::HandlesBorrowed("'a")
543555
} else {
544-
assert!(!self.uses_two_names(&info));
545-
TypeMode::AllBorrowed("'a")
546-
};
556+
TypeMode::Owned
557+
}
558+
} else {
559+
assert!(!self.uses_two_names(&info));
560+
TypeMode::AllBorrowed("'a")
561+
};
547562
result.push((self.result_name(ty), first_mode));
548563
if self.uses_two_names(&info) {
549564
result.push((self.param_name(ty), TypeMode::AllBorrowed("'a")));
@@ -1025,15 +1040,21 @@ pub trait RustGenerator<'a> {
10251040
}
10261041

10271042
fn uses_two_names(&self, info: &TypeInfo) -> bool {
1028-
info.has_list
1043+
// Types are only duplicated if explicitly requested ...
1044+
matches!(
1045+
self.ownership(),
1046+
Ownership::Borrowing {
1047+
duplicate_if_necessary: true
1048+
}
1049+
)
1050+
// ... and if they're both used in a borrowed/owned context
10291051
&& info.borrowed
10301052
&& info.owned
1031-
&& matches!(
1032-
self.ownership(),
1033-
Ownership::Borrowing {
1034-
duplicate_if_necessary: true
1035-
}
1036-
)
1053+
// ... and they have a list ...
1054+
&& info.has_list
1055+
// ... and if there's NOT an `own` handle since those are always
1056+
// done by ownership.
1057+
&& !info.has_own_handle
10371058
}
10381059

10391060
fn lifetime_for(&self, info: &TypeInfo, mode: TypeMode) -> Option<&'static str> {

crates/rust/src/lib.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1462,7 +1462,13 @@ impl Bindgen for FunctionBindgen<'_, '_> {
14621462
}
14631463

14641464
fn is_list_canonical(&self, resolve: &Resolve, ty: &Type) -> bool {
1465-
resolve.all_bits_valid(ty)
1465+
if !resolve.all_bits_valid(ty) {
1466+
return false;
1467+
}
1468+
match ty {
1469+
Type::Id(id) => !self.gen.gen.types.get(*id).has_resource,
1470+
_ => true,
1471+
}
14661472
}
14671473

14681474
fn emit(

0 commit comments

Comments
 (0)