diff --git a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs index ac544ed02e3fea..a8a83cedec3bb5 100644 --- a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs +++ b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs @@ -148,13 +148,9 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType return null; case DefaultInterfaceMethodResolution.DefaultImplementation: - if (dimMethod.OwningType.HasInstantiation || (declMethod != defaultInterfaceDispatchDeclMethod)) + if (declMethod != defaultInterfaceDispatchDeclMethod) { - // If we devirtualized into a default interface method on a generic type, we should actually return an - // instantiating stub but this is not happening. - // Making this work is tracked by https://github.com/dotnet/runtime/issues/9588 - - // In addition, we fail here for variant default interface dispatch + // Fail for variant default interface dispatch devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_DIM; return null; } @@ -219,13 +215,6 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType } } - if (impl != null && impl.HasInstantiation && impl.GetCanonMethodTarget(CanonicalFormKind.Specific).IsCanonicalMethod(CanonicalFormKind.Specific)) - { - // We don't support devirtualization of shared generic virtual methods yet. - devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON; - impl = null; - } - return impl; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 5fc46db5a8978b..b4281b43e2da9b 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1482,6 +1482,50 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) info->resolvedTokenDevirtualizedUnboxedMethod = default(CORINFO_RESOLVED_TOKEN); } + if (!impl.AcquiresInstMethodTableFromThis()) + { + if (originalImpl.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)) + { + // If we end up with a shared MethodTable that is not exact, + // we can't devirtualize since it's not possible to compute the instantiation argument even as a runtime lookup. + info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON; + return false; + } + + if (originalImpl.IsSharedByGenericInstantiations) + { + // TODO: Support for runtime lookup + info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON; + return false; + } + } + + if (impl.RequiresInstMethodDescArg()) + { + if (unboxingStub) + { + // Bail out for now. We need an unboxing stub that points to an instantiated method. + info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON; + return false; + } +#if READYTORUN + MethodWithToken originalImplWithToken = new MethodWithToken(originalImpl, methodWithTokenImpl.Token, null, false, null, null); + info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.MethodDictionary, originalImplWithToken)); + +#else + info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.MethodGenericDictionary(originalImpl)); +#endif + } + else if (impl.RequiresInstMethodTableArg()) + { +#if READYTORUN + info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeDictionary, originalImpl.OwningType)); + +#else + info->instParamLookup.constLookup = CreateConstLookupToSymbol(_compilation.NodeFactory.ConstructedTypeSymbol(originalImpl.OwningType)); +#endif + } + #if READYTORUN // Testing has not shown that concerns about virtual matching are significant // Only generate verification for builds with the stress mode enabled @@ -1496,7 +1540,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) #endif info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_SUCCESS; info->devirtualizedMethod = ObjectToHandle(impl); - info->tokenLookupContext = contextFromType(owningType); + info->tokenLookupContext = impl.RequiresInstMethodDescArg() ? contextFromMethod(originalImpl) : contextFromType(owningType); return true; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DevirtualizationManager.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DevirtualizationManager.cs index 7d0275ff2eaaee..e6e329e5b32663 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DevirtualizationManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DevirtualizationManager.cs @@ -45,9 +45,7 @@ protected override MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefTyp // // Result method checking // 1. Ensure that the resolved result versions with the code, or is the decl method - // 2. Devirtualizing to a default interface method is not currently considered to be useful, and how to check for version - // resilience has not yet been analyzed. - // 3. When checking that the resolved result versions with the code, validate that all of the types + // 2. When checking that the resolved result versions with the code, validate that all of the types // From implType to the owning type of resolved result method also version with the code. bool declMethodCheckFailed; diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index c0ec22f3e75a8f..7c629b79b28ec7 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -8762,15 +8762,6 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) info->detail = CORINFO_DEVIRTUALIZATION_FAILED_LOOKUP; return false; } - - // If we devirtualized into a default interface method on a generic type, we should actually return an - // instantiating stub but this is not happening. - // Making this work is tracked by https://github.com/dotnet/runtime/issues/9588 - if (pDevirtMD->GetMethodTable()->IsInterface() && pDevirtMD->HasClassInstantiation()) - { - info->detail = CORINFO_DEVIRTUALIZATION_FAILED_DIM; - return false; - } } else { @@ -8835,10 +8826,19 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) if (pApproxMT->IsInterface()) { - // As noted above, we can't yet handle generic interfaces - // with default methods. - _ASSERTE(!pDevirtMD->HasClassInstantiation()); + if (pDevirtMD->HasClassInstantiation()) + { + if (TypeHandle::IsCanonicalSubtypeInstantiation(pDevirtMD->GetClassInstantiation())) + { + // If we end up with a shared MethodTable that is not exact, + // we can't devirtualize since it's not possible to compute the instantiation argument even as a runtime lookup. + info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON; + return false; + } + info->instParamLookup.constLookup.handle = (CORINFO_GENERIC_HANDLE)pExactMT; + info->instParamLookup.constLookup.accessType = IAT_VALUE; + } } else if (pBaseMT->IsInterface() && pObjMT->IsArray()) { @@ -8855,10 +8855,29 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) MethodDesc* pPrimaryMD = pDevirtMD; pDevirtMD = MethodDesc::FindOrCreateAssociatedMethodDesc( pPrimaryMD, pExactMT, pExactMT->IsValueType() && !pPrimaryMD->IsStatic(), pBaseMD->GetMethodInstantiation(), true); + if (pDevirtMD->IsSharedByGenericMethodInstantiations()) { - info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON; - return false; + pDevirtMD = MethodDesc::FindOrCreateAssociatedMethodDesc( + pPrimaryMD, pExactMT, pExactMT->IsValueType() && !pPrimaryMD->IsStatic(), pBaseMD->GetMethodInstantiation(), false); + + if (TypeHandle::IsCanonicalSubtypeInstantiation(pDevirtMD->GetClassInstantiation())) + { + // If we end up with a shared MethodTable that is not exact, + // we can't devirtualize since it's not possible to compute the instantiation argument even as a runtime lookup. + info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON; + return false; + } + + // We are dealing with a generic virtual method whose owning type is exact. + // If the method is not exact, a runtime lookup would be required. + const bool requiresRuntimeLookup = TypeHandle::IsCanonicalSubtypeInstantiation(pDevirtMD->GetMethodInstantiation()); + if (requiresRuntimeLookup) + { + // TODO: Support for runtime lookup + info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON; + return false; + } } isGenericVirtual = true; @@ -8873,13 +8892,14 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) } info->tokenLookupContext = MAKE_METHODCONTEXT((CORINFO_METHOD_HANDLE) pDevirtMD); - pDevirtMD = pDevirtMD->IsInstantiatingStub() ? pDevirtMD->GetWrappedMethodDesc() : pDevirtMD; } else { info->tokenLookupContext = MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT); } + pDevirtMD = pDevirtMD->IsInstantiatingStub() ? pDevirtMD->GetWrappedMethodDesc() : pDevirtMD; + // Success! Pass back the results. // info->devirtualizedMethod = (CORINFO_METHOD_HANDLE) pDevirtMD; diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.cs new file mode 100644 index 00000000000000..8a611b3fbef284 --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.cs @@ -0,0 +1,36 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +interface IM +{ + bool UseDefaultM { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => true; } + ValueTask M(T instance) => throw new NotImplementedException("M must be implemented if UseDefaultM is false"); + static ValueTask DefaultM(T instance) + { + return default; + } +} + +struct M : IM { } + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var m = new M(); + if (((IM)m).UseDefaultM) + { + IM.DefaultM(42); + return; + } + else + { + ((IM)m).M(42); + } + throw new UnreachableException(); + } +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.csproj new file mode 100644 index 00000000000000..30d4804022360c --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_github39419.csproj @@ -0,0 +1,11 @@ + + + 1 + + + + + + + + diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.cs new file mode 100644 index 00000000000000..c43a13315f0bac --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.cs @@ -0,0 +1,26 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +interface I where T : IComparable +{ + T GetAt(int i, T[] tx) => tx[i]; +} + +class C : I +{ +} + +public static class Program +{ + private static string[] tx = new string[] { "test" }; + + [Fact] + public static void TestEntryPoint() + { + I c = new C(); + var dcs = c.GetAt(0, tx); + Assert.Equal("test", dcs); + } +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.csproj new file mode 100644 index 00000000000000..30d4804022360c --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_inline.csproj @@ -0,0 +1,11 @@ + + + 1 + + + + + + + + diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.cs new file mode 100644 index 00000000000000..0d96d46bd09252 --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.cs @@ -0,0 +1,31 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +interface I +{ + string DefaultTypeOf() => typeof(T).Name; +} + +class Dummy { } + +class C : I, I, I +{ + string I.DefaultTypeOf() => "C.Dummy"; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)c).DefaultTypeOf(); + Assert.Equal("String", dcs); + var dos = ((I)c).DefaultTypeOf(); + Assert.Equal("Object", dos); + var dds = ((I)c).DefaultTypeOf(); + Assert.Equal("C.Dummy", dds); + } +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.csproj new file mode 100644 index 00000000000000..30d4804022360c --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_simple.csproj @@ -0,0 +1,11 @@ + + + 1 + + + + + + + + diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.cs new file mode 100644 index 00000000000000..4deff94ccc5e94 --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.cs @@ -0,0 +1,24 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +interface I +{ + string DefaultTypeOf() => typeof(string).Name; +} + +class C : I +{ +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)c).DefaultTypeOf(); + Assert.Equal("String", dcs); + } +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.csproj new file mode 100644 index 00000000000000..30d4804022360c --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlenongeneric.csproj @@ -0,0 +1,11 @@ + + + 1 + + + + + + + + diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.cs new file mode 100644 index 00000000000000..b2bb95f36434e1 --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +interface I +{ + string DefaultTypeOf() => typeof(T).Name; +} + +class C : I +{ + public string DefaultTypeOf() => "C.String"; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)c).DefaultTypeOf(); + Assert.Equal("C.String", dcs); + } +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.csproj new file mode 100644 index 00000000000000..30d4804022360c --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverriding.csproj @@ -0,0 +1,11 @@ + + + 1 + + + + + + + + diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.cs new file mode 100644 index 00000000000000..31d8ec3549d629 --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +interface I +{ + string DefaultTypeOf() => typeof(T).Name; +} + +class C : I +{ + public string DefaultTypeOf() => "C." + typeof(T).Name; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)c).DefaultTypeOf(); + Assert.Equal("C.String", dcs); + } +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.csproj new file mode 100644 index 00000000000000..30d4804022360c --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverridinggeneric.csproj @@ -0,0 +1,11 @@ + + + 1 + + + + + + + + diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.cs new file mode 100644 index 00000000000000..91560c952ed6fd --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.cs @@ -0,0 +1,24 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +interface I +{ + string DefaultTypeOf() => typeof(T).Name; +} + +class C : I +{ +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)c).DefaultTypeOf(); + Assert.Equal("Int32", dcs); + } +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.csproj new file mode 100644 index 00000000000000..30d4804022360c --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singleoverstruct.csproj @@ -0,0 +1,11 @@ + + + 1 + + + + + + + + diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.cs new file mode 100644 index 00000000000000..d401949fc5f577 --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +interface I +{ + string DefaultTypeOf(); +} + +struct C : I +{ + public string DefaultTypeOf() => "C." + typeof(T).Name; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)c).DefaultTypeOf(); + Assert.Equal("C.String", dcs); + } +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.csproj new file mode 100644 index 00000000000000..30d4804022360c --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevaluetypenondim.csproj @@ -0,0 +1,11 @@ + + + 1 + + + + + + + + diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.cs new file mode 100644 index 00000000000000..114fcbcf8933d1 --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.cs @@ -0,0 +1,24 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +interface I +{ + string DefaultTypeOf() => typeof(T).Name; +} + +class C : I +{ +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)c).DefaultTypeOf(); + Assert.Equal("Object", dcs); + } +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.csproj new file mode 100644 index 00000000000000..30d4804022360c --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_singlevariance.csproj @@ -0,0 +1,11 @@ + + + 1 + + + + + + + + diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.cs new file mode 100644 index 00000000000000..f384f31c02d756 --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.cs @@ -0,0 +1,22 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + + +struct C +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public string DefaultTypeOf() => typeof(T).Name; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = c.DefaultTypeOf(); + Assert.Equal("String", dcs); + } +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.csproj new file mode 100644 index 00000000000000..30d4804022360c --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_snondimstruct.csproj @@ -0,0 +1,11 @@ + + + 1 + + + + + + + + diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.cs new file mode 100644 index 00000000000000..f33c8b8aaf0fcd --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.cs @@ -0,0 +1,19 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +class C +{ + public static string DefaultTypeOf() => typeof(T).Name; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var dcs = C.DefaultTypeOf(); + Assert.Equal("String", dcs); + } +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.csproj new file mode 100644 index 00000000000000..30d4804022360c --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_staticshared.csproj @@ -0,0 +1,11 @@ + + + 1 + + + + + + + + diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.cs new file mode 100644 index 00000000000000..bbb79c7c3f0313 --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.cs @@ -0,0 +1,31 @@ +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +interface I +{ + string DefaultTypeOf() => typeof(T).Name; +} + +class Dummy { } + +struct C : I, I, I +{ + string I.DefaultTypeOf() => "C.Dummy"; +} + +public static class Program +{ + [Fact] + public static void TestEntryPoint() + { + var c = new C(); + var dcs = ((I)c).DefaultTypeOf(); + Assert.Equal("String", dcs); + var dos = ((I)c).DefaultTypeOf(); + Assert.Equal("Object", dos); + var dds = ((I)c).DefaultTypeOf(); + Assert.Equal("C.Dummy", dds); + } +} diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.csproj new file mode 100644 index 00000000000000..30d4804022360c --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/devirtualization/dim_devirt_structs.csproj @@ -0,0 +1,11 @@ + + + 1 + + + + + + + +