ILLink: mark forwarded type targets when forwarders are marked - #127011

Open
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target
Open

ILLink: mark forwarded type targets when forwarders are marked#127011
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target

Conversation

CopilotAI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Marked type forwarders could survive trimming while their target type definitions were removed, leaving dangling forwarders in rooted and copied assemblies. This change makes forwarder marking also mark the resolved target type unconditionally, so preserved forwarders remain functional.

  • Behavior change

    • Marking an ExportedType now also marks its resolved target TypeDefinition.
    • This applies to both direct exported-type marking and exported types processed later from the pending mark queue.
  • Implementation

    • MarkingHelpers.MarkExportedType now marks the forwarder target after marking the forwarder metadata row.
    • Added a shared helper for marking the resolved target and propagating any preserved-members state from the ExportedType to the target type.
    • Updated pending ExportedType processing in MarkStep to use the same target-marking path.
  • Test updates

    • Updated existing linker tests that previously asserted dangling-forwarder behavior.
    • Rooted/copy library cases now expect the forwarded target type to be kept.
    • Copy-action type-forwarding cases now expect linked target assemblies/types to remain when referenced by kept forwarders.
// Before: preserved forwarder metadata could outlive the target type.// After: marking the forwarder also marks the forwarded-to type.[KeptTypeInAssembly("Forwarder.dll",typeof(ImplementationLibrary))][KeptTypeInAssembly("Implementation.dll",typeof(ImplementationLibrary))]

CopilotAI requested review from Copilot and removed request for CopilotApril 16, 2026 16:57
@dotnet-policy-servicedotnet-policy-serviceBot added the linkable-framework Issues associated with delivering a linker friendly framework label Apr 16, 2026
CopilotAI changed the title [WIP] Fix ILLink to mark target type for forwarded typesILLink: mark forwarded type targets when forwarders are markedApr 16, 2026
CopilotAI requested a review from sbomerApril 16, 2026 17:19
CopilotAI lite review requested due to automatic review settings April 17, 2026 16:47
@sbomer
sbomer marked this pull request as ready for review April 17, 2026 16:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates ILLink’s marking behavior so that when a type forwarder (ExportedType) is preserved, the forwarded-to TypeDefinition is also marked, preventing preserved forwarders from becoming dangling after trimming/copying.

Changes:

  • Update MarkingHelpers.MarkExportedType to also mark the resolved target TypeDefinition for the exported type.
  • Update pending ExportedType processing in MarkStep to mark the exported type target consistently.
  • Adjust existing linker tests to expect forwarded-to target types/assemblies to remain when forwarders are preserved.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
FileDescription
src/tools/illink/src/linker/Linker/MarkingHelpers.csAdds shared helper to mark exported-type targets and propagate preserved-members state.
src/tools/illink/src/linker/Linker.Steps/MarkStep.csEnsures pending exported types also mark their resolved target types during processing.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UsedAndUnusedForwarderWithAssemblyCopy.csUpdates expectations so linked target type is kept when copied forwarders are preserved.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UnusedForwarderWithAssemblyCopyIsKept.csUpdates expectations so forwarded-to implementation type is kept.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryCopyBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for copy behavior.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for root-all behavior.

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs
@github-actions

github-actionsBot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Workflow state for the Holistic Review Orchestrator.

{
"version": 5,
"last_dispatched_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_dispatched_base_ref": "main",
"last_dispatched_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_reviewed_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_reviewed_base_ref": "main",
"last_reviewed_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_recorded_worker_run_id": "29674628683",
"review_attempt_commit": "",
"review_attempt_base_ref": "",
"review_attempt_count": 0,
"max_review_attempts": 5,
"review_history_format": "holistic-review-disclosure-v1",
"review_history": [
{
"commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"review_id": 4730179324
}
]
}

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Holistic Review

Motivation: Marked type forwarders (ExportedType metadata rows) could survive trimming while the target TypeDefinition they point to was removed, producing dangling forwarders in rooted (RootAllLibrary) and copy assemblies. A forwarder whose target type no longer exists is broken metadata: a consumer resolving the forwarded type at runtime would fail. This is a real correctness gap, confirmed by the existing tests that previously asserted [RemovedAssembly(...)] for the forwarded-to target.

Approach: MarkingHelpers.MarkExportedType now, after marking the forwarder metadata row, also resolves and marks the target TypeDefinition via a new shared MarkExportedTypeTarget helper, propagating any preserved-members state from the ExportedType to the target. MarkStep.ProcessMarkedPending routes pending ExportedType items through the same helper instead of the previous no-op. This is a clean, minimal, and consistent fix: the two code paths that can mark a forwarder now converge on one method, and the resolve is guarded (TryResolve returning a non-TypeDefinition is a safe no-op), so unresolvable forwarders degrade gracefully. The test updates correctly flip the previously-asserted dangling behavior to [KeptTypeInAssembly(...)].

Summary: A focused, correct bug fix with matching test coverage; I found no blocking issues. Verdict: LGTM.

Detailed Findings

  • suggestion (non-blocking, src/tools/illink/src/linker/Linker/MarkingHelpers.cs): MarkExportedTypeTarget marks the target with new DependencyInfo(DependencyKind.ExportedType, exportedType). DependencyKind.ExportedType is documented in DependencyInfo.cs as // type -> exported type, but here the dependency runs the other direction (exported type -> target type). Reusing this kind is harmless for trimming behavior and only affects dependency-graph / --dump-dependencies reporting, but the arrow is semantically reversed. Consider a more accurate kind or a short clarifying comment. Not a merge blocker.

  • I verified the other copy/copyused forwarder tests are unaffected: cases like UnusedForwarderWithAssemblyCopyUsed, UsedForwarderWithAssemblyCopyUsedAndUnusedReference, and UsedAndUnusedForwarderReferencedFromCopyUsedAssembly use copyused, where the forwarder assembly itself is removed as unused, so no ExportedType is marked and their [RemovedAssembly(...)] expectations still hold. The four updated tests are the only ones where a forwarder is actually marked. Because these expectations can only be validated by running the linker, CI (the ILLink test suite) should confirm no other test regresses.

Note

This review was generated by this repository's Holistic Review agentic workflow to complement the built-in Copilot review.

Generated by Holistic Review · 89 AIC · ⌖ 10.6 AIC · ⊞ 10K

Queue newly discovered member preservation for types that have already been processed so marking reaches the correct fixed point.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 21, 2026 18:58

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs Outdated
sbomerand others added 2 commits August 24, 2026 08:53
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the new marking helper as an implementation detail rather than expanding the linker assembly's public surface.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 24, 2026 17:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@sbomer
sbomer requested a review from a teamAugust 25, 2026 22:59
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-VM-coreclrlinkable-frameworkIssues associated with delivering a linker friendly framework

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

ILLink: Marking a type forwarder should also mark its target type

3 participants

@sbomer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

ILLink: mark forwarded type targets when forwarders are marked - #127011

Open
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target
Open

