Skip to content

Fix build-task LibraryImport generation with extensionReceiver - #1850

Merged
Jevan Saks (jevansaks) merged 1 commit into
mainfrom
jevansaks-extension-receiver-generation
Oct 8, 2026
Merged

Jevan Saks (jevansaks) merged 1 commit into
mainfrom
jevansaks-extension-receiver-generation

Conversation

@jevansaks

@jevansaks Jevan Saks (jevansaks) commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Summary

Fixes #1825.

Keep LibraryImport partial methods in a private nested partial class, outside C# 14 extension blocks. Expose ordinary forwarding methods through the configured receiver, preserving source-generated marshalling, parameter modifiers, API documentation, and non-import attributes. Normal generation without extensionReceiver is unchanged.

Reuse the existing two-project sdk-roslyn5 integration test rather than adding a new harness. Add the exact PInvoke.GetCurrentThreadId() call from the issue, plus void and pointer/friendly-overload calls. Run that same project with CsWin32RunAsBuildTask=true in both GitHub Actions and Azure Pipelines. Document build-task composition support.

Generated code: before and after

Focused excerpts for GetCurrentThreadId from the integration test's extender, with file headers, XML documentation, unrelated attributes, and other members omitted for clarity.

Before (broken)

namespace Windows.Win32
{
    public static partial class AppPInvokes
    {
        extension (global::Windows.Win32.PInvoke)
        {
            [LibraryImport("KERNEL32.dll")]
            public static partial uint GetCurrentThreadId();
        }
    }
}

The extension block is not a partial type, even though its containing class is partial. The compiler rejects the partial member (CS0751, CS8795), and the LibraryImport generator cannot provide its implementation (SYSLIB1050).

After (fixed)

namespace Windows.Win32
{
    public static partial class AppPInvokes
    {
        extension (global::Windows.Win32.PInvoke)
        {
            public static uint GetCurrentThreadId() =>
                global::Windows.Win32.AppPInvokes.AppPInvokesImports.GetCurrentThreadId();
        }

        private static partial class AppPInvokesImports
        {
            [LibraryImport("KERNEL32.dll")]
            public static partial uint GetCurrentThreadId();
        }
    }
}

The import now lives in a normal partial type, where the LibraryImport generator can implement it. The extension member has a regular forwarding body, so callers still use PInvoke.GetCurrentThreadId() without disabling source-generated marshalling.

Verification

  • Reproduced before the fix: packaged the unchanged generator and built the extended integration test with build-task generation. The owner built successfully; the extender failed with SYSLIB1050, CS8795, and CS0751 for GetCurrentThreadId.
  • After the fix: rebuilt and packaged the generator, then successfully built the integration test in source-generator and build-task modes and executed it on Windows.
  • Also verified build-task generation with DisableRuntimeMarshalling=true, XML documentation generation, and multi-file output with a custom NativeMethods host name.
  • All 22 existing ExtensionReceiverTests passed.
  • Generator build and package succeeded with warnings treated as errors. Integration builds reported only the existing NU1510 package-pruning warnings.

Keep LibraryImport partial methods in a private nested partial class and forward extension members to them, preserving source-generated marshalling. Reuse the two-project integration test to reproduce #1825 with build-task generation and run it in both CI systems.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b8355a91-f69b-4c9c-9d44-86f5b49e32e5
@jevansaks
Jevan Saks (jevansaks) marked this pull request as ready for review October 8, 2026 22:55
@jevansaks
Jevan Saks (jevansaks) enabled auto-merge (squash) October 8, 2026 23:35
@jevansaks
Jevan Saks (jevansaks) merged commit 8270552 into main Oct 8, 2026
33 checks passed
@jevansaks
Jevan Saks (jevansaks) deleted the jevansaks-extension-receiver-generation branch October 8, 2026 23:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

extensionReceiver with CsWin32RunAsBuildTask=true emits unsupported LibraryImport partials

2 participants