Skip to content

Annotate core for trimming and Native AOT compatibility#1492

Merged
tillig merged 14 commits into
developfrom
feature/aot-annotations
Jun 20, 2026
Merged

Annotate core for trimming and Native AOT compatibility#1492
tillig merged 14 commits into
developfrom
feature/aot-annotations

Conversation

@tillig

@tillig tillig commented Jun 20, 2026

Copy link
Copy Markdown
Member

Summary

Annotates Autofac core for trimming and Native AOT compatibility and sets <IsAotCompatible>true</IsAotCompatible> on the modern target frameworks (net8.0/net10.0). The assembly now advertises AOT-compatibility, and the previously-opaque IL2104/IL3053 rollup warnings that downstream AOT consumers saw against Autofac.dll are resolved.

No public API is removed or changed; no runtime behavior changes for non-trimming/non-AOT consumers. All 869 existing tests pass.

What changed

Annotations (the bulk of the diff):

  • The closed-type resolve + reflection-activation hot path (Resolve<T> / Resolve(Type) / TypedParameter, constructor injection, public-property injection) is made genuinely trim/AOT-clean by flowing [DynamicallyAccessedMembers] through the registration → activator chain. The agreed DAM contract for activated types is PublicConstructors | PublicProperties (centralized in Util/ActivatorMemberTypes.cs).
  • Inherently dynamic features are honestly marked so the warning surfaces at the consumer's call site: open generics, generic decorators/composites, generated/delegate factories, and assembly scanning carry [RequiresDynamicCode] / [RequiresUnreferencedCode].
  • Always-registered implicit relationship sources (IEnumerable<T>, Lazy<T>, Meta<T>, Owned<T>, KeyedServiceIndex<,>) use internal [UnconditionalSuppressMessage] with justifications, because marking them would taint ContainerBuilder.Build() for every consumer. This keeps Build() and the closed-type resolve path clean.
  • Util/LinkerAttributes.cs backfills the linker attributes (DynamicallyAccessedMembers, RequiresUnreferencedCode, RequiresDynamicCode, UnconditionalSuppressMessage, and a [Flags] DynamicallyAccessedMemberTypes) for the netstandard targets that lack them.

Build gate: IsAotCompatible=true (net7.0+) implicitly enables the trim/AOT/single-file analyzers; combined with the existing Release TreatWarningsAsErrors this is a permanent in-build gate against new unannotated reflection/dynamic-code sites.

Verification (VerifyAot target + .github/workflows/aot.yml): two complementary layers, neither in Autofac.sln:

  • test/Autofac.Test.Aot — a console app published with PublishAot=true and then executed. The ILC publish proves static AOT-cleanliness; running the native binary proves the AOT-safe surface works at runtime (20 checks), and asserts that a value-type open-generic close correctly throws (the dynamic-code boundary is real).
  • test/Autofac.Test.AotWarnings — a fixture that calls the [Requires*] APIs; VerifyAotWarnings asserts IL2026/IL3050 are still emitted, guarding against silently losing an annotation in a future refactor. Runs on a plain build, no native toolchain.

Compatibility note for release notes

This is a minor release (9.2.0 → 9.3.0). The one thing to call out for consumers: a project that already builds with the trim/AOT analyzers enabled and treats warnings as errors may see a previously-clean build begin to fail, because APIs like RegisterGeneric, assembly scanning, and generated factories now correctly emit IL2026/IL3050 at their call sites. This is accurate new diagnostic information rather than a regression, and only affects consumers who have opted into trim/AOT analysis.

What is NOT in this PR

  • Documentation page describing the AOT/trim-safe API surface and recommended registration patterns — to follow separately.

Empirically verified AOT boundary (net10.0 / osx-arm64)

  • Works at runtime: closed-type resolve, constructor/property injection, child scopes, disposal, modules, RegisterInstance, lambda registration, and reference-typed relationships (IEnumerable<T>, Lazy<T>, Func<T>, Meta<T>, Owned<T>), plus open generics closed over reference types. Even IEnumerable<valueType> works.
  • Throws (expected): open generics closed over a value type and strongly-typed metadata views — these require runtime type/code generation.

@codecov

codecov Bot commented Jun 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.08%. Comparing base (1189581) to head (e2ce0a9).

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #1492   +/-   ##
========================================
  Coverage    78.07%   78.08%           
========================================
  Files          218      218           
  Lines         5944     5945    +1     
  Branches      1273     1273           
========================================
+ Hits          4641     4642    +1     
  Misses         763      763           
  Partials       540      540           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

1 participant