ILLink: mark forwarded type targets when forwarders are marked#127011
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target

Conversation

CopilotAI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Marked type forwarders could survive trimming while their target type definitions were removed, leaving dangling forwarders in rooted and copied assemblies. This change makes forwarder marking also mark the resolved target type unconditionally, so preserved forwarders remain functional.

  • Behavior change

    • Marking an ExportedType now also marks its resolved target TypeDefinition.
    • This applies to both direct exported-type marking and exported types processed later from the pending mark queue.
  • Implementation

    • MarkingHelpers.MarkExportedType now marks the forwarder target after marking the forwarder metadata row.
    • Added a shared helper for marking the resolved target and propagating any preserved-members state from the ExportedType to the target type.
    • Updated pending ExportedType processing in MarkStep to use the same target-marking path.
  • Test updates

    • Updated existing linker tests that previously asserted dangling-forwarder behavior.
    • Rooted/copy library cases now expect the forwarded target type to be kept.
    • Copy-action type-forwarding cases now expect linked target assemblies/types to remain when referenced by kept forwarders.
// Before: preserved forwarder metadata could outlive the target type.// After: marking the forwarder also marks the forwarded-to type.[KeptTypeInAssembly("Forwarder.dll",typeof(ImplementationLibrary))][KeptTypeInAssembly("Implementation.dll",typeof(ImplementationLibrary))]

CopilotAI requested review from Copilot and removed request for CopilotApril 16, 2026 16:57
@dotnet-policy-servicedotnet-policy-serviceBot added the linkable-framework Issues associated with delivering a linker friendly framework label Apr 16, 2026
CopilotAI changed the title [WIP] Fix ILLink to mark target type for forwarded typesILLink: mark forwarded type targets when forwarders are markedApr 16, 2026
CopilotAI requested a review from sbomerApril 16, 2026 17:19
CopilotAI lite review requested due to automatic review settings April 17, 2026 16:47
@sbomer
sbomer marked this pull request as ready for review April 17, 2026 16:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates ILLink’s marking behavior so that when a type forwarder (ExportedType) is preserved, the forwarded-to TypeDefinition is also marked, preventing preserved forwarders from becoming dangling after trimming/copying.

Changes:

  • Update MarkingHelpers.MarkExportedType to also mark the resolved target TypeDefinition for the exported type.
  • Update pending ExportedType processing in MarkStep to mark the exported type target consistently.
  • Adjust existing linker tests to expect forwarded-to target types/assemblies to remain when forwarders are preserved.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
FileDescription
src/tools/illink/src/linker/Linker/MarkingHelpers.csAdds shared helper to mark exported-type targets and propagate preserved-members state.
src/tools/illink/src/linker/Linker.Steps/MarkStep.csEnsures pending exported types also mark their resolved target types during processing.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UsedAndUnusedForwarderWithAssemblyCopy.csUpdates expectations so linked target type is kept when copied forwarders are preserved.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UnusedForwarderWithAssemblyCopyIsKept.csUpdates expectations so forwarded-to implementation type is kept.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryCopyBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for copy behavior.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for root-all behavior.

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs
@github-actions

github-actionsBot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Workflow state for the Holistic Review Orchestrator.

{
"version": 5,
"last_dispatched_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_dispatched_base_ref": "main",
"last_dispatched_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_reviewed_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_reviewed_base_ref": "main",
"last_reviewed_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_recorded_worker_run_id": "29674628683",
"review_attempt_commit": "",
"review_attempt_base_ref": "",
"review_attempt_count": 0,
"max_review_attempts": 5,
"review_history_format": "holistic-review-disclosure-v1",
"review_history": [
{
"commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"review_id": 4730179324
}
]
}

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Holistic Review

Motivation: Marked type forwarders (ExportedType metadata rows) could survive trimming while the target TypeDefinition they point to was removed, producing dangling forwarders in rooted (RootAllLibrary) and copy assemblies. A forwarder whose target type no longer exists is broken metadata: a consumer resolving the forwarded type at runtime would fail. This is a real correctness gap, confirmed by the existing tests that previously asserted [RemovedAssembly(...)] for the forwarded-to target.

Approach: MarkingHelpers.MarkExportedType now, after marking the forwarder metadata row, also resolves and marks the target TypeDefinition via a new shared MarkExportedTypeTarget helper, propagating any preserved-members state from the ExportedType to the target. MarkStep.ProcessMarkedPending routes pending ExportedType items through the same helper instead of the previous no-op. This is a clean, minimal, and consistent fix: the two code paths that can mark a forwarder now converge on one method, and the resolve is guarded (TryResolve returning a non-TypeDefinition is a safe no-op), so unresolvable forwarders degrade gracefully. The test updates correctly flip the previously-asserted dangling behavior to [KeptTypeInAssembly(...)].

Summary: A focused, correct bug fix with matching test coverage; I found no blocking issues. Verdict: LGTM.

Detailed Findings

  • suggestion (non-blocking, src/tools/illink/src/linker/Linker/MarkingHelpers.cs): MarkExportedTypeTarget marks the target with new DependencyInfo(DependencyKind.ExportedType, exportedType). DependencyKind.ExportedType is documented in DependencyInfo.cs as // type -> exported type, but here the dependency runs the other direction (exported type -> target type). Reusing this kind is harmless for trimming behavior and only affects dependency-graph / --dump-dependencies reporting, but the arrow is semantically reversed. Consider a more accurate kind or a short clarifying comment. Not a merge blocker.

  • I verified the other copy/copyused forwarder tests are unaffected: cases like UnusedForwarderWithAssemblyCopyUsed, UsedForwarderWithAssemblyCopyUsedAndUnusedReference, and UsedAndUnusedForwarderReferencedFromCopyUsedAssembly use copyused, where the forwarder assembly itself is removed as unused, so no ExportedType is marked and their [RemovedAssembly(...)] expectations still hold. The four updated tests are the only ones where a forwarder is actually marked. Because these expectations can only be validated by running the linker, CI (the ILLink test suite) should confirm no other test regresses.

Note

This review was generated by this repository's Holistic Review agentic workflow to complement the built-in Copilot review.

Generated by Holistic Review · 89 AIC · ⌖ 10.6 AIC · ⊞ 10K

Queue newly discovered member preservation for types that have already been processed so marking reaches the correct fixed point.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 21, 2026 18:58

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs Outdated
sbomerand others added 2 commits August 24, 2026 08:53
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the new marking helper as an implementation detail rather than expanding the linker assembly's public surface.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 24, 2026 17:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@sbomer
sbomer requested a review from a teamAugust 25, 2026 22:59
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-VM-coreclrlinkable-frameworkIssues associated with delivering a linker friendly framework

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

ILLink: Marking a type forwarder should also mark its target type

3 participants

@sbomer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ILLink: mark forwarded type targets when forwarders are marked - #127011

Open
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target
Open

ILLink: mark forwarded type targets when forwarders are marked#127011
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target

Conversation

