Make WindowsRuntimeDefaultInterface attribute trimmable#2350
Open
Sergio0694 wants to merge 9 commits intostaging/3.0from
Open
Make WindowsRuntimeDefaultInterface attribute trimmable#2350Sergio0694 wants to merge 9 commits intostaging/3.0from
Sergio0694 wants to merge 9 commits intostaging/3.0from
Conversation
Change the attribute to accept both the runtime class type and the default interface type as parameters, rather than just the interface type. This allows the attribute to be applied to a centralized lookup type instead of individual class types, enabling trimming of unused interface types. Also set AllowMultiple = true since the centralized type will need multiple attribute instances for all projected runtime classes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Instead of emitting [WindowsRuntimeDefaultInterface] on each projected runtime class, accumulate all default interface entries during code generation and emit them on a centralized 'WindowsRuntimeDefaultInterfaces' static class in the ABI namespace. This decouples the interface type references from the class types, enabling trimming of unused interfaces. The entries are collected in a concurrent map during parallel namespace processing and written in sorted order to a dedicated file after all namespaces have been processed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update TryGetDefaultInterfaceFromAttribute to look up the WindowsRuntimeDefaultInterfaces type in the ABI namespace of the projection assembly, and iterate its attributes to find the default interface for the requested class type. This replaces the previous approach of looking up the attribute on each individual class type. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add GetDefaultInterfacesLookup extension method on ModuleDefinition, following the same caching pattern as GetTopLevelTypesLookup. This builds a FrozenDictionary keyed by (Namespace, Name) from the attributes on the centralized WindowsRuntimeDefaultInterfaces type, cached via a ConditionalWeakTable for automatic cleanup. Update TryGetDefaultInterfaceFromAttribute to use this cached lookup instead of iterating all attributes on each invocation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace use of GetTopLevelTypesLookup with a direct scan of module.TopLevelTypes to find the ABI.WindowsRuntimeDefaultInterfaces type and return an empty frozen map if it's missing. Simplify attribute handling by directly using classType.Namespace/name as the lookup key (no Resolve call) and collect runtime-class→default-interface pairs. Add a System using and a minor formatting cleanup for a TryGetValue call in SignatureGenerator.
11573f5 to
57518ea
Compare
Use write_file_header() followed by only the minimal usings needed: 'using WindowsRuntime;' for the attribute type and the CSWINRT3001 pragma suppression. This avoids importing namespaces that may not exist in all projection compilation contexts. Move write_file_header() above its first call site to avoid a forward reference compilation error (C3861). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the hardcoded '0.0.0-private.0' version string with the VERSION_STRING constant, matching all other generated file headers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
57518ea to
9da7f1d
Compare
Clear the writer's current namespace before generating interface type names so that all type references, including generic type arguments, are fully qualified with 'global::'. Without this, types in the same namespace as the class being processed would be emitted without qualification, causing compilation errors when the names are emitted in the ABI namespace context. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Some generic type arguments (e.g. Guid) are emitted as unqualified names by the writer. Add 'using System;' so these types resolve correctly in the ABI namespace context. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
Summary
Move the
[WindowsRuntimeDefaultInterface]attribute from individual projected runtime class types to a centralizedWindowsRuntimeDefaultInterfacesstatic class in theABInamespace. This decouples the default interfaceTypereferences from the class types themselves, allowing the trimmer to remove unused interface types at publish time.Previously, each projected runtime class carried a
[WindowsRuntimeDefaultInterface(typeof(IDefaultInterface))]attribute directly on the class. Because attributes are not trimmable, this forced the linker to preserve the interface type even when it was never used at runtime. The attribute is only consumed by the interop generator (WinRT.Interop.Generator) to compute WinRT type signatures.Changes
Attribute definition (
WindowsRuntimeDefaultInterfaceAttribute)Typeparameter (interfaceType) to twoTypeparameters (runtimeClassType,interfaceType)AllowMultiple = truesince the centralized type needs multiple attribute instancesCode generator (
cswinrt.exe)[WindowsRuntimeDefaultInterface]emission fromwrite_classadd_default_interface_entryto accumulate (class, interface) pairs during parallel namespace processingwrite_default_interfaces_classto emit a singleWindowsRuntimeDefaultInterfaces.csfile after all namespaces are processed, with entries sorted for deterministic output!settings.reference_projectionsince the file is only needed for implementation assemblieswrite_begin()for the file header, consistent with all other generated filesInterop generator (
WinRT.Interop.Generator)TryGetDefaultInterfaceFromAttributeto look up the centralizedABI.WindowsRuntimeDefaultInterfacestype instead of searching for the attribute on each individual classGetDefaultInterfacesLookupextension method onModuleDefinitionfollowing the same caching pattern asGetTopLevelTypesLookup: aConditionalWeakTableholding aFrozenDictionary<(Namespace, Name), TypeSignature>for O(1) lookupsInteropReferencesparameter fromTryGetDefaultInterfaceFromAttributesince attribute type validation is no longer needed (the centralized type only has these attributes)Bug fix
write_begin_interface_iidsintype_writers.hwhich was hardcoding version0.0.0-private.0instead of usingVERSION_STRINGGenerated output (before → after)
Before (on each class):
After (centralized file):