Skip to content

Fix AOT trim warnings on net11.0 (iOS + Android) for Integration tests AOT failure - #36125

Merged
jfversluis merged 1 commit into
dotnet:net11.0from
vishnumenon2684:fix/aot-trim-warnings-net11
Jun 26, 2026
Merged

Fix AOT trim warnings on net11.0 (iOS + Android) for Integration tests AOT failure #36125
jfversluis merged 1 commit into
dotnet:net11.0from
vishnumenon2684:fix/aot-trim-warnings-net11

Conversation

@SubhikshaSf4851

@SubhikshaSf4851 SubhikshaSf4851 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment whether this change resolves your issue. Thank you!

Problem 1: iOS/MacCatalyst — IL2009 trim warning

When building a fully-trimmed net11.0-ios or net11.0-maccatalyst MAUI template app, the linker emits:

warning IL2009: Could not find method 'System.Void Activated(T)' on type 'UIKit.UIGestureRecognizer.Callback`1'

This generates an apply-preserve-attribute.xml file in the linker cache. The AOT test infrastructure (BuildWarningsUtilities.AssertWarnings) treats any unexpected warning file as a failure, and the iOS/MacCatalyst expected baseline is empty — so the test fails.

Root Cause

CustomPressGestureRecognizer.Callback has [Preserve(Conditional = true)] on its Activated method. This tells the linker to emit a preserve descriptor in apply-preserve-attribute.xml. The descriptor references the declaring type by its ObjC registration name __UIGestureRecognizer.

In .NET 11, the iOS SDK refactored its internal UIGestureRecognizer callback to a generic type (UIKit.UIGestureRecognizer.Callback<T>). When the linker resolves the preserve descriptor by the shared ObjC name __UIGestureRecognizer, it now binds to the SDK's generic type — which has no Activated(T) member matching the expected signature → IL2009.

This did not happen on main/candidate (.NET 10 SDK) because the SDK's callback was non-generic there.

Fix

  1. Remove [Preserve(Conditional = true)] — The [Export("target:")] attribute already makes Activated() a static-registrar root under full trimming. The [Preserve] is redundant and was the source of the broken descriptor.
  2. Rename [Register("__UIGestureRecognizer")] to a unique name — Eliminates the latent duplicate ObjC class name collision with the SDK's internal type.

Problem 2: Android — stale warning baseline

The Android SDK updated from 36.x to 37.0.0-ci.main.51 on net11.0, which changed the warning signatures:

Change Old New
Method index g__MakeGenericType&#124;4_1 g__MakeGenericType&#124;5_1
New warnings AndroidReflectionJniValueManager ctor, ManagedTypeManager ctor

The test expected the old signatures and failed with "Expected warning message was not found".

Fixes: #36081

iOS/MacCatalyst fix:
- Rename [Register("__UIGestureRecognizer")] to a unique name to avoid
  duplicate ObjC class registration with the SDK's internal type.
- Remove redundant [Preserve(Conditional = true)] on Activated(). The
  [Export("target:")] already makes it a static-registrar root under
  full trimming. The [Preserve] generated a preserve descriptor in
  apply-preserve-attribute.xml that the linker couldn't resolve against
  UIKit.UIGestureRecognizer.Callback<T>, causing IL2009.

Android fix:
- Update expected AOT warning baseline for Android SDK 37.0.0:
  - Method index shifted from |4_1 to |5_1
  - New warnings for AndroidReflectionJniValueManager and
    ManagedTypeManager constructors

Fixes: dotnet#36081

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 36125

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 36125"

