Skip to content

Commit

Permalink
feat: improve compile errors for async commands
Browse files Browse the repository at this point in the history
Async commands that contain references in their
arguments currently have to return `Result`.
Once issue tauri-apps#2533 is resolved, this commit can be
reverted.
  • Loading branch information
Pascal-So committed Jan 22, 2023
1 parent 763f0bd commit 87cba1b
Showing 1 changed file with 53 additions and 1 deletion.
54 changes: 53 additions & 1 deletion core/tauri-macros/src/command/wrapper.rs
Expand Up @@ -5,7 +5,7 @@
use heck::{ToLowerCamelCase, ToSnakeCase};
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use quote::{format_ident, quote, quote_spanned};
use syn::{
ext::IdentExt,
parse::{Parse, ParseStream},
Expand Down Expand Up @@ -103,6 +103,58 @@ pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream {
resolver: format_ident!("__tauri_resolver__"),
};

// Tauri currently doesn't support async commands that take a reference as input and don't return
// a result. See: https://github.com/tauri-apps/tauri/issues/2533
//
// For now, we provide an informative error message to the user in that case. Once #2533 is
// resolved, this check can be removed.
if function.sig.asyncness.is_some() {
let mut returns_result = false;
if let syn::ReturnType::Type(_, ty) = &function.sig.output {
if let syn::Type::Path(path) = &**ty {
if path.path.segments.last().unwrap().ident == "Result" {
returns_result = true;
}
}
}

if !returns_result {
// This check won't catch all possible problems but it should catch the most common ones.
let mut ref_argument_span = None;

for arg in &function.sig.inputs {
if let syn::FnArg::Typed(pat) = arg {
match &*pat.ty {
syn::Type::Reference(_) => {
ref_argument_span = Some(pat.span());
}
syn::Type::Path(path) => {
// Check if the type contains a lifetime argument
let last = path.path.segments.last().unwrap();
if let syn::PathArguments::AngleBracketed(args) = &last.arguments {
if args
.args
.iter()
.any(|arg| matches!(arg, syn::GenericArgument::Lifetime(_)))
{
ref_argument_span = Some(pat.span());
}
}
}
_ => {}
}

if let Some(span) = ref_argument_span {
return quote_spanned! {
span => compile_error!("async commands that take non-'static inputs must return a `Result`");
}
.into();
}
}
}
}
}

// body to the command wrapper or a `compile_error!` of an error occurred while parsing it.
let body = syn::parse::<WrapperAttributes>(attributes)
.map(|mut attrs| {
Expand Down

0 comments on commit 87cba1b

Please sign in to comment.