Skip to content

Prevent trimmer warnings on current SDK#2308

Merged
idg10 merged 7 commits intomainfrom
feature/trim-warnings
Mar 25, 2026
Merged

Prevent trimmer warnings on current SDK#2308
idg10 merged 7 commits intomainfrom
feature/trim-warnings

Conversation

@idg10
Copy link
Copy Markdown
Collaborator

@idg10 idg10 commented Mar 17, 2026

This updates the tool that generates code supporting IQueryable<T> (the HomoIcon tool) so that the generated code is better aligned with the capabilities of the .NET SDK's IL trimming functionality.

The most obvious change is that this fixes some build warnings reporting trimmability analysis problems. But it has also enabled us to remove the suppressions for various diagnostics that had been added as a stopgap to get basic trimming support working in Rx 6. This may also enable the trimming static analysis to better understand the relevant methods.

This also finally drags the HomoIcon tool into the modernish era: it's now a .NET 10 tool instead of .NET FX, and it is also able to generate nullability annotations. (For several years, nullability had been handled by error-prone manual adjustments to the files this tool generates.)

One upshot of updating this tool is that it has revealed inconsistencies between the IQbservable<T> and IObservable<T> APIs, most notably the fact that there were a load of overloads available for CombineLatest and Zip on IQbservable<T> that did not have IObservable<T> equivalents! (Specifically, the forms that return tuples with more than 8 values.) The main IObservable<T> operators have now been extended to align with what the query-space versions have apparently offered for years.

idg10 added 3 commits March 16, 2026 11:20
 * From .NET FX 4.8 to .NET 10
 * Code gen now null-aware
 * Removed unnecessary Qbservable.NAry.tt because the HomoIcon tool handles these methods just fine
 * Replace MethodBase.GetCurrentMethod with delegate (because the trimmer understands the latter but not the former)
 * Suppress warning on ObservableEx
 * Use C# type names in comments for decimal and float, not runtime names

Add new .Homoicon.cs extension to list skipped in license header test. (No longer using .Generated.cs because that was causing us not to see diagnostics for any of the HomoIcon-generated code.)
@idg10 idg10 added this to the Rx 7.0 milestone Mar 17, 2026
@idg10 idg10 self-assigned this Mar 17, 2026
idg10 added 3 commits March 17, 2026 13:08
The IQbservable forms of the tuplet-based versions of these operators all go up to 16 arguments, but for some reason the IObservable forms go up only to 8. Since we've resurrected the HomoIcon tool, this discrepancy has caused a problem: the code gen only generates IQbservable forms corresponding to IObservable forms, and so we end up with the IQbservable API surface area shrinking.

To avoid that, this expands the IObservable CombineLatest and Zip operators to match what IQbservable was already offering.
@idg10 idg10 marked this pull request as ready for review March 18, 2026 16:57
@idg10 idg10 requested a review from Copilot March 19, 2026 05:56
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes the HomoIcon code-generation tool used to produce IQbservable<T>/query-space operator wrappers, aligning the generated code with .NET SDK trimming analysis and adding nullability-aware generation. It also expands IObservable<T> operator surface area (notably CombineLatest/Zip tuple overloads) to match long-standing IQbservable<T> capabilities.

Changes:

  • Port HomoIcon to an SDK-style .NET tool (now net10.0), and update its generated code to avoid trimmer warnings (delegate-based MethodInfo acquisition instead of GetCurrentMethod/MakeGenericMethod patterns).
  • Rename HomoIcon-generated files from *.Generated.cs to *.Homoicon.cs (and adjust license-header scanning exclusions accordingly).
  • Extend IObservable<T>/query language CombineLatest and Zip tuple-returning overloads up to 16 inputs to align with query-space APIs.

Reviewed changes

