Annotate Core/Reflection reflective surface for AOT (closes #252)#259
Merged
Conversation
Largest AOT-pillar slice (#213). 64 IL warnings per TFM across 6 files in Core/Reflection → 0, plus propagated annotations to keep EnumerableTypeExtensions clean. GenericFactoryCache.cs All 8 BuildAs<T> overloads carry [RequiresDynamicCode] from PR #191. Adds matching [UnconditionalSuppressMessage("Trimming", "IL2055")] to suppress the MakeGenericType-in-lambda warnings — the method-level [RequiresDynamicCode] already documents the contract; source-generated callers supply an AOT-safe factoryFactory and never reach MakeGenericType. TypeExtensions.cs [DAM(Interfaces)] on ImplementsInterfaceTemplate, FindInterfaceThatCloses, Closes, FindParameterTypeTo, IsAnEnumerationOf [DAM(PublicConstructors)] on IsConcreteWithDefaultCtor [DAM(PublicParameterlessConstructor)] on Create<T>(), Create [UnconditionalSuppressMessage(IL3050)] on IsGenericEnumerable (closes well-known IEnumerable<T> only) [UnconditionalSuppressMessage(IL2072)] on Closes (recursive interface walk) ReflectionExtensions.cs [DAM(PublicConstructors | NonPublicConstructors)] on HasDefaultConstructor, HasConstructorsWithArguments [DAM(PublicConstructors)] on TryFindConstructor [DAM(PublicMethods | NonPublicMethods)] on TryFindMethod, TryFindStaticMethod [UnconditionalSuppressMessage(IL2072)] on IsAsync (checks well-known Task/ValueTask types) EnumerableTypeExtensions.cs [DAM(Interfaces)] on IsEnumerable (propagated from TypeExtensions.Closes) LambdaBuilder.cs [RequiresUnreferencedCode] on every public method: GetProperty, SetProperty, GetField, SetField, Getter, Setter All compile expression trees via FastExpressionCompiler (itself RUC-annotated). Honest characterization: this whole class is for runtime expression compilation; AOT consumers should source-generate accessor delegates. ValueTypeInfo.cs [RequiresUnreferencedCode] on public ForType(Type), CreateWrapper<TOuter,TInner>, UnWrapper<TOuter,TInner> [DAM(PublicProperties | PublicConstructors | PublicMethods)] on ForType(Type) Strong-typed-id value-type discovery + Expression compilation; both fundamentally trim-hostile. ReflectionHelper.cs [DAM(PublicParameterlessConstructor)] on MeetsSpecialGenericConstraints [UnconditionalSuppressMessage(IL2026/IL3050)] on VisitNew / VisitNewArray (visits existing expression trees; trim invariant owned by whoever built the input) Effect on the punch list JasperFx total per TFM: 188 → 140 (-48) The slice's direct 64-warning count was higher than the net delta because some warnings propagated up cascade chains (ReflectionExtensions inherited 4 from TypeExtensions DAM annotations, etc.) — each propagation got its own annotation, so the net result is the same 0 in the slice plus the surrounding cleanup. Remaining (all pre-existing, not introduced by this PR): #254 ServiceContainer.cs 16 (PR #256 in flight) #255 CodeGeneration/Services 22 (PR #257 in flight) — already addressed by ripple suppression Core/TypeScanning 10 CodeGeneration/Snapshots 8 CodeGeneration/GeneratedType.cs 8 JasperFxOptions.cs 6 misc tail ~24 Verification CoreTests 407/407 pass on net9.0 + net10.0 SmokeTestAot build clean, exits 0 Closes #252.
This was referenced May 13, 2026
thechucklingatom
pushed a commit
to thechucklingatom/jasperfx
that referenced
this pull request
May 19, 2026
Final AOT-pillar cleanup pass for JasperFx (JasperFx#213). After PRs JasperFx#256–JasperFx#259 closed the four largest slices (ServiceContainer, CodeGeneration/Services, Core/IoC, Core/Reflection), 74 warnings per TFM remained across the long tail. This PR brings the JasperFx project to **0 IL warnings** with `IsAotCompatible=true` enabled. Annotated reflective entry points AssemblyFinder.FindAssemblies (3 overloads) — [RUC] IJasperFxAssemblyLoadContext + impl — [RUC] AssemblyTypes(Assembly) — [RUC] TypeRepository.ForAssembly / FindTypes (3x) — [RUC] TypeQuery.Find(IEnumerable<Assembly>) — [RUC] AssemblyScanner.Start + assembly-scan APIs — [RUC] (matches IAssemblyScanner) IAssemblyScanner.AssembliesFrom* — [RUC] on interface CommandLineHostingExtensions.ApplyJasperFx* — already RUC; cascades JasperFxOptions.HasReferenceToJasperFxTool — [RUC] JasperFxOptions.DetermineCallingAssembly — [RUC] JasperFxOptions.establishApplicationAssembly — [RUC] JasperFxOptions.ReadHostEnvironment — [RUC] JasperFxServiceCollectionExtensions.AddJasperFx + CritterStackDefaults — [RUC] EnvironmentCheckExtensions (5 overloads) — [RUC] SnapshotGate.Read / SnapshotGate.Write — [RUC] + [RDC] (STJ JsonSerializer) ISystemPart.WriteToConsole — [RUC] on interface DescribeCommand.Execute — suppress + #pragma on async-state-machine WriteToConsole call CodeGeneration/Frames/MethodCall(Type,string) — [RUC] + [DAM(PublicMethods)] CodeGeneration/Frames/MethodCall.correctedReturnType — suppress IL2067 (well-known Task types) CodeGeneration/Frames/MethodCall.returnsValueTask — suppress IL2072 CodeGeneration/GeneratedAssembly.AddType — [DAM(PublicCtors|PublicMethods|NonPublicMethods)] CodeGeneration/GeneratedAssembly.AttachAssembly — [RUC] CodeGeneration/GeneratedType.CompiledType property — [DAM(PublicCtors)] CodeGeneration/GeneratedType.InheritsFrom<T>/<Type> — [DAM(PublicCtors|Methods)] CodeGeneration/GeneratedType.Implements<T>/(Type) — [DAM(PublicMethods)] CodeGeneration/GeneratedType.FindType + ApplySetterValues — [RUC]/suppress CodeGeneration/Model/Setter.SetInitialValue — [RUC] CodeGeneration/Model/Variable.VariablesForProperties<T> — [DAM(PublicProperties)] CodeGeneration/Model/Variable.DefaultArgName — suppress (cosmetic) CodeGeneration/Expressions/LambdaDefinition.Compile<TFunc> — [RUC] ServiceCollectionServerVariableSource.Matches — suppress (IVariableSource contract doesn't carry DAM) CodeGeneration/CodeGenerationExtensions.BuildExportedTypeIndex — suppress CodeGeneration/Services findFamily — re-applied IL2067 suppression (was lost in JasperFx#256 + JasperFx#257 merge) ServiceContainer.CouldResolve(Type) — [DAM(PublicCtors)] ServiceContainer.findFamily — re-applied IL2067 suppression (was lost in PR JasperFx#256 + JasperFx#257 merge resolution) Descriptors/OptionsDescription — [RUC] on ctor / For() / readProperties Descriptors/DatabaseDescriptor ctors — [RUC] (inherits OptionsDescription) CommandLine/Descriptions/ConfigurationPreview.WriteToConsole — [RUC] CommandLine/Descriptions/DescribeCommand.WriteToConsole (×2 overrides) — [RUC] CommandLine/CommandFactory.IsJasperFxCommandType — [DAM(Interfaces)] CommandLine/CommandFactory.TryRegisterFromGeneratedManifest — IL2072 suppress added Resources/ResourcesCommand.ExecuteOnEach — suppress IL3050 (Spectre WriteException on error-display path) JasperFxAssemblyAttribute ctor — [DAM(PublicCtors|NonPublicCtors)] Effect on the punch list Before: JasperFx total per TFM 74 warnings After: JasperFx total per TFM 0 warnings Cumulative since JasperFx#213 flag-flip (PR JasperFx#247): 236 (initial fallout) → 0 (all addressed) Note on JasperFx.Events The propagation of new annotations into the JasperFx.Events compilation surfaces ~246 warnings per TFM that aren't addressed here. That deserves its own focused PR + likely an issue under JasperFx#213. Verification CoreTests 407/407 pass on net9.0 + net10.0 CommandLineTests 280/280 pass on net9.0 + net10.0 CodegenTests 366/366 pass on net9.0 + net10.0 SmokeTestAot build clean, exits 0 Closes (most) the AOT pillar JasperFx#213 for JasperFx itself. Events follow-up deferred to a separate PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Largest AOT-pillar slice (#213) — closes #252.
64 IL warnings per TFM across 6 files in
Core/Reflection→ 0, plus propagated annotations to keepEnumerableTypeExtensionsclean.Annotations summary
GenericFactoryCache.csAll 8
BuildAs<T>overloads carry[RequiresDynamicCode]from PR #191. Adds matching[UnconditionalSuppressMessage("Trimming", "IL2055")]to suppress theMakeGenericType-in-lambda warnings — the method-level[RequiresDynamicCode]already documents the contract; source-generated callers supply an AOT-safefactoryFactoryand never reachMakeGenericType.TypeExtensions.csImplementsInterfaceTemplate,FindInterfaceThatCloses,Closes,FindParameterTypeTo,IsAnEnumerationOf[DAM(Interfaces)]IsConcreteWithDefaultCtor[DAM(PublicConstructors)]Create<T>(),Create[DAM(PublicParameterlessConstructor)]IsGenericEnumerableIEnumerable<T>only)ClosesReflectionExtensions.csHasDefaultConstructor,HasConstructorsWithArguments[DAM(PublicConstructors | NonPublicConstructors)]TryFindConstructor[DAM(PublicConstructors)]TryFindMethod,TryFindStaticMethod[DAM(PublicMethods | NonPublicMethods)]IsAsyncTask/ValueTask)EnumerableTypeExtensions.csIsEnumerable[DAM(Interfaces)](propagated fromTypeExtensions.Closes)LambdaBuilder.cs[RequiresUnreferencedCode]on every public method:GetProperty,SetProperty,GetField,SetField,Getter,Setter. All compile expression trees via FastExpressionCompiler (itself RUC-annotated). Honest characterization: this whole class is for runtime expression compilation; AOT consumers should source-generate accessor delegates.ValueTypeInfo.cs[RequiresUnreferencedCode]on publicForType(Type),CreateWrapper<TOuter,TInner>,UnWrapper<TOuter,TInner>plus[DAM(PublicProperties | PublicConstructors | PublicMethods)]onForType(Type). Strong-typed-id value-type discovery + Expression compilation — both fundamentally trim-hostile.ReflectionHelper.csMeetsSpecialGenericConstraints[DAM(PublicParameterlessConstructor)]VisitNewNewExpression; trim invariant owned by tree builder)VisitNewArrayNewArrayExpression)Effect on the punch list
The slice's direct 64-warning count was higher than the net delta because some warnings propagated up cascade chains (
ReflectionExtensionsinherited 4 fromTypeExtensionsDAM annotations, etc.) — each propagation got its own annotation, so the net result is 0 in the slice plus the surrounding cleanup.Remaining (none introduced by this PR):
ServiceContainer.csCodeGeneration/ServicesCore/TypeScanningCodeGeneration/SnapshotsCodeGeneration/GeneratedType.csJasperFxOptions.csVerification
CoreTests— 407/407 pass on net9.0 + net10.0SmokeTestAot— build clean, exits 0Closes #252.
🤖 Generated with Claude Code