From b0a02d3fc90dcec976e59d1d787159a6260209f7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Apr 2026 13:03:46 +0000 Subject: [PATCH 1/2] Initial plan From 3b2d49758f9bcf574615d51cb55f892a6f31d9f7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Apr 2026 13:56:48 +0000 Subject: [PATCH 2/2] Apply TypeMap instantiation fix: protected internal virtual + MarkRequirementsForInstantiatedTypes + test Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/b98f3157-9724-49b7-92fe-29cfad891f1e Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com> --- .../src/linker/Linker.Steps/MarkStep.cs | 2 +- .../src/linker/Linker/TypeMapHandler.cs | 2 +- .../Reflection/TypeMap.cs | 22 +++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 977bcdebaf49e5..c48273e97439f9 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -3515,7 +3515,7 @@ static bool TypeIsInlineArrayType(TypeDefinition type) return false; } - protected virtual void MarkRequirementsForInstantiatedTypes(TypeDefinition type) + protected internal virtual void MarkRequirementsForInstantiatedTypes(TypeDefinition type) { if (Annotations.IsInstantiated(type)) return; diff --git a/src/tools/illink/src/linker/Linker/TypeMapHandler.cs b/src/tools/illink/src/linker/Linker/TypeMapHandler.cs index dce5132369f3d3..2b1d2e4a55e8c4 100644 --- a/src/tools/illink/src/linker/Linker/TypeMapHandler.cs +++ b/src/tools/illink/src/linker/Linker/TypeMapHandler.cs @@ -109,7 +109,7 @@ void MarkTypeMapAttribute(CustomAttributeWithOrigin entry, DependencyInfo info) // Mark the target type as instantiated if (entry.TargetType is { } targetType && _context.Resolve(UnwrapToResolvableType(targetType)) is TypeDefinition targetTypeDef) - _context.Annotations.MarkInstantiated(targetTypeDef); + _markStep.MarkRequirementsForInstantiatedTypes(targetTypeDef); } public void ProcessType(TypeDefinition definition) diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeMap.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeMap.cs index ce887a9d5e8458..9747baabb92950 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeMap.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeMap.cs @@ -85,6 +85,15 @@ [assembly: TypeMapAssemblyTarget("library")] [assembly: TypeMapAssemblyTarget("library")] // Should be removed +// Verify that when a TypeMapAttribute's target type is instantiated by TypeMap processing, +// the associated TypeMapAssociation entry is also kept. Without the fix, only MarkInstantiated +// was called (not MarkRequirementsForInstantiatedTypes), preventing ProcessInstantiated from +// being called and leaving TypeMapAssociation entries unmarked. +[assembly: TypeMap("BothInExternalAndProxy", typeof(BothInExternalAndProxy), typeof(BothInExternalAndProxyTrimTarget))] // Kept +[assembly: TypeMapAssociation(typeof(BothInExternalAndProxy), typeof(BothInExternalAndProxyTarget))] // Kept +[assembly: KeptAttributeAttribute(typeof(TypeMapAttribute), "BothInExternalAndProxy", typeof(BothInExternalAndProxy), typeof(BothInExternalAndProxyTrimTarget))] +[assembly: KeptAttributeAttribute(typeof(TypeMapAssociationAttribute), typeof(BothInExternalAndProxy), typeof(BothInExternalAndProxyTarget))] + namespace Mono.Linker.Tests.Cases.Reflection { [SetupLinkerAction("link", "System.Private.CoreLib")] // Needed to get the RemoveAttributeInstances in embedded xml @@ -234,6 +243,11 @@ static void ConstrainedStaticCall(T t) where T : IStaticInterface _ = new int(); _ = TypeMapping.GetOrCreateExternalTypeMapping(); _ = TypeMapping.GetOrCreateProxyTypeMapping(); + + // Instantiate BothInExternalAndProxyTrimTarget to trigger the TypeMap entry for BothInExternalAndProxy. + // BothInExternalAndProxy is only instantiated via TypeMap processing (not directly), which verifies + // that MarkRequirementsForInstantiatedTypes is called to propagate instantiation to TypeMapAssociation. + _ = new BothInExternalAndProxyTrimTarget(); } [ExpectBodyModified] @@ -572,4 +586,12 @@ class ArrayTypeTrimTargetClass; class ArrayTypeTrimTargetUnusedTarget; class ArrayTypeTrimTargetUnusedClass; + + [Kept] + [KeptMember(".ctor()")] + class BothInExternalAndProxyTrimTarget; + [Kept] + class BothInExternalAndProxy; + [Kept] + class BothInExternalAndProxyTarget; }