Fix some wit-bindgen-related issues with generated bindings (#5692)
* Prefix component-bindgen-generated-functions with `call_` This fixes clashes between Rust-native methods and the methods themselves. For example right now `new` is a Rust-generated function for constructing the wrapper but this can conflict with a world-exported function called `new`. Closes #5585 * Fix types being both shared and owned This refactors some inherited cruft from the original `wit-bindgen` repository to be more Wasmtime-specific and fixes a codegen case where a type was used in both a shared and an owned context. Closes #5688
This commit is contained in:
3
crates/component-macro/tests/codegen/function-new.wit
Normal file
3
crates/component-macro/tests/codegen/function-new.wit
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
default world foo {
|
||||||
|
export new: func()
|
||||||
|
}
|
||||||
19
crates/component-macro/tests/codegen/share-types.wit
Normal file
19
crates/component-macro/tests/codegen/share-types.wit
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
interface http-types{
|
||||||
|
record request {
|
||||||
|
method: string
|
||||||
|
}
|
||||||
|
record response {
|
||||||
|
body: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default world http-interface {
|
||||||
|
export http-handler: interface {
|
||||||
|
use self.http-types.{request,response}
|
||||||
|
handle-request: func(request: request) -> response
|
||||||
|
}
|
||||||
|
import http-fetch: interface {
|
||||||
|
use self.http-types.{request,response}
|
||||||
|
fetch-request: func(request: request) -> response
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -101,7 +101,7 @@ impl Wasmtime {
|
|||||||
|
|
||||||
fn import(&mut self, resolve: &Resolve, name: &str, item: &WorldItem) {
|
fn import(&mut self, resolve: &Resolve, name: &str, item: &WorldItem) {
|
||||||
let snake = name.to_snake_case();
|
let snake = name.to_snake_case();
|
||||||
let mut gen = InterfaceGenerator::new(self, resolve, TypeMode::Owned);
|
let mut gen = InterfaceGenerator::new(self, resolve);
|
||||||
let import = match item {
|
let import = match item {
|
||||||
WorldItem::Function(func) => {
|
WorldItem::Function(func) => {
|
||||||
gen.generate_function_trait_sig(TypeOwner::None, &func);
|
gen.generate_function_trait_sig(TypeOwner::None, &func);
|
||||||
@@ -139,7 +139,7 @@ impl Wasmtime {
|
|||||||
|
|
||||||
fn export(&mut self, resolve: &Resolve, name: &str, item: &WorldItem) {
|
fn export(&mut self, resolve: &Resolve, name: &str, item: &WorldItem) {
|
||||||
let snake = name.to_snake_case();
|
let snake = name.to_snake_case();
|
||||||
let mut gen = InterfaceGenerator::new(self, resolve, TypeMode::AllBorrowed("'a"));
|
let mut gen = InterfaceGenerator::new(self, resolve);
|
||||||
let (ty, getter) = match item {
|
let (ty, getter) = match item {
|
||||||
WorldItem::Function(func) => {
|
WorldItem::Function(func) => {
|
||||||
gen.define_rust_guest_export(None, func);
|
gen.define_rust_guest_export(None, func);
|
||||||
@@ -450,21 +450,15 @@ struct InterfaceGenerator<'a> {
|
|||||||
src: Source,
|
src: Source,
|
||||||
gen: &'a mut Wasmtime,
|
gen: &'a mut Wasmtime,
|
||||||
resolve: &'a Resolve,
|
resolve: &'a Resolve,
|
||||||
default_param_mode: TypeMode,
|
|
||||||
current_interface: Option<InterfaceId>,
|
current_interface: Option<InterfaceId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> InterfaceGenerator<'a> {
|
impl<'a> InterfaceGenerator<'a> {
|
||||||
fn new(
|
fn new(gen: &'a mut Wasmtime, resolve: &'a Resolve) -> InterfaceGenerator<'a> {
|
||||||
gen: &'a mut Wasmtime,
|
|
||||||
resolve: &'a Resolve,
|
|
||||||
default_param_mode: TypeMode,
|
|
||||||
) -> InterfaceGenerator<'a> {
|
|
||||||
InterfaceGenerator {
|
InterfaceGenerator {
|
||||||
src: Source::default(),
|
src: Source::default(),
|
||||||
gen,
|
gen,
|
||||||
resolve,
|
resolve,
|
||||||
default_param_mode,
|
|
||||||
current_interface: None,
|
current_interface: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1159,7 +1153,7 @@ impl<'a> InterfaceGenerator<'a> {
|
|||||||
self.rustdoc(&func.docs);
|
self.rustdoc(&func.docs);
|
||||||
uwrite!(
|
uwrite!(
|
||||||
self.src,
|
self.src,
|
||||||
"pub {async_} fn {}<S: wasmtime::AsContextMut>(&self, mut store: S, ",
|
"pub {async_} fn call_{}<S: wasmtime::AsContextMut>(&self, mut store: S, ",
|
||||||
func.name.to_snake_case(),
|
func.name.to_snake_case(),
|
||||||
);
|
);
|
||||||
for (i, param) in func.params.iter().enumerate() {
|
for (i, param) in func.params.iter().enumerate() {
|
||||||
@@ -1351,10 +1345,6 @@ impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> {
|
|||||||
self.current_interface
|
self.current_interface
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_param_mode(&self) -> TypeMode {
|
|
||||||
self.default_param_mode
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_str(&mut self, s: &str) {
|
fn push_str(&mut self, s: &str) {
|
||||||
self.src.push_str(s);
|
self.src.push_str(s);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ pub trait RustGenerator<'a> {
|
|||||||
|
|
||||||
fn push_str(&mut self, s: &str);
|
fn push_str(&mut self, s: &str);
|
||||||
fn info(&self, ty: TypeId) -> TypeInfo;
|
fn info(&self, ty: TypeId) -> TypeInfo;
|
||||||
fn default_param_mode(&self) -> TypeMode;
|
|
||||||
fn current_interface(&self) -> Option<InterfaceId>;
|
fn current_interface(&self) -> Option<InterfaceId>;
|
||||||
|
|
||||||
fn print_ty(&mut self, ty: &Type, mode: TypeMode) {
|
fn print_ty(&mut self, ty: &Type, mode: TypeMode) {
|
||||||
@@ -209,10 +208,10 @@ pub trait RustGenerator<'a> {
|
|||||||
fn modes_of(&self, ty: TypeId) -> Vec<(String, TypeMode)> {
|
fn modes_of(&self, ty: TypeId) -> Vec<(String, TypeMode)> {
|
||||||
let info = self.info(ty);
|
let info = self.info(ty);
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
if info.param {
|
if info.borrowed {
|
||||||
result.push((self.param_name(ty), self.default_param_mode()));
|
result.push((self.param_name(ty), TypeMode::AllBorrowed("'a")));
|
||||||
}
|
}
|
||||||
if info.result && (!info.param || self.uses_two_names(&info)) {
|
if info.owned && (!info.borrowed || self.uses_two_names(&info)) {
|
||||||
result.push((self.result_name(ty), TypeMode::Owned));
|
result.push((self.result_name(ty), TypeMode::Owned));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -358,13 +357,7 @@ pub trait RustGenerator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn uses_two_names(&self, info: &TypeInfo) -> bool {
|
fn uses_two_names(&self, info: &TypeInfo) -> bool {
|
||||||
info.has_list
|
info.has_list && info.borrowed && info.owned
|
||||||
&& info.param
|
|
||||||
&& info.result
|
|
||||||
&& match self.default_param_mode() {
|
|
||||||
TypeMode::AllBorrowed(_) => true,
|
|
||||||
TypeMode::Owned => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lifetime_for(&self, info: &TypeInfo, mode: TypeMode) -> Option<&'static str> {
|
fn lifetime_for(&self, info: &TypeInfo, mode: TypeMode) -> Option<&'static str> {
|
||||||
|
|||||||
@@ -8,13 +8,14 @@ pub struct Types {
|
|||||||
|
|
||||||
#[derive(Default, Clone, Copy, Debug, PartialEq)]
|
#[derive(Default, Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct TypeInfo {
|
pub struct TypeInfo {
|
||||||
/// Whether or not this type is ever used (transitively) within the
|
/// Whether or not this type is ever used (transitively) within a borrowed
|
||||||
/// parameter of a function.
|
/// context, or a parameter to an export function.
|
||||||
pub param: bool,
|
pub borrowed: bool,
|
||||||
|
|
||||||
/// Whether or not this type is ever used (transitively) within the
|
/// Whether or not this type is ever used (transitively) within an owned
|
||||||
/// result of a function.
|
/// context, such as the result of an exported function or in the params or
|
||||||
pub result: bool,
|
/// results of an imported function.
|
||||||
|
pub owned: bool,
|
||||||
|
|
||||||
/// Whether or not this type is ever used (transitively) within the
|
/// Whether or not this type is ever used (transitively) within the
|
||||||
/// error case in the result of a function.
|
/// error case in the result of a function.
|
||||||
@@ -26,8 +27,8 @@ pub struct TypeInfo {
|
|||||||
|
|
||||||
impl std::ops::BitOrAssign for TypeInfo {
|
impl std::ops::BitOrAssign for TypeInfo {
|
||||||
fn bitor_assign(&mut self, rhs: Self) {
|
fn bitor_assign(&mut self, rhs: Self) {
|
||||||
self.param |= rhs.param;
|
self.borrowed |= rhs.borrowed;
|
||||||
self.result |= rhs.result;
|
self.owned |= rhs.owned;
|
||||||
self.error |= rhs.error;
|
self.error |= rhs.error;
|
||||||
self.has_list |= rhs.has_list;
|
self.has_list |= rhs.has_list;
|
||||||
}
|
}
|
||||||
@@ -36,9 +37,14 @@ impl std::ops::BitOrAssign for TypeInfo {
|
|||||||
impl Types {
|
impl Types {
|
||||||
pub fn analyze(&mut self, resolve: &Resolve, world: WorldId) {
|
pub fn analyze(&mut self, resolve: &Resolve, world: WorldId) {
|
||||||
let world = &resolve.worlds[world];
|
let world = &resolve.worlds[world];
|
||||||
for (_, item) in world.imports.iter().chain(world.exports.iter()) {
|
for (import, (_, item)) in world
|
||||||
|
.imports
|
||||||
|
.iter()
|
||||||
|
.map(|i| (true, i))
|
||||||
|
.chain(world.exports.iter().map(|i| (false, i)))
|
||||||
|
{
|
||||||
match item {
|
match item {
|
||||||
WorldItem::Function(f) => self.type_info_func(resolve, f),
|
WorldItem::Function(f) => self.type_info_func(resolve, f, import),
|
||||||
WorldItem::Interface(id) => {
|
WorldItem::Interface(id) => {
|
||||||
let iface = &resolve.interfaces[*id];
|
let iface = &resolve.interfaces[*id];
|
||||||
|
|
||||||
@@ -46,21 +52,26 @@ impl Types {
|
|||||||
self.type_id_info(resolve, *t);
|
self.type_id_info(resolve, *t);
|
||||||
}
|
}
|
||||||
for (_, f) in iface.functions.iter() {
|
for (_, f) in iface.functions.iter() {
|
||||||
self.type_info_func(resolve, f);
|
self.type_info_func(resolve, f, import);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_info_func(&mut self, resolve: &Resolve, func: &Function) {
|
fn type_info_func(&mut self, resolve: &Resolve, func: &Function, import: bool) {
|
||||||
let mut live = LiveTypes::default();
|
let mut live = LiveTypes::default();
|
||||||
for (_, ty) in func.params.iter() {
|
for (_, ty) in func.params.iter() {
|
||||||
self.type_info(resolve, ty);
|
self.type_info(resolve, ty);
|
||||||
live.add_type(resolve, ty);
|
live.add_type(resolve, ty);
|
||||||
}
|
}
|
||||||
for id in live.iter() {
|
for id in live.iter() {
|
||||||
self.type_info.get_mut(&id).unwrap().param = true;
|
let info = self.type_info.get_mut(&id).unwrap();
|
||||||
|
if import {
|
||||||
|
info.owned = true;
|
||||||
|
} else {
|
||||||
|
info.borrowed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let mut live = LiveTypes::default();
|
let mut live = LiveTypes::default();
|
||||||
for ty in func.results.iter_types() {
|
for ty in func.results.iter_types() {
|
||||||
@@ -68,7 +79,7 @@ impl Types {
|
|||||||
live.add_type(resolve, ty);
|
live.add_type(resolve, ty);
|
||||||
}
|
}
|
||||||
for id in live.iter() {
|
for id in live.iter() {
|
||||||
self.type_info.get_mut(&id).unwrap().result = true;
|
self.type_info.get_mut(&id).unwrap().owned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ty in func.results.iter_types() {
|
for ty in func.results.iter_types() {
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ mod no_imports {
|
|||||||
let linker = Linker::new(&engine);
|
let linker = Linker::new(&engine);
|
||||||
let mut store = Store::new(&engine, ());
|
let mut store = Store::new(&engine, ());
|
||||||
let (no_imports, _) = NoImports::instantiate(&mut store, &component, &linker)?;
|
let (no_imports, _) = NoImports::instantiate(&mut store, &component, &linker)?;
|
||||||
no_imports.bar(&mut store)?;
|
no_imports.call_bar(&mut store)?;
|
||||||
no_imports.foo().foo(&mut store)?;
|
no_imports.foo().call_foo(&mut store)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ mod one_import {
|
|||||||
foo::add_to_linker(&mut linker, |f: &mut MyImports| f)?;
|
foo::add_to_linker(&mut linker, |f: &mut MyImports| f)?;
|
||||||
let mut store = Store::new(&engine, MyImports::default());
|
let mut store = Store::new(&engine, MyImports::default());
|
||||||
let (one_import, _) = OneImport::instantiate(&mut store, &component, &linker)?;
|
let (one_import, _) = OneImport::instantiate(&mut store, &component, &linker)?;
|
||||||
one_import.bar(&mut store)?;
|
one_import.call_bar(&mut store)?;
|
||||||
assert!(store.data().hit);
|
assert!(store.data().hit);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,19 +80,22 @@ mod empty_error {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
results
|
results
|
||||||
.empty_error(&mut store, 0.0)
|
.call_empty_error(&mut store, 0.0)
|
||||||
.expect("no trap")
|
.expect("no trap")
|
||||||
.expect("no error returned"),
|
.expect("no error returned"),
|
||||||
0.0
|
0.0
|
||||||
);
|
);
|
||||||
|
|
||||||
results
|
results
|
||||||
.empty_error(&mut store, 1.0)
|
.call_empty_error(&mut store, 1.0)
|
||||||
.expect("no trap")
|
.expect("no trap")
|
||||||
.err()
|
.err()
|
||||||
.expect("() error returned");
|
.expect("() error returned");
|
||||||
|
|
||||||
let e = results.empty_error(&mut store, 2.0).err().expect("trap");
|
let e = results
|
||||||
|
.call_empty_error(&mut store, 2.0)
|
||||||
|
.err()
|
||||||
|
.expect("trap");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{}", e.source().expect("trap message is stored in source")),
|
format!("{}", e.source().expect("trap message is stored in source")),
|
||||||
"empty_error: trap"
|
"empty_error: trap"
|
||||||
@@ -188,20 +191,23 @@ mod string_error {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
results
|
results
|
||||||
.string_error(&mut store, 0.0)
|
.call_string_error(&mut store, 0.0)
|
||||||
.expect("no trap")
|
.expect("no trap")
|
||||||
.expect("no error returned"),
|
.expect("no error returned"),
|
||||||
0.0
|
0.0
|
||||||
);
|
);
|
||||||
|
|
||||||
let e = results
|
let e = results
|
||||||
.string_error(&mut store, 1.0)
|
.call_string_error(&mut store, 1.0)
|
||||||
.expect("no trap")
|
.expect("no trap")
|
||||||
.err()
|
.err()
|
||||||
.expect("error returned");
|
.expect("error returned");
|
||||||
assert_eq!(e, "string_error: error");
|
assert_eq!(e, "string_error: error");
|
||||||
|
|
||||||
let e = results.string_error(&mut store, 2.0).err().expect("trap");
|
let e = results
|
||||||
|
.call_string_error(&mut store, 2.0)
|
||||||
|
.err()
|
||||||
|
.expect("trap");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{}", e.source().expect("trap message is stored in source")),
|
format!("{}", e.source().expect("trap message is stored in source")),
|
||||||
"string_error: trap"
|
"string_error: trap"
|
||||||
@@ -328,7 +334,7 @@ mod enum_error {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
results
|
results
|
||||||
.foo()
|
.foo()
|
||||||
.enum_error(&mut store, 0.0)
|
.call_enum_error(&mut store, 0.0)
|
||||||
.expect("no trap")
|
.expect("no trap")
|
||||||
.expect("no error returned"),
|
.expect("no error returned"),
|
||||||
0.0
|
0.0
|
||||||
@@ -336,7 +342,7 @@ mod enum_error {
|
|||||||
|
|
||||||
let e = results
|
let e = results
|
||||||
.foo()
|
.foo()
|
||||||
.enum_error(&mut store, 1.0)
|
.call_enum_error(&mut store, 1.0)
|
||||||
.expect("no trap")
|
.expect("no trap")
|
||||||
.err()
|
.err()
|
||||||
.expect("error returned");
|
.expect("error returned");
|
||||||
@@ -344,7 +350,7 @@ mod enum_error {
|
|||||||
|
|
||||||
let e = results
|
let e = results
|
||||||
.foo()
|
.foo()
|
||||||
.enum_error(&mut store, 2.0)
|
.call_enum_error(&mut store, 2.0)
|
||||||
.err()
|
.err()
|
||||||
.expect("trap");
|
.expect("trap");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -458,7 +464,7 @@ mod record_error {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
results
|
results
|
||||||
.foo()
|
.foo()
|
||||||
.record_error(&mut store, 0.0)
|
.call_record_error(&mut store, 0.0)
|
||||||
.expect("no trap")
|
.expect("no trap")
|
||||||
.expect("no error returned"),
|
.expect("no error returned"),
|
||||||
0.0
|
0.0
|
||||||
@@ -466,7 +472,7 @@ mod record_error {
|
|||||||
|
|
||||||
let e = results
|
let e = results
|
||||||
.foo()
|
.foo()
|
||||||
.record_error(&mut store, 1.0)
|
.call_record_error(&mut store, 1.0)
|
||||||
.expect("no trap")
|
.expect("no trap")
|
||||||
.err()
|
.err()
|
||||||
.expect("error returned");
|
.expect("error returned");
|
||||||
@@ -480,7 +486,7 @@ mod record_error {
|
|||||||
|
|
||||||
let e = results
|
let e = results
|
||||||
.foo()
|
.foo()
|
||||||
.record_error(&mut store, 2.0)
|
.call_record_error(&mut store, 2.0)
|
||||||
.err()
|
.err()
|
||||||
.expect("trap");
|
.expect("trap");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -594,7 +600,7 @@ mod variant_error {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
results
|
results
|
||||||
.foo()
|
.foo()
|
||||||
.variant_error(&mut store, 0.0)
|
.call_variant_error(&mut store, 0.0)
|
||||||
.expect("no trap")
|
.expect("no trap")
|
||||||
.expect("no error returned"),
|
.expect("no error returned"),
|
||||||
0.0
|
0.0
|
||||||
@@ -602,7 +608,7 @@ mod variant_error {
|
|||||||
|
|
||||||
let e = results
|
let e = results
|
||||||
.foo()
|
.foo()
|
||||||
.variant_error(&mut store, 1.0)
|
.call_variant_error(&mut store, 1.0)
|
||||||
.expect("no trap")
|
.expect("no trap")
|
||||||
.err()
|
.err()
|
||||||
.expect("error returned");
|
.expect("error returned");
|
||||||
@@ -616,7 +622,7 @@ mod variant_error {
|
|||||||
|
|
||||||
let e = results
|
let e = results
|
||||||
.foo()
|
.foo()
|
||||||
.variant_error(&mut store, 2.0)
|
.call_variant_error(&mut store, 2.0)
|
||||||
.err()
|
.err()
|
||||||
.expect("trap");
|
.expect("trap");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
Reference in New Issue
Block a user