Skip to content

Fix variant interface GVM resolution in managed type system#130218

Merged
MichalStrehovsky merged 3 commits into
dotnet:mainfrom
hez2010:r2r-method-generic-variance
Jul 7, 2026
Merged

Fix variant interface GVM resolution in managed type system#130218
MichalStrehovsky merged 3 commits into
dotnet:mainfrom
hez2010:r2r-method-generic-variance

Conversation

@hez2010

@hez2010 hez2010 commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

When resolving an instantiated interface GVM, we passed down the method generic instantiation. However, interface slot selection needs to be done on the GVM definition, otherwise it could resolve to whatever the first compatible interface slot we saw. This can produce the incorrect devirtualized target when a type implements an interface GVM with multiple variant-compatible instantiations.

Fixed it by stripping the method instantiation before resolving the interface slot.

The CoreCLR native type system already handles such cases well so we don't have any issue there.

Found this issue while I was working on GVM devirt for NAOT in #130202. See added tests for repro: previously it failed for the CallOnBase cases. Tests are added to both the managed type system and the normal JIT tests to prevent future regressions in either side.

cc: @MichalStrehovsky

@hez2010 hez2010 requested a review from MichalStrehovsky as a code owner July 5, 2026 12:34
Copilot AI review requested due to automatic review settings July 5, 2026 12:34
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 5, 2026
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Jul 5, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Copilot AI 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 adjusts the CoreCLR managed TypeSystem’s interface virtual method resolution so that interface slot selection for instantiated interface GVMs is performed on the generic method definition (and then the method instantiation is reapplied), avoiding incorrect target selection when multiple variant-compatible interface instantiations exist.

Changes:

  • Update MetadataVirtualMethodAlgorithm to resolve interface GVMs using the method definition and then re-instantiate the resolved target.
  • Add a new variance-focused regression test (plus optimized variant) under src/tests/JIT/Generics/Variance.

Reviewed changes

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

File Description
src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs Resolves instantiated interface GVMs via the definition for slot selection, then reapplies method instantiation.
src/tests/JIT/Generics/Variance/variance_generic_virtual.cs Adds a regression test covering multiple variant-compatible interface instantiations with generic interface methods.
src/tests/JIT/Generics/Variance/variance_generic_virtual.csproj Adds the new JIT test project.
src/tests/JIT/Generics/Variance/variance_generic_virtual_o.csproj Adds an optimized build variant of the same test.

Comment thread src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs Outdated
@hez2010

hez2010 commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

Test failure is #129871. @MichalStrehovsky Please take a look.

Comment thread src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs Outdated
Copilot AI review requested due to automatic review settings July 6, 2026 11:55

Copilot AI 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 8 out of 8 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs
@MichalStrehovsky

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop, runtime-coreclr crossgen2 outerloop, runtime-coreclr outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

@MichalStrehovsky

Copy link
Copy Markdown
Member

/ba-g filed #130286 on the crash in GC. it's unlikely to be related.

@MichalStrehovsky MichalStrehovsky merged commit 4245753 into dotnet:main Jul 7, 2026
226 of 239 checks passed
@MichalStrehovsky

Copy link
Copy Markdown
Member

I didn't merge copilot's spelling nit because then I can no longer approve or merge and that's not a good tradeoff.

@hez2010

hez2010 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

I didn't merge copilot's spelling nit because then I can no longer approve or merge and that's not a good tradeoff.

I didn't merge it either as that would require yet another long outerloop run and that's not a good tradeoff as well.

@Blake-McCullough

Blake-McCullough commented Jul 7, 2026

Copy link
Copy Markdown

Any eta on when this will be pushed into the a release? Currently dealing with this issue.

What i found was when a class implements the same generic interface with different type arguments (e.g., I_IsParent<A, T> and I_IsParent<B, T>), casting to one interface and calling a method sometimes executes the implementation for the other type. This appears to be the same variant interface GVM resolution bug addressed here.

Workaround that worked: The issue can be avoided by extracting the cast and method call into a separate generic helper method, which forces the JIT to resolve the correct interface method at runtime:

private IHaveLevelSettings ResolveParent<TParent>()
    where TParent : class, ICanBeIdentified, ICanBeEnumerated_Base<TParent>, IHaveLevelSettings
{
    if (this is I_IsParent<TParent, LE_LevelSettings> typed)
    {
        return typed.ParentGaurantee();
    }
    throw new ServerException($"No I_IsParent<{typeof(TParent).Name}, LE_LevelSettings> implemented");
}

Code that triggered the bug: Direct casting and calling in a switch statement:

// This incorrectly called the wrong interface method
AP_Instance application = ((I_IsParent<AP_Instance, LE_LevelSettings>)this).ParentGaurantee();

thankyou

@hez2010

hez2010 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Any eta on when this will be pushed into the a release? Currently dealing with this issue.

The issue you described doesn't seem to be the same issue here. Here it's an AOT-specific issue after enabling GVM devirt in .NET 11 preview7 (not released yet). In .NET 10 we don't devirtualize any GVM at all.

Can you share a standalone repro in a new issue so that we can take a look?

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

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants