Skip to content

[dotnet-linker] Gate the TypeMap proxy-attribute workaround to .NET 10 only. Fixes #25276#26018

Merged
rolfbjarne merged 2 commits into
mainfrom
dev/rolf/ubiquitous-waffle
Jul 14, 2026
Merged

[dotnet-linker] Gate the TypeMap proxy-attribute workaround to .NET 10 only. Fixes #25276#26018
rolfbjarne merged 2 commits into
mainfrom
dev/rolf/ubiquitous-waffle

Conversation

@rolfbjarne

@rolfbjarne rolfbjarne commented Jul 9, 2026

Copy link
Copy Markdown
Member

The workaround for dotnet/runtime#127004 (adding the proxy type's attribute to the source type so ILLink's TypeMapHandler keeps the TypeMapAssociation) is no longer needed once the ILLink fix is available.

The fix is only present in .NET 11+, so keep the workaround for .NET 10 and only stop applying it for .NET 11+:

  • In TrimmableRegistrarStep, only add the proxy attribute to the source type when targeting .NET 10 or earlier.
  • In TypeMaps (runtime), only read the workaround attribute from the source type for .NET 10 or earlier (gated with !NET11_0_OR_GREATER).

A separate validation-only PR targeting net11.0 (#26019) confirms everything still pass on .NET 11 with the workaround disabled (except the AppSizeTest test failed because NativeAOT app sizes went down ("App size changed significantly (-16,413 bytes)") - which is both expected and desirable).

Fixes #25276

🤖 Pull request created by Copilot

…0 only

The workaround for dotnet/runtime#127004 (adding
the proxy type's attribute to the source type so ILLink's TypeMapHandler keeps
the TypeMapAssociation) is no longer needed once the ILLink fix is available.

The fix is only present in .NET 11+, so keep the workaround for .NET 10 and
only stop applying it for .NET 11+:

* In TrimmableRegistrarStep, only add the proxy attribute to the source type
  when targeting .NET 10 or earlier.
* In TypeMaps (runtime), only read the workaround attribute from the source
  type for .NET 10 or earlier (gated with !NET11_0_OR_GREATER).

Fixes #25276.

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

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

…indClass

When looking up the Objective-C class for a managed type, the trimmable
static registrar's FindClass looked up the *closed* generic type (e.g.
UIGestureRecognizer.Callback<UITapGestureRecognizer>) in the type maps.
However, generic types are registered using their generic type definition
(the maps are keyed by the *open* generic type, e.g. Callback`1), so the
lookup failed and the runtime tried to fall back to the dynamic registrar
(which has been linked away), throwing MT8026:

    Can't register the class UIKit.UIGestureRecognizer+Callback`1[[UIKit.UITapGestureRecognizer, ...]] when the dynamic registrar has been linked away.

This was previously masked by the workaround for
dotnet/runtime#127004: reading the proxy attribute
directly off the closed generic type (Type.GetCustomAttribute) returns the
attribute stamped on the open generic definition, so the lookup happened to
succeed. Once that workaround was gated off for .NET 11+ (commit
d255353), the missing generic-type-definition reduction was exposed,
causing MT8026 (and, depending on timing, a NullReferenceException in
UIGestureRecognizer.OnDispose during finalization of an uninitialized
UITapGestureRecognizer).

Mirror the reduction already done in the non-trimmable FindClass path
(which does `if (type.IsGenericType) type = type.GetGenericTypeDefinition ()`).

Verified with:

    make build run-bare -C tests/monotouch-test/dotnet/MacCatalyst \
        TEST_VARIATION='trimmable-static-registrar-all-optimizations-linkall|release' CONFIG=Release \
        RUN_ARGUMENTS="--test=MonoTouchFixtures.UIKit.GestureRecognizerTest.GenericCallbackTest"

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 22caaaa0-7267-4c5e-8c22-58e5b04e9f42
@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.

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.

Pull request overview

This PR updates the trimmable static registrar TypeMap workaround for the ILLink TypeMapHandler bug (dotnet/runtime#127004) so that it’s only applied for .NET 10 (and earlier), and is disabled for .NET 11+ where the upstream fix exists.

Changes:

  • Gate the linker step’s “copy proxy attribute onto source type” workaround to TargetFramework.Version.Major <= 10.
  • Gate the runtime TypeMaps fallback that reads proxy attributes from the source type to !NET11_0_OR_GREATER.
  • Improve trimmable static registrar class-handle lookup for generic types by resolving via the open generic type definition.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
tools/dotnet-linker/Steps/TrimmableRegistrarStep.cs Only applies the proxy-attribute workaround when targeting .NET 10 or earlier.
src/ObjCRuntime/TypeMaps.cs Stops reading the workaround attribute on .NET 11+ builds (keeps it for .NET 10 and earlier).
src/ObjCRuntime/Class.cs Normalizes constructed generic types to their generic type definition for trimmable TypeMap lookups.
Comments suppressed due to low confidence (1)

src/ObjCRuntime/TypeMaps.cs:362

  • NSObjectProxyTypes lookups don't normalize constructed generic types to their generic type definition. The rest of the registration/type-map lookup logic (for example Class.FindClass and Class.GetTokenReference) normalizes generics before consulting maps, and the new comment here indicates the type maps are keyed by the open generic type. Without this normalization, callers that pass a closed generic type (e.g. Foo<int>) won't find the proxy mapping even though Foo<> is present.
#endif // !NET11_0_OR_GREATER
		// end workaround for https://github.com/dotnet/runtime/issues/127004

		if (!NSObjectProxyTypes.TryGetValue (managedType, out var proxyType)) {
#if LOG_TRIMMABLE_TYPEMAP

@rolfbjarne rolfbjarne marked this pull request as ready for review July 14, 2026 09:49
@rolfbjarne rolfbjarne enabled auto-merge (squash) July 14, 2026 09:49
@vs-mobiletools-engineering-service2

This comment has been minimized.

@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: 70fb83f6fc812034575b05b92b1de7c2f152ac42 [PR build]

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

🚀 [CI Build #70fb83f] Test results 🚀

Test results

✅ All tests passed on VSTS: test results.

🎉 All 199 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. [attempt 2] Html Report (VSDrops) Download
✅ introspection: All 4 tests passed. Html Report (VSDrops) Download
✅ linker (iOS): All 15 tests passed. Html Report (VSDrops) Download
✅ linker (MacCatalyst): All 15 tests passed. Html Report (VSDrops) Download
✅ linker (macOS): All 21 tests passed. Html Report (VSDrops) Download
✅ linker (tvOS): All 15 tests passed. Html Report (VSDrops) Download
✅ monotouch (iOS): All 18 tests passed. Html Report (VSDrops) Download
✅ monotouch (MacCatalyst): All 17 tests passed. Html Report (VSDrops) Download
✅ monotouch (macOS): All 18 tests passed. Html Report (VSDrops) Download
✅ monotouch (tvOS): All 18 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 Monterey (12): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Ventura (13): All 5 tests passed. Html Report (VSDrops) Download
✅ 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: 70fb83f6fc812034575b05b92b1de7c2f152ac42 [PR build]

@rolfbjarne rolfbjarne merged commit b0cda39 into main Jul 14, 2026
57 checks passed
@rolfbjarne rolfbjarne deleted the dev/rolf/ubiquitous-waffle branch July 14, 2026 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Workaround] Remove proxy type attribute on source type when dotnet/runtime#127004 is fixed

4 participants