Skip to content

Support TypeDefinition handles for struct-typed constants in nesting and extension blocks - #1846

Open
Austin (AustinAviv) wants to merge 1 commit into
microsoft:mainfrom
AustinAviv:fix/typedef-constant-handle
Open

Austin (AustinAviv) wants to merge 1 commit into
microsoft:mainfrom
AustinAviv:fix/typedef-constant-handle

Conversation

@AustinAviv

Copy link
Copy Markdown

Summary

Fixes #1845. Struct constant nesting and extension block resolution now support constants whose type is encoded as a TypeDefinitionHandle in metadata signatures.

Details

In Generator.Constant.cs, constant signatures typed as typedef structs were only inspected if handleInfo.Handle.Kind == HandleKind.TypeReference. For metadata modules where types in the same assembly are referenced directly via HandleKind.TypeDefinition:

  • fieldType was left null, so constants were not injected into the struct declaration.
  • extensionStructName was left null, so forwarders under extensionReceiver did not attach to the struct extension block.
  • CreateConstant assumed TypeReferenceHandle, failing if invoked with a TypeDefinitionHandle.

This change:

  1. Handles both HandleKind.TypeDefinition and HandleKind.TypeReference when extracting the type name, namespace, and definition handle for constant nesting.
  2. Accepts EntityHandle in CreateConstant to support both handle kinds when instantiating target types.
  3. Adds IL test fixture TypeDefConstant.il / TypeDefConstant.winmd and test coverage in MultiMetadataTests verifying struct nesting and extension block binding.

@AustinAviv
Austin (AustinAviv) force-pushed the fix/typedef-constant-handle branch from 7307a49 to a292593 Compare October 9, 2026 02:29

@jevansaks Jevan Saks (jevansaks) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The core TypeDefinition nesting change looks directionally correct, and the nesting test covers the metadata-default-value path. I am requesting changes because the extension regression test bypasses the production validation path and currently accepts generated code that does not compile, while the new ConstantAttribute/TypeDefinition branch is not exercised.

Non-blocking: CreateConstant can reuse the existing TryGetTypeDefHandle(EntityHandle, out QualifiedTypeDefinitionHandle) helper rather than duplicating its TypeReference/TypeDefinition switch, while retaining the Guid fallback for unresolved type references.

Comment thread test/Microsoft.Windows.CsWin32.Tests/MultiMetadataTests.cs
Comment thread test/Microsoft.Windows.CsWin32.Tests/MultiMetadataTests.cs
Comment thread src/Microsoft.Windows.CsWin32/Generator.Constant.cs Outdated
@jevansaks

Copy link
Copy Markdown
Member

Austin (@AustinAviv)
Austin (AustinAviv) requested a review from Jevan Saks (jevansaks) 37 minutes ago

I don't see any responses to the comments or pushes to the PR. Please take a look at the comments I left.

@jevansaks

Copy link
Copy Markdown
Member

Could you share the practical, real-world repro that led to #1845? In particular, is there an actual WinMD/package or metadata-generation tool that emits a typedef struct and a constant of that type using a TypeDefinition handle, and what API/constant is affected?

The regression fixture in this PR is hand-authored IL, and the current Windows SDK metadata does not appear to contain this encoding for constants. A representative WinMD (or the producer and exact declaration) would help establish the impact and confirm that the fixture matches the real metadata shape. If this is anticipatory support rather than a reported real-world failure, please confirm that as well.

@AustinAviv

Copy link
Copy Markdown
Author

Austin (Austin (@AustinAviv))
Austin (AustinAviv) requested a review from Jevan Saks (jevansaks) 37 minutes ago

I don't see any responses to the comments or pushes to the PR. Please take a look at the comments I left.

Thanks for the review, Jevan Saks (@jevansaks)! Sorry, I missed your comments when I checked GitHub around midnight.

I'll fix the tests so they properly check the generated code and try to find a real-world WinMD example that reproduces the issue. If I can't find one, I'll mention that this is anticipatory support.

Thanks for taking the time to review my PR!

@AustinAviv
Austin (AustinAviv) force-pushed the fix/typedef-constant-handle branch from a292593 to a706e75 Compare October 10, 2026 08:38
@AustinAviv

Copy link
Copy Markdown
Author

Thanks for the detailed review Jevan Saks (@jevansaks)! I pushed an update addressing all points:

  1. Reverted CreateConstant changes: Kept the PR strictly focused on the TypeDefinition constant nesting logic in Generator.Constant.cs as suggested.
  2. Fixed receiver test configuration: Updated TypeDefConstant_WithExtensionReceiver_AttachesToStructExtensionBlock to use a distinct host class name (PInvokeExtensions), kept ExtensionReceiver = "PInvoke", declared the receiver stub in TypeDefConstant.PInvoke, added an explicit int conversion operator to CUSTOM_HANDLE, and enabled AssertNoDiagnostics(). Both tests compile cleanly and pass with zero warnings.
  3. Context / Repro: To confirm, this is anticipatory support for valid ECMA-335 metadata shapes rather than a failure in the published Windows SDK winmd (which references its types via TypeReference). We ran into this when working with custom metadata modules where typedef structs and their constants are defined in the same module and emitted as TypeDefinition handles.

@jevansaks

Copy link
Copy Markdown
Member

Got it. And so was the metadata you ran into this problem with generated by the winmdgenerator tooling? Or the windows-rs tooling? Or something else custom?

This branch has not been deployed

No deployments
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.

Struct-typed constants defined with TypeDefinition handles fail to nest into target struct

2 participants