@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label Jun 25, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Hey there @@SubhikshaSf4851! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@dotnet-policy-service dotnet-policy-service Bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Jun 25, 2026
@SubhikshaSf4851
SubhikshaSf4851 marked this pull request as ready for review June 25, 2026 13:05
@SubhikshaSf4851 SubhikshaSf4851 changed the title [WIP] Fix AOT trim warnings on net11.0 (iOS + Android) Fix AOT trim warnings on net11.0 (iOS + Android) Jun 25, 2026
@sheiksyedm sheiksyedm added the area-testing Unit tests, device tests label Jun 25, 2026
@sheiksyedm sheiksyedm changed the title Fix AOT trim warnings on net11.0 (iOS + Android) Fix AOT trim warnings on net11.0 (iOS + Android) for Integration tests AOT failure Jun 25, 2026
@sheiksyedm
sheiksyedm requested a review from kubaflo June 25, 2026 13:36
@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jun 25, 2026
@MauiBot MauiBot added s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Jun 25, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AI Review Summary

@SubhikshaSf4851 — new AI review results are available based on this last commit: b276285. To request a fresh review after new comments or commits, comment /review rerun.

Gate Inconclusive Confidence Low Platform iOS


🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix

Gate Result: ⚠️ INCONCLUSIVE

Platform: IOS

⚠️ verify-tests-fail.ps1 exited before writing a verification report. Diagnostics below.

Exit code: 3

Likely cause:

  • Test detection failed — no runnable tests were found in the PR diff.
Gate output log (last 60 lines)
📁 Output directory: CustomAgentLogsTmp/PRState/36125/PRAgent/gate/verify-tests-fail
🔍 Detecting base branch and merge point...
No PR detected, scanning remote branches for closest base...
✅ Base branch: net11.0 (via closest-merge-base)
✅ Merge base commit: cfea02d9
   (1 commits ahead of net11.0)
╔═══════════════════════════════════════════════════════════╗
║         FULL VERIFICATION MODE                            ║
╠═══════════════════════════════════════════════════════════╣
║  Fix files detected - will verify:                        ║
║  1. Tests FAIL without fix                                ║
║  2. Tests PASS with fix                                   ║
╚═══════════════════════════════════════════════════════════╝
✅ Fix files (1):
   - src/Controls/src/Core/Platform/iOS/CustomPressGestureRecognizer.cs
🔍 Auto-detecting test filter from changed test files...
⚠️ No tests detected in this PR.
   Searched for: UI tests, unit tests, XAML tests, device tests
   Consider adding tests via write-tests-agent.

📋 Pre-Flight — Context & Validation

Issue: #36081 - [ci-scan-net11] AOT macOS integration tests fail every build — IL2009 warning from apply-preserve-attribute.xml on iOS/MacCatalyst (net11.0)
PR: #36125 - Fix AOT trim warnings on net11.0 (iOS + Android) for Integration tests AOT failure
Platforms Affected: iOS, MacCatalyst, Android NativeAOT warning baseline
Files Changed: 2 implementation/test-infrastructure, 0 test

Key Findings

  • The linked issue reports repeatable net11.0 AOT macOS integration failures: IL2009 from apply-preserve-attribute.xml for Activated(T) on UIKit.UIGestureRecognizer.Callback<T>.
  • The PR's iOS fix removes [Preserve(Conditional = true)] from CustomPressGestureRecognizer.Callback.Activated and changes the nested callback ObjC registration from __UIGestureRecognizer to a unique MAUI-specific name.
  • The PR also updates Android NativeAOT expected warning messages after Android SDK warning text/signature drift.
  • No PR inline review comments or prior ❌ review findings were found via the public API surfaces available in this unauthenticated environment.
  • Impacted UI test categories: NONE for UI test category selection; this is an AOT/integration-test warning regression, not a UI behavior test-category change.

Code Review Summary

Verdict: NEEDS_DISCUSSION
Confidence: low
Errors: 0 | Warnings: 1 | Suggestions: 0

Key code review findings:

  • ⚠️ src/Controls/src/Core/Platform/iOS/CustomPressGestureRecognizer.cs:35-46 — removing [Preserve(Conditional = true)] relies on [Export("target:")]/static registrar behavior to keep a selector-only callback rooted under linked/AOT builds; runtime selector dispatch should be explicitly verified.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #36125 Remove conditional preserve from Activated, rename callback registration to a unique ObjC name, and update Android NativeAOT expected warning baseline. ⚠️ INCONCLUSIVE (Gate: build/run environment error) src/Controls/src/Core/Platform/iOS/CustomPressGestureRecognizer.cs, src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs Original PR; code review warning is selector callback preservation evidence gap.

