diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-06-22 20:21:41 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-06-22 20:21:41 +0800 |
| commit | d7c9ad94113cca2f782666e37a0aa4fb7b8d7d86 (patch) | |
| tree | 323dfc74a274463500ac52c7bb7b83029b771411 /mingling_macros | |
| parent | 232f31c6649e6348a5b0b64362f185f7f4db1dc0 (diff) | |
Support qualified type paths in four macros
Diffstat (limited to 'mingling_macros')
| -rw-r--r-- | mingling_macros/src/chain.rs | 6 | ||||
| -rw-r--r-- | mingling_macros/src/completion.rs | 29 | ||||
| -rw-r--r-- | mingling_macros/src/help.rs | 5 | ||||
| -rw-r--r-- | mingling_macros/src/lib.rs | 29 | ||||
| -rw-r--r-- | mingling_macros/src/renderer.rs | 14 | ||||
| -rw-r--r-- | mingling_macros/src/res_injection.rs | 16 |
6 files changed, 17 insertions, 82 deletions
diff --git a/mingling_macros/src/chain.rs b/mingling_macros/src/chain.rs index fb5999a..eaf43fb 100644 --- a/mingling_macros/src/chain.rs +++ b/mingling_macros/src/chain.rs @@ -377,15 +377,17 @@ pub fn chain_attr(attr: TokenStream, item: TokenStream) -> TokenStream { /// Builds a match arm for chain mapping pub fn build_chain_arm(struct_name: &Ident, previous_type: &TypePath) -> proc_macro2::TokenStream { + let enum_variant = &previous_type.path.segments.last().unwrap().ident; quote! { - #struct_name => #previous_type, + #struct_name => #enum_variant, } } /// Builds a match arm for chain existence check pub fn build_chain_exist_arm(previous_type: &TypePath) -> proc_macro2::TokenStream { + let enum_variant = &previous_type.path.segments.last().unwrap().ident; quote! { - Self::#previous_type => true, + Self::#enum_variant => true, } } diff --git a/mingling_macros/src/completion.rs b/mingling_macros/src/completion.rs index ba0de2e..720ac49 100644 --- a/mingling_macros/src/completion.rs +++ b/mingling_macros/src/completion.rs @@ -1,14 +1,13 @@ use proc_macro::TokenStream; use quote::quote; -use syn::spanned::Spanned; -use syn::{FnArg, Ident, ItemFn, PatType, Type, parse_macro_input}; +use syn::{Ident, ItemFn, TypePath, parse_macro_input}; #[cfg(feature = "comp")] pub fn completion_attr(attr: TokenStream, item: TokenStream) -> TokenStream { - // Parse the attribute arguments (e.g., HelloEntry from #[completion(HelloEntry)]) + // Parse the attribute arguments (e.g., HelloEntry or crate::EntryFine from #[completion(crate::EntryFine)]) use crate::get_global_set; - let previous_type_ident = if attr.is_empty() { + let previous_type_path: TypePath = if attr.is_empty() { return syn::Error::new( proc_macro2::Span::call_site(), "completion attribute requires a previous type argument, e.g. #[completion(HelloEntry)]", @@ -16,8 +15,9 @@ pub fn completion_attr(attr: TokenStream, item: TokenStream) -> TokenStream { .to_compile_error() .into(); } else { - parse_macro_input!(attr as Ident) + parse_macro_input!(attr as TypePath) }; + let previous_type_ident = &previous_type_path.path.segments.last().unwrap().ident; // Parse the function item let input_fn = parse_macro_input!(item as ItemFn); @@ -48,23 +48,6 @@ pub fn completion_attr(attr: TokenStream, item: TokenStream) -> TokenStream { .into(); } - // Check that the function parameter type is a single-segment type path (no `::`) - if let Some(arg) = inputs.first() - && let FnArg::Typed(PatType { ty, .. }) = arg - && let Type::Path(type_path) = &**ty - && type_path.path.segments.len() > 1 - { - return syn::Error::new( - type_path.span(), - format!( - "The type `{}` in #[completion] function must be a simple single-segment type, e.g. `HelloEntry` instead of `other::HelloEntry`. Qualified paths with `::` are not allowed here.", - quote! { #type_path } - ), - ) - .to_compile_error() - .into(); - } - // Get the function body let fn_body = &input_fn.block; @@ -93,7 +76,7 @@ pub fn completion_attr(attr: TokenStream, item: TokenStream) -> TokenStream { #vis struct #struct_name; impl ::mingling::Completion for #struct_name { - type Previous = #previous_type_ident; + type Previous = #previous_type_path; fn comp(#inputs) #output { #fn_body diff --git a/mingling_macros/src/help.rs b/mingling_macros/src/help.rs index 2721bf5..e9e91cf 100644 --- a/mingling_macros/src/help.rs +++ b/mingling_macros/src/help.rs @@ -71,11 +71,6 @@ pub fn help_attr(item: TokenStream) -> TokenStream { Err(e) => return e.to_compile_error().into(), }; - // Check that the entry type is a single-segment type (no `::`) - if let Some(err_tokens) = crate::check_single_segment_type(&entry_type, "#[help]") { - return err_tokens.into(); - } - // Validate return type if let Err(e) = validate_return_type(&input_fn.sig) { return e.to_compile_error().into(); diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs index e774335..204d59c 100644 --- a/mingling_macros/src/lib.rs +++ b/mingling_macros/src/lib.rs @@ -195,35 +195,6 @@ pub(crate) static CHAINS_EXIST: Registry = OnceLock::new(); pub(crate) static RENDERERS_EXIST: Registry = OnceLock::new(); pub(crate) static HELP_REQUESTS: Registry = OnceLock::new(); -/// Checks that a `TypePath` is a simple single-segment identifier (no `::` in the path). -/// -/// This is used by `#[renderer]`, `#[help]`, `#[chain]`, and `#[completion]` attribute macros -/// to ensure that the type in the function signature is a bare identifier like `Empty`, -/// not a qualified path like `other::Empty`. -/// -/// Returns `None` if the type is valid, or a `compile_error!` token stream if it contains `::`. -pub(crate) fn check_single_segment_type( - type_path: &syn::TypePath, - attr_name: &str, -) -> Option<proc_macro2::TokenStream> { - if type_path.path.segments.len() > 1 { - let type_str = quote! { #type_path }; - Some(quote! { - compile_error!(concat!( - "The type `", - #type_str, - "` in ", - #attr_name, - " function must be a simple single-segment type, ", - "e.g. `Empty` instead of `other::Empty`. ", - "Qualified paths with `::` are not allowed here." - )); - }) - } else { - None - } -} - /// Registers an outside-type as a member of a program group without modifying its definition. /// /// This macro allows you to use outside-types from external crates (like `std::io::Error`) diff --git a/mingling_macros/src/renderer.rs b/mingling_macros/src/renderer.rs index ac82799..c4b2786 100644 --- a/mingling_macros/src/renderer.rs +++ b/mingling_macros/src/renderer.rs @@ -44,11 +44,6 @@ pub fn renderer_attr(attr: TokenStream, item: TokenStream) -> TokenStream { Err(e) => return e.to_compile_error().into(), }; - // Check that the previous type is a single-segment type (no `::`) - if let Some(err_tokens) = crate::check_single_segment_type(&previous_type, "#[renderer]") { - return err_tokens.into(); - } - // Validate return type – now returns Some(type) if custom type, None if () let return_type = extract_return_type(&input_fn.sig); @@ -174,23 +169,26 @@ pub fn build_renderer_entry( struct_name: &syn::Ident, previous_type: &TypePath, ) -> proc_macro2::TokenStream { + let enum_variant = &previous_type.path.segments.last().unwrap().ident; quote! { - #struct_name => #previous_type, + #struct_name => #enum_variant, } } /// Builds the renderer existence check entry pub fn build_renderer_exist_entry(previous_type: &TypePath) -> proc_macro2::TokenStream { + let enum_variant = &previous_type.path.segments.last().unwrap().ident; quote! { - Self::#previous_type => true, + Self::#enum_variant => true, } } /// Builds the general renderer entry #[cfg(feature = "general_renderer")] pub fn build_general_renderer_entry(previous_type: &TypePath) -> proc_macro2::TokenStream { + let enum_variant = &previous_type.path.segments.last().unwrap().ident; quote! { - Self::#previous_type => { + Self::#enum_variant => { // SAFETY: Only types that match will enter this branch for forced conversion, // and `AnyOutput::new` ensures the type implements serde::Serialize let raw = unsafe { any.restore::<#previous_type>().unwrap_unchecked() }; diff --git a/mingling_macros/src/res_injection.rs b/mingling_macros/src/res_injection.rs index f2280e3..4f0be88 100644 --- a/mingling_macros/src/res_injection.rs +++ b/mingling_macros/src/res_injection.rs @@ -30,21 +30,7 @@ pub(crate) fn extract_args_info( FnArg::Typed(PatType { pat, ty, .. }) => { let param_pat = (**pat).clone(); match &**ty { - Type::Path(type_path) => { - // Check that the type is a single-segment type (no `::`) - if type_path.path.segments.len() > 1 { - return Err(syn::Error::new( - type_path.span(), - format!( - "The type `{}` must be a simple single-segment type, \ - e.g. `Empty` instead of `other::Empty`. \ - Qualified paths with `::` are not allowed here.", - quote! { #type_path } - ), - )); - } - (param_pat, type_path.clone()) - } + Type::Path(type_path) => (param_pat, type_path.clone()), Type::Reference(_) => { return Err(syn::Error::new( ty.span(), |
