Do not treat Windows Runtime attribute types as Windows Runtime types - #2497
Open
Sergio0694 wants to merge 1 commit into
Open
Do not treat Windows Runtime attribute types as Windows Runtime types#2497Sergio0694 wants to merge 1 commit into
Sergio0694 wants to merge 1 commit into
Conversation
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
Sergio0694
force-pushed
the
user/sergiopedri/erase-winrt-attribute-generics
branch
from
July 29, 2026 05:20
4e9e553 to
5e67017
Compare
Sergio0694
force-pushed
the
user/sergiopedri/erase-winrt-attribute-generics
branch
from
July 29, 2026 19:32
590330c to
3990dee
Compare
Sergio0694
marked this pull request as draft
July 29, 2026 21:57
Sergio0694
force-pushed
the
user/sergiopedri/erase-winrt-attribute-generics
branch
from
July 29, 2026 22:26
0bb5607 to
92217c3
Compare
Windows Runtime attributes are metadata-only: they are never activated and
never cross the ABI boundary, so the projection deliberately emits no
marshalling infrastructure for them (no default interface, no IID, no 'Impl'
type, no marshaller). It did however still stamp them with the
'[WindowsRuntimeType]' marker, which is exactly the statement that a type
participates in Windows Runtime marshalling. Both consumers believed it and
then failed to find any marshalling logic:
- The interop generator classifies a generic instantiation as a Windows
Runtime one only when every type argument is a Windows Runtime type, so
'IEnumerable<SomeAttribute>' was routed into the Windows Runtime path and
then failed the whole build with 'CSWINRTINTEROPGEN0055', as no type
signature can be computed for the attribute type.
- The runtime resolved the attribute type as its own metadata provider and
then threw from 'GetComWrappersMarshaller' when an instance was marshalled.
Attribute types are now excluded from both, so they behave like any managed
type: 'List<SomeAttribute>' is handled exactly like 'List<SomeManagedClass>'
(its CCW gets 'IIterable<IInspectable>' from the covariance expansion, and it
still gets its own proxy entry), and the attribute instances marshal as opaque
'IInspectable' objects. Reference projections need the structural check on the
generator side, as they carry no per-type marker at all.
The '.winmd' stem for attribute types is still recorded in the centralized
metadata lookup, as that is build-time only data for the other generators.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8e084ca2-e552-4f3c-82dd-cf30a5970335
Sergio0694
force-pushed
the
user/sergiopedri/erase-winrt-attribute-generics
branch
from
July 29, 2026 22:31
92217c3 to
8d143d3
Compare
Sergio0694
marked this pull request as ready for review
July 29, 2026 22:32
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Using a projected Windows Runtime attribute type as a generic type argument failed the whole build:
type.GetCustomAttributes<SomeAttribute>()is enough to trigger it — it createsIEnumerable<SomeAttribute>andIEnumerator<SomeAttribute>instantiations in the assembly.Root cause
Windows Runtime attributes are metadata-only: they are never activated and never cross the ABI boundary, so the projection deliberately emits no marshalling infrastructure for them — no default interface, no IID, no
Impltype, no marshaller (everything inProjectionGenerator.Namespace.csis guarded on!type.IsAttributeType).It did however still stamp them with
[WindowsRuntimeType], which is precisely the statement "this type participates in Windows Runtime marshalling". Both consumers believed it and then failed to find any marshalling logic:IsWindowsRuntimeTypeclassifies a generic instantiation as a Windows Runtime one only when every type argument is a Windows Runtime type. That is whyIEnumerable<SomeManagedClass>is not one, is never tracked, and the CCW instead getsIEnumerable<object>from the covariance expansion. Attribute types wrongly passed that check, soIEnumerable<SomeAttribute>went down the Windows Runtime path andSignatureGenerator.Classfound neither a default interface nor an IID →CSWINRTINTEROPGEN0055.WindowsRuntimeMarshallingInfo.GetMetadataProviderTypeshort-circuits on[WindowsRuntimeType]for non-generic types and returns the type as its own metadata provider.GetOrCreateComInterfaceForObjectthen callsGetComWrappersMarshaller(), which throwsNotSupportedExceptioninstead of falling through to the opaque-IInspectablepath that every other managed object takes.One cause, two symptoms — the second only became reachable once the first was worked around.
Fix
Stop reporting attribute types as Windows Runtime types.
[WindowsRuntimeType]on attribute types. The.winmdstem is still recorded in the centralizedABI.WindowsRuntimeMetadataTypeslookup, since that is build-time only data for the other generators.IsWindowsRuntimeType/IsNotExclusiveToWindowsRuntimeType. This is still needed on top of the above, because reference projections carry no per-type marker at all:IsReferenceProjectionWindowsRuntimeTypeis assembly-level, so every type in a NuGet-shipped reference projection would otherwise still qualify.Attribute types now behave like any managed type:
List<SomeAttribute>is handled exactly likeList<SomeManagedClass>— it still gets its own proxy/type-map entry, its CCW getsIIterable<IInspectable>from the covariance expansion, and the attribute instances marshal as opaqueIInspectableobjects.The detection is a direct base-type comparison against
System.Attribute. Windows Runtime attributes always derive directly from it (the type system does not allow an attribute to derive from another one), so no base-class-chain walk is needed.Notes
An earlier revision of this PR type-erased the attribute type arguments to
objectin the interop generator instead. That treated the symptom rather than the cause: it needed a dedicated eraser, erasure call sites in three discovery entry points, careful ordering against the resolvability guards, and an extra parameter threaded throughTryAddExposedInterfaceTypefor the dedup invariant — and it still left the runtime failure in place. All of that is gone; the existing managed/covariance path already does the right thing once the classification is correct.It also removes the
IsAssignableFromcall that was tripping theNullReferenceExceptionreported in Washi1337/AsmResolver#770.Tests
Two tests in
src/Tests/UnitTest:TestGenericsOverWindowsRuntimeAttributeTypes— the original repro (GetCustomAttributes<T>), then marshals aList<SomeAttribute>across the ABI through anIIterable<Object>property and round-trips it back. The test building covers theCSWINRTINTEROPGEN0055failure; the assertions cover theGetComWrappersMarshallerone, since the native side enumerates the collection and marshals the attribute instances.TestWindowsRuntimeAttributeTypeInterfaceEntriesAreNotDuplicated— reads the CCW's IIDs viaIInspectable::GetIidsand assertsIIterable<IInspectable>appears exactly once (a duplicate entry is invisible toQueryInterface, so this is the only way to observe it).Validation
ObjectLifetimeTests.Lifted.TestComponentCSharpimplementation projection and confirmedMyStringAttributeno longer carries[WindowsRuntimeType], that real runtime classes such asNonAgileClassstill carry it plus their marshaller, and that the.winmdstem entry is still emitted.