🔬 Code Review — Deep Analysis

Code Review — PR #36125

Independent Assessment

What this changes: Removes a conditional preserve marker from the iOS CustomPressGestureRecognizer selector callback, gives its ObjC registration a unique name, and updates the Android NativeAOT warning baseline.
Inferred motivation: Fix net11 AOT/integration-test failures caused by stale Android warnings and an iOS linker IL2009 warning from the old preserve descriptor.

Reconciliation with PR Narrative

Author claims: [Export("target:")] is sufficient to keep Activated, and the duplicate __UIGestureRecognizer registration caused the iOS warning; Android warnings changed with the SDK.
Agreement/disagreement: The duplicate registration explanation and Android baseline update match the diff. The preservation claim is plausible but is the main risk: the method is still invoked only via selector dispatch, so I would want evidence that the static registrar roots it under linked/AOT builds.

Prior Review Reconciliation

No prior ❌ Error findings found. REST review surfaces showed 0 reviews, 0 inline comments, and 3 issue comments without ❌/[major]/[moderate] findings.

Blast Radius Assessment

  • Runs for all instances: No — only views with PointerGestureRecognizer on iOS/MacCatalyst.
  • Startup impact: No direct startup impact.
  • Static/shared state: No new static/shared state.

CI Status

  • Required-check result: Undetermined via required-check command — gh pr checks --required failed due missing GitHub auth.
  • Classification: Pending/undetermined. REST check-runs for head b276285... show relevant AOT macOS and RunOniOS NativeAOT jobs passing, but overall maui-pr and several jobs were still queued/in progress; one unrelated-looking agent check was failed.
  • Action taken: Confidence capped low; no LGTM.

Findings

⚠️ Warning — Selector callback preservation relies on unproven registrar behavior

src/Controls/src/Core/Platform/iOS/CustomPressGestureRecognizer.cs:35-46

The old [Preserve(Conditional = true)] was removed from Activated, but this method is still reached only through Selector.GetHandle("target:") / [Export("target:")], not a managed call. If [Export] does not root the method in the linked/AOT case, pointer press gestures could fail at runtime even though the IL2009 warning disappears. Consider keeping preservation now that the ObjC registration name is unique, or document/verify the static-registrar rooting behavior with a linked/AOT runtime test.

Failure-Mode Probing

  • Full trim/AOT selector dispatch: build warnings appear fixed, but runtime selector invocation is not proven by the baseline update alone.
  • Duplicate ObjC registration: unique registration name should remove the collision with SDK UIGestureRecognizer.Callback<T>.
  • Android warning drift: exact-message baseline remains intentionally strict; future SDK warning changes will fail tests again by design.
  • Handler disconnect/reconnect: unchanged; weak-reference guards in the caller still prevent stale handler use.

Verdict: NEEDS_DISCUSSION

Confidence: low
Summary: The fix likely addresses the reported CI warnings, and the Android baseline update is straightforward. I would not mark LGTM while required CI is still pending/undetermined and the removed preserve attribute depends on registrar/linker behavior that should be explicitly verified.


