Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 3, 2025

The AOT analyzer warns with IL3050 when calling MakeGenericType even when the type arguments are provably reference types through dataflow analysis (e.g., after checking !t.IsValueType) or have class constraints.

// Currently warns, but shouldn't - we know t is a reference type
void Foo(Type t) {
    if (!t.IsValueType)
        typeof(G<>).MakeGenericType(t);
}

// Currently warns, but shouldn't - T is constrained to reference types
void Bar<T>() where T : class {
    typeof(G<>).MakeGenericType(typeof(T));
}

Changes

Added reference type analysis to HandleCallAction.cs:

  • AreAllArgumentsKnownReferenceTypes() method checks if type arguments are provably reference types by examining:
    • SystemTypeValue for !Type.IsValueType
    • GenericParameterValue for HasReferenceTypeConstraint (class constraint)
  • Applied to both Type_MakeGenericType and MethodInfo_MakeGenericMethod intrinsics
  • IL3050 warning now only triggers when types could be value types

Added test coverage:

  • Test cases verifying no warnings for reference types with runtime checks and class constraints
  • Test cases verifying warnings still occur for value types and unknown types

Fixes #110797

Original prompt

This section details on the original issue you should resolve

<issue_title>AOT/analyzer should not warn for MakeGenericType of reference type</issue_title>
<issue_description>- [ ] MakeGenericType over reference types is supported in native AOT, so the following should not warn:

void Foo(Type t) {
    if (!t.IsValueType)
        typeof(G<>).MakeGenericType(t); // currently warns with IL3050
}
  • Probably the class constraint should be supported as well:
void Foo<T>() where T : class {
    typeof(G<>).MakeGenericType(typeof(T));
}
  • We may also want to introduce an annotation to propagate the fact that a type is a reference type across methods, for example:
void Foo(Type t) {
    if (!t.IsValueType)
        Bar(t);
}

void Bar([ReferenceType] Type t) {
    typeof(G<>).MakeGenericType(t);
}

(The latter idea is something that has come up in discussion with @vitek-karas and @MichalStrehovsky, not sure if there's another tracking issue for it already.)

Context: https://github.com/dotnet/maui/pull/20058/files/7f4d26ca0aee7dc9d995e9776573125b35ad44b6#r1463169163</issue_description>

Comments on the Issue (you are @copilot in this section)

@ Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas See info in [area-owners.md](https://github.com/dotnet/runtime/blob/main/docs/area-owners.md) if you want to be subscribed.
Issue Details

MakeGenericType over reference types is supported in native AOT, so the following should not warn:

void Foo(Type t) {
    if (!t.IsValueType)
        typeof(G<>).MakeGenericType(t); // currently warns with IL3050
}

Probably the class constraint should be supported as well:

void Foo<T>() where T : class {
    typeof(G<>).MakeGenericType(typeof(T));
}

We may also want to introduce an annotation to propagate the fact that a type is a reference type across methods, for example:

void Foo(Type t) {
    if (!t.IsValueType)
        Bar(t);
}

void Bar([ReferenceType] Type t) {
    typeof(G<>).MakeGenericType(t);
}

(The latter idea is something that has come up in discussion with @vitek-karas and @MichalStrehovsky, not sure if there's another tracking issue for it already.)

Context: https://github.com/dotnet/maui/pull/20058/files/7f4d26ca0aee7dc9d995e9776573125b35ad44b6#r1463169163

Author: sbomer
Assignees: -
Labels:

untriaged, area-NativeAOT-coreclr, needs-area-label

Milestone: -
@sbomer Based on some experimentation, it looks like it doesn't always generate the shared impl. I'm not sure exactly what is enough to generate the shared impl. Just calling `G.Method()` won't do it - but accessing some of the generic type's methods via reflection will. For example `MakeGenericType` fails here:
typeof(G<>).MakeGenericType(typeof(C));
// typeof(G<>).GetMethod("Foo");

class G<T> {
    public static void Foo() {
        Console.WriteLine(typeof(T));
    }
}

class C {}

but succeeds if you uncomment the GetMethod("Foo").

@MichalStrehovsky could probably give a better answer.</comment_new>
<comment_new>@MichalStrehovsky

Based on some experimentation, it looks like it doesn't always generate the shared impl. I'm not sure exactly what is enough to generate the shared impl. Just calling G<SomeOtherReferenceType>.Method() won't do it - but accessing some of the generic type's methods via reflection will. For example MakeGenericType fails here:

typeof(G<>).MakeGenericType(typeof(C));
// typeof(G<>).GetMethod("Foo");

class G<T> {
    public static void Foo() {
        Console.WriteLine(typeof(T));
    }
}

class C {}

but succeeds if you uncomment the GetMethod("Foo").

@MichalStrehovsky could probably give a better answer.

Looks like we don't treat MakeGenericType specially in dataflow analysis - the only special handling is to trigger the AOT warning here:

// Special case some intrinsics for AOT handling (on top of the trimming handling done in the HandleCallAction)
switch (intrinsicId)
{
case IntrinsicId.Type_MakeGenericType:
case IntrinsicId.MethodInfo_MakeGenericMethod:
CheckAndReportRequires(diagnosticContext, calledMethod, DiagnosticUtilities.RequiresDynamicCodeAttribute);
break;

It works if a method/constructor/field is subsequently accessed because dataflow will report "G<>.Foo is reflection accessed" and then the compiler will try to make G<>.Foo work on at least something.

It shouldn't be hard to make this work for an unused type.</comment_new>


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…e check

Co-authored-by: agocke <515774+agocke@users.noreply.github.com>
@dotnet-policy-service dotnet-policy-service bot added the linkable-framework Issues associated with delivering a linker friendly framework label Nov 3, 2025
Co-authored-by: agocke <515774+agocke@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix AOT warning for MakeGenericType on reference types Suppress IL3050 warning for MakeGenericType/MakeGenericMethod with known reference types Nov 3, 2025
Copilot finished work on behalf of agocke November 3, 2025 22:28
Copilot AI requested a review from agocke November 3, 2025 22:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

linkable-framework Issues associated with delivering a linker friendly framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AOT/analyzer should not warn for MakeGenericType of reference type

2 participants