CopilotAI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Marked type forwarders could survive trimming while their target type definitions were removed, leaving dangling forwarders in rooted and copied assemblies. This change makes forwarder marking also mark the resolved target type unconditionally, so preserved forwarders remain functional.

  • Behavior change

    • Marking an ExportedType now also marks its resolved target TypeDefinition.
    • This applies to both direct exported-type marking and exported types processed later from the pending mark queue.
  • Implementation

    • MarkingHelpers.MarkExportedType now marks the forwarder target after marking the forwarder metadata row.
    • Added a shared helper for marking the resolved target and propagating any preserved-members state from the ExportedType to the target type.
    • Updated pending ExportedType processing in MarkStep to use the same target-marking path.
  • Test updates

    • Updated existing linker tests that previously asserted dangling-forwarder behavior.
    • Rooted/copy library cases now expect the forwarded target type to be kept.
    • Copy-action type-forwarding cases now expect linked target assemblies/types to remain when referenced by kept forwarders.
// Before: preserved forwarder metadata could outlive the target type.// After: marking the forwarder also marks the forwarded-to type.[KeptTypeInAssembly("Forwarder.dll",typeof(ImplementationLibrary))][KeptTypeInAssembly("Implementation.dll",typeof(ImplementationLibrary))]

CopilotAI requested review from Copilot and removed request for CopilotApril 16, 2026 16:57
@dotnet-policy-servicedotnet-policy-serviceBot added the linkable-framework Issues associated with delivering a linker friendly framework label Apr 16, 2026
CopilotAI changed the title [WIP] Fix ILLink to mark target type for forwarded typesILLink: mark forwarded type targets when forwarders are markedApr 16, 2026
CopilotAI requested a review from sbomerApril 16, 2026 17:19
CopilotAI lite review requested due to automatic review settings April 17, 2026 16:47
@sbomer
sbomer marked this pull request as ready for review April 17, 2026 16:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates ILLink’s marking behavior so that when a type forwarder (ExportedType) is preserved, the forwarded-to TypeDefinition is also marked, preventing preserved forwarders from becoming dangling after trimming/copying.

Changes:

  • Update MarkingHelpers.MarkExportedType to also mark the resolved target TypeDefinition for the exported type.
  • Update pending ExportedType processing in MarkStep to mark the exported type target consistently.
  • Adjust existing linker tests to expect forwarded-to target types/assemblies to remain when forwarders are preserved.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
FileDescription
src/tools/illink/src/linker/Linker/MarkingHelpers.csAdds shared helper to mark exported-type targets and propagate preserved-members state.
src/tools/illink/src/linker/Linker.Steps/MarkStep.csEnsures pending exported types also mark their resolved target types during processing.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UsedAndUnusedForwarderWithAssemblyCopy.csUpdates expectations so linked target type is kept when copied forwarders are preserved.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UnusedForwarderWithAssemblyCopyIsKept.csUpdates expectations so forwarded-to implementation type is kept.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryCopyBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for copy behavior.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for root-all behavior.

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs
@github-actions

github-actionsBot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Workflow state for the Holistic Review Orchestrator.

{
"version": 5,
"last_dispatched_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_dispatched_base_ref": "main",
"last_dispatched_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_reviewed_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_reviewed_base_ref": "main",
"last_reviewed_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_recorded_worker_run_id": "29674628683",
"review_attempt_commit": "",
"review_attempt_base_ref": "",
"review_attempt_count": 0,
"max_review_attempts": 5,
"review_history_format": "holistic-review-disclosure-v1",
"review_history": [
{
"commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"review_id": 4730179324
}
]
}

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Holistic Review

Motivation: Marked type forwarders (ExportedType metadata rows) could survive trimming while the target TypeDefinition they point to was removed, producing dangling forwarders in rooted (RootAllLibrary) and copy assemblies. A forwarder whose target type no longer exists is broken metadata: a consumer resolving the forwarded type at runtime would fail. This is a real correctness gap, confirmed by the existing tests that previously asserted [RemovedAssembly(...)] for the forwarded-to target.

Approach: MarkingHelpers.MarkExportedType now, after marking the forwarder metadata row, also resolves and marks the target TypeDefinition via a new shared MarkExportedTypeTarget helper, propagating any preserved-members state from the ExportedType to the target. MarkStep.ProcessMarkedPending routes pending ExportedType items through the same helper instead of the previous no-op. This is a clean, minimal, and consistent fix: the two code paths that can mark a forwarder now converge on one method, and the resolve is guarded (TryResolve returning a non-TypeDefinition is a safe no-op), so unresolvable forwarders degrade gracefully. The test updates correctly flip the previously-asserted dangling behavior to [KeptTypeInAssembly(...)].

Summary: A focused, correct bug fix with matching test coverage; I found no blocking issues. Verdict: LGTM.

Detailed Findings

  • suggestion (non-blocking, src/tools/illink/src/linker/Linker/MarkingHelpers.cs): MarkExportedTypeTarget marks the target with new DependencyInfo(DependencyKind.ExportedType, exportedType). DependencyKind.ExportedType is documented in DependencyInfo.cs as // type -> exported type, but here the dependency runs the other direction (exported type -> target type). Reusing this kind is harmless for trimming behavior and only affects dependency-graph / --dump-dependencies reporting, but the arrow is semantically reversed. Consider a more accurate kind or a short clarifying comment. Not a merge blocker.

  • I verified the other copy/copyused forwarder tests are unaffected: cases like UnusedForwarderWithAssemblyCopyUsed, UsedForwarderWithAssemblyCopyUsedAndUnusedReference, and UsedAndUnusedForwarderReferencedFromCopyUsedAssembly use copyused, where the forwarder assembly itself is removed as unused, so no ExportedType is marked and their [RemovedAssembly(...)] expectations still hold. The four updated tests are the only ones where a forwarder is actually marked. Because these expectations can only be validated by running the linker, CI (the ILLink test suite) should confirm no other test regresses.

Note

This review was generated by this repository's Holistic Review agentic workflow to complement the built-in Copilot review.

Generated by Holistic Review · 89 AIC · ⌖ 10.6 AIC · ⊞ 10K

Queue newly discovered member preservation for types that have already been processed so marking reaches the correct fixed point.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 21, 2026 18:58

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs Outdated
sbomerand others added 2 commits August 24, 2026 08:53
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the new marking helper as an implementation detail rather than expanding the linker assembly's public surface.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 24, 2026 17:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@sbomer
sbomer requested a review from a teamAugust 25, 2026 22:59
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-VM-coreclrlinkable-frameworkIssues associated with delivering a linker friendly framework

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

ILLink: Marking a type forwarder should also mark its target type

3 participants

@sbomer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ILLink: mark forwarded type targets when forwarders are marked - #127011

Open
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target
Open

ILLink: mark forwarded type targets when forwarders are marked#127011
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target

Conversation

