use lifetimes on types that require it

This commit is contained in:
Pat Hickey
2020-01-31 15:18:49 -08:00
parent 29c3ef9d09
commit f321f05a98
5 changed files with 81 additions and 31 deletions

View File

@@ -2,7 +2,7 @@ use proc_macro2::TokenStream;
use quote::quote; use quote::quote;
use crate::names::Names; 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 { pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream {
let ident = names.func(&func.name); 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), witx::TypePassedBy::Value(atom) => names.atom_type(atom),
_ => unreachable!("err should always be passed by value"), _ => 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! { quote! {
let err: #err_typename = ::memory::GuestErrorType::from_error(e, ctx); let err: #err_typename = ::memory::GuestErrorType::from_error(e, ctx);
return #abi_ret::from(err); 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 marshal_rets_post = marshal_rets.map(|(_pre, post)| post);
let success = if let Some(err_type) = err_type { 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! { quote! {
let success:#err_typename = ::memory::GuestErrorType::success(); let success:#err_typename = ::memory::GuestErrorType::success();
#abi_ret::from(success) #abi_ret::from(success)
@@ -133,7 +133,7 @@ fn marshal_arg(
error_handling: TokenStream, error_handling: TokenStream,
) -> TokenStream { ) -> TokenStream {
let tref = &param.tref; let tref = &param.tref;
let interface_typename = names.type_ref(&tref); let interface_typename = names.type_ref(&tref, anon_lifetime());
let try_into_conversion = { let try_into_conversion = {
let name = names.func_param(&param.name); let name = names.func_param(&param.name);
@@ -180,7 +180,7 @@ fn marshal_arg(
witx::BuiltinType::String => unimplemented!("string types unimplemented"), witx::BuiltinType::String => unimplemented!("string types unimplemented"),
}, },
witx::Type::Pointer(pointee) => { 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(&param.name); let name = names.func_param(&param.name);
quote! { quote! {
let #name = match memory.ptr_mut::<#pointee_type>(#name as u32) { let #name = match memory.ptr_mut::<#pointee_type>(#name as u32) {
@@ -192,7 +192,7 @@ fn marshal_arg(
} }
} }
witx::Type::ConstPointer(pointee) => { 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(&param.name); let name = names.func_param(&param.name);
quote! { quote! {
let #name = match memory.ptr::<#pointee_type>(#name as u32) { 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) => { 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(&param.name); let arg_name = names.func_ptr_binding(&param.name);
let name = names.func_param(&param.name); let name = names.func_param(&param.name);
quote! { quote! {
@@ -222,7 +222,7 @@ fn marshal_arg(
} }
} }
witx::Type::Struct(s) if !struct_is_copy(&s) => { 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(&param.name); let arg_name = names.func_ptr_binding(&param.name);
let name = names.func_param(&param.name); let name = names.func_param(&param.name);
quote! { quote! {
@@ -251,7 +251,7 @@ fn marshal_result(
let tref = &result.tref; let tref = &result.tref;
let write_val_to_ptr = { 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. // core type is given func_ptr_binding name.
let ptr_name = names.func_ptr_binding(&result.name); let ptr_name = names.func_ptr_binding(&result.name);
let pre = quote! { let pre = quote! {

View File

@@ -2,6 +2,7 @@ use proc_macro2::TokenStream;
use quote::quote; use quote::quote;
use crate::names::Names; use crate::names::Names;
use crate::types::anon_lifetime;
use witx::Module; use witx::Module;
pub fn define_module_trait(names: &Names, m: &Module) -> TokenStream { 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 funcname = names.func(&f.name);
let args = f.params.iter().map(|arg| { let args = f.params.iter().map(|arg| {
let arg_name = names.func_param(&arg.name); 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() { let arg_type = match arg.tref.type_().passed_by() {
witx::TypePassedBy::Value { .. } => quote!(#arg_typename), witx::TypePassedBy::Value { .. } => quote!(#arg_typename),
witx::TypePassedBy::Pointer { .. } => quote!(&#arg_typename), witx::TypePassedBy::Pointer { .. } => quote!(&#arg_typename),
@@ -22,11 +23,11 @@ pub fn define_module_trait(names: &Names, m: &Module) -> TokenStream {
.results .results
.iter() .iter()
.skip(1) .skip(1)
.map(|ret| names.type_ref(&ret.tref)); .map(|ret| names.type_ref(&ret.tref, anon_lifetime()));
let err = f let err = f
.results .results
.get(0) .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!(())); .unwrap_or(quote!(()));
quote!(fn #funcname(&mut self, #(#args),*) -> Result<(#(#rets),*), #err>;) quote!(fn #funcname(&mut self, #(#args),*) -> Result<(#(#rets),*), #err>;)
}); });

View File

@@ -3,6 +3,7 @@ use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use witx::{AtomType, BuiltinType, Id, TypeRef}; use witx::{AtomType, BuiltinType, Id, TypeRef};
use crate::types::type_needs_lifetime;
use crate::Config; use crate::Config;
#[derive(Debug, Clone)] #[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 { match tref {
TypeRef::Name(nt) => { TypeRef::Name(nt) => {
let ident = self.type_(&nt.name); let ident = self.type_(&nt.name);
if type_needs_lifetime(&nt.tref) {
quote!(#ident<#lifetime>)
} else {
quote!(#ident) quote!(#ident)
} }
}
TypeRef::Value(ty) => match &**ty { TypeRef::Value(ty) => match &**ty {
witx::Type::Builtin(builtin) => self.builtin_type(*builtin), witx::Type::Builtin(builtin) => self.builtin_type(*builtin),
witx::Type::Pointer(pointee) => { witx::Type::Pointer(pointee) => {
let pointee_type = self.type_ref(&pointee); let pointee_type = self.type_ref(&pointee, lifetime.clone());
quote!(::memory::GuestPtrMut<#pointee_type>) quote!(::memory::GuestPtrMut<#lifetime, #pointee_type>)
} }
witx::Type::ConstPointer(pointee) => { witx::Type::ConstPointer(pointee) => {
let pointee_type = self.type_ref(&pointee); let pointee_type = self.type_ref(&pointee, lifetime.clone());
quote!(::memory::GuestPtr<#pointee_type>) quote!(::memory::GuestPtr<#lifetime, #pointee_type>)
} }
_ => unimplemented!("anonymous type ref"), _ => unimplemented!("anonymous type ref"),
}, },

View File

@@ -21,8 +21,12 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea
witx::Type::Union(_) => unimplemented!("union types"), witx::Type::Union(_) => unimplemented!("union types"),
witx::Type::Handle(_h) => unimplemented!("handle types"), witx::Type::Handle(_h) => unimplemented!("handle types"),
witx::Type::Builtin(b) => define_builtin(names, &namedtype.name, *b), witx::Type::Builtin(b) => define_builtin(names, &namedtype.name, *b),
witx::Type::Pointer { .. } => unimplemented!("pointer types"), witx::Type::Pointer(p) => {
witx::Type::ConstPointer { .. } => unimplemented!("constpointer types"), 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"), 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 { fn define_alias(names: &Names, name: &witx::Id, to: &witx::NamedType) -> TokenStream {
let ident = names.type_(name); let ident = names.type_(name);
let to = names.type_(&to.name); let rhs = names.type_(&to.name);
if type_needs_lifetime(&to.tref) {
quote!(pub type #ident = #to;) 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 { 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;) 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 { pub fn struct_is_copy(s: &witx::StructDatatype) -> bool {
s.members.iter().all(|m| match &*m.tref.type_() { s.members.iter().all(|m| match &*m.tref.type_() {
witx::Type::Struct(s) => struct_is_copy(&s), 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 member_decls = s.members.iter().map(|m| {
let name = names.struct_member(&m.name); 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_) quote!(pub #name: #type_)
}); });
let member_valids = s.member_layout().into_iter().map(|ml| { 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 offset = ml.offset as u32;
let fieldname = names.struct_member(&ml.member.name); let fieldname = names.struct_member(&ml.member.name);
quote! { quote! {
@@ -221,11 +245,11 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) -
witx::TypeRef::Value(ty) => match &**ty { witx::TypeRef::Value(ty) => match &**ty {
witx::Type::Builtin(builtin) => names.builtin_type(*builtin), witx::Type::Builtin(builtin) => names.builtin_type(*builtin),
witx::Type::Pointer(pointee) => { 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>) quote!(::memory::GuestPtrMut<'a, #pointee_type>)
} }
witx::Type::ConstPointer(pointee) => { 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>) quote!(::memory::GuestPtr<'a, #pointee_type>)
} }
_ => unimplemented!("other anonymous struct members"), _ => 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::TypeRef::Value(ty) => match &**ty {
witx::Type::Builtin(builtin) => names.builtin_type(*builtin), witx::Type::Builtin(builtin) => names.builtin_type(*builtin),
witx::Type::Pointer(pointee) => { 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>) quote!(::memory::GuestPtrMut::<#pointee_type>)
} }
witx::Type::ConstPointer(pointee) => { 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>) quote!(::memory::GuestPtr::<#pointee_type>)
} }
_ => unimplemented!("other anonymous struct members"), _ => 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) => { witx::Type::Pointer(pointee) => {
let pointee_type = names.type_ref(&pointee); let pointee_type = names.type_ref(&pointee, anon_lifetime());
quote! { quote! {
let #name = ::memory::GuestPtrMut::<#pointee_type>::read_from_guest(&location.cast(#offset)?)?; let #name = ::memory::GuestPtrMut::<#pointee_type>::read_from_guest(&location.cast(#offset)?)?;
} }
} }
witx::Type::ConstPointer(pointee) => { witx::Type::ConstPointer(pointee) => {
let pointee_type = names.type_ref(&pointee); let pointee_type = names.type_ref(&pointee, anon_lifetime());
quote! { quote! {
let #name = ::memory::GuestPtr::<#pointee_type>::read_from_guest(&location.cast(#offset)?)?; 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 { fn int_repr_tokens(int_repr: witx::IntRepr) -> TokenStream {
match int_repr { match int_repr {
witx::IntRepr::U8 => quote!(u8), witx::IntRepr::U8 => quote!(u8),
@@ -356,3 +393,7 @@ fn atom_token(atom: witx::AtomType) -> TokenStream {
witx::AtomType::F64 => quote!(f64), witx::AtomType::F64 => quote!(f64),
} }
} }
pub fn anon_lifetime() -> TokenStream {
quote!('_)
}

View File

@@ -24,6 +24,9 @@
(field $first (@witx const_pointer s32)) (field $first (@witx const_pointer s32))
(field $second (@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 (module $foo
(@interface func (export "bar") (@interface func (export "bar")
(param $an_int u32) (param $an_int u32)