Skip to content

[linker] Only generate NSObject factories for generic types. Fixes #25232. - #26510

Merged
rolfbjarne merged 17 commits into
mainfrom
dev/rolf/generic-nsobject-factories
Sep 5, 2026
Merged

[linker] Only generate NSObject factories for generic types. Fixes #25232.#26510
rolfbjarne merged 17 commits into
mainfrom
dev/rolf/generic-nsobject-factories

Conversation

@rolfbjarne

Copy link
Copy Markdown
Member

Non-generic types are constructed through the trimmable registrar type map, so only generic NSObject types need to implement INSObjectFactory.

Remove the broad interface-preservation dependency and rely on ILLink to retain generated interface implementations through their method overrides. This avoids preserving unrelated interface implementations and reduces app size.

Add assembly-preparer coverage for generic and non-generic factory generation, and update the expected app sizes.

Tests:

  • Assembly-preparer test suite
  • Mac Catalyst monotouch-test with the trimmable static registrar and full trimming (3,650 passed; one unrelated transient network test failure)

Fixes #25232

🤖 Pull request created by Copilot

rolfbjarne and others added 2 commits September 1, 2026 14:19
Non-generic types are constructed through the trimmable registrar type map. Let ILLink retain generated interface implementations through their method overrides instead of broadly preserving every interface on each type.

Add an assembly-preparer test covering generic and non-generic factory generation.

Fixes #25232.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ef04d7c1-e5e3-4244-ac92-f7341ddac90e
Copilot AI lite review requested due to automatic review settings September 1, 2026 12:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Pull request overview

This PR refines trimmable-static registrar factory generation to reduce unnecessary interface preservation and app size impact, aligning non-generic NSObject construction with the trimmable registrar type map while keeping factory methods only where type-map construction can’t work (generic NSObject types).

Changes:

  • Generate INSObjectFactory._Xamarin_ConstructNSObject only for generic NSObject types in the trimmable-static registrar pipeline.
  • Remove the trimmable-static “preserve all interfaces” dynamic dependency from generated interface implementations and rely on the generated method overrides instead.
  • Add assembly-preparer coverage for generic vs non-generic factory generation and update expected app-size baselines.
File summaries
File Description
tools/dotnet-linker/Steps/ManagedRegistrarStep.cs Limits NSObject factory method generation to generic types under the trimmable-static registrar.
tools/dotnet-linker/AppBundleRewriter.cs Removes the interface-preservation dynamic dependency for trimmable-static; keeps marking behavior for other registrar modes.
tests/assembly-preparer/ManagedRegistrarStepTests.cs Adds test coverage verifying factory generation behavior for generic vs non-generic NSObject types.
tests/dotnet/UnitTests/expected/TVOS-NativeAOT-TrimmableStatic-size.txt Updates expected app size after preservation reduction.
tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-TrimmableStatic-size.txt Updates expected app size after preservation reduction.
tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-Interpreter-TrimmableStatic-size.txt Updates expected app size after preservation reduction.
tests/dotnet/UnitTests/expected/MacCatalyst-NativeAOT-TrimmableStatic-size.txt Updates expected app size after preservation reduction.
tests/dotnet/UnitTests/expected/iOS-NativeAOT-TrimmableStatic-size.txt Updates expected app size after preservation reduction.
Review details

Suppressed comments (1)

tests/assembly-preparer/ManagedRegistrarStepTests.cs:51

  • 💡 Testing — For the same reason as the non-generic case, also assert that the generated _Xamarin_ConstructINativeObject method on the generic type has an override to ObjCRuntime.INativeObject, since the trimmer-retention strategy depends on method overrides.
		var factoryMethod = genericType.Methods.Single (v => v.Name == "_Xamarin_ConstructNSObject");
		Assert.That (factoryMethod.Overrides.Select (v => v.DeclaringType.FullName), Does.Contain ("Foundation.INSObjectFactory"), "Generic method overrides");

  • Files reviewed: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/assembly-preparer/ManagedRegistrarStepTests.cs
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

⚠️ AppSizeTest expected files changed ⚠️

The AppSizeTest detected changes in the expected app size files.

To update the expected files, add a comment with the following command:

/apply-gist https://gist.github.com/vs-mobiletools-engineering-service2/5daef29a70e478893d0caf276efe733d
Updated files
  • iOS-CoreCLR-Interpreter-preservedapis.txt
  • iOS-CoreCLR-Interpreter-size.txt
  • iOS-CoreCLR-R2R-preservedapis.txt
  • iOS-CoreCLR-R2R-size.txt
  • iOS-NativeAOT-size.txt
  • iOS-NativeAOT-TrimmableStatic-size.txt
  • MacCatalyst-CoreCLR-Interpreter-preservedapis.txt
  • MacCatalyst-CoreCLR-Interpreter-size.txt
  • MacCatalyst-CoreCLR-R2R-preservedapis.txt
  • MacCatalyst-CoreCLR-R2R-size.txt
  • MacCatalyst-NativeAOT-size.txt
  • MacCatalyst-NativeAOT-TrimmableStatic-size.txt
  • MacOSX-CoreCLR-Interpreter-size.txt
  • MacOSX-CoreCLR-Interpreter-TrimmableStatic-size.txt
  • MacOSX-CoreCLR-R2R-size.txt
  • MacOSX-NativeAOT-size.txt
  • MacOSX-NativeAOT-TrimmableStatic-size.txt
  • TVOS-CoreCLR-Interpreter-preservedapis.txt
  • TVOS-CoreCLR-Interpreter-size.txt
  • TVOS-CoreCLR-R2R-preservedapis.txt
  • TVOS-CoreCLR-R2R-size.txt
  • TVOS-NativeAOT-size.txt
  • TVOS-NativeAOT-TrimmableStatic-size.txt