CopilotAI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Marked type forwarders could survive trimming while their target type definitions were removed, leaving dangling forwarders in rooted and copied assemblies. This change makes forwarder marking also mark the resolved target type unconditionally, so preserved forwarders remain functional.

  • Behavior change

    • Marking an ExportedType now also marks its resolved target TypeDefinition.
    • This applies to both direct exported-type marking and exported types processed later from the pending mark queue.
  • Implementation

    • MarkingHelpers.MarkExportedType now marks the forwarder target after marking the forwarder metadata row.
    • Added a shared helper for marking the resolved target and propagating any preserved-members state from the ExportedType to the target type.
    • Updated pending ExportedType processing in MarkStep to use the same target-marking path.
  • Test updates

    • Updated existing linker tests that previously asserted dangling-forwarder behavior.
    • Rooted/copy library cases now expect the forwarded target type to be kept.
    • Copy-action type-forwarding cases now expect linked target assemblies/types to remain when referenced by kept forwarders.
// Before: preserved forwarder metadata could outlive the target type.// After: marking the forwarder also marks the forwarded-to type.[KeptTypeInAssembly("Forwarder.dll",typeof(ImplementationLibrary))][KeptTypeInAssembly("Implementation.dll",typeof(ImplementationLibrary))]

CopilotAI requested review from Copilot and removed request for CopilotApril 16, 2026 16:57
@dotnet-policy-servicedotnet-policy-serviceBot added the linkable-framework Issues associated with delivering a linker friendly framework label Apr 16, 2026
CopilotAI changed the title [WIP] Fix ILLink to mark target type for forwarded typesILLink: mark forwarded type targets when forwarders are markedApr 16, 2026
CopilotAI requested a review from sbomerApril 16, 2026 17:19
CopilotAI lite review requested due to automatic review settings April 17, 2026 16:47
@sbomer
sbomer marked this pull request as ready for review April 17, 2026 16:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates ILLink’s marking behavior so that when a type forwarder (ExportedType) is preserved, the forwarded-to TypeDefinition is also marked, preventing preserved forwarders from becoming dangling after trimming/copying.

Changes:

  • Update MarkingHelpers.MarkExportedType to also mark the resolved target TypeDefinition for the exported type.
  • Update pending ExportedType processing in MarkStep to mark the exported type target consistently.
  • Adjust existing linker tests to expect forwarded-to target types/assemblies to remain when forwarders are preserved.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
FileDescription
src/tools/illink/src/linker/Linker/MarkingHelpers.csAdds shared helper to mark exported-type targets and propagate preserved-members state.
src/tools/illink/src/linker/Linker.Steps/MarkStep.csEnsures pending exported types also mark their resolved target types during processing.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UsedAndUnusedForwarderWithAssemblyCopy.csUpdates expectations so linked target type is kept when copied forwarders are preserved.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UnusedForwarderWithAssemblyCopyIsKept.csUpdates expectations so forwarded-to implementation type is kept.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryCopyBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for copy behavior.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for root-all behavior.

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs
@github-actions

github-actionsBot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Workflow state for the Holistic Review Orchestrator.

{
"version": 5,
"last_dispatched_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_dispatched_base_ref": "main",
"last_dispatched_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_reviewed_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_reviewed_base_ref": "main",
"last_reviewed_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_recorded_worker_run_id": "29674628683",
"review_attempt_commit": "",
"review_attempt_base_ref": "",
"review_attempt_count": 0,
"max_review_attempts": 5,
"review_history_format": "holistic-review-disclosure-v1",
"review_history": [
{
"commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"review_id": 4730179324
}
]
}

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Holistic Review

Motivation: Marked type forwarders (ExportedType metadata rows) could survive trimming while the target TypeDefinition they point to was removed, producing dangling forwarders in rooted (RootAllLibrary) and copy assemblies. A forwarder whose target type no longer exists is broken metadata: a consumer resolving the forwarded type at runtime would fail. This is a real correctness gap, confirmed by the existing tests that previously asserted [RemovedAssembly(...)] for the forwarded-to target.

Approach: MarkingHelpers.MarkExportedType now, after marking the forwarder metadata row, also resolves and marks the target TypeDefinition via a new shared MarkExportedTypeTarget helper, propagating any preserved-members state from the ExportedType to the target. MarkStep.ProcessMarkedPending routes pending ExportedType items through the same helper instead of the previous no-op. This is a clean, minimal, and consistent fix: the two code paths that can mark a forwarder now converge on one method, and the resolve is guarded (TryResolve returning a non-TypeDefinition is a safe no-op), so unresolvable forwarders degrade gracefully. The test updates correctly flip the previously-asserted dangling behavior to [KeptTypeInAssembly(...)].

Summary: A focused, correct bug fix with matching test coverage; I found no blocking issues. Verdict: LGTM.

Detailed Findings

  • suggestion (non-blocking, src/tools/illink/src/linker/Linker/MarkingHelpers.cs): MarkExportedTypeTarget marks the target with new DependencyInfo(DependencyKind.ExportedType, exportedType). DependencyKind.ExportedType is documented in DependencyInfo.cs as // type -> exported type, but here the dependency runs the other direction (exported type -> target type). Reusing this kind is harmless for trimming behavior and only affects dependency-graph / --dump-dependencies reporting, but the arrow is semantically reversed. Consider a more accurate kind or a short clarifying comment. Not a merge blocker.

  • I verified the other copy/copyused forwarder tests are unaffected: cases like UnusedForwarderWithAssemblyCopyUsed, UsedForwarderWithAssemblyCopyUsedAndUnusedReference, and UsedAndUnusedForwarderReferencedFromCopyUsedAssembly use copyused, where the forwarder assembly itself is removed as unused, so no ExportedType is marked and their [RemovedAssembly(...)] expectations still hold. The four updated tests are the only ones where a forwarder is actually marked. Because these expectations can only be validated by running the linker, CI (the ILLink test suite) should confirm no other test regresses.

Note

This review was generated by this repository's Holistic Review agentic workflow to complement the built-in Copilot review.

Generated by Holistic Review · 89 AIC · ⌖ 10.6 AIC · ⊞ 10K

Queue newly discovered member preservation for types that have already been processed so marking reaches the correct fixed point.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 21, 2026 18:58

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs Outdated
sbomerand others added 2 commits August 24, 2026 08:53
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the new marking helper as an implementation detail rather than expanding the linker assembly's public surface.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 24, 2026 17:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@sbomer
sbomer requested a review from a teamAugust 25, 2026 22:59
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-VM-coreclrlinkable-frameworkIssues associated with delivering a linker friendly framework

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

ILLink: Marking a type forwarder should also mark its target type

3 participants

@sbomer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

ILLink: mark forwarded type targets when forwarders are marked - #127011

Open
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target
Open

ILLink: mark forwarded type targets when forwarders are marked#127011
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target

Conversation

