Skip to content

feat: reflection-free Type-based APIs through a slim source generator - #70

Merged
Blind-Striker merged 2 commits into
aot/generic-path-static-factoriesfrom
aot/slim-generator
Oct 23, 2026
Merged

Blind-Striker merged 2 commits into
aot/generic-path-static-factoriesfrom
aot/slim-generator

Conversation

@Blind-Striker

@Blind-Striker Blind-Striker commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Stack (review bottom-up, merge as one stack): #62 base, #66 the #63 fix, #67 Native AOT test lane, #68 static-factory generic path, #70 slim generator, #71 public docs, #72 internal docs and 3.0.0, #73 reflection-free test, #74 package consumer in CI, #75 convention clean-up, #76 service catalog refresh.

Goal of the stack: 3.0.0, where existing consumers upgrade without code changes, both packages support Native AOT on net10.0/net11.0, and the libraries use no runtime reflection for types the compiler can see (a JIT-only fallback covers the rest).

This PR

Makes the Type-based APIs and ISessionReflection reflection-free on net10.0/net11.0. The rewritten generator emits direct C# for accessible, concrete, non-generic clients found in the consumer and its references: an UnsafeAccessor for serviceMetadata, new TConfig() for the (credentials, clientConfig) shape, direct constructors (most-derived config first), a direct ForcePathStyle setter for the simple public bool shape, and a plain-RegionEndpoint flag. Generated code contains no reflection and no Type.GetType.

Shapes the generator does not cover (F#/VB for the Type APIs, runtime-loaded assemblies, private or generic custom clients, unusual constructors or properties) keep the previous behaviour through a reflection fallback behind ReflectionFallback.IsSupported. That property is a FeatureGuard auto-property, so trimmed and Native AOT apps compile the fallback away without warnings or suppressions. Core and Extensions set IsAotCompatible from IsLocalStackModernTarget, so it covers net10.0, net11.0 and any later modern target without a literal.

Review fixes included:

  • Shapes the compiler would reject in generated code are skipped (init-only, ref/out, required, Obsolete/Experimental).
  • One non-inlined registration method per type, so a missing runtime assembly cannot abort the module initializer.
  • Transitive AWSSDK.Core references are discovered.
  • Reference discovery caches only candidates per MetadataReference; with 121 AWS SDK packages referenced, an unrelated edit went from about 4.2 s to about 60 ms.

Verification

Build with 0 warnings. Core 106 (net10/11) and 100 (net472), Integration 244 x3, Generator 65, Extensions 62, Functional 50 x2. Native AOT lane 35/35 with 0 IL warnings. The native executable contains none of the fallback methods (checked by name), while the normal-path methods are present.

@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

On net10.0/net11.0, the Type-based APIs (CreateClientByInterface(Type),
CreateClientByImplementation, ISessionReflection) no longer use runtime
reflection for clients and configs the compiler can see.

The generator that ships in Core now emits direct C# for every accessible,
concrete, non-generic AmazonServiceClient it finds in the consumer
compilation and its references:

- metadata: an UnsafeAccessor for the client's private static
  serviceMetadata field, read lazily
- config: new TConfig() for the (credentials, clientConfig) constructor
  shape, with the same zero/multiple-match failures as before
- client: direct constructor calls, most-derived config type first
- config entries: a direct ForcePathStyle setter for the simple public
  bool shape, and whether RegionEndpoint is shadowed

It skips shapes the compiler would reject in generated code (init-only
setters, ref/out parameters, required members, Obsolete/Experimental
symbols), registers each type in its own non-inlined method so a missing
runtime assembly cannot abort the module initializer, and discovers
clients in references that reach AWSSDK.Core only transitively. Reference
discovery caches only candidate types per MetadataReference; with 121 AWS
SDK packages referenced, an unrelated edit drops from ~4.2 s to ~60 ms.

Types the generator does not cover (F#/VB projects, runtime-loaded
assemblies, private or generic custom clients, unusual shapes) keep the
previous behaviour through a reflection fallback guarded by
ReflectionFallback.IsSupported, a FeatureGuard auto-property that trimmed
and Native AOT apps compile away without warnings or suppressions.

Core and Extensions set IsAotCompatible on net10.0/net11.0.
The test built an AmazonS3Client from a bare AmazonS3Config, which only
passes on machines with an AWS default region in the shared config; CI
runners have none and the SDK threw "No RegionEndpoint or ServiceURL
configured". Start from us-east-1 so SetClientRegion's change to
eu-west-2 is still observable.
@Blind-Striker
Blind-Striker marked this pull request as ready for review October 23, 2026 21:55
@Blind-Striker
Blind-Striker merged commit 49573c2 into master Oct 23, 2026
17 checks passed
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