Skip to content

[ILLink] Fix crash when array types are used as TypeMap trim targets with PublishTrimmed#126380

Open
Copilot wants to merge 3 commits intomainfrom
copilot/fix-array-type-map-build-failure
Open

[ILLink] Fix crash when array types are used as TypeMap trim targets with PublishTrimmed#126380
Copilot wants to merge 3 commits intomainfrom
copilot/fix-array-type-map-build-failure

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 31, 2026

PublishTrimmed crashes with NotSupportedException: TypeDefinition cannot be resolved from 'Mono.Cecil.ArrayType' when a TypeMap attribute specifies an array type as its trim target (e.g., typeof(Foo[])). PublishAot is unaffected (handled in #123031).

Root cause: LinkContext.Resolve throws for any TypeSpecification that isn't a GenericInstanceType. Array types, pointer types, and byref types all fall into this category.

Description

  • TypeMapHandler.AddExternalTypeMapEntry: Strip non-resolvable TypeSpecification wrappers (array, pointer, byref, etc.) from the trim target before passing to RecordTypeMapEntry, using the element type instead. Loop terminates at the first TypeDefinition or GenericInstanceType (both resolvable).
  • TypeMapHandler.AddProxyTypeMapEntry: Same fix applied symmetrically to the source type parameter. Corrected the comment to accurately state that TypeMapAssociationAttribute has two constructor type arguments (source and proxy).
// Before fix: crashes with NotSupportedException
[assembly: TypeMap<TestTypeMap>("Key", typeof(SomeTarget), typeof(Foo[]))]

// After fix: strips Foo[] → Foo, uses Foo as the trim dependency
// The TypeMap entry is included iff Foo (the element type) is trimmer-reachable

The loop handles nested arrays (Foo[][]Foo), pointer types, and mixed cases like List<Foo>[] (strips to List<Foo>, which is a GenericInstanceType and resolvable).

Customer Impact

PublishTrimmed builds fail with an unhandled NotSupportedException / fatal ILLink error when any assembly attribute uses an array type as a TypeMap trim target. No workaround short of removing the array type.

Regression

No — this is a new feature (TypeMap) that never handled array trim targets correctly in ILLink.

Testing

Added test cases to TypeMap.cs:

  • TrimTargetIsUsedArrayType: array trim target whose element type is reachable — attribute must be preserved; verified with KeptAttributeAttribute.
  • TrimTargetIsUnusedArrayType: array trim target whose element type is unreachable — attribute and target types are removed; verified with explicit RemovedTypeInAssembly("test", ...) assertions on both ArrayTypeTrimTargetUnusedClass and ArrayTypeTrimTargetUnusedTarget.

Both existing Reflection.TypeMap and Reflection.TypeMapEntryAssembly tests pass.

Risk

Low. The change is localized to two private methods in TypeMapHandler. The stripping logic mirrors the existing TypeSpecification/GenericInstanceType guard already present in LinkContext.Resolve. No behavior change for existing valid (non-array) trim targets.

Package authoring no longer needed in .NET 9

IMPORTANT: Starting with .NET 9, you no longer need to edit a NuGet package's csproj to enable building and bump the version.
Keep in mind that we still need package authoring in .NET 8 and older versions.

Strip parameterized types (array, pointer, etc.) from TypeMap trim targets
and source types, using the element type instead. This fixes the crash
when typeof(SomeType[]) is used as a trim target in TypeMap attributes
during PublishTrimmed.

Add test cases for array type trim targets (used and unused) to TypeMap.cs.

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/82e75422-6094-47d8-be6f-7a4527457908

Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
@dotnet-policy-service dotnet-policy-service bot added the linkable-framework Issues associated with delivering a linker friendly framework label Mar 31, 2026
Copilot AI changed the title [WIP] Fix build failure for array TypeMap entries when PublishTrimmed [ILLink] Fix crash when array types are used as TypeMap trim targets with PublishTrimmed Mar 31, 2026
Copilot AI requested a review from jkoritzinsky March 31, 2026 23:01
@jkoritzinsky jkoritzinsky marked this pull request as ready for review March 31, 2026 23:34
@jkoritzinsky jkoritzinsky requested a review from sbomer as a code owner March 31, 2026 23:34
Copilot AI review requested due to automatic review settings March 31, 2026 23:34
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes an ILLink crash in PublishTrimmed when TypeMap attributes specify non-resolvable TypeSpecification types (notably arrays) as trim targets by stripping wrappers down to a resolvable element type before calling LinkContext.Resolve.

Changes:

  • Normalize TypeMap trim targets and association source types by unwrapping TypeSpecification (array/pointer/byref/…) to an element type until reaching a TypeDefinition or GenericInstanceType.
  • Add new linker test coverage for an array-type trim target scenario (kept case), and introduce a second unused-case scenario that should assert removal.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/tools/illink/src/linker/Linker/TypeMapHandler.cs Unwraps TypeSpecification wrappers before resolving trim targets / proxy source types to avoid NotSupportedException crashes.
src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeMap.cs Adds test inputs for array-type trim targets and ensures at least the reachable-element case is preserved.

@jkoritzinsky
Copy link
Copy Markdown
Member

@copilot please address the feedback from @copilot and validate test changes

- Add RemovedTypeInAssembly("test", ...) for unused array trim target types
  to make the expected removal behavior explicit
- Fix misleading comment in AddProxyTypeMapEntry: TypeMapAssociationAttribute
  has two constructor type arguments (source and proxy), not one

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/8d0dbb63-91fb-4d87-8ccd-60e91da2e1e9

Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 1, 2026

@copilot please address the feedback from @copilot and validate test changes

Done in af0ac93:

  1. Added explicit RemovedTypeInAssembly("test", typeof(ArrayTypeTrimTargetUnusedClass)) and RemovedTypeInAssembly("test", typeof(ArrayTypeTrimTargetUnusedTarget)) assertions on the TypeMap class so the expected removal is explicitly verified by the test runner.
  2. Fixed the misleading comment in AddProxyTypeMapEntry — it now says "two constructor type arguments (source and proxy)" instead of "single type argument".

Both Reflection.TypeMap and Reflection.TypeMapEntryAssembly tests still pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-TypeSystem-coreclr linkable-framework Issues associated with delivering a linker friendly framework

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

[area-Tools-ILLink]: TypeMap entries for array types result in build failure when PublishTrimmed

3 participants