Handle canonical types in casting logic - #127146

Merged
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604
Apr 21, 2026
Merged

Handle canonical types in casting logic#127146
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604

Conversation

@MichalStrehovsky

Copy link
Copy Markdown
Member

Fixes#126604.

When we're doing dataflow analysis of MakeGenericXXX calls, we run constraint validation to ensure we don't precompile something invalid. However, because most reflection analysis within the compiler happens with canonical types, we can end up in a situation where a constraint check is necessary but all we have are canonical types. Constraint checking and CanCastTo logic was treating this a class __Canon : object { } case, but this is not that.

Cc @dotnet/ilc-contrib

MichalStrehovskyand others added 4 commits April 20, 2026 16:04
The AOT compiler's CheckConstraints was rejecting valid canonical
instantiations because CanCastTo has no awareness of canonical types.
When MakeGenericType produces canonical forms like GenericType<TestRequest,
__Canon>, type constraints (interface/base-type) would fail because e.g.
IRequest<TestRequest, string> doesn't match IRequest<TestRequest, __Canon>.
Add CanCastToConstraintWithCanon to TypeSystemConstraintsHelpers that
handles canonical types in constraint checking:
- __Canon/__UniversalCanon as the instantiation param: wildcard, accepts
any type constraint (runtime validates with concrete types).
- __Canon/__UniversalCanon as the constraint type itself: __Canon accepts
reference types, __UniversalCanon accepts anything.
- Canonical subtypes in constraint type args: uses ConvertToCanonForm to
compare canonicalized forms, with variance support for variant positions.
- Universal canon fallback for nested __UniversalCanon under Specific
canonicalization.
Split into Canon/NonCanon partial files following the existing pattern
for IsSpecialTypeMeetingConstraint. Add NormalizeInstantiation call in
HandleCallAction's MakeGenericTypeSite.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move IsCanonicalTypeArgMatch and IsCanonEquivalent from
TypeSystemConstraintsHelpers.Canon.cs into CastingHelper.Canon.cs so
that CanCastTo naturally handles canonical types. This eliminates the
duplicated interface-walking, base-chain-walking, and variance logic
that was in CanCastToConstraintWithCanon.
Key changes to CastingHelper:
- IsCanonicalCastTarget in CanCastToInternal: __Canon accepts any
reference type as a cast source, __UniversalCanon accepts any type.
This makes array covariance (string[] -> __Canon[]) work naturally.
- IsCanonicalTypeArgMatch in CanCastByVarianceToInterfaceOrDelegate:
handles invariant positions where type args differ by canonicalization.
- IsCanonEquivalent in CanCastToNonVariantInterface and CanCastToClass:
handles non-variant interfaces and base types with canon type args.
CanCastToConstraintWithCanon is simplified to only handle wildcard cases
where the param or constraint IS __Canon/__UniversalCanon directly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
IsCanonicalTypeArgMatch did not handle parameterized types like arrays:
string[] vs __Canon[] failed because IsCanonEquivalent checks
Instantiation which is empty for arrays. Add ParameterizedType
structural matching that recursively compares element types.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exercises MakeGenericType where the canonical instantiation
(Gen<Atom, __Canon, object>) must pass constraint checking with
__Canon satisfying interface and new() constraints.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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 fixes NativeAOT reflection/dataflow constraint validation when generic instantiations are analyzed in canonical form (__Canon / __UniversalCanon), ensuring MakeGenericType sites aren’t incorrectly treated as invalid and therefore skipped for rooting/compilation.

Changes:

  • Normalize instantiated reflected generic types before constraint checking in MakeGenericType dataflow handling.
  • Extend casting and constraint-validation helpers to correctly treat canonical definition types as wildcards/compatible where appropriate (with canon vs non-canon partial implementations).
  • Add unit and smoke tests covering canonical-type constraint scenarios and constrained MakeGenericType dataflow.

Reviewed changes

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

Show a summary per file
FileDescription
src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.csAdds a new smoke test exercising constrained MakeGenericType rooting during dataflow analysis.
src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csprojIncludes new Canon-specific helper implementations in the TypeSystem build.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/GenericConstraints.csAdds new generic constraint shapes for canonical constraint tests.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ConstraintsValidationTest.csAdds a comprehensive canonical-constraint validation test suite.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.csNormalizes instantiated generic types before constraint validation/rooting.
src/coreclr/tools/ILVerification/ILVerification.projitemsAdds non-canon stub helper files required by the verifier’s non-canon TypeSystem build.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.csMakes helpers partial and adds canon-aware special-constraint and type-constraint checks.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.NonCanon.csProvides non-canon stub implementations for new partial helpers.
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.csAdds canon-aware matching hooks into cast logic (interfaces, variance, base chain).
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.NonCanon.csProvides non-canon stubs for new canon-aware cast helpers.
src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemConstraintsHelpers.Canon.csCanon-specific implementations for wildcard-like canonical constraint handling.
src/coreclr/tools/Common/TypeSystem/Canon/CastingHelper.Canon.csCanon-specific canonical matching logic for casts and type-arg comparisons.
src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csprojEnsures TypeLoader picks up canon-aware casting helper.

Comment threadsrc/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 21, 2026 00:48

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

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

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NativeAOT MakeGenericType fails to activate reflected generic type when generic parameter has self-referential interface constraint

4 participants

@MichalStrehovsky@jkoritzinsky@jkotas
, '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

Handle canonical types in casting logic - #127146

Merged
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604
Apr 21, 2026
Merged

Handle canonical types in casting logic#127146
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604

Conversation

@MichalStrehovsky

Copy link
Copy Markdown
Member

Fixes#126604.

When we're doing dataflow analysis of MakeGenericXXX calls, we run constraint validation to ensure we don't precompile something invalid. However, because most reflection analysis within the compiler happens with canonical types, we can end up in a situation where a constraint check is necessary but all we have are canonical types. Constraint checking and CanCastTo logic was treating this a class __Canon : object { } case, but this is not that.

Cc @dotnet/ilc-contrib

MichalStrehovskyand others added 4 commits April 20, 2026 16:04
The AOT compiler's CheckConstraints was rejecting valid canonical
instantiations because CanCastTo has no awareness of canonical types.
When MakeGenericType produces canonical forms like GenericType<TestRequest,
__Canon>, type constraints (interface/base-type) would fail because e.g.
IRequest<TestRequest, string> doesn't match IRequest<TestRequest, __Canon>.
Add CanCastToConstraintWithCanon to TypeSystemConstraintsHelpers that
handles canonical types in constraint checking:
- __Canon/__UniversalCanon as the instantiation param: wildcard, accepts
any type constraint (runtime validates with concrete types).
- __Canon/__UniversalCanon as the constraint type itself: __Canon accepts
reference types, __UniversalCanon accepts anything.
- Canonical subtypes in constraint type args: uses ConvertToCanonForm to
compare canonicalized forms, with variance support for variant positions.
- Universal canon fallback for nested __UniversalCanon under Specific
canonicalization.
Split into Canon/NonCanon partial files following the existing pattern
for IsSpecialTypeMeetingConstraint. Add NormalizeInstantiation call in
HandleCallAction's MakeGenericTypeSite.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move IsCanonicalTypeArgMatch and IsCanonEquivalent from
TypeSystemConstraintsHelpers.Canon.cs into CastingHelper.Canon.cs so
that CanCastTo naturally handles canonical types. This eliminates the
duplicated interface-walking, base-chain-walking, and variance logic
that was in CanCastToConstraintWithCanon.
Key changes to CastingHelper:
- IsCanonicalCastTarget in CanCastToInternal: __Canon accepts any
reference type as a cast source, __UniversalCanon accepts any type.
This makes array covariance (string[] -> __Canon[]) work naturally.
- IsCanonicalTypeArgMatch in CanCastByVarianceToInterfaceOrDelegate:
handles invariant positions where type args differ by canonicalization.
- IsCanonEquivalent in CanCastToNonVariantInterface and CanCastToClass:
handles non-variant interfaces and base types with canon type args.
CanCastToConstraintWithCanon is simplified to only handle wildcard cases
where the param or constraint IS __Canon/__UniversalCanon directly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
IsCanonicalTypeArgMatch did not handle parameterized types like arrays:
string[] vs __Canon[] failed because IsCanonEquivalent checks
Instantiation which is empty for arrays. Add ParameterizedType
structural matching that recursively compares element types.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exercises MakeGenericType where the canonical instantiation
(Gen<Atom, __Canon, object>) must pass constraint checking with
__Canon satisfying interface and new() constraints.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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 fixes NativeAOT reflection/dataflow constraint validation when generic instantiations are analyzed in canonical form (__Canon / __UniversalCanon), ensuring MakeGenericType sites aren’t incorrectly treated as invalid and therefore skipped for rooting/compilation.

Changes:

  • Normalize instantiated reflected generic types before constraint checking in MakeGenericType dataflow handling.
  • Extend casting and constraint-validation helpers to correctly treat canonical definition types as wildcards/compatible where appropriate (with canon vs non-canon partial implementations).
  • Add unit and smoke tests covering canonical-type constraint scenarios and constrained MakeGenericType dataflow.

Reviewed changes

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

Show a summary per file
FileDescription
src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.csAdds a new smoke test exercising constrained MakeGenericType rooting during dataflow analysis.
src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csprojIncludes new Canon-specific helper implementations in the TypeSystem build.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/GenericConstraints.csAdds new generic constraint shapes for canonical constraint tests.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ConstraintsValidationTest.csAdds a comprehensive canonical-constraint validation test suite.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.csNormalizes instantiated generic types before constraint validation/rooting.
src/coreclr/tools/ILVerification/ILVerification.projitemsAdds non-canon stub helper files required by the verifier’s non-canon TypeSystem build.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.csMakes helpers partial and adds canon-aware special-constraint and type-constraint checks.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.NonCanon.csProvides non-canon stub implementations for new partial helpers.
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.csAdds canon-aware matching hooks into cast logic (interfaces, variance, base chain).
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.NonCanon.csProvides non-canon stubs for new canon-aware cast helpers.
src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemConstraintsHelpers.Canon.csCanon-specific implementations for wildcard-like canonical constraint handling.
src/coreclr/tools/Common/TypeSystem/Canon/CastingHelper.Canon.csCanon-specific canonical matching logic for casts and type-arg comparisons.
src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csprojEnsures TypeLoader picks up canon-aware casting helper.

Comment threadsrc/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 21, 2026 00:48

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

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

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NativeAOT MakeGenericType fails to activate reflected generic type when generic parameter has self-referential interface constraint

4 participants

@MichalStrehovsky@jkoritzinsky@jkotas
, '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

Handle canonical types in casting logic - #127146

Merged
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604
Apr 21, 2026
Merged

Handle canonical types in casting logic#127146
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604

Conversation

@MichalStrehovsky

Copy link
Copy Markdown
Member

Fixes#126604.

When we're doing dataflow analysis of MakeGenericXXX calls, we run constraint validation to ensure we don't precompile something invalid. However, because most reflection analysis within the compiler happens with canonical types, we can end up in a situation where a constraint check is necessary but all we have are canonical types. Constraint checking and CanCastTo logic was treating this a class __Canon : object { } case, but this is not that.

Cc @dotnet/ilc-contrib

MichalStrehovskyand others added 4 commits April 20, 2026 16:04
The AOT compiler's CheckConstraints was rejecting valid canonical
instantiations because CanCastTo has no awareness of canonical types.
When MakeGenericType produces canonical forms like GenericType<TestRequest,
__Canon>, type constraints (interface/base-type) would fail because e.g.
IRequest<TestRequest, string> doesn't match IRequest<TestRequest, __Canon>.
Add CanCastToConstraintWithCanon to TypeSystemConstraintsHelpers that
handles canonical types in constraint checking:
- __Canon/__UniversalCanon as the instantiation param: wildcard, accepts
any type constraint (runtime validates with concrete types).
- __Canon/__UniversalCanon as the constraint type itself: __Canon accepts
reference types, __UniversalCanon accepts anything.
- Canonical subtypes in constraint type args: uses ConvertToCanonForm to
compare canonicalized forms, with variance support for variant positions.
- Universal canon fallback for nested __UniversalCanon under Specific
canonicalization.
Split into Canon/NonCanon partial files following the existing pattern
for IsSpecialTypeMeetingConstraint. Add NormalizeInstantiation call in
HandleCallAction's MakeGenericTypeSite.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move IsCanonicalTypeArgMatch and IsCanonEquivalent from
TypeSystemConstraintsHelpers.Canon.cs into CastingHelper.Canon.cs so
that CanCastTo naturally handles canonical types. This eliminates the
duplicated interface-walking, base-chain-walking, and variance logic
that was in CanCastToConstraintWithCanon.
Key changes to CastingHelper:
- IsCanonicalCastTarget in CanCastToInternal: __Canon accepts any
reference type as a cast source, __UniversalCanon accepts any type.
This makes array covariance (string[] -> __Canon[]) work naturally.
- IsCanonicalTypeArgMatch in CanCastByVarianceToInterfaceOrDelegate:
handles invariant positions where type args differ by canonicalization.
- IsCanonEquivalent in CanCastToNonVariantInterface and CanCastToClass:
handles non-variant interfaces and base types with canon type args.
CanCastToConstraintWithCanon is simplified to only handle wildcard cases
where the param or constraint IS __Canon/__UniversalCanon directly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
IsCanonicalTypeArgMatch did not handle parameterized types like arrays:
string[] vs __Canon[] failed because IsCanonEquivalent checks
Instantiation which is empty for arrays. Add ParameterizedType
structural matching that recursively compares element types.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exercises MakeGenericType where the canonical instantiation
(Gen<Atom, __Canon, object>) must pass constraint checking with
__Canon satisfying interface and new() constraints.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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 fixes NativeAOT reflection/dataflow constraint validation when generic instantiations are analyzed in canonical form (__Canon / __UniversalCanon), ensuring MakeGenericType sites aren’t incorrectly treated as invalid and therefore skipped for rooting/compilation.

Changes:

  • Normalize instantiated reflected generic types before constraint checking in MakeGenericType dataflow handling.
  • Extend casting and constraint-validation helpers to correctly treat canonical definition types as wildcards/compatible where appropriate (with canon vs non-canon partial implementations).
  • Add unit and smoke tests covering canonical-type constraint scenarios and constrained MakeGenericType dataflow.

Reviewed changes

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

Show a summary per file
FileDescription
src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.csAdds a new smoke test exercising constrained MakeGenericType rooting during dataflow analysis.
src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csprojIncludes new Canon-specific helper implementations in the TypeSystem build.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/GenericConstraints.csAdds new generic constraint shapes for canonical constraint tests.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ConstraintsValidationTest.csAdds a comprehensive canonical-constraint validation test suite.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.csNormalizes instantiated generic types before constraint validation/rooting.
src/coreclr/tools/ILVerification/ILVerification.projitemsAdds non-canon stub helper files required by the verifier’s non-canon TypeSystem build.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.csMakes helpers partial and adds canon-aware special-constraint and type-constraint checks.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.NonCanon.csProvides non-canon stub implementations for new partial helpers.
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.csAdds canon-aware matching hooks into cast logic (interfaces, variance, base chain).
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.NonCanon.csProvides non-canon stubs for new canon-aware cast helpers.
src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemConstraintsHelpers.Canon.csCanon-specific implementations for wildcard-like canonical constraint handling.
src/coreclr/tools/Common/TypeSystem/Canon/CastingHelper.Canon.csCanon-specific canonical matching logic for casts and type-arg comparisons.
src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csprojEnsures TypeLoader picks up canon-aware casting helper.

Comment threadsrc/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 21, 2026 00:48

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

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

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NativeAOT MakeGenericType fails to activate reflected generic type when generic parameter has self-referential interface constraint

4 participants

@MichalStrehovsky@jkoritzinsky@jkotas
, '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

Handle canonical types in casting logic - #127146

Merged
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604
Apr 21, 2026
Merged

Handle canonical types in casting logic#127146
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604

Conversation

@MichalStrehovsky

Copy link
Copy Markdown
Member

Fixes#126604.

When we're doing dataflow analysis of MakeGenericXXX calls, we run constraint validation to ensure we don't precompile something invalid. However, because most reflection analysis within the compiler happens with canonical types, we can end up in a situation where a constraint check is necessary but all we have are canonical types. Constraint checking and CanCastTo logic was treating this a class __Canon : object { } case, but this is not that.

Cc @dotnet/ilc-contrib

MichalStrehovskyand others added 4 commits April 20, 2026 16:04
The AOT compiler's CheckConstraints was rejecting valid canonical
instantiations because CanCastTo has no awareness of canonical types.
When MakeGenericType produces canonical forms like GenericType<TestRequest,
__Canon>, type constraints (interface/base-type) would fail because e.g.
IRequest<TestRequest, string> doesn't match IRequest<TestRequest, __Canon>.
Add CanCastToConstraintWithCanon to TypeSystemConstraintsHelpers that
handles canonical types in constraint checking:
- __Canon/__UniversalCanon as the instantiation param: wildcard, accepts
any type constraint (runtime validates with concrete types).
- __Canon/__UniversalCanon as the constraint type itself: __Canon accepts
reference types, __UniversalCanon accepts anything.
- Canonical subtypes in constraint type args: uses ConvertToCanonForm to
compare canonicalized forms, with variance support for variant positions.
- Universal canon fallback for nested __UniversalCanon under Specific
canonicalization.
Split into Canon/NonCanon partial files following the existing pattern
for IsSpecialTypeMeetingConstraint. Add NormalizeInstantiation call in
HandleCallAction's MakeGenericTypeSite.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move IsCanonicalTypeArgMatch and IsCanonEquivalent from
TypeSystemConstraintsHelpers.Canon.cs into CastingHelper.Canon.cs so
that CanCastTo naturally handles canonical types. This eliminates the
duplicated interface-walking, base-chain-walking, and variance logic
that was in CanCastToConstraintWithCanon.
Key changes to CastingHelper:
- IsCanonicalCastTarget in CanCastToInternal: __Canon accepts any
reference type as a cast source, __UniversalCanon accepts any type.
This makes array covariance (string[] -> __Canon[]) work naturally.
- IsCanonicalTypeArgMatch in CanCastByVarianceToInterfaceOrDelegate:
handles invariant positions where type args differ by canonicalization.
- IsCanonEquivalent in CanCastToNonVariantInterface and CanCastToClass:
handles non-variant interfaces and base types with canon type args.
CanCastToConstraintWithCanon is simplified to only handle wildcard cases
where the param or constraint IS __Canon/__UniversalCanon directly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
IsCanonicalTypeArgMatch did not handle parameterized types like arrays:
string[] vs __Canon[] failed because IsCanonEquivalent checks
Instantiation which is empty for arrays. Add ParameterizedType
structural matching that recursively compares element types.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exercises MakeGenericType where the canonical instantiation
(Gen<Atom, __Canon, object>) must pass constraint checking with
__Canon satisfying interface and new() constraints.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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 fixes NativeAOT reflection/dataflow constraint validation when generic instantiations are analyzed in canonical form (__Canon / __UniversalCanon), ensuring MakeGenericType sites aren’t incorrectly treated as invalid and therefore skipped for rooting/compilation.

Changes:

  • Normalize instantiated reflected generic types before constraint checking in MakeGenericType dataflow handling.
  • Extend casting and constraint-validation helpers to correctly treat canonical definition types as wildcards/compatible where appropriate (with canon vs non-canon partial implementations).
  • Add unit and smoke tests covering canonical-type constraint scenarios and constrained MakeGenericType dataflow.

Reviewed changes

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

Show a summary per file
FileDescription
src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.csAdds a new smoke test exercising constrained MakeGenericType rooting during dataflow analysis.
src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csprojIncludes new Canon-specific helper implementations in the TypeSystem build.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/GenericConstraints.csAdds new generic constraint shapes for canonical constraint tests.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ConstraintsValidationTest.csAdds a comprehensive canonical-constraint validation test suite.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.csNormalizes instantiated generic types before constraint validation/rooting.
src/coreclr/tools/ILVerification/ILVerification.projitemsAdds non-canon stub helper files required by the verifier’s non-canon TypeSystem build.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.csMakes helpers partial and adds canon-aware special-constraint and type-constraint checks.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.NonCanon.csProvides non-canon stub implementations for new partial helpers.
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.csAdds canon-aware matching hooks into cast logic (interfaces, variance, base chain).
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.NonCanon.csProvides non-canon stubs for new canon-aware cast helpers.
src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemConstraintsHelpers.Canon.csCanon-specific implementations for wildcard-like canonical constraint handling.
src/coreclr/tools/Common/TypeSystem/Canon/CastingHelper.Canon.csCanon-specific canonical matching logic for casts and type-arg comparisons.
src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csprojEnsures TypeLoader picks up canon-aware casting helper.

Comment threadsrc/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 21, 2026 00:48

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

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

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NativeAOT MakeGenericType fails to activate reflected generic type when generic parameter has self-referential interface constraint

4 participants

@MichalStrehovsky@jkoritzinsky@jkotas
, '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

Handle canonical types in casting logic - #127146

Merged
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604
Apr 21, 2026
Merged

Handle canonical types in casting logic#127146
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604

Conversation

@MichalStrehovsky

Copy link
Copy Markdown
Member

Fixes#126604.

When we're doing dataflow analysis of MakeGenericXXX calls, we run constraint validation to ensure we don't precompile something invalid. However, because most reflection analysis within the compiler happens with canonical types, we can end up in a situation where a constraint check is necessary but all we have are canonical types. Constraint checking and CanCastTo logic was treating this a class __Canon : object { } case, but this is not that.

Cc @dotnet/ilc-contrib

MichalStrehovskyand others added 4 commits April 20, 2026 16:04
The AOT compiler's CheckConstraints was rejecting valid canonical
instantiations because CanCastTo has no awareness of canonical types.
When MakeGenericType produces canonical forms like GenericType<TestRequest,
__Canon>, type constraints (interface/base-type) would fail because e.g.
IRequest<TestRequest, string> doesn't match IRequest<TestRequest, __Canon>.
Add CanCastToConstraintWithCanon to TypeSystemConstraintsHelpers that
handles canonical types in constraint checking:
- __Canon/__UniversalCanon as the instantiation param: wildcard, accepts
any type constraint (runtime validates with concrete types).
- __Canon/__UniversalCanon as the constraint type itself: __Canon accepts
reference types, __UniversalCanon accepts anything.
- Canonical subtypes in constraint type args: uses ConvertToCanonForm to
compare canonicalized forms, with variance support for variant positions.
- Universal canon fallback for nested __UniversalCanon under Specific
canonicalization.
Split into Canon/NonCanon partial files following the existing pattern
for IsSpecialTypeMeetingConstraint. Add NormalizeInstantiation call in
HandleCallAction's MakeGenericTypeSite.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move IsCanonicalTypeArgMatch and IsCanonEquivalent from
TypeSystemConstraintsHelpers.Canon.cs into CastingHelper.Canon.cs so
that CanCastTo naturally handles canonical types. This eliminates the
duplicated interface-walking, base-chain-walking, and variance logic
that was in CanCastToConstraintWithCanon.
Key changes to CastingHelper:
- IsCanonicalCastTarget in CanCastToInternal: __Canon accepts any
reference type as a cast source, __UniversalCanon accepts any type.
This makes array covariance (string[] -> __Canon[]) work naturally.
- IsCanonicalTypeArgMatch in CanCastByVarianceToInterfaceOrDelegate:
handles invariant positions where type args differ by canonicalization.
- IsCanonEquivalent in CanCastToNonVariantInterface and CanCastToClass:
handles non-variant interfaces and base types with canon type args.
CanCastToConstraintWithCanon is simplified to only handle wildcard cases
where the param or constraint IS __Canon/__UniversalCanon directly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
IsCanonicalTypeArgMatch did not handle parameterized types like arrays:
string[] vs __Canon[] failed because IsCanonEquivalent checks
Instantiation which is empty for arrays. Add ParameterizedType
structural matching that recursively compares element types.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exercises MakeGenericType where the canonical instantiation
(Gen<Atom, __Canon, object>) must pass constraint checking with
__Canon satisfying interface and new() constraints.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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 fixes NativeAOT reflection/dataflow constraint validation when generic instantiations are analyzed in canonical form (__Canon / __UniversalCanon), ensuring MakeGenericType sites aren’t incorrectly treated as invalid and therefore skipped for rooting/compilation.

Changes:

  • Normalize instantiated reflected generic types before constraint checking in MakeGenericType dataflow handling.
  • Extend casting and constraint-validation helpers to correctly treat canonical definition types as wildcards/compatible where appropriate (with canon vs non-canon partial implementations).
  • Add unit and smoke tests covering canonical-type constraint scenarios and constrained MakeGenericType dataflow.

Reviewed changes

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

Show a summary per file
FileDescription
src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.csAdds a new smoke test exercising constrained MakeGenericType rooting during dataflow analysis.
src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csprojIncludes new Canon-specific helper implementations in the TypeSystem build.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/GenericConstraints.csAdds new generic constraint shapes for canonical constraint tests.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ConstraintsValidationTest.csAdds a comprehensive canonical-constraint validation test suite.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.csNormalizes instantiated generic types before constraint validation/rooting.
src/coreclr/tools/ILVerification/ILVerification.projitemsAdds non-canon stub helper files required by the verifier’s non-canon TypeSystem build.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.csMakes helpers partial and adds canon-aware special-constraint and type-constraint checks.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.NonCanon.csProvides non-canon stub implementations for new partial helpers.
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.csAdds canon-aware matching hooks into cast logic (interfaces, variance, base chain).
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.NonCanon.csProvides non-canon stubs for new canon-aware cast helpers.
src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemConstraintsHelpers.Canon.csCanon-specific implementations for wildcard-like canonical constraint handling.
src/coreclr/tools/Common/TypeSystem/Canon/CastingHelper.Canon.csCanon-specific canonical matching logic for casts and type-arg comparisons.
src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csprojEnsures TypeLoader picks up canon-aware casting helper.

Comment threadsrc/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 21, 2026 00:48

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

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

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NativeAOT MakeGenericType fails to activate reflected generic type when generic parameter has self-referential interface constraint

4 participants

@MichalStrehovsky@jkoritzinsky@jkotas
, '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

Handle canonical types in casting logic - #127146

Merged
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604
Apr 21, 2026
Merged

Handle canonical types in casting logic#127146
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604

Conversation

@MichalStrehovsky

Copy link
Copy Markdown
Member

Fixes#126604.

When we're doing dataflow analysis of MakeGenericXXX calls, we run constraint validation to ensure we don't precompile something invalid. However, because most reflection analysis within the compiler happens with canonical types, we can end up in a situation where a constraint check is necessary but all we have are canonical types. Constraint checking and CanCastTo logic was treating this a class __Canon : object { } case, but this is not that.

Cc @dotnet/ilc-contrib

MichalStrehovskyand others added 4 commits April 20, 2026 16:04
The AOT compiler's CheckConstraints was rejecting valid canonical
instantiations because CanCastTo has no awareness of canonical types.
When MakeGenericType produces canonical forms like GenericType<TestRequest,
__Canon>, type constraints (interface/base-type) would fail because e.g.
IRequest<TestRequest, string> doesn't match IRequest<TestRequest, __Canon>.
Add CanCastToConstraintWithCanon to TypeSystemConstraintsHelpers that
handles canonical types in constraint checking:
- __Canon/__UniversalCanon as the instantiation param: wildcard, accepts
any type constraint (runtime validates with concrete types).
- __Canon/__UniversalCanon as the constraint type itself: __Canon accepts
reference types, __UniversalCanon accepts anything.
- Canonical subtypes in constraint type args: uses ConvertToCanonForm to
compare canonicalized forms, with variance support for variant positions.
- Universal canon fallback for nested __UniversalCanon under Specific
canonicalization.
Split into Canon/NonCanon partial files following the existing pattern
for IsSpecialTypeMeetingConstraint. Add NormalizeInstantiation call in
HandleCallAction's MakeGenericTypeSite.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move IsCanonicalTypeArgMatch and IsCanonEquivalent from
TypeSystemConstraintsHelpers.Canon.cs into CastingHelper.Canon.cs so
that CanCastTo naturally handles canonical types. This eliminates the
duplicated interface-walking, base-chain-walking, and variance logic
that was in CanCastToConstraintWithCanon.
Key changes to CastingHelper:
- IsCanonicalCastTarget in CanCastToInternal: __Canon accepts any
reference type as a cast source, __UniversalCanon accepts any type.
This makes array covariance (string[] -> __Canon[]) work naturally.
- IsCanonicalTypeArgMatch in CanCastByVarianceToInterfaceOrDelegate:
handles invariant positions where type args differ by canonicalization.
- IsCanonEquivalent in CanCastToNonVariantInterface and CanCastToClass:
handles non-variant interfaces and base types with canon type args.
CanCastToConstraintWithCanon is simplified to only handle wildcard cases
where the param or constraint IS __Canon/__UniversalCanon directly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
IsCanonicalTypeArgMatch did not handle parameterized types like arrays:
string[] vs __Canon[] failed because IsCanonEquivalent checks
Instantiation which is empty for arrays. Add ParameterizedType
structural matching that recursively compares element types.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exercises MakeGenericType where the canonical instantiation
(Gen<Atom, __Canon, object>) must pass constraint checking with
__Canon satisfying interface and new() constraints.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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 fixes NativeAOT reflection/dataflow constraint validation when generic instantiations are analyzed in canonical form (__Canon / __UniversalCanon), ensuring MakeGenericType sites aren’t incorrectly treated as invalid and therefore skipped for rooting/compilation.

Changes:

  • Normalize instantiated reflected generic types before constraint checking in MakeGenericType dataflow handling.
  • Extend casting and constraint-validation helpers to correctly treat canonical definition types as wildcards/compatible where appropriate (with canon vs non-canon partial implementations).
  • Add unit and smoke tests covering canonical-type constraint scenarios and constrained MakeGenericType dataflow.

Reviewed changes

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

Show a summary per file
FileDescription
src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.csAdds a new smoke test exercising constrained MakeGenericType rooting during dataflow analysis.
src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csprojIncludes new Canon-specific helper implementations in the TypeSystem build.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/GenericConstraints.csAdds new generic constraint shapes for canonical constraint tests.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ConstraintsValidationTest.csAdds a comprehensive canonical-constraint validation test suite.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.csNormalizes instantiated generic types before constraint validation/rooting.
src/coreclr/tools/ILVerification/ILVerification.projitemsAdds non-canon stub helper files required by the verifier’s non-canon TypeSystem build.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.csMakes helpers partial and adds canon-aware special-constraint and type-constraint checks.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.NonCanon.csProvides non-canon stub implementations for new partial helpers.
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.csAdds canon-aware matching hooks into cast logic (interfaces, variance, base chain).
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.NonCanon.csProvides non-canon stubs for new canon-aware cast helpers.
src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemConstraintsHelpers.Canon.csCanon-specific implementations for wildcard-like canonical constraint handling.
src/coreclr/tools/Common/TypeSystem/Canon/CastingHelper.Canon.csCanon-specific canonical matching logic for casts and type-arg comparisons.
src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csprojEnsures TypeLoader picks up canon-aware casting helper.

Comment threadsrc/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 21, 2026 00:48

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

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

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NativeAOT MakeGenericType fails to activate reflected generic type when generic parameter has self-referential interface constraint

4 participants

@MichalStrehovsky@jkoritzinsky@jkotas
, '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

Handle canonical types in casting logic - #127146

Merged
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604
Apr 21, 2026
Merged

Handle canonical types in casting logic#127146
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604

Conversation

@MichalStrehovsky

Copy link
Copy Markdown
Member

Fixes#126604.

When we're doing dataflow analysis of MakeGenericXXX calls, we run constraint validation to ensure we don't precompile something invalid. However, because most reflection analysis within the compiler happens with canonical types, we can end up in a situation where a constraint check is necessary but all we have are canonical types. Constraint checking and CanCastTo logic was treating this a class __Canon : object { } case, but this is not that.

Cc @dotnet/ilc-contrib

MichalStrehovskyand others added 4 commits April 20, 2026 16:04
The AOT compiler's CheckConstraints was rejecting valid canonical
instantiations because CanCastTo has no awareness of canonical types.
When MakeGenericType produces canonical forms like GenericType<TestRequest,
__Canon>, type constraints (interface/base-type) would fail because e.g.
IRequest<TestRequest, string> doesn't match IRequest<TestRequest, __Canon>.
Add CanCastToConstraintWithCanon to TypeSystemConstraintsHelpers that
handles canonical types in constraint checking:
- __Canon/__UniversalCanon as the instantiation param: wildcard, accepts
any type constraint (runtime validates with concrete types).
- __Canon/__UniversalCanon as the constraint type itself: __Canon accepts
reference types, __UniversalCanon accepts anything.
- Canonical subtypes in constraint type args: uses ConvertToCanonForm to
compare canonicalized forms, with variance support for variant positions.
- Universal canon fallback for nested __UniversalCanon under Specific
canonicalization.
Split into Canon/NonCanon partial files following the existing pattern
for IsSpecialTypeMeetingConstraint. Add NormalizeInstantiation call in
HandleCallAction's MakeGenericTypeSite.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move IsCanonicalTypeArgMatch and IsCanonEquivalent from
TypeSystemConstraintsHelpers.Canon.cs into CastingHelper.Canon.cs so
that CanCastTo naturally handles canonical types. This eliminates the
duplicated interface-walking, base-chain-walking, and variance logic
that was in CanCastToConstraintWithCanon.
Key changes to CastingHelper:
- IsCanonicalCastTarget in CanCastToInternal: __Canon accepts any
reference type as a cast source, __UniversalCanon accepts any type.
This makes array covariance (string[] -> __Canon[]) work naturally.
- IsCanonicalTypeArgMatch in CanCastByVarianceToInterfaceOrDelegate:
handles invariant positions where type args differ by canonicalization.
- IsCanonEquivalent in CanCastToNonVariantInterface and CanCastToClass:
handles non-variant interfaces and base types with canon type args.
CanCastToConstraintWithCanon is simplified to only handle wildcard cases
where the param or constraint IS __Canon/__UniversalCanon directly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
IsCanonicalTypeArgMatch did not handle parameterized types like arrays:
string[] vs __Canon[] failed because IsCanonEquivalent checks
Instantiation which is empty for arrays. Add ParameterizedType
structural matching that recursively compares element types.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exercises MakeGenericType where the canonical instantiation
(Gen<Atom, __Canon, object>) must pass constraint checking with
__Canon satisfying interface and new() constraints.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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 fixes NativeAOT reflection/dataflow constraint validation when generic instantiations are analyzed in canonical form (__Canon / __UniversalCanon), ensuring MakeGenericType sites aren’t incorrectly treated as invalid and therefore skipped for rooting/compilation.

Changes:

  • Normalize instantiated reflected generic types before constraint checking in MakeGenericType dataflow handling.
  • Extend casting and constraint-validation helpers to correctly treat canonical definition types as wildcards/compatible where appropriate (with canon vs non-canon partial implementations).
  • Add unit and smoke tests covering canonical-type constraint scenarios and constrained MakeGenericType dataflow.

Reviewed changes

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

Show a summary per file
FileDescription
src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.csAdds a new smoke test exercising constrained MakeGenericType rooting during dataflow analysis.
src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csprojIncludes new Canon-specific helper implementations in the TypeSystem build.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/GenericConstraints.csAdds new generic constraint shapes for canonical constraint tests.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ConstraintsValidationTest.csAdds a comprehensive canonical-constraint validation test suite.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.csNormalizes instantiated generic types before constraint validation/rooting.
src/coreclr/tools/ILVerification/ILVerification.projitemsAdds non-canon stub helper files required by the verifier’s non-canon TypeSystem build.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.csMakes helpers partial and adds canon-aware special-constraint and type-constraint checks.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.NonCanon.csProvides non-canon stub implementations for new partial helpers.
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.csAdds canon-aware matching hooks into cast logic (interfaces, variance, base chain).
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.NonCanon.csProvides non-canon stubs for new canon-aware cast helpers.
src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemConstraintsHelpers.Canon.csCanon-specific implementations for wildcard-like canonical constraint handling.
src/coreclr/tools/Common/TypeSystem/Canon/CastingHelper.Canon.csCanon-specific canonical matching logic for casts and type-arg comparisons.
src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csprojEnsures TypeLoader picks up canon-aware casting helper.

Comment threadsrc/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 21, 2026 00:48

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

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

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NativeAOT MakeGenericType fails to activate reflected generic type when generic parameter has self-referential interface constraint

4 participants

@MichalStrehovsky@jkoritzinsky@jkotas
, '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

Handle canonical types in casting logic - #127146

Merged
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604
Apr 21, 2026
Merged

Handle canonical types in casting logic#127146
MichalStrehovsky merged 5 commits into
dotnet:mainfrom
MichalStrehovsky:fix126604

Conversation

@MichalStrehovsky

Copy link
Copy Markdown
Member

Fixes#126604.

When we're doing dataflow analysis of MakeGenericXXX calls, we run constraint validation to ensure we don't precompile something invalid. However, because most reflection analysis within the compiler happens with canonical types, we can end up in a situation where a constraint check is necessary but all we have are canonical types. Constraint checking and CanCastTo logic was treating this a class __Canon : object { } case, but this is not that.

Cc @dotnet/ilc-contrib

MichalStrehovskyand others added 4 commits April 20, 2026 16:04
The AOT compiler's CheckConstraints was rejecting valid canonical
instantiations because CanCastTo has no awareness of canonical types.
When MakeGenericType produces canonical forms like GenericType<TestRequest,
__Canon>, type constraints (interface/base-type) would fail because e.g.
IRequest<TestRequest, string> doesn't match IRequest<TestRequest, __Canon>.
Add CanCastToConstraintWithCanon to TypeSystemConstraintsHelpers that
handles canonical types in constraint checking:
- __Canon/__UniversalCanon as the instantiation param: wildcard, accepts
any type constraint (runtime validates with concrete types).
- __Canon/__UniversalCanon as the constraint type itself: __Canon accepts
reference types, __UniversalCanon accepts anything.
- Canonical subtypes in constraint type args: uses ConvertToCanonForm to
compare canonicalized forms, with variance support for variant positions.
- Universal canon fallback for nested __UniversalCanon under Specific
canonicalization.
Split into Canon/NonCanon partial files following the existing pattern
for IsSpecialTypeMeetingConstraint. Add NormalizeInstantiation call in
HandleCallAction's MakeGenericTypeSite.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move IsCanonicalTypeArgMatch and IsCanonEquivalent from
TypeSystemConstraintsHelpers.Canon.cs into CastingHelper.Canon.cs so
that CanCastTo naturally handles canonical types. This eliminates the
duplicated interface-walking, base-chain-walking, and variance logic
that was in CanCastToConstraintWithCanon.
Key changes to CastingHelper:
- IsCanonicalCastTarget in CanCastToInternal: __Canon accepts any
reference type as a cast source, __UniversalCanon accepts any type.
This makes array covariance (string[] -> __Canon[]) work naturally.
- IsCanonicalTypeArgMatch in CanCastByVarianceToInterfaceOrDelegate:
handles invariant positions where type args differ by canonicalization.
- IsCanonEquivalent in CanCastToNonVariantInterface and CanCastToClass:
handles non-variant interfaces and base types with canon type args.
CanCastToConstraintWithCanon is simplified to only handle wildcard cases
where the param or constraint IS __Canon/__UniversalCanon directly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
IsCanonicalTypeArgMatch did not handle parameterized types like arrays:
string[] vs __Canon[] failed because IsCanonEquivalent checks
Instantiation which is empty for arrays. Add ParameterizedType
structural matching that recursively compares element types.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exercises MakeGenericType where the canonical instantiation
(Gen<Atom, __Canon, object>) must pass constraint checking with
__Canon satisfying interface and new() constraints.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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 fixes NativeAOT reflection/dataflow constraint validation when generic instantiations are analyzed in canonical form (__Canon / __UniversalCanon), ensuring MakeGenericType sites aren’t incorrectly treated as invalid and therefore skipped for rooting/compilation.

Changes:

  • Normalize instantiated reflected generic types before constraint checking in MakeGenericType dataflow handling.
  • Extend casting and constraint-validation helpers to correctly treat canonical definition types as wildcards/compatible where appropriate (with canon vs non-canon partial implementations).
  • Add unit and smoke tests covering canonical-type constraint scenarios and constrained MakeGenericType dataflow.

Reviewed changes

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

Show a summary per file
FileDescription
src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.csAdds a new smoke test exercising constrained MakeGenericType rooting during dataflow analysis.
src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csprojIncludes new Canon-specific helper implementations in the TypeSystem build.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/GenericConstraints.csAdds new generic constraint shapes for canonical constraint tests.
src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ConstraintsValidationTest.csAdds a comprehensive canonical-constraint validation test suite.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.csNormalizes instantiated generic types before constraint validation/rooting.
src/coreclr/tools/ILVerification/ILVerification.projitemsAdds non-canon stub helper files required by the verifier’s non-canon TypeSystem build.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.csMakes helpers partial and adds canon-aware special-constraint and type-constraint checks.
src/coreclr/tools/Common/TypeSystem/Common/TypeSystemConstraintsHelpers.NonCanon.csProvides non-canon stub implementations for new partial helpers.
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.csAdds canon-aware matching hooks into cast logic (interfaces, variance, base chain).
src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.NonCanon.csProvides non-canon stubs for new canon-aware cast helpers.
src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemConstraintsHelpers.Canon.csCanon-specific implementations for wildcard-like canonical constraint handling.
src/coreclr/tools/Common/TypeSystem/Canon/CastingHelper.Canon.csCanon-specific canonical matching logic for casts and type-arg comparisons.
src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csprojEnsures TypeLoader picks up canon-aware casting helper.

Comment threadsrc/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings April 21, 2026 00:48

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

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

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NativeAOT MakeGenericType fails to activate reflected generic type when generic parameter has self-referential interface constraint

4 participants

@MichalStrehovsky@jkoritzinsky@jkotas