Pipeline on Agent
Hash: 76dde6bcf9c657dac5185d7715f41bb289ebe0b7 [PR build]

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

rolfbjarne and others added 2 commits September 3, 2026 06:52
The generic NSObject factory optimization allows additional protocol-only frameworks to be trimmed from fully linked CoreCLR apps. Update the expected native library lists accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

rolfbjarne and others added 3 commits September 3, 2026 17:29
Use the platform assembly name generated by CreatePreparer, including the required .dll suffix, so ManagedRegistrarStep processes the test assembly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

rolfbjarne and others added 3 commits September 4, 2026 12:54
…ate protocol'

The VB iOS/MacCatalyst 'SceneDelegate' template subclasses the
'UIWindowSceneDelegate' Model class (VB doesn't support consuming C#'s
default interface implementations, so implementing the corresponding
interface directly would require implementing dozens of members).

The linker/trimmer strips the 'IUIWindowSceneDelegate' interface
implementation from the 'UIWindowSceneDelegate' Model class itself once
trimmed (since nothing calls through it directly), which means the
native registrar can no longer see that 'SceneDelegate' transitively
conforms to the 'UIWindowSceneDelegate' protocol. At runtime this causes
UIKit to reject the class with:

    NSInternalInconsistencyException: 'representation's delegateClass
    must conform to UISceneDelegate protocol'

Fix this by adding an explicit '<Adopts ("UIWindowSceneDelegate")>'
attribute to the class, which tells the registrar to declare the
protocol conformance regardless of what the (trimmed) base class
implements.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0d41380a-e6ee-470e-b837-68411050a4f6
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The “only generate NSObject factories for generic types” behavior isn’t applied consistently (ManagedRegistrarLookupTablesStep still unconditionally generates the NSObject factory), so the fix appears incomplete for some build flows.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 29/29 changed files
  • Comments generated: 2
  • Review effort level: Lite

Comment thread tools/dotnet-linker/Steps/ManagedRegistrarStep.cs
Comment thread tests/assembly-preparer/ManagedRegistrarStepTests.cs
rolfbjarne and others added 3 commits September 4, 2026 19:26
Treat a missing static constructor as having no interface dynamic
dependencies, so the test remains focused on the behavior it verifies.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0d41380a-e6ee-470e-b837-68411050a4f6
@rolfbjarne rolfbjarne added the ready-to-review This PR is ready to review/merge. label Sep 4, 2026
@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ API diff for current PR / commit

NET (empty diffs)

✅ API diff vs stable

NET (empty diffs)

ℹ️ Generator diff

Generator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes)

Pipeline on Agent
Hash: ebb8d3f3b08487d0e0ec7dce311fca4a86fb9b68 [PR build]

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

🚀 [CI Build #ebb8d3f] Test results 🚀

Test results

✅ All tests passed on VSTS: test results.

🎉 All 264 tests passed 🎉

Tests counts

✅ assembly-processing: All 1 tests passed. Html Report (VSDrops) Download
✅ cecil: All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (iOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (MacCatalyst): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (macOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (Multiple platforms): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (tvOS): All 1 tests passed. Html Report (VSDrops) Download
✅ framework: All 2 tests passed. Html Report (VSDrops) Download
✅ fsharp: All 4 tests passed. Html Report (VSDrops) Download
✅ generator: All 5 tests passed. Html Report (VSDrops) Download
✅ interdependent-binding-projects: All 4 tests passed. Html Report (VSDrops) Download
✅ introspection: All 7 tests passed. Html Report (VSDrops) Download
✅ linker (iOS): All 31 tests passed. Html Report (VSDrops) Download
✅ linker (MacCatalyst): All 31 tests passed. Html Report (VSDrops) Download
✅ linker (macOS): All 21 tests passed. Html Report (VSDrops) Download
✅ linker (tvOS): All 31 tests passed. Html Report (VSDrops) Download
✅ monotouch (iOS): All 25 tests passed. Html Report (VSDrops) Download
✅ monotouch (MacCatalyst): All 25 tests passed. Html Report (VSDrops) Download
✅ monotouch (macOS): All 20 tests passed. Html Report (VSDrops) Download
✅ monotouch (tvOS): All 25 tests passed. Html Report (VSDrops) Download
✅ msbuild: All 2 tests passed. Html Report (VSDrops) Download
✅ sharpie: All 1 tests passed. Html Report (VSDrops) Download
✅ windows: All 3 tests passed. Html Report (VSDrops) Download
✅ xcframework: All 4 tests passed. Html Report (VSDrops) Download
✅ xtro: All 1 tests passed. Html Report (VSDrops) Download

macOS tests

✅ Tests on macOS Sonoma (14): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Sequoia (15): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Tahoe (26): All 5 tests passed. Html Report (VSDrops) Download

Linux Build Verification

Linux build succeeded

Pipeline on Agent
Hash: ebb8d3f3b08487d0e0ec7dce311fca4a86fb9b68 [PR build]

@rolfbjarne
rolfbjarne merged commit 1915b9a into main Sep 5, 2026
54 checks passed
@rolfbjarne
rolfbjarne deleted the dev/rolf/generic-nsobject-factories branch September 5, 2026 10:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

copilot ready-to-review This PR is ready to review/merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Trimmable-static-registrar: investigate why it's necessary to manually preserve the NSObject and INativeObject factory interfaces and methods

4 participants