CopilotAI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Marked type forwarders could survive trimming while their target type definitions were removed, leaving dangling forwarders in rooted and copied assemblies. This change makes forwarder marking also mark the resolved target type unconditionally, so preserved forwarders remain functional.

  • Behavior change

    • Marking an ExportedType now also marks its resolved target TypeDefinition.
    • This applies to both direct exported-type marking and exported types processed later from the pending mark queue.
  • Implementation

    • MarkingHelpers.MarkExportedType now marks the forwarder target after marking the forwarder metadata row.
    • Added a shared helper for marking the resolved target and propagating any preserved-members state from the ExportedType to the target type.
    • Updated pending ExportedType processing in MarkStep to use the same target-marking path.
  • Test updates

    • Updated existing linker tests that previously asserted dangling-forwarder behavior.
    • Rooted/copy library cases now expect the forwarded target type to be kept.
    • Copy-action type-forwarding cases now expect linked target assemblies/types to remain when referenced by kept forwarders.
// Before: preserved forwarder metadata could outlive the target type.// After: marking the forwarder also marks the forwarded-to type.[KeptTypeInAssembly("Forwarder.dll",typeof(ImplementationLibrary))][KeptTypeInAssembly("Implementation.dll",typeof(ImplementationLibrary))]

CopilotAI requested review from Copilot and removed request for CopilotApril 16, 2026 16:57
@dotnet-policy-servicedotnet-policy-serviceBot added the linkable-framework Issues associated with delivering a linker friendly framework label Apr 16, 2026
CopilotAI changed the title [WIP] Fix ILLink to mark target type for forwarded typesILLink: mark forwarded type targets when forwarders are markedApr 16, 2026
CopilotAI requested a review from sbomerApril 16, 2026 17:19
CopilotAI lite review requested due to automatic review settings April 17, 2026 16:47
@sbomer
sbomer marked this pull request as ready for review April 17, 2026 16:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates ILLink’s marking behavior so that when a type forwarder (ExportedType) is preserved, the forwarded-to TypeDefinition is also marked, preventing preserved forwarders from becoming dangling after trimming/copying.

Changes:

  • Update MarkingHelpers.MarkExportedType to also mark the resolved target TypeDefinition for the exported type.
  • Update pending ExportedType processing in MarkStep to mark the exported type target consistently.
  • Adjust existing linker tests to expect forwarded-to target types/assemblies to remain when forwarders are preserved.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
FileDescription
src/tools/illink/src/linker/Linker/MarkingHelpers.csAdds shared helper to mark exported-type targets and propagate preserved-members state.
src/tools/illink/src/linker/Linker.Steps/MarkStep.csEnsures pending exported types also mark their resolved target types during processing.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UsedAndUnusedForwarderWithAssemblyCopy.csUpdates expectations so linked target type is kept when copied forwarders are preserved.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UnusedForwarderWithAssemblyCopyIsKept.csUpdates expectations so forwarded-to implementation type is kept.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryCopyBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for copy behavior.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for root-all behavior.

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs
@github-actions

github-actionsBot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Workflow state for the Holistic Review Orchestrator.

{
"version": 5,
"last_dispatched_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_dispatched_base_ref": "main",
"last_dispatched_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_reviewed_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_reviewed_base_ref": "main",
"last_reviewed_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_recorded_worker_run_id": "29674628683",
"review_attempt_commit": "",
"review_attempt_base_ref": "",
"review_attempt_count": 0,
"max_review_attempts": 5,
"review_history_format": "holistic-review-disclosure-v1",
"review_history": [
{
"commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"review_id": 4730179324
}
]
}

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Holistic Review

Motivation: Marked type forwarders (ExportedType metadata rows) could survive trimming while the target TypeDefinition they point to was removed, producing dangling forwarders in rooted (RootAllLibrary) and copy assemblies. A forwarder whose target type no longer exists is broken metadata: a consumer resolving the forwarded type at runtime would fail. This is a real correctness gap, confirmed by the existing tests that previously asserted [RemovedAssembly(...)] for the forwarded-to target.

Approach: MarkingHelpers.MarkExportedType now, after marking the forwarder metadata row, also resolves and marks the target TypeDefinition via a new shared MarkExportedTypeTarget helper, propagating any preserved-members state from the ExportedType to the target. MarkStep.ProcessMarkedPending routes pending ExportedType items through the same helper instead of the previous no-op. This is a clean, minimal, and consistent fix: the two code paths that can mark a forwarder now converge on one method, and the resolve is guarded (TryResolve returning a non-TypeDefinition is a safe no-op), so unresolvable forwarders degrade gracefully. The test updates correctly flip the previously-asserted dangling behavior to [KeptTypeInAssembly(...)].

Summary: A focused, correct bug fix with matching test coverage; I found no blocking issues. Verdict: LGTM.

Detailed Findings

  • suggestion (non-blocking, src/tools/illink/src/linker/Linker/MarkingHelpers.cs): MarkExportedTypeTarget marks the target with new DependencyInfo(DependencyKind.ExportedType, exportedType). DependencyKind.ExportedType is documented in DependencyInfo.cs as // type -> exported type, but here the dependency runs the other direction (exported type -> target type). Reusing this kind is harmless for trimming behavior and only affects dependency-graph / --dump-dependencies reporting, but the arrow is semantically reversed. Consider a more accurate kind or a short clarifying comment. Not a merge blocker.

  • I verified the other copy/copyused forwarder tests are unaffected: cases like UnusedForwarderWithAssemblyCopyUsed, UsedForwarderWithAssemblyCopyUsedAndUnusedReference, and UsedAndUnusedForwarderReferencedFromCopyUsedAssembly use copyused, where the forwarder assembly itself is removed as unused, so no ExportedType is marked and their [RemovedAssembly(...)] expectations still hold. The four updated tests are the only ones where a forwarder is actually marked. Because these expectations can only be validated by running the linker, CI (the ILLink test suite) should confirm no other test regresses.

Note

This review was generated by this repository's Holistic Review agentic workflow to complement the built-in Copilot review.

Generated by Holistic Review · 89 AIC · ⌖ 10.6 AIC · ⊞ 10K

Queue newly discovered member preservation for types that have already been processed so marking reaches the correct fixed point.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 21, 2026 18:58

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs Outdated
sbomerand others added 2 commits August 24, 2026 08:53
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the new marking helper as an implementation detail rather than expanding the linker assembly's public surface.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 24, 2026 17:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@sbomer
sbomer requested a review from a teamAugust 25, 2026 22:59
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-VM-coreclrlinkable-frameworkIssues associated with delivering a linker friendly framework

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

ILLink: Marking a type forwarder should also mark its target type

3 participants

@sbomer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ILLink: mark forwarded type targets when forwarders are marked - #127011

Open
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target
Open

ILLink: mark forwarded type targets when forwarders are marked#127011
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target

Conversation

