From 8498a8c4826a10c8c04ad1b9c45d83fb0759121b Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Tue, 23 Jun 2026 01:12:01 +0800 Subject: Add entry-str dedup and registry cleanup in final gen --- CHANGELOG.md | 2 ++ mingling_macros/src/chain.rs | 10 +++++++--- mingling_macros/src/completion.rs | 1 + mingling_macros/src/help.rs | 12 ++++++++---- mingling_macros/src/lib.rs | 22 ++++++++++++++++++++++ mingling_macros/src/renderer.rs | 1 + 6 files changed, 41 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9bb4d4..1fefdfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,8 @@ 3. **\[macros\]** Consolidated `__dispatch_program_renderers!` and `__dispatch_program_chains!` from `macro_rules!` into the `program_final_gen` proc-macro (`mingling_macros/src/lib.rs`), removing them from `mingling_core/src/program.rs`. The `render()` and `do_chain()` match dispatch is now generated directly by the proc-macro, using a compile-time `ASYNC_ENABLED` constant (via `#[cfg(feature = "async")]`) to select the correct sync/async signature at proc-macro compilation time, replacing the previous `#[cfg]`-gated `macro_rules!` dispatch that relied on per-crate feature resolution. +4. **\[macros\]** Added global registry cleanup at the end of `program_final_gen`, clearing all `OnceLock>` registries after consuming them. This prevents stale state accumulation across compilation sessions. + #### Features: 1. **\[core\]** Added the `unpack_chain_process!` macro for ergonomically extracting the inner value from a `ChainProcess` result. diff --git a/mingling_macros/src/chain.rs b/mingling_macros/src/chain.rs index a678858..92020ea 100644 --- a/mingling_macros/src/chain.rs +++ b/mingling_macros/src/chain.rs @@ -440,9 +440,13 @@ pub fn register_chain(input: TokenStream) -> TokenStream { .unwrap() .ident .to_string(); - if let Err(err) = - crate::check_duplicate_variant(&chains, &variant_name, "chain", previous_type.span()) - { + if let Err(err) = crate::check_duplicate_variant( + &chains, + &chain_entry_str, + &variant_name, + "chain", + previous_type.span(), + ) { return err.into(); } diff --git a/mingling_macros/src/completion.rs b/mingling_macros/src/completion.rs index c4870d9..ae01462 100644 --- a/mingling_macros/src/completion.rs +++ b/mingling_macros/src/completion.rs @@ -158,6 +158,7 @@ pub fn completion_attr(attr: TokenStream, item: TokenStream) -> TokenStream { let variant_name = previous_type_ident.to_string(); if let Err(err) = crate::check_duplicate_variant( &completions, + &completion_str, &variant_name, "completion", previous_type_path.span(), diff --git a/mingling_macros/src/help.rs b/mingling_macros/src/help.rs index e1095e6..6d427b9 100644 --- a/mingling_macros/src/help.rs +++ b/mingling_macros/src/help.rs @@ -110,9 +110,13 @@ pub fn help_attr(item: TokenStream) -> TokenStream { let variant_name = entry_type.path.segments.last().unwrap().ident.to_string(); { let helps = get_global_set(&crate::HELP_REQUESTS).lock().unwrap(); - if let Err(err) = - crate::check_duplicate_variant(&helps, &variant_name, "help", entry_type.span()) - { + if let Err(err) = crate::check_duplicate_variant( + &helps, + &entry_str, + &variant_name, + "help", + entry_type.span(), + ) { return err.into(); } } @@ -208,7 +212,7 @@ pub fn register_help(input: TokenStream) -> TokenStream { // Check for duplicate variant (different struct, same type) let variant_name = entry_type.path.segments.last().unwrap().ident.to_string(); if let Err(err) = - crate::check_duplicate_variant(&helps, &variant_name, "help", entry_type.span()) + crate::check_duplicate_variant(&helps, &entry_str, &variant_name, "help", entry_type.span()) { return err.into(); } diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs index 5bc73a4..8aa16f2 100644 --- a/mingling_macros/src/lib.rs +++ b/mingling_macros/src/lib.rs @@ -199,11 +199,16 @@ pub(crate) static HELP_REQUESTS: Registry = OnceLock::new(); /// Returns a `compile_error` token stream if a duplicate is found. pub(crate) fn check_duplicate_variant( set: &std::collections::BTreeSet, + entry_str: &str, variant_name: &str, kind: &str, error_span: proc_macro2::Span, ) -> Result<(), proc_macro2::TokenStream> { for existing in set.iter() { + if existing == entry_str { + // Exact same entry - re-registration from RA re-analysis, skip + continue; + } if entry_has_variant(existing, variant_name) { return Err(syn::Error::new( error_span, @@ -1972,6 +1977,23 @@ pub fn program_final_gen(_input: TokenStream) -> TokenStream { } }; + // Clear all global registries to prevent stale state in Rust Analyzer + get_global_set(&PACKED_TYPES).lock().unwrap().clear(); + get_global_set(&CHAINS).lock().unwrap().clear(); + get_global_set(&CHAINS_EXIST).lock().unwrap().clear(); + get_global_set(&RENDERERS).lock().unwrap().clear(); + get_global_set(&RENDERERS_EXIST).lock().unwrap().clear(); + get_global_set(&HELP_REQUESTS).lock().unwrap().clear(); + #[cfg(feature = "comp")] + get_global_set(&COMPLETIONS).lock().unwrap().clear(); + #[cfg(feature = "dispatch_tree")] + get_global_set(&COMPILE_TIME_DISPATCHERS) + .lock() + .unwrap() + .clear(); + #[cfg(feature = "general_renderer")] + get_global_set(&GENERAL_RENDERERS).lock().unwrap().clear(); + TokenStream::from(expanded) } diff --git a/mingling_macros/src/renderer.rs b/mingling_macros/src/renderer.rs index 79128ef..a82744a 100644 --- a/mingling_macros/src/renderer.rs +++ b/mingling_macros/src/renderer.rs @@ -252,6 +252,7 @@ pub fn register_renderer(input: TokenStream) -> TokenStream { let renderers = get_global_set(&crate::RENDERERS).lock().unwrap(); if let Err(err) = crate::check_duplicate_variant( &renderers, + &renderer_entry_str, &variant_name, "renderer", previous_type.span(), -- cgit