diff --git a/components/salsa-macros/src/query_group.rs b/components/salsa-macros/src/query_group.rs index c4e2af4a..65003b96 100644 --- a/components/salsa-macros/src/query_group.rs +++ b/components/salsa-macros/src/query_group.rs @@ -37,14 +37,13 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream let mut queries = vec![]; for item in input.items { if let TraitItem::Method(method) = item { + let query_name = method.sig.ident.to_string(); + let mut storage = QueryStorage::Memoized; let mut cycle = None; let mut invoke = None; - let query_name = method.sig.ident.to_string(); - let mut query_type = Ident::new( - &format!("{}Query", method.sig.ident.to_string().to_camel_case()), - Span::call_site(), - ); + + let mut query_type = format_ident!("{}Query", query_name.to_string().to_camel_case()); let mut num_storages = 0; // Extract attributes. @@ -88,9 +87,10 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream } } + let sig_span = method.sig.span(); // Check attribute combinations. if num_storages > 1 { - return Error::new(method.sig.span(), "multiple storage attributes specified") + return Error::new(sig_span, "multiple storage attributes specified") .to_compile_error() .into(); } @@ -112,26 +112,27 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream Some(FnArg::Receiver(sr)) if sr.mutability.is_none() => (), _ => { return Error::new( - method.sig.span(), - format!( - "first argument of query `{}` must be `&self`", - method.sig.ident, - ), + sig_span, + format!("first argument of query `{}` must be `&self`", query_name), ) .to_compile_error() .into(); } } - let mut keys: Vec = vec![]; - for arg in iter { - match *arg { - FnArg::Typed(ref arg) => { - keys.push((*arg.ty).clone()); - } - ref arg => { + let mut keys: Vec<(Ident, Type)> = vec![]; + for (idx, arg) in iter.enumerate() { + match arg { + FnArg::Typed(syn::PatType { pat, ty, .. }) => keys.push(( + match pat.as_ref() { + syn::Pat::Ident(ident_pat) => ident_pat.ident.clone(), + _ => format_ident!("key{}", idx), + }, + Type::clone(ty), + )), + arg => { return Error::new( arg.span(), - format!("unsupported argument `{:?}` of `{}`", arg, method.sig.ident,), + format!("unsupported argument `{:?}` of `{}`", arg, query_name,), ) .to_compile_error() .into(); @@ -145,10 +146,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream ref ret => { return Error::new( ret.span(), - format!( - "unsupported return type `{:?}` of `{}`", - ret, method.sig.ident - ), + format!("unsupported return type `{:?}` of `{}`", ret, query_name), ) .to_compile_error() .into(); @@ -165,23 +163,15 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream // // fn lookup_foo(&self, x: u32) -> (Key1, Key2) let lookup_query = if let QueryStorage::Interned = storage { - let lookup_query_type = Ident::new( - &format!( - "{}LookupQuery", - method.sig.ident.to_string().to_camel_case() - ), - Span::call_site(), - ); - let lookup_fn_name = Ident::new( - &format!("lookup_{}", method.sig.ident.to_string()), - method.sig.ident.span(), - ); - let keys = &keys; + let lookup_query_type = + format_ident!("{}LookupQuery", query_name.to_string().to_camel_case()); + let lookup_fn_name = format_ident!("lookup_{}", query_name); + let keys = keys.iter().map(|(_, ty)| ty); let lookup_value: Type = parse_quote!((#(#keys),*)); - let lookup_keys = vec![value.clone()]; + let lookup_keys = vec![(parse_quote! { key }, value.clone())]; Some(Query { query_type: lookup_query_type, - query_name: format!("lookup_{}", query_name), + query_name: format!("{}", lookup_fn_name), fn_name: lookup_fn_name, attrs: vec![], // FIXME -- some automatically generated docs on this method? storage: QueryStorage::InternedLookup { @@ -212,20 +202,15 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream } } - let group_storage = Ident::new( - &format!("{}GroupStorage__", trait_name.to_string()), - Span::call_site(), - ); + let group_storage = format_ident!("{}GroupStorage__", trait_name, span = Span::call_site()); let mut query_fn_declarations = proc_macro2::TokenStream::new(); let mut query_fn_definitions = proc_macro2::TokenStream::new(); let mut storage_fields = proc_macro2::TokenStream::new(); let mut queries_with_storage = vec![]; for query in &queries { - let key_names: &Vec<_> = &(0..query.keys.len()) - .map(|i| Ident::new(&format!("key{}", i), Span::call_site())) - .collect(); - let keys = &query.keys; + let (key_names, keys): (Vec<_>, Vec<_>) = + query.keys.iter().map(|(pat, ty)| (pat, ty)).unzip(); let value = &query.value; let fn_name = &query.fn_name; let qt = &query.query_type; @@ -266,9 +251,8 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream // For input queries, we need `set_foo` etc if let QueryStorage::Input = query.storage { - let set_fn_name = Ident::new(&format!("set_{}", fn_name), fn_name.span()); - let set_with_durability_fn_name = - Ident::new(&format!("set_{}_with_durability", fn_name), fn_name.span()); + let set_fn_name = format_ident!("set_{}", fn_name); + let set_with_durability_fn_name = format_ident!("set_{}_with_durability", fn_name); let set_fn_docs = format!( " @@ -396,7 +380,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream } QueryStorage::Transparent => panic!("should have been filtered"), }; - let keys = &query.keys; + let keys = query.keys.iter().map(|(_, ty)| ty); let value = &query.value; let query_name = &query.query_name; @@ -489,9 +473,8 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream // Implement the QueryFunction trait for queries which need it. if query.storage.needs_query_function() { let span = query.fn_name.span(); - let key_names: &Vec<_> = &(0..query.keys.len()) - .map(|i| Ident::new(&format!("key{}", i), Span::call_site())) - .collect(); + + let key_names: Vec<_> = query.keys.iter().map(|(pat, _)| pat).collect(); let key_pattern = if query.keys.len() == 1 { quote! { #(#key_names),* } } else { @@ -683,7 +666,7 @@ struct Query { attrs: Vec, query_type: Ident, storage: QueryStorage, - keys: Vec, + keys: Vec<(Ident, syn::Type)>, value: syn::Type, invoke: Option, cycle: Option,