CopilotAI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Marked type forwarders could survive trimming while their target type definitions were removed, leaving dangling forwarders in rooted and copied assemblies. This change makes forwarder marking also mark the resolved target type unconditionally, so preserved forwarders remain functional.

  • Behavior change

    • Marking an ExportedType now also marks its resolved target TypeDefinition.
    • This applies to both direct exported-type marking and exported types processed later from the pending mark queue.
  • Implementation

    • MarkingHelpers.MarkExportedType now marks the forwarder target after marking the forwarder metadata row.
    • Added a shared helper for marking the resolved target and propagating any preserved-members state from the ExportedType to the target type.
    • Updated pending ExportedType processing in MarkStep to use the same target-marking path.
  • Test updates

    • Updated existing linker tests that previously asserted dangling-forwarder behavior.
    • Rooted/copy library cases now expect the forwarded target type to be kept.
    • Copy-action type-forwarding cases now expect linked target assemblies/types to remain when referenced by kept forwarders.
// Before: preserved forwarder metadata could outlive the target type.// After: marking the forwarder also marks the forwarded-to type.[KeptTypeInAssembly("Forwarder.dll",typeof(ImplementationLibrary))][KeptTypeInAssembly("Implementation.dll",typeof(ImplementationLibrary))]

CopilotAI requested review from Copilot and removed request for CopilotApril 16, 2026 16:57
@dotnet-policy-servicedotnet-policy-serviceBot added the linkable-framework Issues associated with delivering a linker friendly framework label Apr 16, 2026
CopilotAI changed the title [WIP] Fix ILLink to mark target type for forwarded typesILLink: mark forwarded type targets when forwarders are markedApr 16, 2026
CopilotAI requested a review from sbomerApril 16, 2026 17:19
CopilotAI lite review requested due to automatic review settings April 17, 2026 16:47
@sbomer
sbomer marked this pull request as ready for review April 17, 2026 16:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates ILLink’s marking behavior so that when a type forwarder (ExportedType) is preserved, the forwarded-to TypeDefinition is also marked, preventing preserved forwarders from becoming dangling after trimming/copying.

Changes:

  • Update MarkingHelpers.MarkExportedType to also mark the resolved target TypeDefinition for the exported type.
  • Update pending ExportedType processing in MarkStep to mark the exported type target consistently.
  • Adjust existing linker tests to expect forwarded-to target types/assemblies to remain when forwarders are preserved.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
FileDescription
src/tools/illink/src/linker/Linker/MarkingHelpers.csAdds shared helper to mark exported-type targets and propagate preserved-members state.
src/tools/illink/src/linker/Linker.Steps/MarkStep.csEnsures pending exported types also mark their resolved target types during processing.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UsedAndUnusedForwarderWithAssemblyCopy.csUpdates expectations so linked target type is kept when copied forwarders are preserved.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UnusedForwarderWithAssemblyCopyIsKept.csUpdates expectations so forwarded-to implementation type is kept.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryCopyBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for copy behavior.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for root-all behavior.

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs
@github-actions

github-actionsBot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Workflow state for the Holistic Review Orchestrator.

{
"version": 5,
"last_dispatched_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_dispatched_base_ref": "main",
"last_dispatched_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_reviewed_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_reviewed_base_ref": "main",
"last_reviewed_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_recorded_worker_run_id": "29674628683",
"review_attempt_commit": "",
"review_attempt_base_ref": "",
"review_attempt_count": 0,
"max_review_attempts": 5,
"review_history_format": "holistic-review-disclosure-v1",
"review_history": [
{
"commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"review_id": 4730179324
}
]
}

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Holistic Review

Motivation: Marked type forwarders (ExportedType metadata rows) could survive trimming while the target TypeDefinition they point to was removed, producing dangling forwarders in rooted (RootAllLibrary) and copy assemblies. A forwarder whose target type no longer exists is broken metadata: a consumer resolving the forwarded type at runtime would fail. This is a real correctness gap, confirmed by the existing tests that previously asserted [RemovedAssembly(...)] for the forwarded-to target.

Approach: MarkingHelpers.MarkExportedType now, after marking the forwarder metadata row, also resolves and marks the target TypeDefinition via a new shared MarkExportedTypeTarget helper, propagating any preserved-members state from the ExportedType to the target. MarkStep.ProcessMarkedPending routes pending ExportedType items through the same helper instead of the previous no-op. This is a clean, minimal, and consistent fix: the two code paths that can mark a forwarder now converge on one method, and the resolve is guarded (TryResolve returning a non-TypeDefinition is a safe no-op), so unresolvable forwarders degrade gracefully. The test updates correctly flip the previously-asserted dangling behavior to [KeptTypeInAssembly(...)].

Summary: A focused, correct bug fix with matching test coverage; I found no blocking issues. Verdict: LGTM.

Detailed Findings

  • suggestion (non-blocking, src/tools/illink/src/linker/Linker/MarkingHelpers.cs): MarkExportedTypeTarget marks the target with new DependencyInfo(DependencyKind.ExportedType, exportedType). DependencyKind.ExportedType is documented in DependencyInfo.cs as // type -> exported type, but here the dependency runs the other direction (exported type -> target type). Reusing this kind is harmless for trimming behavior and only affects dependency-graph / --dump-dependencies reporting, but the arrow is semantically reversed. Consider a more accurate kind or a short clarifying comment. Not a merge blocker.

  • I verified the other copy/copyused forwarder tests are unaffected: cases like UnusedForwarderWithAssemblyCopyUsed, UsedForwarderWithAssemblyCopyUsedAndUnusedReference, and UsedAndUnusedForwarderReferencedFromCopyUsedAssembly use copyused, where the forwarder assembly itself is removed as unused, so no ExportedType is marked and their [RemovedAssembly(...)] expectations still hold. The four updated tests are the only ones where a forwarder is actually marked. Because these expectations can only be validated by running the linker, CI (the ILLink test suite) should confirm no other test regresses.

Note

This review was generated by this repository's Holistic Review agentic workflow to complement the built-in Copilot review.

Generated by Holistic Review · 89 AIC · ⌖ 10.6 AIC · ⊞ 10K

Queue newly discovered member preservation for types that have already been processed so marking reaches the correct fixed point.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 21, 2026 18:58

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs Outdated
sbomerand others added 2 commits August 24, 2026 08:53
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the new marking helper as an implementation detail rather than expanding the linker assembly's public surface.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 24, 2026 17:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@sbomer
sbomer requested a review from a teamAugust 25, 2026 22:59
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-VM-coreclrlinkable-frameworkIssues associated with delivering a linker friendly framework

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

ILLink: Marking a type forwarder should also mark its target type

3 participants

@sbomer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ILLink: mark forwarded type targets when forwarders are marked - #127011

Open
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target
Open

ILLink: mark forwarded type targets when forwarders are marked#127011
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target

Conversation

CopilotAI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Marked type forwarders could survive trimming while their target type definitions were removed, leaving dangling forwarders in rooted and copied assemblies. This change makes forwarder marking also mark the resolved target type unconditionally, so preserved forwarders remain functional.

  • Behavior change

    • Marking an ExportedType now also marks its resolved target TypeDefinition.
    • This applies to both direct exported-type marking and exported types processed later from the pending mark queue.
  • Implementation

    • MarkingHelpers.MarkExportedType now marks the forwarder target after marking the forwarder metadata row.
    • Added a shared helper for marking the resolved target and propagating any preserved-members state from the ExportedType to the target type.
    • Updated pending ExportedType processing in MarkStep to use the same target-marking path.
  • Test updates

    • Updated existing linker tests that previously asserted dangling-forwarder behavior.
    • Rooted/copy library cases now expect the forwarded target type to be kept.
    • Copy-action type-forwarding cases now expect linked target assemblies/types to remain when referenced by kept forwarders.
// Before: preserved forwarder metadata could outlive the target type.// After: marking the forwarder also marks the forwarded-to type.[KeptTypeInAssembly("Forwarder.dll",typeof(ImplementationLibrary))][KeptTypeInAssembly("Implementation.dll",typeof(ImplementationLibrary))]

CopilotAI requested review from Copilot and removed request for CopilotApril 16, 2026 16:57
@dotnet-policy-servicedotnet-policy-serviceBot added the linkable-framework Issues associated with delivering a linker friendly framework label Apr 16, 2026
CopilotAI changed the title [WIP] Fix ILLink to mark target type for forwarded typesILLink: mark forwarded type targets when forwarders are markedApr 16, 2026
CopilotAI requested a review from sbomerApril 16, 2026 17:19
CopilotAI lite review requested due to automatic review settings April 17, 2026 16:47
@sbomer
sbomer marked this pull request as ready for review April 17, 2026 16:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates ILLink’s marking behavior so that when a type forwarder (ExportedType) is preserved, the forwarded-to TypeDefinition is also marked, preventing preserved forwarders from becoming dangling after trimming/copying.

Changes:

  • Update MarkingHelpers.MarkExportedType to also mark the resolved target TypeDefinition for the exported type.
  • Update pending ExportedType processing in MarkStep to mark the exported type target consistently.
  • Adjust existing linker tests to expect forwarded-to target types/assemblies to remain when forwarders are preserved.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
FileDescription
src/tools/illink/src/linker/Linker/MarkingHelpers.csAdds shared helper to mark exported-type targets and propagate preserved-members state.
src/tools/illink/src/linker/Linker.Steps/MarkStep.csEnsures pending exported types also mark their resolved target types during processing.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UsedAndUnusedForwarderWithAssemblyCopy.csUpdates expectations so linked target type is kept when copied forwarders are preserved.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UnusedForwarderWithAssemblyCopyIsKept.csUpdates expectations so forwarded-to implementation type is kept.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryCopyBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for copy behavior.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for root-all behavior.

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs
@github-actions

github-actionsBot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Workflow state for the Holistic Review Orchestrator.

{
"version": 5,
"last_dispatched_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_dispatched_base_ref": "main",
"last_dispatched_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_reviewed_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_reviewed_base_ref": "main",
"last_reviewed_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_recorded_worker_run_id": "29674628683",
"review_attempt_commit": "",
"review_attempt_base_ref": "",
"review_attempt_count": 0,
"max_review_attempts": 5,
"review_history_format": "holistic-review-disclosure-v1",
"review_history": [
{
"commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"review_id": 4730179324
}
]
}

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Holistic Review

Motivation: Marked type forwarders (ExportedType metadata rows) could survive trimming while the target TypeDefinition they point to was removed, producing dangling forwarders in rooted (RootAllLibrary) and copy assemblies. A forwarder whose target type no longer exists is broken metadata: a consumer resolving the forwarded type at runtime would fail. This is a real correctness gap, confirmed by the existing tests that previously asserted [RemovedAssembly(...)] for the forwarded-to target.

Approach: MarkingHelpers.MarkExportedType now, after marking the forwarder metadata row, also resolves and marks the target TypeDefinition via a new shared MarkExportedTypeTarget helper, propagating any preserved-members state from the ExportedType to the target. MarkStep.ProcessMarkedPending routes pending ExportedType items through the same helper instead of the previous no-op. This is a clean, minimal, and consistent fix: the two code paths that can mark a forwarder now converge on one method, and the resolve is guarded (TryResolve returning a non-TypeDefinition is a safe no-op), so unresolvable forwarders degrade gracefully. The test updates correctly flip the previously-asserted dangling behavior to [KeptTypeInAssembly(...)].

Summary: A focused, correct bug fix with matching test coverage; I found no blocking issues. Verdict: LGTM.

Detailed Findings

  • suggestion (non-blocking, src/tools/illink/src/linker/Linker/MarkingHelpers.cs): MarkExportedTypeTarget marks the target with new DependencyInfo(DependencyKind.ExportedType, exportedType). DependencyKind.ExportedType is documented in DependencyInfo.cs as // type -> exported type, but here the dependency runs the other direction (exported type -> target type). Reusing this kind is harmless for trimming behavior and only affects dependency-graph / --dump-dependencies reporting, but the arrow is semantically reversed. Consider a more accurate kind or a short clarifying comment. Not a merge blocker.

  • I verified the other copy/copyused forwarder tests are unaffected: cases like UnusedForwarderWithAssemblyCopyUsed, UsedForwarderWithAssemblyCopyUsedAndUnusedReference, and UsedAndUnusedForwarderReferencedFromCopyUsedAssembly use copyused, where the forwarder assembly itself is removed as unused, so no ExportedType is marked and their [RemovedAssembly(...)] expectations still hold. The four updated tests are the only ones where a forwarder is actually marked. Because these expectations can only be validated by running the linker, CI (the ILLink test suite) should confirm no other test regresses.

Note

This review was generated by this repository's Holistic Review agentic workflow to complement the built-in Copilot review.

Generated by Holistic Review · 89 AIC · ⌖ 10.6 AIC · ⊞ 10K

Queue newly discovered member preservation for types that have already been processed so marking reaches the correct fixed point.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 21, 2026 18:58

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs Outdated
sbomerand others added 2 commits August 24, 2026 08:53
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the new marking helper as an implementation detail rather than expanding the linker assembly's public surface.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 24, 2026 17:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@sbomer
sbomer requested a review from a teamAugust 25, 2026 22:59
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-VM-coreclrlinkable-frameworkIssues associated with delivering a linker friendly framework

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

ILLink: Marking a type forwarder should also mark its target type

3 participants

@sbomer
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

ILLink: mark forwarded type targets when forwarders are marked - #127011

Open
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target
Open

ILLink: mark forwarded type targets when forwarders are marked#127011
sbomer with Copilot wants to merge 6 commits into
mainfrom
copilot/ilink-mark-type-forwarder-target

Conversation

