Skip to content

Comments

feat: replace reflection-based trigger discovery with source-generated registry#28

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/make-libraries-aot-and-trimmed
Draft

feat: replace reflection-based trigger discovery with source-generated registry#28
Copilot wants to merge 3 commits intomainfrom
copilot/make-libraries-aot-and-trimmed

Conversation

Copy link
Contributor

Copilot AI commented Feb 22, 2026

The unused-trigger analysis in StateMachineAnalysis used Assembly.GetTypes() and Type.GetProperty() at runtime to discover concrete trigger subtypes — blocking full AOT/trim compatibility and requiring [RequiresUnreferencedCode] / [UnconditionalSuppressMessage] suppression annotations.

New: FunctionalStateMachine.Core.Generator

A Roslyn incremental source generator that discovers trigger type hierarchies at compile time and replaces all runtime reflection.

  • Detects StateMachine<TState, TTrigger, ...>.Create() calls (both 3-param NoData and 4-param with-data variants)
  • For each unique TTrigger, finds all non-abstract concrete derived types via Roslyn symbol APIs
  • Skips types inaccessible from the generated initializer (private nested types filtered out)
  • Skips generation if [ModuleInitializerAttribute] is unavailable (graceful no-op on netstandard2.0 without polyfills)
  • Packaged inside FunctionalStateMachine.Core at analyzers/dotnet/cs — applies automatically to all NuGet consumers

Generated output:

// <auto-generated />
namespace FunctionalStateMachine.Core.Generated
{
    internal static class TriggerTypeRegistrationBootstrap
    {
        [ModuleInitializer]
        internal static void Initialize()
        {
            TriggerTypeRegistry.Register<global::MyApp.MyTrigger>(new[]
            {
                typeof(global::MyApp.MyTrigger.TriggerA),
                typeof(global::MyApp.MyTrigger.TriggerB)
            });
        }
    }
}

Core library changes

  • TriggerTypeRegistry (new): static TTrigger → Type[] registry populated by the generated initializer
  • StateMachineAnalysis: using System.Reflection removed entirely; AnalyzeUnusedTriggers reads from the registry and silently skips if not populated; [RequiresUnreferencedCode] / [UnconditionalSuppressMessage] annotations removed
  • Bug fix: GetTriggerTypeName was calling .GetType().Name on Type objects (returning "RuntimeType" in error messages); now returns the actual type name

AOT impact

IsAotCompatible=true (net8.0+) is now fully clean — zero remaining IL2026/IL2070 suppressions needed.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Co-authored-by: leeoades <2321091+leeoades@users.noreply.github.com>
Copilot AI changed the title [WIP] Make libraries AOT and trimmed for better consumption feat: AOT and trim compatibility for Core and CommandRunner libraries Feb 22, 2026
Copilot AI requested a review from leeoades February 22, 2026 09:56
…d trigger type registry

Co-authored-by: leeoades <2321091+leeoades@users.noreply.github.com>
Copilot AI changed the title feat: AOT and trim compatibility for Core and CommandRunner libraries feat: replace reflection-based trigger discovery with source-generated registry Feb 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants