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 @@ + + + + +