// Shortcut for generic approx type scenario
if (pMTInterfaceMapOwner != NULL &&
+ !pMTInterfaceMapOwner->ContainsGenericVariables() &&
IsSpecialMarkerTypeForGenericCasting() &&
GetTypeDefRid() == pTargetMT->GetTypeDefRid() &&
GetModule() == pTargetMT->GetModule() &&
for (DWORD i = 0; i < inst.GetNumArgs(); i++)
{
TypeHandle thArg = inst[i];
- if (IsSpecialMarkerTypeForGenericCasting() && pMTInterfaceMapOwner)
+ if (IsSpecialMarkerTypeForGenericCasting() && pMTInterfaceMapOwner && !pMTInterfaceMapOwner->ContainsGenericVariables())
{
thArg = pMTInterfaceMapOwner;
}
CONTRACT_END;
MethodTable *pResult = m_pMap->GetMethodTable();
- if (pResult->IsSpecialMarkerTypeForGenericCasting())
+ if (pResult->IsSpecialMarkerTypeForGenericCasting() && !pMTOwner->ContainsGenericVariables())
{
TypeHandle ownerAsInst[MaxGenericParametersForSpecialMarkerType];
for (DWORD i = 0; i < MaxGenericParametersForSpecialMarkerType; i++)
{
if (pCurrentMethodTable->HasSameTypeDefAs(pMT) &&
pMT->HasInstantiation() &&
- pCurrentMethodTable->IsSpecialMarkerTypeForGenericCasting() &&
+ pCurrentMethodTable->IsSpecialMarkerTypeForGenericCasting() &&
+ !pMTOwner->ContainsGenericVariables() &&
pMT->GetInstantiation().ContainsAllOneType(pMTOwner))
{
exactMatch = true;
while (--numInterfaces);
// Second scan, looking for the curiously recurring generic scenario
- if (pInterface->HasInstantiation() && pInterface->GetInstantiation().ContainsAllOneType(this))
+ if (pInterface->HasInstantiation() && !ContainsGenericVariables() && pInterface->GetInstantiation().ContainsAllOneType(this))
{
numInterfaces = GetNumInterfaces();
pInfo = GetInterfaceMap();
MethodTable **pExactMTs = (MethodTable**) _alloca(sizeof(MethodTable *) * nInterfacesCount);
BOOL duplicates;
bool retry = false;
- bool retryWithExactInterfaces = !pMT->IsValueType() || pMT->IsSharedByGenericInstantiations(); // Always use exact loading behavior with classes or shared generics, as they have to deal with inheritance, and the
- // inexact matching logic for classes would be more complex to write.
+
+ // Always use exact loading behavior with classes or shared generics, as they have to deal with inheritance, and the
+ // inexact matching logic for classes would be more complex to write.
+ // Also always use the exact loading behavior with any generic that contains generic variables, as the open type is used
+ // to represent a type instantiated over its own generic variables, and the special marker type is currently the open type
+ // and we make this case distinguishable by simply disallowing the optimization in those cases.
+ bool retryWithExactInterfaces = !pMT->IsValueType() || pMT->IsSharedByGenericInstantiations() || pMT->ContainsGenericVariables();
DWORD nAssigned = 0;
do
(const Substitution*)0,
retryWithExactInterfaces ? NULL : pMT).GetMethodTable();
- bool uninstGenericCase = pNewIntfMT->IsSpecialMarkerTypeForGenericCasting();
+ bool uninstGenericCase = !retryWithExactInterfaces && pNewIntfMT->IsSpecialMarkerTypeForGenericCasting();
duplicates |= InsertMethodTable(pNewIntfMT, pExactMTs, nInterfacesCount, &nAssigned);
--- /dev/null
+namespace CuriouslyRecurringPatternThroughInterface
+{
+ interface IGeneric<T_IGeneric>
+ {
+ }
+ interface ICuriouslyRecurring<T_ICuriouslyRecurring> : IGeneric<CuriouslyRecurringThroughInterface<T_ICuriouslyRecurring>>
+ {
+ }
+ class CuriouslyRecurringThroughInterface<T_CuriouslyRecurringThroughInterface> : ICuriouslyRecurring<T_CuriouslyRecurringThroughInterface>
+ {
+ }
+
+ class Program
+ {
+ static object _o;
+ static int Main(string[] args)
+ {
+ // Test that the a generic using a variant of the curiously recurring pattern involving an interface can be loaded.
+ _o = typeof(CuriouslyRecurringThroughInterface<int>);
+ return 100;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <OutputType>Exe</OutputType>
+ <CLRTestKind>BuildAndRun</CLRTestKind>
+ <CLRTestPriority>1</CLRTestPriority>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="CuriouslyRecurringThroughInterface.cs" />
+ </ItemGroup>
+</Project>
\ No newline at end of file