🛠️ Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix-1 Restore [Preserve(Conditional = true)] while keeping the PR's unique callback [Register]. ⚠️ Blocked 1 file Tests could not run because .dotnet/packs/Microsoft.Maui.Sdk is missing. The candidate directly tests whether duplicate ObjC registration, not Preserve itself, caused IL2009.
2 try-fix-2 Add DynamicDependency from the action constructor to Callback.Activated; keep unique [Register] and no MAUI Preserve. ⚠️ Blocked 1 file Tests could not run because .dotnet/packs/Microsoft.Maui.Sdk is missing. Strongest theoretical alternative because it explicitly roots the selector method without the Preserve XML path.
3 try-fix-3 Remove selector callback path and invoke the managed action directly from touch overrides. ⚠️ Blocked 1 file Tests could not run because .dotnet/packs/Microsoft.Maui.Sdk is missing. Expert self-review found a major behavior-timing risk.
4 try-fix-4 Use targeted linker/trimmer descriptor rooting for the callback method. ⚠️ Blocked / Not Applied 0 files Rejected during expert review: no existing transitive descriptor packaging pattern in this repo area; speculative infrastructure wiring.
PR PR #36125 Remove [Preserve], keep [Export], use unique callback [Register], update Android NativeAOT baseline. ⚠️ INCONCLUSIVE (Gate) 2 files Original PR; gate could not build/run. Code review warning remains around Export-only selector rooting evidence.

Cross-Pollination

Model Round New Ideas? Details
gpt-5.5 expert 1 Yes Candidate 1: restore MAUI Preserve after unique registration.
gpt-5.5 expert 2 Yes Candidate 2: use DynamicDependency instead of MAUI Preserve or Export-only rooting.
gpt-5.5 expert 3 Yes Candidate 3: remove selector callback helper and invoke action directly from touch overrides.
claude-opus-4.6 4 Yes Suggested switching pointer handling to UIHoverGestureRecognizer; not applied because the bug is in the press recognizer path and this does not preserve secondary-button press semantics by itself.
claude-opus-4.7 4 Yes Suggested targeted linker root descriptor; recorded as candidate 4 and rejected as speculative without repo packaging pattern.
gpt-5.3-codex 4 Yes Suggested ILLink descriptor XML; same disposition as candidate 4.
gpt-5.5 4 Yes Suggested using a different recognizer target instance with exported method; not applied because it retains selector rooting and is a variation on the same target/action mechanism rather than a stronger alternative to candidates 1/2.

Exhausted: Yes
Selected Fix: None — no candidate passed tests or was demonstrably better than the PR's fix in this environment. Candidate #2 is the strongest theoretical alternative because it avoids both Export-only rooting and the MAUI Preserve XML path, but it remains unverified. Candidate #3 is not recommended due the major behavior-timing risk; candidate #4 is not recommended due speculative build/package wiring.


📝 Recommended PR Title & Description

Assessment: ✏️ Recommend updating — the description is detailed and accurate, but the title should include MacCatalyst and follow the platform/component formula.

Recommended title

[iOS/MacCatalyst/Android] IntegrationTests: Fix net11.0 NativeAOT trim warning baselines

Recommended description

## Problem 1: iOS/MacCatalyst — IL2009 trim warning

When building a fully-trimmed `net11.0-ios` or `net11.0-maccatalyst` MAUI template app, the linker emits:

warning IL2009: Could not find method 'System.Void Activated(T)' on type 'UIKit.UIGestureRecognizer.Callback`1'

This generates an `apply-preserve-attribute.xml` file in the linker cache. The AOT test infrastructure (`BuildWarningsUtilities.AssertWarnings`) treats any unexpected warning file as a failure, and the iOS/MacCatalyst expected baseline is empty — so the test fails.

### Root Cause

`CustomPressGestureRecognizer.Callback` has `[Preserve(Conditional = true)]` on its `Activated` method. This tells the linker to emit a preserve descriptor in `apply-preserve-attribute.xml`. The descriptor references the declaring type by its ObjC registration name `__UIGestureRecognizer`.

In .NET 11, the iOS SDK refactored its internal `UIGestureRecognizer` callback to a generic type (`UIKit.UIGestureRecognizer.Callback<T>`). When the linker resolves the preserve descriptor by the shared ObjC name `__UIGestureRecognizer`, it now binds to the SDK's generic type — which has no `Activated(T)` member matching the expected signature → `IL2009`.

This did not happen on `main`/`candidate` (.NET 10 SDK) because the SDK's callback was non-generic there.

### Fix