Copilot reviewed 26 out of 30 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
Rx.NET/tools/HomoIcon/Properties/AssemblyInfo.cs Removes legacy .NET Framework assembly attribute file as part of SDK-style migration.
Rx.NET/tools/HomoIcon/Program.cs Updates generator logic for trimming-friendly MethodInfo retrieval, file naming, TFM selection, and nullability emission.
Rx.NET/tools/HomoIcon/HomoIcon.slnx Adds new solution format for the tool.
Rx.NET/tools/HomoIcon/HomoIcon.sln Removes legacy VS2010 solution file.
Rx.NET/tools/HomoIcon/HomoIcon.csproj Migrates the tool to SDK-style project targeting net10.0.
Rx.NET/tools/HomoIcon/app.config Removes .NET Framework runtime config.
Rx.NET/Source/tests/Tests.System.Reactive/Tests/LicenseHeaderTest.cs Excludes *.Homoicon.cs files from license-header scanning (like *.Generated.cs).
Rx.NET/Source/src/System.Reactive/System.Reactive.csproj Removes T4 item metadata tied to deleted QbservableEx.NAry template output.
Rx.NET/Source/src/System.Reactive/Platforms/Desktop/Linq/Observable.Remoting.cs Switches query expression MethodInfo retrieval to delegate-based approach for trimming friendliness.
Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.Zip.tt Expands generated Zip tuple overloads up to 16 inputs.
Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.Zip.cs Regenerates query language Zip overloads to match updated template.
Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.CombineLatest.tt Expands generated CombineLatest tuple overloads up to 16 inputs.
Rx.NET/Source/src/System.Reactive/Linq/QueryLanguage.Multiple.CombineLatest.cs Regenerates query language CombineLatest overloads to match updated template.
Rx.NET/Source/src/System.Reactive/Linq/QbservableEx.NAry.tt Removes legacy T4 generator for QbservableEx N-ary operators (superseded by HomoIcon output).
Rx.NET/Source/src/System.Reactive/Linq/QbservableEx.Homoicon.cs Updates generated QbservableEx operators to trimming-friendly MethodInfo patterns and improved nullability pragmas/docs.
Rx.NET/Source/src/System.Reactive/Linq/QbservableEx.Generated.cs Removes prior generated file in favor of *.Homoicon.cs naming/output.
Rx.NET/Source/src/System.Reactive/Linq/Qbservable.Joins.cs Replaces GetCurrentMethod/MakeGenericMethod usage with delegate-based MethodInfo retrieval.
Rx.NET/Source/src/System.Reactive/Linq/Qbservable.cs Replaces GetCurrentMethod/MakeGenericMethod usage with delegate-based MethodInfo retrieval.
Rx.NET/Source/src/System.Reactive/Linq/Observable.Multiple.Zip.tt Expands generated ObservableEx.Zip tuple overloads up to 16 inputs (and adjusts CA1711 suppression placement).
Rx.NET/Source/src/System.Reactive/Linq/Observable.Multiple.Zip.cs Regenerates ObservableEx.Zip overloads to match updated template.
Rx.NET/Source/src/System.Reactive/Linq/Observable.Multiple.CombineLatest.tt Expands generated ObservableEx.CombineLatest tuple overloads up to 16 inputs (and adjusts CA1711 suppression placement).
Rx.NET/Source/src/System.Reactive/Linq/Observable.Multiple.CombineLatest.cs Regenerates ObservableEx.CombineLatest overloads to match updated template.
Rx.NET/Source/src/System.Reactive/Linq/IQueryLanguage.NAry.tt Expands generated interface IQueryLanguageEx signatures to include tuple overloads up to 16 inputs.
Rx.NET/Source/src/System.Reactive/Linq/IQueryLanguage.NAry.cs Regenerates IQueryLanguageEx N-ary signatures to match updated template.
Rx.NET/Source/src/System.Reactive/Linq/FuncExtra.cs Adds a 17-argument Func delegate type to support delegate-based MethodInfo retrieval beyond BCL Func arity.
Rx.NET/Source/src/System.Reactive.Observable.Aliases/Qbservable.Aliases.Homoicon.cs Updates generated alias query operators (nullability pragmas/imports and regenerated header).
Rx.NET/Documentation/adr/0008-trimming-vs-qbservable.md Adds ADR documenting trimming warnings and the delegate-based mitigation strategy.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Rx.NET/tools/HomoIcon/Program.cs
Comment thread Rx.NET/tools/HomoIcon/Program.cs
Comment thread Rx.NET/tools/HomoIcon/Program.cs Outdated

Whether an operator creates a brand new source from scratch (as in `Range`) or bolts onto an existing sequence (as in `Where`), these `IQbservable<T>` operators are all implemented in much the same way: they call the `IQbservableProvider.CreateQuery<int>` method passing an `Expression` describing the query. (In the case of combinators like `Where`, they obtain the `IQbservableProvider` from the `Provider` property of the incoming source).

This expression is available as part of `IQbservable<T>` (or more precisely, its base type, `IQbservable`), so we can inspect the expression for an `IQbserable<T>`:
Comment thread Rx.NET/Documentation/adr/0008-trimming-vs-qbservable.md Outdated
Comment thread Rx.NET/Documentation/adr/0008-trimming-vs-qbservable.md Outdated
Comment thread Rx.NET/Documentation/adr/0008-trimming-vs-qbservable.md Outdated
Comment thread Rx.NET/Documentation/adr/0008-trimming-vs-qbservable.md Outdated
Comment thread Rx.NET/Documentation/adr/0008-trimming-vs-qbservable.md Outdated
Comment thread Rx.NET/Source/src/System.Reactive/Linq/FuncExtra.cs Outdated
Copy link
Copy Markdown
Collaborator

@HowardvanRooijen HowardvanRooijen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you created an integration test for running behaviour successfully on a trimmed assembly?

@idg10
Copy link
Copy Markdown
Collaborator Author

idg10 commented Mar 25, 2026

@HowardvanRooijen :`

Have you created an integration test for running behaviour successfully on a trimmed assembly?

I considered this but it was rather beyond the scope of this particular PR: the primary goal was to preserve existing functionality but to remove build warnings.

To test trimming properly I think we'd need to broaden the integration testing. We'd want to include Blazor since that was the original motivation for adding trimming annotations in the first place. Since wasm testing still appears to be a pain, that's not straightforward and might not even be possible yet. (I've not yet seen anything to indicate that the new test platform did anything to improve testability on WASM. I would hope that it did, and if so, migrating to that would be a prerequisite.)

So I've created #2310 to track this.

@idg10 idg10 merged commit 5d2d40b into main Mar 25, 2026
7 checks passed
@idg10 idg10 deleted the feature/trim-warnings branch March 25, 2026 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants