wiggle: new error configuration for generating a "trappable error" (#5276)

* Add a new "trappable" mode for wiggle to make an error type

start refactoring how errors are generated and configured

put a pin in this - you can now configure a generated error

but i need to go fix Names

Names is no longer a struct, rt is hardcoded to wiggle

rest of fixes to pass tests

its called a trappable error now

don't generate UserErrorConversion trait if empty

mention in macro docs

* undo omitting the user error conversion trait when empty
This commit is contained in:
Pat Hickey
2022-11-16 08:54:41 -08:00
committed by GitHub
parent 1bd78f1a35
commit 22433ed726
15 changed files with 561 additions and 464 deletions

View File

@@ -1,7 +1,7 @@
use crate::codegen_settings::CodegenSettings;
use crate::codegen_settings::{CodegenSettings, ErrorType};
use crate::lifetimes::anon_lifetime;
use crate::module_trait::passed_by_reference;
use crate::names::Names;
use crate::names;
use crate::types::WiggleType;
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
@@ -9,54 +9,50 @@ use std::mem;
use witx::Instruction;
pub fn define_func(
names: &Names,
module: &witx::Module,
func: &witx::InterfaceFunc,
settings: &CodegenSettings,
) -> TokenStream {
let (ts, _bounds) = _define_func(names, module, func, settings);
let (ts, _bounds) = _define_func(module, func, settings);
ts
}
pub fn func_bounds(
names: &Names,
module: &witx::Module,
func: &witx::InterfaceFunc,
settings: &CodegenSettings,
) -> Vec<Ident> {
let (_ts, bounds) = _define_func(names, module, func, settings);
let (_ts, bounds) = _define_func(module, func, settings);
bounds
}
fn _define_func(
names: &Names,
module: &witx::Module,
func: &witx::InterfaceFunc,
settings: &CodegenSettings,
) -> (TokenStream, Vec<Ident>) {
let rt = names.runtime_mod();
let ident = names.func(&func.name);
let ident = names::func(&func.name);
let (wasm_params, wasm_results) = func.wasm_signature();
let param_names = (0..wasm_params.len())
.map(|i| Ident::new(&format!("arg{}", i), Span::call_site()))
.collect::<Vec<_>>();
let abi_params = wasm_params.iter().zip(&param_names).map(|(arg, name)| {
let wasm = names.wasm_type(*arg);
let wasm = names::wasm_type(*arg);
quote!(#name : #wasm)
});
let abi_ret = match wasm_results.len() {
0 => quote!(()),
1 => {
let ty = names.wasm_type(wasm_results[0]);
let ty = names::wasm_type(wasm_results[0]);
quote!(#ty)
}
_ => unimplemented!(),
};
let mut body = TokenStream::new();
let mut bounds = vec![names.trait_name(&module.name)];
let mut bounds = vec![names::trait_name(&module.name)];
func.call_interface(
&module.name,
&mut Rust {
@@ -64,8 +60,6 @@ fn _define_func(
params: &param_names,
block_storage: Vec::new(),
blocks: Vec::new(),
rt: &rt,
names,
module,
funcname: func.name.as_str(),
settings,
@@ -76,8 +70,8 @@ fn _define_func(
let mod_name = &module.name.as_str();
let func_name = &func.name.as_str();
let mk_span = quote!(
let _span = #rt::tracing::span!(
#rt::tracing::Level::TRACE,
let _span = wiggle::tracing::span!(
wiggle::tracing::Level::TRACE,
"wiggle abi",
module = #mod_name,
function = #func_name
@@ -99,9 +93,9 @@ fn _define_func(
#[allow(unreachable_code)] // deals with warnings in noreturn functions
pub fn #ident(
ctx: &mut (impl #(#bounds)+*),
memory: &dyn #rt::GuestMemory,
memory: &dyn wiggle::GuestMemory,
#(#abi_params),*
) -> #rt::anyhow::Result<#abi_ret> {
) -> wiggle::anyhow::Result<#abi_ret> {
use std::convert::TryFrom as _;
#traced_body
}
@@ -111,7 +105,7 @@ fn _define_func(
} else {
let traced_body = if settings.tracing.enabled_for(&mod_name, &func_name) {
quote!(
use #rt::tracing::Instrument as _;
use wiggle::tracing::Instrument as _;
#mk_span
async move {
#body
@@ -129,9 +123,9 @@ fn _define_func(
#[allow(unreachable_code)] // deals with warnings in noreturn functions
pub fn #ident<'a>(
ctx: &'a mut (impl #(#bounds)+*),
memory: &'a dyn #rt::GuestMemory,
memory: &'a dyn wiggle::GuestMemory,
#(#abi_params),*
) -> impl std::future::Future<Output = #rt::anyhow::Result<#abi_ret>> + 'a {
) -> impl std::future::Future<Output = wiggle::anyhow::Result<#abi_ret>> + 'a {
use std::convert::TryFrom as _;
#traced_body
}
@@ -146,8 +140,6 @@ struct Rust<'a> {
params: &'a [Ident],
block_storage: Vec<TokenStream>,
blocks: Vec<TokenStream>,
rt: &'a TokenStream,
names: &'a Names,
module: &'a witx::Module,
funcname: &'a str,
settings: &'a CodegenSettings,
@@ -196,17 +188,16 @@ impl witx::Bindgen for Rust<'_> {
operands: &mut Vec<TokenStream>,
results: &mut Vec<TokenStream>,
) {
let rt = self.rt;
let wrap_err = |location: &str| {
let modulename = self.module.name.as_str();
let funcname = self.funcname;
quote! {
|e| {
#rt::GuestError::InFunc {
wiggle::GuestError::InFunc {
modulename: #modulename,
funcname: #funcname,
location: #location,
err: Box::new(#rt::GuestError::from(e)),
err: Box::new(wiggle::GuestError::from(e)),
}
}
}
@@ -226,9 +217,9 @@ impl witx::Bindgen for Rust<'_> {
Instruction::PointerFromI32 { ty } | Instruction::ConstPointerFromI32 { ty } => {
let val = operands.pop().unwrap();
let pointee_type = self.names.type_ref(ty, anon_lifetime());
let pointee_type = names::type_ref(ty, anon_lifetime());
results.push(quote! {
#rt::GuestPtr::<#pointee_type>::new(memory, #val as u32)
wiggle::GuestPtr::<#pointee_type>::new(memory, #val as u32)
});
}
@@ -238,12 +229,12 @@ impl witx::Bindgen for Rust<'_> {
let ty = match &**ty.type_() {
witx::Type::Builtin(witx::BuiltinType::Char) => quote!(str),
_ => {
let ty = self.names.type_ref(ty, anon_lifetime());
let ty = names::type_ref(ty, anon_lifetime());
quote!([#ty])
}
};
results.push(quote! {
#rt::GuestPtr::<#ty>::new(memory, (#ptr as u32, #len as u32));
wiggle::GuestPtr::<#ty>::new(memory, (#ptr as u32, #len as u32));
})
}
@@ -252,7 +243,7 @@ impl witx::Bindgen for Rust<'_> {
// out, and afterwards we call the function with those bindings.
let mut args = Vec::new();
for (i, param) in func.params.iter().enumerate() {
let name = self.names.func_param(&param.name);
let name = names::func_param(&param.name);
let val = &operands[i];
self.src.extend(quote!(let #name = #val;));
if passed_by_reference(param.tref.type_()) {
@@ -271,21 +262,21 @@ impl witx::Bindgen for Rust<'_> {
.params
.iter()
.map(|param| {
let name = self.names.func_param(&param.name);
let name = names::func_param(&param.name);
if param.impls_display() {
quote!( #name = #rt::tracing::field::display(&#name) )
quote!( #name = wiggle::tracing::field::display(&#name) )
} else {
quote!( #name = #rt::tracing::field::debug(&#name) )
quote!( #name = wiggle::tracing::field::debug(&#name) )
}
})
.collect::<Vec<_>>();
self.src.extend(quote! {
#rt::tracing::event!(#rt::tracing::Level::TRACE, #(#args),*);
wiggle::tracing::event!(wiggle::tracing::Level::TRACE, #(#args),*);
});
}
let trait_name = self.names.trait_name(&self.module.name);
let ident = self.names.func(&func.name);
let trait_name = names::trait_name(&self.module.name);
let ident = names::func(&func.name);
if self.settings.get_async(&self.module, &func).is_sync() {
self.src.extend(quote! {
let ret = #trait_name::#ident(ctx, #(#args),*);
@@ -301,9 +292,9 @@ impl witx::Bindgen for Rust<'_> {
.enabled_for(self.module.name.as_str(), self.funcname)
{
self.src.extend(quote! {
#rt::tracing::event!(
#rt::tracing::Level::TRACE,
result = #rt::tracing::field::debug(&ret),
wiggle::tracing::event!(
wiggle::tracing::Level::TRACE,
result = wiggle::tracing::field::debug(&ret),
);
});
}
@@ -322,11 +313,12 @@ impl witx::Bindgen for Rust<'_> {
Instruction::EnumLower { ty } => {
let val = operands.pop().unwrap();
let val = match self.settings.errors.for_name(ty) {
Some(custom) => {
let method = self.names.user_error_conversion_method(&custom);
Some(ErrorType::User(custom)) => {
let method = names::user_error_conversion_method(&custom);
self.bound(quote::format_ident!("UserErrorConversion"));
quote!(UserErrorConversion::#method(ctx, #val)?)
}
Some(ErrorType::Generated(_)) => quote!(#val.downcast()?),
None => val,
};
results.push(quote!(#val as i32));
@@ -336,10 +328,10 @@ impl witx::Bindgen for Rust<'_> {
let err = self.blocks.pop().unwrap();
let ok = self.blocks.pop().unwrap();
let val = operands.pop().unwrap();
let err_typename = self.names.type_ref(err_ty.unwrap(), anon_lifetime());
let err_typename = names::type_ref(err_ty.unwrap(), anon_lifetime());
results.push(quote! {
match #val {
Ok(e) => { #ok; <#err_typename as #rt::GuestErrorType>::success() as i32 }
Ok(e) => { #ok; <#err_typename as wiggle::GuestErrorType>::success() as i32 }
Err(e) => { #err }
}
});
@@ -369,9 +361,9 @@ impl witx::Bindgen for Rust<'_> {
let ptr = operands.pop().unwrap();
let val = operands.pop().unwrap();
let wrap_err = wrap_err(&format!("write {}", ty.name.as_str()));
let pointee_type = self.names.type_(&ty.name);
let pointee_type = names::type_(&ty.name);
self.src.extend(quote! {
#rt::GuestPtr::<#pointee_type>::new(memory, #ptr as u32)
wiggle::GuestPtr::<#pointee_type>::new(memory, #ptr as u32)
.write(#val)
.map_err(#wrap_err)?;
});
@@ -380,9 +372,9 @@ impl witx::Bindgen for Rust<'_> {
Instruction::Load { ty } => {
let ptr = operands.pop().unwrap();
let wrap_err = wrap_err(&format!("read {}", ty.name.as_str()));
let pointee_type = self.names.type_(&ty.name);
let pointee_type = names::type_(&ty.name);
results.push(quote! {
#rt::GuestPtr::<#pointee_type>::new(memory, #ptr as u32)
wiggle::GuestPtr::<#pointee_type>::new(memory, #ptr as u32)
.read()
.map_err(#wrap_err)?
});
@@ -390,7 +382,7 @@ impl witx::Bindgen for Rust<'_> {
Instruction::HandleFromI32 { ty } => {
let val = operands.pop().unwrap();
let ty = self.names.type_(&ty.name);
let ty = names::type_(&ty.name);
results.push(quote!(#ty::from(#val)));
}
@@ -418,7 +410,7 @@ impl witx::Bindgen for Rust<'_> {
Instruction::EnumLift { ty }
| Instruction::BitflagsFromI64 { ty }
| Instruction::BitflagsFromI32 { ty } => {
let ty = self.names.type_(&ty.name);
let ty = names::type_(&ty.name);
try_from(quote!(#ty))
}