Skip to content

[sharpie] Emit correct nullability for block/delegate parameters#25837

Draft
rolfbjarne wants to merge 7 commits into
mainfrom
dev/rolf/sharpie-block-nullability
Draft

[sharpie] Emit correct nullability for block/delegate parameters#25837
rolfbjarne wants to merge 7 commits into
mainfrom
dev/rolf/sharpie-block-nullability

Conversation

@rolfbjarne

Copy link
Copy Markdown
Member

When ObjC declares a block with nullable parameters (e.g., void (^)(BOOL success, NSError * _Nullable error)), sharpie previously produced Action<bool, NSError>, losing the nullability information. This PR teaches sharpie to produce Action<bool, NSError?> instead.

Approach

The fix operates at two levels in the sharpie pipeline:

  • TypeBinder.VisitFunctionType -- After resolving each block parameter type, checks for CX_AttrKind_TypeNullable in the AttributedType annotations (which clang already attaches). If found, wraps the resolved type with ComposedType.HasNullableSpecifier = true to produce the ? suffix in type arguments. This handles the inline Action<>/Func<> case.

  • CustomDelegateMassager + BindingGenerator -- When converting inline delegates to named delegate declarations, unwraps the nullable ComposedType back to its base type while preserving annotations. This allows the existing NullabilityMassager to add [NullAllowed] to the delegate parameter (the correct representation for binding definition delegates).

xtro-sharpie validation

Extends NullabilityCheck to validate block parameter nullability:

  • Detects BlockPointerType parameters and inspects the underlying FunctionProtoType
  • For each block parameter, compares native nullability against the managed NullableAttribute byte array positions
  • Reports !missing-null-allowed! / !extra-null-allowed! for mismatches

This addresses the existing TODO in NullabilityCheck: "check the generics (don't think we have such cases yet)".

🤖 Pull request created by Copilot

rolfbjarne and others added 7 commits June 26, 2026 17:44
When ObjC declares a block with nullable parameters (e.g.,
void (^)(BOOL, NSError * _Nullable)), sharpie now produces
Action<bool, NSError?> instead of Action<bool, NSError>.

This also applies to the return type of Func<> delegates.

The logic checks for CX_AttrKind_TypeNullable annotations on
resolved types and wraps them with ComposedType.HasNullableSpecifier
to produce the '?' suffix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When CustomDelegateMassager or BindingGenerator convert inline
Action<>/Func<> types to named delegate declarations, unwrap
nullable ComposedTypes (T?) back to their base type. This preserves
the annotations so NullabilityMassager can add [NullAllowed] to
the delegate parameter instead, which is the correct representation
for binding definition delegate parameters.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extend the NullabilityCheck to inspect block/delegate parameters
for nullability mismatches between native and managed code.

When a method parameter is a block type (e.g., void (^)(BOOL, NSError *)),
the check now validates nullability of each block parameter against
the NullableAttribute byte array on the managed generic type arguments.

Reports !missing-null-allowed! and !extra-null-allowed! for block
parameter nullability mismatches.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When ObjC declares a block with nullable parameters (e.g.,
void (^)(BOOL, NSError * _Nullable)), sharpie now produces
Action<bool, NSError?> instead of Action<bool, NSError>.

This also applies to the return type of Func<> delegates.

The logic checks for CX_AttrKind_TypeNullable annotations on
resolved types and wraps them with ComposedType.HasNullableSpecifier
to produce the '?' suffix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When CustomDelegateMassager or BindingGenerator convert inline
Action<>/Func<> types to named delegate declarations, unwrap
nullable ComposedTypes (T?) back to their base type. This preserves
the annotations so NullabilityMassager can add [NullAllowed] to
the delegate parameter instead, which is the correct representation
for binding definition delegate parameters.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extend the NullabilityCheck to inspect block/delegate parameters
for nullability mismatches between native and managed code.

When a method parameter is a block type (e.g., void (^)(BOOL, NSError *)),
the check now validates nullability of each block parameter against
the NullableAttribute byte array on the managed generic type arguments.

Reports !missing-null-allowed! and !extra-null-allowed! for block
parameter nullability mismatches.

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

This comment has been minimized.

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ [PR Build #898c0bb] Build passed (Detect API changes) ✅

Pipeline on Agent
Hash: 898c0bbc5b4520c1c929172e9e49f5cced8f78b3 [PR build]

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ [PR Build #898c0bb] Build passed (Build packages) ✅

Pipeline on Agent
Hash: 898c0bbc5b4520c1c929172e9e49f5cced8f78b3 [PR build]

@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: 898c0bbc5b4520c1c929172e9e49f5cced8f78b3 [PR build]

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ [PR Build #898c0bb] Build passed (Build macOS tests) ✅

Pipeline on Agent
Hash: 898c0bbc5b4520c1c929172e9e49f5cced8f78b3 [PR build]

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

🔥 [CI Build #898c0bb] Test results 🔥

Test results

❌ Tests failed on VSTS: test results

0 tests crashed, 3 tests failed, 196 tests passed.

Failures

❌ monotouch tests (MacCatalyst)

1 tests failed, 16 tests passed.

Failed tests

  • monotouch-test/Mac Catalyst/Release (link sdk): Failed (Test run failed.
    Tests run: 3768 Passed: 3583 Inconclusive: 19 Failed: 1 Ignored: 184)

Html Report (VSDrops) Download

❌ sharpie tests

1 tests failed, 0 tests passed.

Failed tests

  • Sharpie tests: Failed (Execution failed with exit code 1)
    • Sharpie.Bind.Tests.OnDiskTests.ParseRunTest("Nullability.h","iph...: Expected binding code
      Assert.That(actual, Is.EqualTo (expected))
      Expected string length 3659 but was 3660. Strings differ at...
    • Sharpie.Bind.Tests.OnDiskTests.ParseRunTest("Nullability.h","mac...: Expected binding code
      Assert.That(actual, Is.EqualTo (expected))
      Expected string length 3659 but was 3660. Strings differ at...

Html Report (VSDrops) Download

❌ xtro tests

1 tests failed, 0 tests passed.

Failed tests

  • Xtro: Failed (Execution failed with exit code 1)
    • Xamarin.Tests.Xtro.RunTest: ExitCode
      Assert.That(rv, Is.EqualTo (0))
      Expected: 0
      But was: 2

Html Report (VSDrops) Download

Successes

✅ 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 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 (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
✅ windows: All 3 tests passed. Html Report (VSDrops) Download
✅ xcframework: All 4 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: 898c0bbc5b4520c1c929172e9e49f5cced8f78b3 [PR build]

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.

2 participants