diff --git a/src/coreclr/vm/clsload.cpp b/src/coreclr/vm/clsload.cpp
index c2ef611fd0c595..ba86d440ecb2fc 100644
--- a/src/coreclr/vm/clsload.cpp
+++ b/src/coreclr/vm/clsload.cpp
@@ -4623,6 +4623,22 @@ BOOL ClassLoader::CanAccessFamily(
#endif // #ifndef DACCESS_COMPILE
+bool ClassLoader::EligibleForSpecialMarkerTypeUsage(Instantiation inst, MethodTable* pOwnerMT)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ if (pOwnerMT == NULL)
+ return false;
+
+ if (inst.GetNumArgs() > MethodTable::MaxGenericParametersForSpecialMarkerType)
+ return false;
+
+ if (!inst.ContainsAllOneType(pOwnerMT->GetSpecialInstantiationType()))
+ return false;
+
+ return true;
+}
+
#ifdef DACCESS_COMPILE
void
diff --git a/src/coreclr/vm/clsload.hpp b/src/coreclr/vm/clsload.hpp
index a0abb68be7c58e..9f9113c26dfc45 100644
--- a/src/coreclr/vm/clsload.hpp
+++ b/src/coreclr/vm/clsload.hpp
@@ -1004,6 +1004,8 @@ class ClassLoader
TypeHandle typeHnd,
ClassLoadLevel targetLevel);
#endif //!DACCESS_COMPILE
+public:
+ static bool EligibleForSpecialMarkerTypeUsage(Instantiation inst, MethodTable* pOwnerMT);
}; // class ClassLoader
diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp
index d76a31b61460b3..302fdf9a645d24 100644
--- a/src/coreclr/vm/methodtablebuilder.cpp
+++ b/src/coreclr/vm/methodtablebuilder.cpp
@@ -9805,8 +9805,6 @@ MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT)
break;
}
- bool uninstGenericCase = !retryWithExactInterfaces && pNewIntfMT->IsSpecialMarkerTypeForGenericCasting();
-
duplicates |= InsertMethodTable(pNewIntfMT, pExactMTs, nInterfacesCount, &nAssigned);
// We have a special algorithm for interface maps in CoreLib, which doesn't expand interfaces, and assumes no ambiguous
@@ -9816,23 +9814,112 @@ MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT)
MethodTable::InterfaceMapIterator intIt = pNewIntfMT->IterateInterfaceMap();
while (intIt.Next())
{
- MethodTable *pItfPossiblyApprox = intIt.GetInterfaceApprox();
- if (uninstGenericCase && pItfPossiblyApprox->HasInstantiation() && pItfPossiblyApprox->ContainsGenericVariables())
+ if (retryWithExactInterfaces)
{
- // We allow a limited set of interface generic shapes with type variables. In particular, we require the
- // instantiations to be exactly simple type variables, and to have a relatively small number of generic arguments
- // so that the fallback instantiating logic works efficiently
- if (InstantiationIsAllTypeVariables(pItfPossiblyApprox->GetInstantiation()) && pItfPossiblyApprox->GetInstantiation().GetNumArgs() <= MethodTable::MaxGenericParametersForSpecialMarkerType)
+ duplicates |= InsertMethodTable(intIt.GetInterface(pNewIntfMT, CLASS_LOAD_EXACTPARENTS), pExactMTs, nInterfacesCount, &nAssigned);
+ }
+ else
+ {
+ MethodTable *pItfPossiblyApprox = intIt.GetInterfaceApprox();
+
+ // pItfPossiblyApprox can be in 4 situations
+ // 1. It has no instantiation
+ // 2. It is a special marker type, AND pNewItfMT is a special marker type. Compute the exact instantiation as containing entirely a list of types corresponding to calling GetSpecialInstantiationType on pMT (This rule works based on the current behavior of GetSpecialInstantiationType where it treats all interfaces the same)
+ // 3. It is a special marker type, but pNewItfMT is NOT a special marker type. Compute the exact instantiation as containing entirely a list of types corresponding to calling GetSpecialInstantiationType on pNewItfMT
+ // 4. It is an exact instantiation
+ //
+ // NOTE: pItfPossiblyApprox must not be considered a special marker type if pNewItfMT has the MayHaveOpenInterfacesInInterfaceMap flag set
+ //
+ // Then determine if all of the following conditions hold true.
+ // 1. All generic arguments are the same (always true for cases 2 and 3 above)
+ // 2. The first generic argument in the instantiation is exactly the value of calling GetSpecialInstantiationType on pMT (always true for case 2)
+ //
+ // If so, then we should insert the special marker type
+ // Otherwise, we should insert the exact instantiation of the interface
+ // HOWEVER: If the exact instantiation IS a special marker interface, we need to retry with exact interfaces to avoid ambiguity situations
+ //
+ // NOTE: This is also part of the logic which determines if we need to call SetMayHaveOpenInterfacesInInterfaceMap. The CLR type system has a bug in its structure
+ // such that if you attempt to instantiate a type over its own type parameter from the open type, we will load the GenericTypeDefinition instead of loading
+ // a type explicitly instantiated over those type parameters. We re-use the GenericTypeDefinition as the special marker type, which leads to a conflict
+ // when something like that happens. So, we need to detect when something like that happens, and set the MayHaveOpenInterfacesInInterfaceMap flag,
+ // and avoid using the special marker type in those situations.
+ MethodTable *pItfToInsert = NULL;
+ bool intendedExactMatch = false;
+
+ if (!pItfPossiblyApprox->HasInstantiation())
+ {
+ // case 1
+ pItfToInsert = pItfPossiblyApprox;
+ intendedExactMatch = true;
+ }
+ else if (pItfPossiblyApprox->IsSpecialMarkerTypeForGenericCasting() && !pNewIntfMT->GetAuxiliaryData()->MayHaveOpenInterfacesInInterfaceMap())
{
- pItfPossiblyApprox = ClassLoader::LoadTypeDefThrowing(pItfPossiblyApprox->GetModule(), pItfPossiblyApprox->GetCl(), ClassLoader::ThrowIfNotFound, ClassLoader::PermitUninstDefOrRef, 0, CLASS_LOAD_EXACTPARENTS).AsMethodTable();
+ // We are in case 2 or 3 above
+ bool pNewIntfMTIsSpecialMarkerType = pNewIntfMT->IsSpecialMarkerTypeForGenericCasting() && !pMT->GetAuxiliaryData()->MayHaveOpenInterfacesInInterfaceMap();
+ if (pNewIntfMTIsSpecialMarkerType)
+ {
+ // case 2
+ pItfToInsert = pItfPossiblyApprox; // We have the special marker type already, so this is what we insert
+ }
+ else
+ {
+ // case 3
+ bool mustUseSpecialMarkerType = pNewIntfMT->GetSpecialInstantiationType() == pMT->GetSpecialInstantiationType();
+ if (mustUseSpecialMarkerType)
+ {
+ pItfToInsert = pItfPossiblyApprox; // We have the special marker type already, so this is what we insert
+ }
+ else
+ {
+ pItfToInsert = intIt.GetInterface(pNewIntfMT, CLASS_LOAD_EXACTPARENTS);
+ intendedExactMatch = true;
+ }
+ }
}
else
{
- retry = true;
- break;
+ // case 4 (We have an exact interface)
+ if (ClassLoader::EligibleForSpecialMarkerTypeUsage(pItfPossiblyApprox->GetInstantiation(), pMT))
+ {
+ // Validated that all generic arguments are the same, and that the first generic argument in the instantiation is exactly the value of calling GetSpecialInstantiationType on pMT
+ // Then use the special marker type here
+ pItfToInsert = ClassLoader::LoadTypeDefThrowing(pItfPossiblyApprox->GetModule(), pItfPossiblyApprox->GetCl(), ClassLoader::ThrowIfNotFound, ClassLoader::PermitUninstDefOrRef, 0, CLASS_LOAD_EXACTPARENTS).AsMethodTable();
+ }
+ else
+ {
+ pItfToInsert = pItfPossiblyApprox;
+ intendedExactMatch = true;
+ }
}
+
+ if (pItfToInsert->IsSpecialMarkerTypeForGenericCasting())
+ {
+ if (intendedExactMatch)
+ {
+ // We are trying to insert a special marker type into the interface list, but it is exactly the same as the exact instantiation we should actually want, we need to set the
+ // MayHaveOpenInterfacesInInterfaceMap flag, so trigger the retry logic.
+ retry = true;
+ break;
+ }
+ else if (pMT->GetSpecialInstantiationType() == pItfToInsert->GetInstantiation()[0])
+ {
+ // We are trying to insert a special marker type into the interface list, but the first generic argument
+ // in the instantiation is exactly the value of calling GetSpecialInstantiationType on pMT.
+ // This implies that the special marker type is actually the exact instantiation that we should be using, which
+ // will cause the same ambiguity situation as above. Trigger a retry, which will set MayHaveOpenInterfacesInInterfaceMap
+ // and disable the special marker type behavior for this type.
+ retry = true;
+ break;
+ }
+ }
+
+ if (!intendedExactMatch)
+ {
+ _ASSERTE(pItfToInsert->IsSpecialMarkerTypeForGenericCasting());
+ }
+
+ duplicates |= InsertMethodTable(pItfToInsert, pExactMTs, nInterfacesCount, &nAssigned);
}
- duplicates |= InsertMethodTable(intIt.GetInterface(pNewIntfMT, CLASS_LOAD_EXACTPARENTS), pExactMTs, nInterfacesCount, &nAssigned);
}
}
@@ -9869,7 +9956,7 @@ MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT)
_ASSERTE(!duplicates || !(pMT->GetModule()->IsSystem() && (pMT->IsValueType() || pMT->IsInterface())));
CONSISTENCY_CHECK(duplicates || (nAssigned == pMT->GetNumInterfaces()));
- if (duplicates)
+ if (duplicates || (nAssigned != pMT->GetNumInterfaces()))
{
//#LoadExactInterfaceMap_Algorithm2
// Exact interface instantiation loading TECHNIQUE 2 - The exact instantiation has caused some duplicates to
diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp
index b3dcfaed54168e..b5c7213a415489 100644
--- a/src/coreclr/vm/siginfo.cpp
+++ b/src/coreclr/vm/siginfo.cpp
@@ -1618,9 +1618,17 @@ TypeHandle SigPointer::GetTypeHandleThrowing(
Instantiation genericLoadInst(thisinst, ntypars);
- if (pMTInterfaceMapOwner != NULL && genericLoadInst.ContainsAllOneType(pMTInterfaceMapOwner->GetSpecialInstantiationType()))
+ if (ClassLoader::EligibleForSpecialMarkerTypeUsage(genericLoadInst, pMTInterfaceMapOwner))
{
thRet = ClassLoader::LoadTypeDefThrowing(pGenericTypeModule, tkGenericType, ClassLoader::ThrowIfNotFound, ClassLoader::PermitUninstDefOrRef, 0, level);
+ if (thRet.AsMethodTable()->GetInstantiation()[0] == pMTInterfaceMapOwner->GetSpecialInstantiationType())
+ {
+ // We loaded the special marker type, but it is ALSO the exact expected type which isn't a valid combination
+ // In this case return something else (object) to indicate that
+ // we found an invalid situation and this function should be retried without the special marker type logic enabled.
+ thRet = TypeHandle(g_pObjectClass);
+ break;
+ }
}
else
{
@@ -1645,7 +1653,7 @@ TypeHandle SigPointer::GetTypeHandleThrowing(
// the loaded type is not the expected type we should be looking for to return a special marker type, but the normal load has
// found a type which claims to be a special marker type. In this case return something else (object) to indicate that
// we found an invalid situation and this function should be retried without the special marker type logic enabled.
- thRet = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_OBJECT));
+ thRet = TypeHandle(g_pObjectClass);
break;
}
else if (!handlingRecursiveGenericFieldScenario)
diff --git a/src/coreclr/vm/typehandle.h b/src/coreclr/vm/typehandle.h
index 9c5e5f8b424625..0e36acba4b3ecb 100644
--- a/src/coreclr/vm/typehandle.h
+++ b/src/coreclr/vm/typehandle.h
@@ -697,6 +697,7 @@ class Instantiation
bool ContainsAllOneType(TypeHandle th)
{
+ LIMITED_METHOD_DAC_CONTRACT;
for (DWORD i = GetNumArgs(); i > 0;)
{
if ((*this)[--i] != th)
diff --git a/src/tests/Directory.Build.props b/src/tests/Directory.Build.props
index 1822cbe9f31195..65fa0b556bc8ed 100644
--- a/src/tests/Directory.Build.props
+++ b/src/tests/Directory.Build.props
@@ -122,6 +122,11 @@
$(DefineConstants);DEBUG;TRACE;XUNIT_PERF
+
+
+ $(DefineConstants.Replace(';',','))
+
+
true
diff --git a/src/tests/Loader/classloader/regressions/GitHub_123254/GitHub_123254.vb b/src/tests/Loader/classloader/regressions/GitHub_123254/GitHub_123254.vb
new file mode 100644
index 00000000000000..10079ed277c6c2
--- /dev/null
+++ b/src/tests/Loader/classloader/regressions/GitHub_123254/GitHub_123254.vb
@@ -0,0 +1,199 @@
+' Licensed to the .NET Foundation under one or more agreements.
+' The .NET Foundation licenses this file to you under the MIT license.
+
+Imports System
+Imports System.Collections
+Imports System.Collections.Generic
+Imports Xunit
+
+' This test needs to be written in VB, since the C# compiler has a different rule around
+' filling in the InterfaceImpl table. Notably, the C# compiler will emit into the table, all of the
+' interfaces that are transitively implemented by a class that the C# compiler is aware of, and
+' the VB compiler will only emit the interfaces as specified in the source. In practice, this isn't
+' supposed to have any meaningful impact unless the set of assemblies being used at runtime does not
+' match the set of assemblies used at compile time, but it does impact some of the runtimes internal
+' algorithms around interface resolution, notably the behavior of LoadExactInterfaceMap has an optimization
+' that avoids doing quite a lot of work.
+Public Class GitHub_123254
+
+ ' Test the scenario where the implied interface is in the interface map of a containing interface as a special marker type, and the containing interface itself is ALSO a special marker type.
+ ' The critical path is that when establishing the interface map for ILayer3_1(Of T) we find read ILayer1_1(Of T) as a special marker type member of ILayer2_1(Of T), and the ILayer2_1(Of T) itself is a special marker type.
+
+ Public Shared Sub Test_Method1()
+ Dim w As New TestClass1(Of Integer)
+ Dim en As IEnumerator(Of Integer) = DirectCast(w, ILayer1_1(Of Integer)).GetEnumerator()
+ End Sub
+
+ Public Class TestClass1(Of T)
+ Implements ILayer3_1(Of T)
+
+ Public ReadOnly Property Count As Integer Implements ILayer2_1(Of T).Count
+
+ Public Function GetEnumerator() As IEnumerator(Of T) Implements ILayer1_1(Of T).GetEnumerator
+ Return DirectCast(Array.Empty(Of T)(), IEnumerable(Of T)).GetEnumerator()
+ End Function
+ End Class
+
+ Public Interface ILayer3_1(Of T)
+ Inherits ILayer2_1(Of T)
+ End Interface
+
+ Public Interface ILayer2_1(Of T)
+ Inherits ILayer1_1(Of T)
+ ReadOnly Property Count As Integer
+ End Interface
+
+ Public Interface ILayer1_1(Of T)
+ Function GetEnumerator() As IEnumerator(Of T)
+ End Interface
+
+ ' Test the scenario where the implied interface is in the interface map of a containing interface as a special marker type, and the containing interface itself is NOT a special marker type.
+ ' The critical path is that when establishing the interface map for ILayer3_2(Of T) we find read ILayer1_2(Of T) as a special marker type member of ILayer2_2(Of T), and the ILayer2_2(Of T) itself is a special marker type.
+ ' Then, it will also turn out that even though we had a special marker type in the interface map we're expanding, we will need to put an exact type into the map since that's what we actually need.
+
+ Public Shared Sub Test_Method2()
+ Dim w As New TestClass2(Of Integer)
+ Dim en As IEnumerator(Of String) = DirectCast(w, ILayer1_2(Of String)).GetEnumerator()
+ End Sub
+
+ Public Class TestClass2(Of T)
+ Implements ILayer3_2(Of T)
+ Public ReadOnly Property Count As Integer Implements ILayer2_2(Of String).Count
+
+ Public Function GetEnumerator() As IEnumerator(Of String) Implements ILayer1_2(Of String).GetEnumerator
+ Return DirectCast(Array.Empty(Of String)(), IEnumerable(Of String)).GetEnumerator()
+ End Function
+ End Class
+
+ Public Interface ILayer3_2(Of T)
+ Inherits ILayer2_2(Of String)
+ End Interface
+
+ Public Interface ILayer2_2(Of T)
+ Inherits ILayer1_2(Of T)
+ ReadOnly Property Count As Integer
+ End Interface
+
+ Public Interface ILayer1_2(Of T)
+ Function GetEnumerator() As IEnumerator(Of T)
+ End Interface
+
+ ' Test the scenario where the implied interface is in the interface map of a containing interface as a special marker type, and the containing interface itself is NOT a special marker type.
+ ' The critical path is that when establishing the interface map for TestClass3 we find read ILayer1_3(Of T) as a special marker type member of ILayer3_3(Of TestClass, Integer), but when we place
+ ' the interface onto TestClass3 we find that we can use the special marker type even though the containing interface is not the special marker type.
+
+ Public Shared Sub Test_Method3()
+ Dim w As New TestClass3
+ Dim en As IEnumerator(Of TestClass3) = DirectCast(w, ILayer1_3(Of TestClass3)).GetEnumerator()
+ End Sub
+
+ Public Structure TestClass3
+ Implements ILayer3_3(Of TestClass3, Integer)
+ Public ReadOnly Property Count As Integer Implements ILayer2_3(Of TestClass3).Count
+
+ Public Function GetEnumerator() As IEnumerator(Of TestClass3) Implements ILayer1_3(Of TestClass3).GetEnumerator
+ Return DirectCast(Array.Empty(Of TestClass3)(), IEnumerable(Of TestClass3)).GetEnumerator()
+ End Function
+ End Structure
+
+ Public Interface ILayer3_3(Of T, SomethingElse)
+ Inherits ILayer2_3(Of T)
+ End Interface
+
+ Public Interface ILayer2_3(Of T)
+ Inherits ILayer1_3(Of T)
+ ReadOnly Property Count As Integer
+ End Interface
+
+ Public Interface ILayer1_3(Of T)
+ Function GetEnumerator() As IEnumerator(Of T)
+ End Interface
+
+ ' Test the scenario where the implied interface is in the interface map of a containing interface as a special marker type, and the containing interface itself is NOT a special marker type.
+ ' The critical path is that when establishing the interface map for TestClass4 we find read ILayer3_4(Of String) and then under that there are exact types ILayer2_4(Of Integer) and ILayer1_4(Of TestClass4)
+ ' Then the algorithm will decide to put a special marker type for ILayer1_4(Of T) into the map since it is the appropriate shape, and we will place the exact type ILayer2_4(Of Integer) into the map since that is the exact type needed.
+
+ Public Shared Sub Test_Method4()
+ Dim w As New TestClass4
+ Dim en As IEnumerator(Of TestClass4) = DirectCast(w, ILayer1_4(Of TestClass4)).GetEnumerator()
+ Dim countVal As Integer = DirectCast(w, ILayer2_4(Of Integer)).Count
+ End Sub
+
+ Public Structure TestClass4
+ Implements ILayer3_4(Of String)
+ Public ReadOnly Property Count As Integer Implements ILayer2_4(Of Integer).Count
+
+ Public Function GetEnumerator() As IEnumerator(Of TestClass4) Implements ILayer1_4(Of TestClass4).GetEnumerator
+ Return DirectCast(Array.Empty(Of TestClass4)(), IEnumerable(Of TestClass4)).GetEnumerator()
+ End Function
+ End Structure
+
+ Public Interface ILayer3_4(Of T)
+ Inherits ILayer2_4(Of Integer)
+ End Interface
+
+ Public Interface ILayer2_4(Of T)
+ Inherits ILayer1_4(Of TestClass4)
+ ReadOnly Property Count As Integer
+ End Interface
+
+ Public Interface ILayer1_4(Of T)
+ Function GetEnumerator() As IEnumerator(Of T)
+ End Interface
+
+ ' Test path for forcing the interface map out of the supporting special marker types due to a conflict with the concept of special marker types
+ ' I could only find a way to hit this path with reflection, and since reflection is imperfect on NativeAOT, just skip this test there.
+
+ Public Shared Sub Test_Method5()
+ ' Test indirect implementation of interface
+ Dim testClassType As Type = GetType(TestClass5(Of Integer)).GetGenericTypeDefinition().MakeGenericType(GetType(ILayer1_5(Of Integer)).GetGenericTypeDefinition().GetGenericArguments()(0))
+ Console.WriteLine("testClassType first generic argument: " & testClassType.GetGenericArguments()(0).Name)
+ For Each iface As Type In testClassType.GetInterfaces()
+ Console.WriteLine("IFace name: " & iface.Name)
+ Console.WriteLine("IFace first generic argument: " & iface.GetGenericArguments()(0).Name)
+ Assert.Equal("Z", iface.GetGenericArguments()(0).Name)
+ Next
+
+ ' Test direct implementation of interface
+ testClassType = GetType(TestClass6(Of Integer)).GetGenericTypeDefinition().MakeGenericType(GetType(ILayer1_5(Of Integer)).GetGenericTypeDefinition().GetGenericArguments()(0))
+ Console.WriteLine("testClassType first generic argument: " & testClassType.GetGenericArguments()(0).Name)
+ For Each iface As Type In testClassType.GetInterfaces()
+ Console.WriteLine("IFace name: " & iface.Name)
+ Console.WriteLine("IFace first generic argument: " & iface.GetGenericArguments()(0).Name)
+ Assert.Equal("Z", iface.GetGenericArguments()(0).Name)
+ Next
+
+ ' Test implementation via containing interface
+ testClassType = GetType(ILayer3_5(Of Integer)).GetGenericTypeDefinition().MakeGenericType(GetType(ILayer1_5(Of Integer)).GetGenericTypeDefinition().GetGenericArguments()(0))
+ Console.WriteLine("testClassType first generic argument: " & testClassType.GetGenericArguments()(0).Name)
+ For Each iface As Type In testClassType.GetInterfaces()
+ Console.WriteLine("IFace name: " & iface.Name)
+ Console.WriteLine("IFace first generic argument: " & iface.GetGenericArguments()(0).Name)
+ Assert.Equal("Z", iface.GetGenericArguments()(0).Name)
+ Next
+ End Sub
+
+ Public Structure TestClass5(Of T)
+ Implements ILayer2_5(Of T, Integer)
+ Sub GetEnumerator(argument As TestClass5(Of T)) Implements ILayer1_5(Of T).GetEnumerator
+ End Sub
+ End Structure
+
+ Public Structure TestClass6(Of U)
+ Implements ILayer1_5(Of U)
+ Sub GetEnumerator(argument As TestClass5(Of U)) Implements ILayer1_5(Of U).GetEnumerator
+ End Sub
+ End Structure
+
+ Public Interface ILayer3_5(Of R)
+ Inherits ILayer2_5(Of R, Integer)
+ End Interface
+
+ Public Interface ILayer2_5(Of V, W)
+ Inherits ILayer1_5(Of V)
+ End Interface
+
+ Public Interface ILayer1_5(Of Z)
+ Sub GetEnumerator(argument As TestClass5(Of Z))
+ End Interface
+End Class
\ No newline at end of file
diff --git a/src/tests/Loader/classloader/regressions/GitHub_123254/GitHub_123254.vbproj b/src/tests/Loader/classloader/regressions/GitHub_123254/GitHub_123254.vbproj
new file mode 100644
index 00000000000000..249ae2126432d0
--- /dev/null
+++ b/src/tests/Loader/classloader/regressions/GitHub_123254/GitHub_123254.vbproj
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/tests/Loader/classloader/regressions/GitHub_123318/GitHub_123318.cs b/src/tests/Loader/classloader/regressions/GitHub_123318/GitHub_123318.cs
new file mode 100644
index 00000000000000..1f105b9bfcfe4b
--- /dev/null
+++ b/src/tests/Loader/classloader/regressions/GitHub_123318/GitHub_123318.cs
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// this test verifies that loading using the special marker type will not cause problems with generics with more than 8 parameters
+
+
+using System;
+using Xunit;
+
+public class GitHub_123318
+{
+ [Fact]
+ public static void Test()
+ {
+ var i = new MyEntity(); // <-- Throws System.ExecutionEngineException in System.Reflection.MethodBaseInvoker.InvokeWithOneArg(...)
+ }
+
+ public sealed class MyEntity : IEditableEntity
+ {
+ public TItem1 Item1 {get; set;}
+ public TItem2 Item2 {get; set;}
+ public TItem3 Item3 {get; set;}
+ public TItem4 Item4 {get; set;}
+ public TItem5 Item5 {get; set;}
+ public TItem6 Item6 {get; set;}
+ public TItem7 Item7 {get; set;}
+ public TItem8 Item8 {get; set;}
+ public TItem9 Item9 {get; set;}
+ }
+
+ public interface IReadonlyEntity
+ {
+ TItem1 Item1 {get;}
+ TItem2 Item2 {get;}
+ TItem3 Item3 {get;}
+ TItem4 Item4 {get;}
+ TItem5 Item5 {get;}
+ TItem6 Item6 {get;}
+ TItem7 Item7 {get;}
+ TItem8 Item8 {get;}
+ TItem9 Item9 {get;}
+ }
+
+ public interface IEditableEntity : IReadonlyEntity
+ {
+ new TItem1 Item1 {get;set;}
+ new TItem2 Item2 {get;set;}
+ new TItem3 Item3 {get;set;}
+ new TItem4 Item4 {get;set;}
+ new TItem5 Item5 {get;set;}
+ new TItem6 Item6 {get;set;}
+ new TItem7 Item7 {get;set;}
+ new TItem8 Item8 {get;set;}
+ new TItem9 Item9 {get;set;}
+ }
+}
diff --git a/src/tests/Loader/classloader/regressions/GitHub_123318/GitHub_123318.csproj b/src/tests/Loader/classloader/regressions/GitHub_123318/GitHub_123318.csproj
new file mode 100644
index 00000000000000..6db93a4e390f9f
--- /dev/null
+++ b/src/tests/Loader/classloader/regressions/GitHub_123318/GitHub_123318.csproj
@@ -0,0 +1,5 @@
+
+
+
+
+