CopilotAI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Marked type forwarders could survive trimming while their target type definitions were removed, leaving dangling forwarders in rooted and copied assemblies. This change makes forwarder marking also mark the resolved target type unconditionally, so preserved forwarders remain functional.

  • Behavior change

    • Marking an ExportedType now also marks its resolved target TypeDefinition.
    • This applies to both direct exported-type marking and exported types processed later from the pending mark queue.
  • Implementation

    • MarkingHelpers.MarkExportedType now marks the forwarder target after marking the forwarder metadata row.
    • Added a shared helper for marking the resolved target and propagating any preserved-members state from the ExportedType to the target type.
    • Updated pending ExportedType processing in MarkStep to use the same target-marking path.
  • Test updates

    • Updated existing linker tests that previously asserted dangling-forwarder behavior.
    • Rooted/copy library cases now expect the forwarded target type to be kept.
    • Copy-action type-forwarding cases now expect linked target assemblies/types to remain when referenced by kept forwarders.
// Before: preserved forwarder metadata could outlive the target type.// After: marking the forwarder also marks the forwarded-to type.[KeptTypeInAssembly("Forwarder.dll",typeof(ImplementationLibrary))][KeptTypeInAssembly("Implementation.dll",typeof(ImplementationLibrary))]

CopilotAI requested review from Copilot and removed request for CopilotApril 16, 2026 16:57
@dotnet-policy-servicedotnet-policy-serviceBot added the linkable-framework Issues associated with delivering a linker friendly framework label Apr 16, 2026
CopilotAI changed the title [WIP] Fix ILLink to mark target type for forwarded typesILLink: mark forwarded type targets when forwarders are markedApr 16, 2026
CopilotAI requested a review from sbomerApril 16, 2026 17:19
CopilotAI lite review requested due to automatic review settings April 17, 2026 16:47
@sbomer
sbomer marked this pull request as ready for review April 17, 2026 16:47

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates ILLink’s marking behavior so that when a type forwarder (ExportedType) is preserved, the forwarded-to TypeDefinition is also marked, preventing preserved forwarders from becoming dangling after trimming/copying.

Changes:

  • Update MarkingHelpers.MarkExportedType to also mark the resolved target TypeDefinition for the exported type.
  • Update pending ExportedType processing in MarkStep to mark the exported type target consistently.
  • Adjust existing linker tests to expect forwarded-to target types/assemblies to remain when forwarders are preserved.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
FileDescription
src/tools/illink/src/linker/Linker/MarkingHelpers.csAdds shared helper to mark exported-type targets and propagate preserved-members state.
src/tools/illink/src/linker/Linker.Steps/MarkStep.csEnsures pending exported types also mark their resolved target types during processing.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UsedAndUnusedForwarderWithAssemblyCopy.csUpdates expectations so linked target type is kept when copied forwarders are preserved.
src/tools/illink/test/Mono.Linker.Tests.Cases/TypeForwarding/UnusedForwarderWithAssemblyCopyIsKept.csUpdates expectations so forwarded-to implementation type is kept.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryCopyBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for copy behavior.
src/tools/illink/test/Mono.Linker.Tests.Cases/Libraries/RootAllLibraryBehavior.csUpdates expectations so forwarded-to exportedtype assembly/type is kept for root-all behavior.

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs
@github-actions

github-actionsBot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Workflow state for the Holistic Review Orchestrator.

{
"version": 5,
"last_dispatched_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_dispatched_base_ref": "main",
"last_dispatched_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_reviewed_commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"last_reviewed_base_ref": "main",
"last_reviewed_base_sha": "9d24c4d12540aca6019a5e212b7e170f5f3a0207",
"last_recorded_worker_run_id": "29674628683",
"review_attempt_commit": "",
"review_attempt_base_ref": "",
"review_attempt_count": 0,
"max_review_attempts": 5,
"review_history_format": "holistic-review-disclosure-v1",
"review_history": [
{
"commit": "118f2229fc4d3f2a358bc7c7a89b2e6e9cab45b5",
"review_id": 4730179324
}
]
}

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Holistic Review

Motivation: Marked type forwarders (ExportedType metadata rows) could survive trimming while the target TypeDefinition they point to was removed, producing dangling forwarders in rooted (RootAllLibrary) and copy assemblies. A forwarder whose target type no longer exists is broken metadata: a consumer resolving the forwarded type at runtime would fail. This is a real correctness gap, confirmed by the existing tests that previously asserted [RemovedAssembly(...)] for the forwarded-to target.

Approach: MarkingHelpers.MarkExportedType now, after marking the forwarder metadata row, also resolves and marks the target TypeDefinition via a new shared MarkExportedTypeTarget helper, propagating any preserved-members state from the ExportedType to the target. MarkStep.ProcessMarkedPending routes pending ExportedType items through the same helper instead of the previous no-op. This is a clean, minimal, and consistent fix: the two code paths that can mark a forwarder now converge on one method, and the resolve is guarded (TryResolve returning a non-TypeDefinition is a safe no-op), so unresolvable forwarders degrade gracefully. The test updates correctly flip the previously-asserted dangling behavior to [KeptTypeInAssembly(...)].

Summary: A focused, correct bug fix with matching test coverage; I found no blocking issues. Verdict: LGTM.

Detailed Findings

  • suggestion (non-blocking, src/tools/illink/src/linker/Linker/MarkingHelpers.cs): MarkExportedTypeTarget marks the target with new DependencyInfo(DependencyKind.ExportedType, exportedType). DependencyKind.ExportedType is documented in DependencyInfo.cs as // type -> exported type, but here the dependency runs the other direction (exported type -> target type). Reusing this kind is harmless for trimming behavior and only affects dependency-graph / --dump-dependencies reporting, but the arrow is semantically reversed. Consider a more accurate kind or a short clarifying comment. Not a merge blocker.

  • I verified the other copy/copyused forwarder tests are unaffected: cases like UnusedForwarderWithAssemblyCopyUsed, UsedForwarderWithAssemblyCopyUsedAndUnusedReference, and UsedAndUnusedForwarderReferencedFromCopyUsedAssembly use copyused, where the forwarder assembly itself is removed as unused, so no ExportedType is marked and their [RemovedAssembly(...)] expectations still hold. The four updated tests are the only ones where a forwarder is actually marked. Because these expectations can only be validated by running the linker, CI (the ILLink test suite) should confirm no other test regresses.

Note

This review was generated by this repository's Holistic Review agentic workflow to complement the built-in Copilot review.

Generated by Holistic Review · 89 AIC · ⌖ 10.6 AIC · ⊞ 10K

Queue newly discovered member preservation for types that have already been processed so marking reaches the correct fixed point.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 21, 2026 18:58

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment threadsrc/tools/illink/src/linker/Linker/MarkingHelpers.cs Outdated
sbomerand others added 2 commits August 24, 2026 08:53
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the new marking helper as an implementation detail rather than expanding the linker assembly's public surface.
Assisted-by: GitHub Copilot:gpt-5.6-sol
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 24, 2026 17:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@sbomer
sbomer requested a review from a teamAugust 25, 2026 22:59
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-VM-coreclrlinkable-frameworkIssues associated with delivering a linker friendly framework

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

ILLink: Marking a type forwarder should also mark its target type

3 participants

@sbomer