1. **Remove `[Preserve(Conditional = true)]`** — The `[Export("target:")]` attribute already makes `Activated()` a static-registrar root under full trimming. The `[Preserve]` is redundant and was the source of the broken descriptor.
2. **Rename `[Register("__UIGestureRecognizer")]` to a unique name** — Eliminates the latent duplicate ObjC class name collision with the SDK's internal type.

## Problem 2: Android — stale warning baseline

The Android SDK updated from `36.x` to `37.0.0-ci.main.51` on `net11.0`, which changed the warning signatures:

| Change | Old | New |
|---|---|---|
| Method index | `g__MakeGenericType&#124;4_1` | `g__MakeGenericType&#124;5_1` |
| New warnings | — | `AndroidReflectionJniValueManager` ctor, `ManagedTypeManager` ctor |

The test expected the old signatures and failed with `"Expected warning message was not found"`.

Fixes: https://github.com/dotnet/maui/issues/36081

🏁 Report — Final Recommendation

Comparative Analysis — PR #36125

Candidate Ranking

Rank Candidate Regression result Assessment
1 pr-plus-reviewer ⚠️ Inconclusive / not failed Winner. The expert reviewer found no actionable issues, so this is identical to the PR fix but with expert review applied. It is the most localized fix that matches the root cause and avoids speculative additional trim annotations or gesture behavior changes.
2 pr ⚠️ Inconclusive / not failed Equivalent code to pr-plus-reviewer, but ranked below the reviewed candidate label because Phase 1 explicitly validated that no reviewer changes were needed.
3 try-fix-2 ⚠️ Blocked / not failed Strongest theoretical alternative: adds DynamicDependency to explicitly root Callback.Activated while avoiding the MAUI Preserve XML path. It is not selected because it adds unverified trim annotation surface to solve a concern the expert review did not find actionable.
4 try-fix-1 ⚠️ Blocked / not failed Keeps explicit preservation after the unique registration rename. It may be viable, but it reintroduces the same MAUI Preserve descriptor mechanism involved in the original failure, making it less attractive than the PR's descriptor-removal approach.
5 try-fix-3 ⚠️ Blocked / not failed Removes selector dispatch entirely, but changes callback timing by invoking the action directly from touch overrides. Its own expert self-review found a major gesture timing/simultaneous-recognition risk.
6 try-fix-4 ⚠️ Blocked / not applied Rejected design-level candidate. It has no final diff and would require speculative linker descriptor/package wiring not established in this repo area.

Winning Candidate

pr-plus-reviewer is the single winning candidate.

The expert review produced no inline findings and no actionable sandbox feedback, so pr-plus-reviewer is identical to the submitted PR fix. It wins because it directly addresses both documented warning failures with the smallest behavioral surface: iOS/MacCatalyst keeps the existing target/action gesture callback path while removing the problematic preserve descriptor source and duplicate ObjC registration name; Android updates only the strict expected warning baseline.

Test Result Handling

No candidate passed regression tests in this environment, but none failed regression tests either. The PR gate and try-fix runs were inconclusive/blocked by environment issues, so the ranking is based on code-review merit, blast radius, and candidate risk rather than treating any candidate as test-failed.

Why the Alternatives Did Not Win

try-fix-2 is the best fallback if maintainers want explicit trimmer rooting beyond [Export], but it remains unverified and the expert reviewer did not identify missing rooting as an actionable defect. try-fix-1 preserves more aggressively but brings back the descriptor mechanism implicated in the original warning. try-fix-3 changes gesture dispatch semantics, and try-fix-4 has no concrete implementation.


🧭 Next Steps — review latest findings

No alternative fix was selected for this run. Review the session findings and CI results before merging.

@PureWeen

Copy link
Copy Markdown
Member

@simonrozsival @jonathanpeppers this look alright?

@jfversluis
jfversluis merged commit 630ffae into dotnet:net11.0 Jun 26, 2026
35 of 36 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-testing Unit tests, device tests community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants