Skip to content

NativeAOT: GVM that requires runtime lookup but doesn't override the base method won't compile #129697

Closed

Description

@hez2010

Repro1:

RuntimeLookupDelegateGenericVirtual.Test<string>();

internal class RuntimeLookupDelegateGenericVirtual
{
    internal static void Test<T>()
    {
        var test2 = new Derived();
        Delegate m1 = test2.Foo<List<T>>();
        Delegate m2 = test2.Foo<List<List<T>>>;
        if (m1.Method != m2.Method)
        {
            throw new Exception($"Unexpected different methods returned from generic virtual method.");
        }
    }
}

internal interface Base
{
    public virtual Delegate Foo<U>()
    {
        return Foo<U>;
    }
}

internal struct Derived : Base
{
    public Delegate Foo<U1>()
    {
        return Foo<List<U1>>;
    }
}

Repro2 (changing the struct to class):

RuntimeLookupDelegateGenericVirtual.Test<string>();

internal class RuntimeLookupDelegateGenericVirtual
{
    internal static void Test<T>()
    {
        var test2 = new Derived();
        Delegate m1 = test2.Foo<List<T>>();
        Delegate m2 = test2.Foo<List<List<T>>>;
        if (m1.Method != m2.Method)
        {
            throw new Exception($"Unexpected different methods returned from generic virtual method.");
        }
    }
}

internal interface Base
{
    public virtual Delegate Foo<U>()
    {
        return Foo<U>;
    }
}

internal class Derived : Base
{
    public Delegate Foo<U1>()
    {
        return Foo<List<U1>>;
    }
}

Repro3 (changing the interface to a base class, but don't override the method in derived class):

RuntimeLookupDelegateGenericVirtual.Test<string>();

internal class RuntimeLookupDelegateGenericVirtual
{
    internal static void Test<T>()
    {
        var test2 = new Derived();
        Delegate m1 = test2.Foo<List<T>>();
        Delegate m2 = test2.Foo<List<List<T>>>;
        if (m1.Method != m2.Method)
        {
            throw new Exception($"Unexpected different methods returned from generic virtual method.");
        }
    }
}

internal class Base
{
    public virtual Delegate Foo<U>()
    {
        return Foo<U>;
    }
}

internal class Derived : Base
{
    public new Delegate Foo<U1>()
    {
        return Foo<List<U1>>;
    }
}

Ilc will never complete compiling the above snippets and will stick there forever.

It only compiles when you are overriding the base method of a class.

RuntimeLookupDelegateGenericVirtual.Test<string>();

internal class RuntimeLookupDelegateGenericVirtual
{
    internal static void Test<T>()
    {
        var test2 = new Derived();
        Delegate m1 = test2.Foo<List<T>>();
        Delegate m2 = test2.Foo<List<List<T>>>;
        if (m1.Method != m2.Method)
        {
            throw new Exception($"Unexpected different methods returned from generic virtual method.");
        }
    }
}

internal class Base
{
    public virtual Delegate Foo<U>()
    {
        return Foo<U>;
    }
}

internal class Derived : Base
{
    public override Delegate Foo<U1>()
    {
        return Foo<List<U1>>;
    }
}

cc: @MichalStrehovsky

Activity

  1. added
    area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
    on Jun 22, 2026
  2. dotnet-policy-service commented on Jun 22, 2026

    @dotnet-policy-service
    Contributor

    Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
    See info in area-owners.md if you want to be subscribed.

  3. dotnet-policy-service commented on Jun 23, 2026

    @dotnet-policy-service
    Contributor

    Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
    See info in area-owners.md if you want to be subscribed.

  4. added a commit that references this issue on Jun 23, 2026
    3500de6
  5. added a commit that references this issue on Jul 15, 2026
    f707d16
  6. locked and limited conversation to collaborators on Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    • Status
      No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions