From 3800e9e4d20b937760c7a4731103cd34096d8ecc Mon Sep 17 00:00:00 2001 From: Steven He Date: Sun, 5 Jul 2026 21:25:05 +0900 Subject: [PATCH 1/3] Fix variant interface GVM resolution in crossgen2 --- .../Common/MetadataVirtualMethodAlgorithm.cs | 18 ++++++ .../Variance/variance_generic_virtual.cs | 62 +++++++++++++++++++ .../Variance/variance_generic_virtual.csproj | 10 +++ .../variance_generic_virtual_o.csproj | 11 ++++ 4 files changed, 101 insertions(+) create mode 100644 src/tests/JIT/Generics/Variance/variance_generic_virtual.cs create mode 100644 src/tests/JIT/Generics/Variance/variance_generic_virtual.csproj create mode 100644 src/tests/JIT/Generics/Variance/variance_generic_virtual_o.csproj diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs index b1444f1afe5077..7f937b26f0ee4a 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs @@ -696,6 +696,15 @@ private static MethodDesc ResolveInterfaceMethodToVirtualMethodOnType(MethodDesc { Debug.Assert(!interfaceMethod.Signature.IsStatic); + MethodDesc interfaceMethodDefinition = interfaceMethod.GetMethodDefinition(); + if (interfaceMethod != interfaceMethodDefinition) + { + // Generic method arguments do not participate in interface slot selection. + // Resolve the GVM definition first and reapply the instantiation to the resolved target. + MethodDesc impl = ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethodDefinition, currentType, returnRecursive); + return impl?.MakeInstantiatedMethod(interfaceMethod.Instantiation); + } + // This would be a default interface method resolution. The algorithm below would sort of work, but doesn't handle // things like diamond cases and it's better not to let it resolve as such. if (currentType.IsInterface) @@ -769,6 +778,15 @@ public static MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(Meth { Debug.Assert(!interfaceMethod.Signature.IsStatic); + MethodDesc interfaceMethodDefinition = interfaceMethod.GetMethodDefinition(); + if (interfaceMethod != interfaceMethodDefinition) + { + // Generic method arguments do not participate in interface slot selection. + // Resolve the GVM definition first and reapply the instantiation to the resolved target. + MethodDesc impl = ResolveVariantInterfaceMethodToVirtualMethodOnType(interfaceMethodDefinition, currentType); + return impl?.MakeInstantiatedMethod(interfaceMethod.Instantiation); + } + MetadataType interfaceType = (MetadataType)interfaceMethod.OwningType; bool foundInterface = IsInterfaceImplementedOnType(currentType, interfaceType); MethodDesc implMethod; diff --git a/src/tests/JIT/Generics/Variance/variance_generic_virtual.cs b/src/tests/JIT/Generics/Variance/variance_generic_virtual.cs new file mode 100644 index 00000000000000..44b59919f09e10 --- /dev/null +++ b/src/tests/JIT/Generics/Variance/variance_generic_virtual.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +using Xunit; + +class Base +{ + +} + +class Derived : Base +{ + +} + +interface IInVariant +{ + string Func(T t); +} + +interface IOutVariant +{ + string Func(); +} + +class ClassWithVariantGvms : IInVariant, IInVariant, IOutVariant, IOutVariant +{ + string IInVariant.Func(object t) + { + return "CallOnObject"; + } + string IInVariant.Func(Base t) + { + return "CallOnBase"; + } + string IOutVariant.Func() + { + return "CallOnDerived"; + } + string IOutVariant.Func() + { + return "CallOnBase"; + } +} + +public class VarianceGenericVirtual +{ + [Fact] + public static void TestEntryPoint() + { + ClassWithVariantGvms testClass = new ClassWithVariantGvms(); + + Assert.Equal("CallOnObject", ((IInVariant)testClass).Func(new Derived())); + Assert.Equal("CallOnBase", ((IInVariant)testClass).Func(new Derived())); + Assert.Equal("CallOnObject", ((IInVariant)testClass).Func(new Derived())); + + Assert.Equal("CallOnDerived", ((IOutVariant)testClass).Func()); + Assert.Equal("CallOnBase", ((IOutVariant)testClass).Func()); + Assert.Equal("CallOnDerived", ((IOutVariant)testClass).Func()); + } +} diff --git a/src/tests/JIT/Generics/Variance/variance_generic_virtual.csproj b/src/tests/JIT/Generics/Variance/variance_generic_virtual.csproj new file mode 100644 index 00000000000000..d46f3d457f1a61 --- /dev/null +++ b/src/tests/JIT/Generics/Variance/variance_generic_virtual.csproj @@ -0,0 +1,10 @@ + + + PdbOnly + 1 + + + + + + diff --git a/src/tests/JIT/Generics/Variance/variance_generic_virtual_o.csproj b/src/tests/JIT/Generics/Variance/variance_generic_virtual_o.csproj new file mode 100644 index 00000000000000..76a31cdd0d2547 --- /dev/null +++ b/src/tests/JIT/Generics/Variance/variance_generic_virtual_o.csproj @@ -0,0 +1,11 @@ + + + PdbOnly + True + 1 + + + + + + From b99bf00e6e2b8ec463d2045d71c32eff3a12b3a7 Mon Sep 17 00:00:00 2001 From: Steven He Date: Sun, 5 Jul 2026 21:57:48 +0900 Subject: [PATCH 2/3] Improve tests --- .../VirtualFunctionOverride.cs | 26 ++++++++++++++ .../VirtualFunctionOverrideTests.cs | 34 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/VirtualFunctionOverride.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/VirtualFunctionOverride.cs index 76b16f3ca46c9f..51ea0fcd7c2334 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/VirtualFunctionOverride.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/VirtualFunctionOverride.cs @@ -15,6 +15,32 @@ class HasMethodInterfaceOverrideOfGenericMethod : IIFaceWithGenericMethod void IIFaceWithGenericMethod.GenMethod() { } } + class GvmVariantBase + { + } + + class GvmVariantDerived : GvmVariantBase + { + } + + interface IInVariantGvm + { + string Func(T t); + } + + interface IOutVariantGvm + { + string Func(); + } + + class ClassWithVariantGvms : IInVariantGvm, IInVariantGvm, IOutVariantGvm, IOutVariantGvm + { + string IInVariantGvm.Func(object t) => "CallOnObject"; + string IInVariantGvm.Func(GvmVariantBase t) => "CallOnBase"; + string IOutVariantGvm.Func() => "CallOnDerived"; + string IOutVariantGvm.Func() => "CallOnBase"; + } + class SimpleGeneric { public override string ToString() diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/VirtualFunctionOverrideTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/VirtualFunctionOverrideTests.cs index b6ddb314c70dfc..a37431fcd922d2 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/VirtualFunctionOverrideTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/VirtualFunctionOverrideTests.cs @@ -72,6 +72,40 @@ public void TestGenericMethodInterfaceMethodImplOverride() Assert.Equal(expectedVirtualMethod, objectType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod)); } + [Fact] + public void TestVariantInterfaceGenericMethodResolution() + { + DefType objectType = _context.GetWellKnownType(WellKnownType.Object); + MetadataType baseType = _testModule.GetType("VirtualFunctionOverride"u8, "GvmVariantBase"u8); + MetadataType derivedType = _testModule.GetType("VirtualFunctionOverride"u8, "GvmVariantDerived"u8); + MetadataType implementationType = _testModule.GetType("VirtualFunctionOverride"u8, "ClassWithVariantGvms"u8); + + MetadataType inVariantType = _testModule.GetType("VirtualFunctionOverride"u8, "IInVariantGvm`1"u8); + MetadataType outVariantType = _testModule.GetType("VirtualFunctionOverride"u8, "IOutVariantGvm`1"u8); + + MethodDesc inObjectMethod = inVariantType.MakeInstantiatedType(objectType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); + MethodDesc inBaseMethod = inVariantType.MakeInstantiatedType(baseType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); + MethodDesc inDerivedMethod = inVariantType.MakeInstantiatedType(derivedType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); + MethodDesc outObjectMethod = outVariantType.MakeInstantiatedType(objectType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); + MethodDesc outBaseMethod = outVariantType.MakeInstantiatedType(baseType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); + MethodDesc outDerivedMethod = outVariantType.MakeInstantiatedType(derivedType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); + + MethodImplRecord[] methodImpls = implementationType.FindMethodsImplWithMatchingDeclName(inObjectMethod.Name); + Assert.NotNull(methodImpls); + + MethodDesc inObjectImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == inObjectMethod.GetMethodDefinition()).Body.MakeInstantiatedMethod(objectType); + MethodDesc inBaseImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == inBaseMethod.GetMethodDefinition()).Body.MakeInstantiatedMethod(objectType); + MethodDesc outDerivedImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == outDerivedMethod.GetMethodDefinition()).Body.MakeInstantiatedMethod(objectType); + MethodDesc outBaseImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == outBaseMethod.GetMethodDefinition()).Body.MakeInstantiatedMethod(objectType); + + Assert.Equal(inObjectImpl, implementationType.ResolveVariantInterfaceMethodToVirtualMethodOnType(inObjectMethod)); + Assert.Equal(inBaseImpl, implementationType.ResolveVariantInterfaceMethodToVirtualMethodOnType(inBaseMethod)); + Assert.Equal(inObjectImpl, implementationType.ResolveVariantInterfaceMethodToVirtualMethodOnType(inDerivedMethod)); + Assert.Equal(outDerivedImpl, implementationType.ResolveVariantInterfaceMethodToVirtualMethodOnType(outObjectMethod)); + Assert.Equal(outBaseImpl, implementationType.ResolveVariantInterfaceMethodToVirtualMethodOnType(outBaseMethod)); + Assert.Equal(outDerivedImpl, implementationType.ResolveVariantInterfaceMethodToVirtualMethodOnType(outDerivedMethod)); + } + [Fact] public void TestVirtualDispatchOnGenericType() { From 17dc64150b738d317711e809813d833253bc459a Mon Sep 17 00:00:00 2001 From: Steven He Date: Mon, 6 Jul 2026 20:55:01 +0900 Subject: [PATCH 3/3] Fix the issue at callsite --- .../Compiler/DevirtualizationManager.cs | 4 ++- .../Common/MetadataVirtualMethodAlgorithm.cs | 18 ---------- .../DevirtualizationTests.cs | 36 +++++++++++++++++++ .../GvmVariantInterface.cs | 31 ++++++++++++++++ .../CoreTestAssembly/CoreTestAssembly.csproj | 4 +++ .../VirtualFunctionOverride.cs | 26 -------------- .../VirtualFunctionOverrideTests.cs | 30 ++++++++-------- 7 files changed, 89 insertions(+), 60 deletions(-) create mode 100644 src/coreclr/tools/aot/ILCompiler.Compiler.Tests/ILCompiler.Compiler.Tests.Assets/GvmVariantInterface.cs diff --git a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs index 9e23da8fb606b3..840dc86281783e 100644 --- a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs +++ b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs @@ -100,7 +100,9 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType return null; } - impl = implType.ResolveInterfaceMethodTargetWithVariance(declMethod); + // Strip the method instantation as interface slot resolution works on method definitions. + // Method instantiation will be applied again after resolution. + impl = implType.ResolveInterfaceMethodTargetWithVariance(declMethod.GetMethodDefinition()); if (impl != null) { diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs index 7f937b26f0ee4a..b1444f1afe5077 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs @@ -696,15 +696,6 @@ private static MethodDesc ResolveInterfaceMethodToVirtualMethodOnType(MethodDesc { Debug.Assert(!interfaceMethod.Signature.IsStatic); - MethodDesc interfaceMethodDefinition = interfaceMethod.GetMethodDefinition(); - if (interfaceMethod != interfaceMethodDefinition) - { - // Generic method arguments do not participate in interface slot selection. - // Resolve the GVM definition first and reapply the instantiation to the resolved target. - MethodDesc impl = ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethodDefinition, currentType, returnRecursive); - return impl?.MakeInstantiatedMethod(interfaceMethod.Instantiation); - } - // This would be a default interface method resolution. The algorithm below would sort of work, but doesn't handle // things like diamond cases and it's better not to let it resolve as such. if (currentType.IsInterface) @@ -778,15 +769,6 @@ public static MethodDesc ResolveVariantInterfaceMethodToVirtualMethodOnType(Meth { Debug.Assert(!interfaceMethod.Signature.IsStatic); - MethodDesc interfaceMethodDefinition = interfaceMethod.GetMethodDefinition(); - if (interfaceMethod != interfaceMethodDefinition) - { - // Generic method arguments do not participate in interface slot selection. - // Resolve the GVM definition first and reapply the instantiation to the resolved target. - MethodDesc impl = ResolveVariantInterfaceMethodToVirtualMethodOnType(interfaceMethodDefinition, currentType); - return impl?.MakeInstantiatedMethod(interfaceMethod.Instantiation); - } - MetadataType interfaceType = (MetadataType)interfaceMethod.OwningType; bool foundInterface = IsInterfaceImplementedOnType(currentType, interfaceType); MethodDesc implMethod; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler.Tests/DevirtualizationTests.cs b/src/coreclr/tools/aot/ILCompiler.Compiler.Tests/DevirtualizationTests.cs index 206007612e6aaa..ee667e641a9115 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler.Tests/DevirtualizationTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler.Tests/DevirtualizationTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Linq; using Internal.IL; using Internal.TypeSystem; @@ -66,5 +67,40 @@ public void TestDevirtualizeAbstract() Assert.False(scanDevirt.IsEffectivelySealed(testType.GetNestedType("Abstract"u8))); } + + [Fact] + public void TestVariantInterfaceGenericMethodResolution() + { + DefType objectType = _context.GetWellKnownType(WellKnownType.Object); + MetadataType baseType = _testModule.GetType("GvmVariantInterface"u8, "GvmVariantBase"u8); + MetadataType derivedType = _testModule.GetType("GvmVariantInterface"u8, "GvmVariantDerived"u8); + MetadataType implementationType = _testModule.GetType("GvmVariantInterface"u8, "ClassWithVariantGvms"u8); + + MetadataType inVariantType = _testModule.GetType("GvmVariantInterface"u8, "IInVariantGvm`1"u8); + MetadataType outVariantType = _testModule.GetType("GvmVariantInterface"u8, "IOutVariantGvm`1"u8); + + MethodDesc inObjectMethod = inVariantType.MakeInstantiatedType(objectType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); + MethodDesc inBaseMethod = inVariantType.MakeInstantiatedType(baseType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); + MethodDesc inDerivedMethod = inVariantType.MakeInstantiatedType(derivedType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); + MethodDesc outObjectMethod = outVariantType.MakeInstantiatedType(objectType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); + MethodDesc outBaseMethod = outVariantType.MakeInstantiatedType(baseType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); + MethodDesc outDerivedMethod = outVariantType.MakeInstantiatedType(derivedType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); + + MethodImplRecord[] methodImpls = implementationType.FindMethodsImplWithMatchingDeclName(inObjectMethod.Name); + Assert.NotNull(methodImpls); + + MethodDesc inObjectImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == inObjectMethod.GetMethodDefinition()).Body.MakeInstantiatedMethod(objectType); + MethodDesc inBaseImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == inBaseMethod.GetMethodDefinition()).Body.MakeInstantiatedMethod(objectType); + MethodDesc outDerivedImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == outDerivedMethod.GetMethodDefinition()).Body.MakeInstantiatedMethod(objectType); + MethodDesc outBaseImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == outBaseMethod.GetMethodDefinition()).Body.MakeInstantiatedMethod(objectType); + + var devirt = new DevirtualizationManager(); + Assert.Equal(inObjectImpl, devirt.ResolveVirtualMethod(inObjectMethod, implementationType, out _)); + Assert.Equal(inBaseImpl, devirt.ResolveVirtualMethod(inBaseMethod, implementationType, out _)); + Assert.Equal(inObjectImpl, devirt.ResolveVirtualMethod(inDerivedMethod, implementationType, out _)); + Assert.Equal(outDerivedImpl, devirt.ResolveVirtualMethod(outObjectMethod, implementationType, out _)); + Assert.Equal(outBaseImpl, devirt.ResolveVirtualMethod(outBaseMethod, implementationType, out _)); + Assert.Equal(outDerivedImpl, devirt.ResolveVirtualMethod(outDerivedMethod, implementationType, out _)); + } } } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler.Tests/ILCompiler.Compiler.Tests.Assets/GvmVariantInterface.cs b/src/coreclr/tools/aot/ILCompiler.Compiler.Tests/ILCompiler.Compiler.Tests.Assets/GvmVariantInterface.cs new file mode 100644 index 00000000000000..4dea83eecf5b22 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler.Tests/ILCompiler.Compiler.Tests.Assets/GvmVariantInterface.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace GvmVariantInterface +{ + class GvmVariantBase + { + } + + class GvmVariantDerived : GvmVariantBase + { + } + + interface IInVariantGvm + { + string Func(T t); + } + + interface IOutVariantGvm + { + string Func(); + } + + class ClassWithVariantGvms : IInVariantGvm, IInVariantGvm, IOutVariantGvm, IOutVariantGvm + { + string IInVariantGvm.Func(object t) => "CallOnObject"; + string IInVariantGvm.Func(GvmVariantBase t) => "CallOnBase"; + string IOutVariantGvm.Func() => "CallOnDerived"; + string IOutVariantGvm.Func() => "CallOnBase"; + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/CoreTestAssembly.csproj b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/CoreTestAssembly.csproj index 3edc005bedc6b4..961a4bf4b8a448 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/CoreTestAssembly.csproj +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/CoreTestAssembly.csproj @@ -16,4 +16,8 @@ false + + + + diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/VirtualFunctionOverride.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/VirtualFunctionOverride.cs index 51ea0fcd7c2334..76b16f3ca46c9f 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/VirtualFunctionOverride.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/VirtualFunctionOverride.cs @@ -15,32 +15,6 @@ class HasMethodInterfaceOverrideOfGenericMethod : IIFaceWithGenericMethod void IIFaceWithGenericMethod.GenMethod() { } } - class GvmVariantBase - { - } - - class GvmVariantDerived : GvmVariantBase - { - } - - interface IInVariantGvm - { - string Func(T t); - } - - interface IOutVariantGvm - { - string Func(); - } - - class ClassWithVariantGvms : IInVariantGvm, IInVariantGvm, IOutVariantGvm, IOutVariantGvm - { - string IInVariantGvm.Func(object t) => "CallOnObject"; - string IInVariantGvm.Func(GvmVariantBase t) => "CallOnBase"; - string IOutVariantGvm.Func() => "CallOnDerived"; - string IOutVariantGvm.Func() => "CallOnBase"; - } - class SimpleGeneric { public override string ToString() diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/VirtualFunctionOverrideTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/VirtualFunctionOverrideTests.cs index a37431fcd922d2..65d89061179851 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/VirtualFunctionOverrideTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/VirtualFunctionOverrideTests.cs @@ -76,27 +76,27 @@ public void TestGenericMethodInterfaceMethodImplOverride() public void TestVariantInterfaceGenericMethodResolution() { DefType objectType = _context.GetWellKnownType(WellKnownType.Object); - MetadataType baseType = _testModule.GetType("VirtualFunctionOverride"u8, "GvmVariantBase"u8); - MetadataType derivedType = _testModule.GetType("VirtualFunctionOverride"u8, "GvmVariantDerived"u8); - MetadataType implementationType = _testModule.GetType("VirtualFunctionOverride"u8, "ClassWithVariantGvms"u8); + MetadataType baseType = _testModule.GetType("GvmVariantInterface"u8, "GvmVariantBase"u8); + MetadataType derivedType = _testModule.GetType("GvmVariantInterface"u8, "GvmVariantDerived"u8); + MetadataType implementationType = _testModule.GetType("GvmVariantInterface"u8, "ClassWithVariantGvms"u8); - MetadataType inVariantType = _testModule.GetType("VirtualFunctionOverride"u8, "IInVariantGvm`1"u8); - MetadataType outVariantType = _testModule.GetType("VirtualFunctionOverride"u8, "IOutVariantGvm`1"u8); + MetadataType inVariantType = _testModule.GetType("GvmVariantInterface"u8, "IInVariantGvm`1"u8); + MetadataType outVariantType = _testModule.GetType("GvmVariantInterface"u8, "IOutVariantGvm`1"u8); - MethodDesc inObjectMethod = inVariantType.MakeInstantiatedType(objectType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); - MethodDesc inBaseMethod = inVariantType.MakeInstantiatedType(baseType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); - MethodDesc inDerivedMethod = inVariantType.MakeInstantiatedType(derivedType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); - MethodDesc outObjectMethod = outVariantType.MakeInstantiatedType(objectType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); - MethodDesc outBaseMethod = outVariantType.MakeInstantiatedType(baseType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); - MethodDesc outDerivedMethod = outVariantType.MakeInstantiatedType(derivedType).GetMethods().Single(m => m.GetName() == "Func").MakeInstantiatedMethod(objectType); + MethodDesc inObjectMethod = inVariantType.MakeInstantiatedType(objectType).GetMethods().Single(m => m.GetName() == "Func"); + MethodDesc inBaseMethod = inVariantType.MakeInstantiatedType(baseType).GetMethods().Single(m => m.GetName() == "Func"); + MethodDesc inDerivedMethod = inVariantType.MakeInstantiatedType(derivedType).GetMethods().Single(m => m.GetName() == "Func"); + MethodDesc outObjectMethod = outVariantType.MakeInstantiatedType(objectType).GetMethods().Single(m => m.GetName() == "Func"); + MethodDesc outBaseMethod = outVariantType.MakeInstantiatedType(baseType).GetMethods().Single(m => m.GetName() == "Func"); + MethodDesc outDerivedMethod = outVariantType.MakeInstantiatedType(derivedType).GetMethods().Single(m => m.GetName() == "Func"); MethodImplRecord[] methodImpls = implementationType.FindMethodsImplWithMatchingDeclName(inObjectMethod.Name); Assert.NotNull(methodImpls); - MethodDesc inObjectImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == inObjectMethod.GetMethodDefinition()).Body.MakeInstantiatedMethod(objectType); - MethodDesc inBaseImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == inBaseMethod.GetMethodDefinition()).Body.MakeInstantiatedMethod(objectType); - MethodDesc outDerivedImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == outDerivedMethod.GetMethodDefinition()).Body.MakeInstantiatedMethod(objectType); - MethodDesc outBaseImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == outBaseMethod.GetMethodDefinition()).Body.MakeInstantiatedMethod(objectType); + MethodDesc inObjectImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == inObjectMethod.GetMethodDefinition()).Body; + MethodDesc inBaseImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == inBaseMethod.GetMethodDefinition()).Body; + MethodDesc outDerivedImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == outDerivedMethod.GetMethodDefinition()).Body; + MethodDesc outBaseImpl = methodImpls.Single(m => m.Decl.GetMethodDefinition() == outBaseMethod.GetMethodDefinition()).Body; Assert.Equal(inObjectImpl, implementationType.ResolveVariantInterfaceMethodToVirtualMethodOnType(inObjectMethod)); Assert.Equal(inBaseImpl, implementationType.ResolveVariantInterfaceMethodToVirtualMethodOnType(inBaseMethod));