diff --git a/crates/generate/src/funcs.rs b/crates/generate/src/funcs.rs index 8313fe0c1c..bd3d1f0349 100644 --- a/crates/generate/src/funcs.rs +++ b/crates/generate/src/funcs.rs @@ -2,7 +2,7 @@ use proc_macro2::TokenStream; use quote::quote; use crate::names::Names; -use crate::types::struct_is_copy; +use crate::types::{anon_lifetime, struct_is_copy}; pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream { let ident = names.func(&func.name); @@ -58,7 +58,7 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream { witx::TypePassedBy::Value(atom) => names.atom_type(atom), _ => unreachable!("err should always be passed by value"), }; - let err_typename = names.type_ref(&tref); + let err_typename = names.type_ref(&tref, anon_lifetime()); quote! { let err: #err_typename = ::memory::GuestErrorType::from_error(e, ctx); return #abi_ret::from(err); @@ -106,7 +106,7 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream { let marshal_rets_post = marshal_rets.map(|(_pre, post)| post); let success = if let Some(err_type) = err_type { - let err_typename = names.type_ref(&err_type); + let err_typename = names.type_ref(&err_type, anon_lifetime()); quote! { let success:#err_typename = ::memory::GuestErrorType::success(); #abi_ret::from(success) @@ -133,7 +133,7 @@ fn marshal_arg( error_handling: TokenStream, ) -> TokenStream { let tref = ¶m.tref; - let interface_typename = names.type_ref(&tref); + let interface_typename = names.type_ref(&tref, anon_lifetime()); let try_into_conversion = { let name = names.func_param(¶m.name); @@ -180,7 +180,7 @@ fn marshal_arg( witx::BuiltinType::String => unimplemented!("string types unimplemented"), }, witx::Type::Pointer(pointee) => { - let pointee_type = names.type_ref(pointee); + let pointee_type = names.type_ref(pointee, anon_lifetime()); let name = names.func_param(¶m.name); quote! { let #name = match memory.ptr_mut::<#pointee_type>(#name as u32) { @@ -192,7 +192,7 @@ fn marshal_arg( } } witx::Type::ConstPointer(pointee) => { - let pointee_type = names.type_ref(pointee); + let pointee_type = names.type_ref(pointee, anon_lifetime()); let name = names.func_param(¶m.name); quote! { let #name = match memory.ptr::<#pointee_type>(#name as u32) { @@ -204,7 +204,7 @@ fn marshal_arg( } } witx::Type::Struct(s) if struct_is_copy(&s) => { - let pointee_type = names.type_ref(tref); + let pointee_type = names.type_ref(tref, anon_lifetime()); let arg_name = names.func_ptr_binding(¶m.name); let name = names.func_param(¶m.name); quote! { @@ -222,7 +222,7 @@ fn marshal_arg( } } witx::Type::Struct(s) if !struct_is_copy(&s) => { - let pointee_type = names.type_ref(tref); + let pointee_type = names.type_ref(tref, anon_lifetime()); let arg_name = names.func_ptr_binding(¶m.name); let name = names.func_param(¶m.name); quote! { @@ -251,7 +251,7 @@ fn marshal_result( let tref = &result.tref; let write_val_to_ptr = { - let pointee_type = names.type_ref(tref); + let pointee_type = names.type_ref(tref, anon_lifetime()); // core type is given func_ptr_binding name. let ptr_name = names.func_ptr_binding(&result.name); let pre = quote! { diff --git a/crates/generate/src/module_trait.rs b/crates/generate/src/module_trait.rs index 19669fa410..c92fe85ffc 100644 --- a/crates/generate/src/module_trait.rs +++ b/crates/generate/src/module_trait.rs @@ -2,6 +2,7 @@ use proc_macro2::TokenStream; use quote::quote; use crate::names::Names; +use crate::types::anon_lifetime; use witx::Module; pub fn define_module_trait(names: &Names, m: &Module) -> TokenStream { @@ -10,7 +11,7 @@ pub fn define_module_trait(names: &Names, m: &Module) -> TokenStream { let funcname = names.func(&f.name); let args = f.params.iter().map(|arg| { let arg_name = names.func_param(&arg.name); - let arg_typename = names.type_ref(&arg.tref); + let arg_typename = names.type_ref(&arg.tref, anon_lifetime()); let arg_type = match arg.tref.type_().passed_by() { witx::TypePassedBy::Value { .. } => quote!(#arg_typename), witx::TypePassedBy::Pointer { .. } => quote!(&#arg_typename), @@ -22,11 +23,11 @@ pub fn define_module_trait(names: &Names, m: &Module) -> TokenStream { .results .iter() .skip(1) - .map(|ret| names.type_ref(&ret.tref)); + .map(|ret| names.type_ref(&ret.tref, anon_lifetime())); let err = f .results .get(0) - .map(|err_result| names.type_ref(&err_result.tref)) + .map(|err_result| names.type_ref(&err_result.tref, anon_lifetime())) .unwrap_or(quote!(())); quote!(fn #funcname(&mut self, #(#args),*) -> Result<(#(#rets),*), #err>;) }); diff --git a/crates/generate/src/names.rs b/crates/generate/src/names.rs index c9ad2ba253..3759113218 100644 --- a/crates/generate/src/names.rs +++ b/crates/generate/src/names.rs @@ -3,6 +3,7 @@ use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use witx::{AtomType, BuiltinType, Id, TypeRef}; +use crate::types::type_needs_lifetime; use crate::Config; #[derive(Debug, Clone)] @@ -47,21 +48,25 @@ impl Names { } } - pub fn type_ref(&self, tref: &TypeRef) -> TokenStream { + pub fn type_ref(&self, tref: &TypeRef, lifetime: TokenStream) -> TokenStream { match tref { TypeRef::Name(nt) => { let ident = self.type_(&nt.name); - quote!(#ident) + if type_needs_lifetime(&nt.tref) { + quote!(#ident<#lifetime>) + } else { + quote!(#ident) + } } TypeRef::Value(ty) => match &**ty { witx::Type::Builtin(builtin) => self.builtin_type(*builtin), witx::Type::Pointer(pointee) => { - let pointee_type = self.type_ref(&pointee); - quote!(::memory::GuestPtrMut<#pointee_type>) + let pointee_type = self.type_ref(&pointee, lifetime.clone()); + quote!(::memory::GuestPtrMut<#lifetime, #pointee_type>) } witx::Type::ConstPointer(pointee) => { - let pointee_type = self.type_ref(&pointee); - quote!(::memory::GuestPtr<#pointee_type>) + let pointee_type = self.type_ref(&pointee, lifetime.clone()); + quote!(::memory::GuestPtr<#lifetime, #pointee_type>) } _ => unimplemented!("anonymous type ref"), }, diff --git a/crates/generate/src/types.rs b/crates/generate/src/types.rs index 096015ae21..e5cd4c0abe 100644 --- a/crates/generate/src/types.rs +++ b/crates/generate/src/types.rs @@ -21,8 +21,12 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea witx::Type::Union(_) => unimplemented!("union types"), witx::Type::Handle(_h) => unimplemented!("handle types"), witx::Type::Builtin(b) => define_builtin(names, &namedtype.name, *b), - witx::Type::Pointer { .. } => unimplemented!("pointer types"), - witx::Type::ConstPointer { .. } => unimplemented!("constpointer types"), + witx::Type::Pointer(p) => { + define_witx_pointer(names, &namedtype.name, quote!(::memory::GuestPtrMut), p) + } + witx::Type::ConstPointer(p) => { + define_witx_pointer(names, &namedtype.name, quote!(::memory::GuestPtr), p) + } witx::Type::Array { .. } => unimplemented!("array types"), }, } @@ -30,9 +34,12 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea fn define_alias(names: &Names, name: &witx::Id, to: &witx::NamedType) -> TokenStream { let ident = names.type_(name); - let to = names.type_(&to.name); - - quote!(pub type #ident = #to;) + let rhs = names.type_(&to.name); + if type_needs_lifetime(&to.tref) { + quote!(pub type #ident<'a> = #rhs<'a>;) + } else { + quote!(pub type #ident = #rhs;) + } } fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenStream { @@ -133,6 +140,23 @@ fn define_builtin(names: &Names, name: &witx::Id, builtin: witx::BuiltinType) -> quote!(pub type #ident = #built;) } +pub fn type_needs_lifetime(tref: &witx::TypeRef) -> bool { + match &*tref.type_() { + witx::Type::Builtin(b) => match b { + witx::BuiltinType::String => unimplemented!(), + _ => false, + }, + witx::Type::Enum { .. } + | witx::Type::Flags { .. } + | witx::Type::Int { .. } + | witx::Type::Handle { .. } => false, + witx::Type::Struct(s) => !struct_is_copy(&s), + witx::Type::Union { .. } => true, + witx::Type::Pointer { .. } | witx::Type::ConstPointer { .. } => true, + witx::Type::Array { .. } => unimplemented!(), + } +} + pub fn struct_is_copy(s: &witx::StructDatatype) -> bool { s.members.iter().all(|m| match &*m.tref.type_() { witx::Type::Struct(s) => struct_is_copy(&s), @@ -158,11 +182,11 @@ fn define_copy_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) let member_decls = s.members.iter().map(|m| { let name = names.struct_member(&m.name); - let type_ = names.type_ref(&m.tref); + let type_ = names.type_ref(&m.tref, anon_lifetime()); quote!(pub #name: #type_) }); let member_valids = s.member_layout().into_iter().map(|ml| { - let type_ = names.type_ref(&ml.member.tref); + let type_ = names.type_ref(&ml.member.tref, anon_lifetime()); let offset = ml.offset as u32; let fieldname = names.struct_member(&ml.member.name); quote! { @@ -221,11 +245,11 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) - witx::TypeRef::Value(ty) => match &**ty { witx::Type::Builtin(builtin) => names.builtin_type(*builtin), witx::Type::Pointer(pointee) => { - let pointee_type = names.type_ref(&pointee); + let pointee_type = names.type_ref(&pointee, quote!('a)); quote!(::memory::GuestPtrMut<'a, #pointee_type>) } witx::Type::ConstPointer(pointee) => { - let pointee_type = names.type_ref(&pointee); + let pointee_type = names.type_ref(&pointee, quote!('a)); quote!(::memory::GuestPtr<'a, #pointee_type>) } _ => unimplemented!("other anonymous struct members"), @@ -239,11 +263,11 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) - witx::TypeRef::Value(ty) => match &**ty { witx::Type::Builtin(builtin) => names.builtin_type(*builtin), witx::Type::Pointer(pointee) => { - let pointee_type = names.type_ref(&pointee); + let pointee_type = names.type_ref(&pointee, anon_lifetime()); quote!(::memory::GuestPtrMut::<#pointee_type>) } witx::Type::ConstPointer(pointee) => { - let pointee_type = names.type_ref(&pointee); + let pointee_type = names.type_ref(&pointee, anon_lifetime()); quote!(::memory::GuestPtr::<#pointee_type>) } _ => unimplemented!("other anonymous struct members"), @@ -286,13 +310,13 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) - } } witx::Type::Pointer(pointee) => { - let pointee_type = names.type_ref(&pointee); + let pointee_type = names.type_ref(&pointee, anon_lifetime()); quote! { let #name = ::memory::GuestPtrMut::<#pointee_type>::read_from_guest(&location.cast(#offset)?)?; } } witx::Type::ConstPointer(pointee) => { - let pointee_type = names.type_ref(&pointee); + let pointee_type = names.type_ref(&pointee, anon_lifetime()); quote! { let #name = ::memory::GuestPtr::<#pointee_type>::read_from_guest(&location.cast(#offset)?)?; } @@ -340,6 +364,19 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) - } } } + +fn define_witx_pointer( + names: &Names, + name: &witx::Id, + pointer_type: TokenStream, + pointee: &witx::TypeRef, +) -> TokenStream { + let ident = names.type_(name); + let pointee_type = names.type_ref(pointee, quote!('a)); + + quote!(pub type #ident<'a> = #pointer_type<'a, #pointee_type>;) +} + fn int_repr_tokens(int_repr: witx::IntRepr) -> TokenStream { match int_repr { witx::IntRepr::U8 => quote!(u8), @@ -356,3 +393,7 @@ fn atom_token(atom: witx::AtomType) -> TokenStream { witx::AtomType::F64 => quote!(f64), } } + +pub fn anon_lifetime() -> TokenStream { + quote!('_) +} diff --git a/test.witx b/test.witx index 3fa2ae5ac7..41036284e1 100644 --- a/test.witx +++ b/test.witx @@ -24,6 +24,9 @@ (field $first (@witx const_pointer s32)) (field $second (@witx const_pointer s32)))) +(typename $named_ptr (@witx pointer f32)) +(typename $named_ptr_to_ptr (@witx pointer (@witx pointer f64))) + (module $foo (@interface func (export "bar") (param $an_int u32)