From c1c9cdce0d53e57f9b8c9cc9071192e9f3ef84de Mon Sep 17 00:00:00 2001 From: Fadi Hanna Date: Sun, 22 Mar 2020 19:41:49 -0700 Subject: [PATCH 01/13] Initial implementation: allowing covariant return types on MethodImpl overrides on classes Changes are mostly a boolean flag being passed around to allow for covariant type checking in method signatures. Generics not properly handled yet in this commit. --- src/coreclr/src/vm/classcompat.cpp | 5 +- src/coreclr/src/vm/ecall.cpp | 2 +- src/coreclr/src/vm/memberload.cpp | 6 +- src/coreclr/src/vm/methodtablebuilder.cpp | 78 ++++++++++++-- src/coreclr/src/vm/methodtablebuilder.h | 4 +- src/coreclr/src/vm/runtimehandles.cpp | 3 +- src/coreclr/src/vm/siginfo.cpp | 122 ++++++++++++++++++---- src/coreclr/src/vm/siginfo.hpp | 21 ++-- 8 files changed, 194 insertions(+), 47 deletions(-) diff --git a/src/coreclr/src/vm/classcompat.cpp b/src/coreclr/src/vm/classcompat.cpp index f74c2247ba29d6..c89c4ee6067fb6 100644 --- a/src/coreclr/src/vm/classcompat.cpp +++ b/src/coreclr/src/vm/classcompat.cpp @@ -1405,7 +1405,7 @@ VOID MethodTableBuilder::BuildInteropVTable_PlaceVtableMethods( bmtType->pModule, NULL, pInterfaceMethodSig, cInterfaceMethodSig, - pInterfaceMD->GetModule(), NULL)) + pInterfaceMD->GetModule(), NULL, FALSE)) { // Found match, break from loop break; } @@ -2263,7 +2263,8 @@ VOID MethodTableBuilder::EnumerateMethodImpls() pSigBody, cbSigBody, bmtType->pModule, - NULL)) + NULL, + FALSE)) { BuildMethodTableThrowException(IDS_CLASSLOAD_MI_BODY_DECL_MISMATCH); } diff --git a/src/coreclr/src/vm/ecall.cpp b/src/coreclr/src/vm/ecall.cpp index 7231cd3ff8f15a..414838c01fa108 100644 --- a/src/coreclr/src/vm/ecall.cpp +++ b/src/coreclr/src/vm/ecall.cpp @@ -349,7 +349,7 @@ static INT FindECIndexForMethod(MethodDesc *pMD, const LPVOID* impls) //@GENERICS: none of these methods belong to generic classes so there is no instantiation info to pass in if (!MetaSig::CompareMethodSigs(pMethodSig, cbMethodSigLen, pModule, NULL, - sig.GetRawSig(), sig.GetRawSigLen(), MscorlibBinder::GetModule(), NULL)) + sig.GetRawSig(), sig.GetRawSigLen(), MscorlibBinder::GetModule(), NULL, FALSE)) { continue; } diff --git a/src/coreclr/src/vm/memberload.cpp b/src/coreclr/src/vm/memberload.cpp index 1881b3f0b779ce..c0e26d74d32f5e 100644 --- a/src/coreclr/src/vm/memberload.cpp +++ b/src/coreclr/src/vm/memberload.cpp @@ -243,7 +243,7 @@ void MemberLoader::GetDescFromMemberRef(Module * pModule, pMethodDef->GetSig(&pMethodSig, &cMethodSig); if (!MetaSig::CompareMethodSigs(pSig, cSig, pModule, NULL, pMethodSig, - cMethodSig, pModule, NULL)) + cMethodSig, pModule, NULL, FALSE)) { // If the signatures do not match, then the correct MethodDesc has not been found. fMissingMethod = TRUE; @@ -1043,7 +1043,7 @@ BOOL CompareMethodSigWithCorrectSubstitution( pCurDeclMD->GetSig(&pCurMethodSig, &cCurMethodSig); return MetaSig::CompareMethodSigs(pSignature, cSignature, pModule, NULL, pCurMethodSig, - cCurMethodSig, pCurDeclMD->GetModule(), pDefSubst); + cCurMethodSig, pCurDeclMD->GetModule(), pDefSubst, FALSE); } else { @@ -1443,7 +1443,7 @@ MemberLoader::FindConstructor(MethodTable * pMT, PCCOR_SIGNATURE pSignature,DWOR DWORD cCurMethodSig; pCurMethod->GetSig(&pCurMethodSig, &cCurMethodSig); - if (MetaSig::CompareMethodSigs(pSignature, cSignature, pModule, NULL, pCurMethodSig, cCurMethodSig, pCurMethod->GetModule(), NULL)) + if (MetaSig::CompareMethodSigs(pSignature, cSignature, pModule, NULL, pCurMethodSig, cCurMethodSig, pCurMethod->GetModule(), NULL, FALSE)) { return pCurMethod; } diff --git a/src/coreclr/src/vm/methodtablebuilder.cpp b/src/coreclr/src/vm/methodtablebuilder.cpp index 14ccfd4371061d..2a3c8c147da63f 100644 --- a/src/coreclr/src/vm/methodtablebuilder.cpp +++ b/src/coreclr/src/vm/methodtablebuilder.cpp @@ -892,13 +892,15 @@ MethodTableBuilder::MethodSignature::NamesEqual( /*static*/ bool MethodTableBuilder::MethodSignature::SignaturesEquivalent( const MethodSignature & sig1, - const MethodSignature & sig2) + const MethodSignature & sig2, + BOOL allowCovariantReturn) { STANDARD_VM_CONTRACT; return !!MetaSig::CompareMethodSigs( sig1.GetSignature(), static_cast(sig1.GetSignatureLength()), sig1.GetModule(), &sig1.GetSubstitution(), - sig2.GetSignature(), static_cast(sig2.GetSignatureLength()), sig2.GetModule(), &sig2.GetSubstitution()); + sig2.GetSignature(), static_cast(sig2.GetSignatureLength()), sig2.GetModule(), &sig2.GetSubstitution(), + allowCovariantReturn); } //******************************************************************************* @@ -913,7 +915,7 @@ MethodTableBuilder::MethodSignature::SignaturesExactlyEqual( return !!MetaSig::CompareMethodSigs( sig1.GetSignature(), static_cast(sig1.GetSignatureLength()), sig1.GetModule(), &sig1.GetSubstitution(), sig2.GetSignature(), static_cast(sig2.GetSignatureLength()), sig2.GetModule(), &sig2.GetSubstitution(), - &newVisited); + FALSE, &newVisited); } //******************************************************************************* @@ -923,7 +925,7 @@ MethodTableBuilder::MethodSignature::Equivalent( { STANDARD_VM_CONTRACT; - return NamesEqual(*this, rhs) && SignaturesEquivalent(*this, rhs); + return NamesEqual(*this, rhs) && SignaturesEquivalent(*this, rhs, FALSE); } //******************************************************************************* @@ -2365,6 +2367,47 @@ MethodTableBuilder::EnumerateMethodImpls() { BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MISSING_SIG_BODY); } + + hr = pMDInternalImport->GetParentToken(theDecl, &tkParent); + if (FAILED(hr)) + BuildMethodTableThrowException(hr, *bmtError); + + // Note on covariant return types: right now we only support covariant returns for MethodImpls on + // class, where the MethodDecl is also on a class. Interface methods are not supported. In order to allow + // covariant return type checking in the call to CompareMethodSigs, we need to verify whether the type with + // the MethodDecl is an interface. + // We will also allow covariant return types if both the MethodImpl and MethodDecl are not on the same type. + + BOOL isBodyOnInterface = IsInterface(); + BOOL isDeclOnInterface = FALSE; + BOOL methodImplAndMethodDeclOnSameType = (GetCl() == tkParent); + + if (!isBodyOnInterface && !methodImplAndMethodDeclOnSameType) + { + // Skip checking if the declaring type is an interface if we already know this is a scenario where + // we can't allow for covariant returns + + CONTRACT_VIOLATION(LoadsTypeViolation); + MethodTable* pDeclMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing( + GetModule(), + tkParent, + &bmtGenerics->typeContext, + ClassLoader::ThrowIfNotFound, + ClassLoader::PermitUninstDefOrRef, + ClassLoader::LoadTypes, + CLASS_LOAD_APPROXPARENTS, + TRUE).GetMethodTable()->GetCanonicalMethodTable(); + + CONSISTENCY_CHECK(pDeclMT != NULL); + + isDeclOnInterface = pDeclMT->IsInterface(); + } + + if (strstr(this->GetHalfBakedClass()->m_szDebugClassName, "MyFoo") != NULL || strstr(this->GetHalfBakedClass()->m_szDebugClassName, "MyBar") != NULL) + { + int a = 0; + } + // Can't use memcmp because there may be two AssemblyRefs // in this scope, pointing to the same assembly, etc.). if (!MetaSig::CompareMethodSigs( @@ -2375,7 +2418,8 @@ MethodTableBuilder::EnumerateMethodImpls() pSigBody, cbSigBody, GetModule(), - NULL)) + NULL, + !isBodyOnInterface && !isDeclOnInterface && !methodImplAndMethodDeclOnSameType)) { BuildMethodTableThrowException(IDS_CLASSLOAD_MI_BODY_DECL_MISMATCH); } @@ -3648,10 +3692,10 @@ BOOL MethodTableBuilder::IsSelfReferencingStaticValueTypeField(mdToken dwByV PCCOR_SIGNATURE pFieldSig = pMemberSignature + 1; // skip the CALLCONV_FIELD - return MetaSig::CompareElementType(pFakeSig, pFieldSig, + return MetaSig::CompareElementType(pFakeSig, pFieldSig, pFakeSig + cFakeSig, pMemberSignature + cMemberSignature, GetModule(), GetModule(), - NULL, NULL); + NULL, NULL, FALSE); } @@ -5568,6 +5612,11 @@ MethodTableBuilder::ProcessMethodImpls() HRESULT hr = S_OK; + if (strstr(this->GetHalfBakedClass()->m_szDebugClassName, "MyFoo") != NULL || strstr(this->GetHalfBakedClass()->m_szDebugClassName, "MyBar") != NULL) + { + int a = 0; + } + DeclaredMethodIterator it(*this); while (it.Next()) { @@ -5783,8 +5832,9 @@ MethodTableBuilder::ProcessMethodImpls() bmtRTType *pCurDeclType = pDeclType; do { - // two pass algorithm. search for exact matches followed - // by equivalent matches. + // Two pass algorithm: + // 1: Search for exact matches + // 2: Search for equivalent matches. for (int iPass = 0; (iPass < 2) && (declMethod.IsNull()); iPass++) { MethodTable *pCurDeclMT = pCurDeclType->GetMethodTable(); @@ -5818,6 +5868,7 @@ MethodTableBuilder::ProcessMethodImpls() cbCurMDSig, pCurMD->GetModule(), &pCurDeclType->GetSubstitution(), + FALSE, iPass == 0 ? &newVisited : NULL)) { declMethod = (*bmtParent->pSlotTable)[pCurMD->GetSlot()].Decl(); @@ -6118,6 +6169,7 @@ VOID MethodTableBuilder::MethodImplCompareSignatures( bmtMethodHandle hDecl, bmtMethodHandle hImpl, + BOOL allowCovariantReturn, DWORD dwConstraintErrorCode) { CONTRACTL { @@ -6131,7 +6183,7 @@ MethodTableBuilder::MethodImplCompareSignatures( const MethodSignature &declSig(hDecl.GetMethodSignature()); const MethodSignature &implSig(hImpl.GetMethodSignature()); - if (!MethodSignature::SignaturesEquivalent(declSig, implSig)) + if (!MethodSignature::SignaturesEquivalent(declSig, implSig, allowCovariantReturn)) { LOG((LF_CLASSLOADER, LL_INFO1000, "BADSIG placing MethodImpl: %x\n", declSig.GetToken())); BuildMethodTableThrowException(COR_E_TYPELOAD, IDS_CLASSLOAD_MI_BADSIGNATURE, declSig.GetToken()); @@ -6379,6 +6431,7 @@ MethodTableBuilder::PlaceLocalDeclarationOnClass( MethodImplCompareSignatures( pDecl, pImpl, + FALSE /* allowCovariantReturn */, IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_LOCAL_METHOD_IMPL); /////////////////////////////// @@ -6450,6 +6503,7 @@ VOID MethodTableBuilder::PlaceInterfaceDeclarationOnClass( MethodImplCompareSignatures( pDecl, pImpl, + FALSE /* allowCovariantReturn */, IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL); /////////////////////////////// @@ -6552,6 +6606,7 @@ VOID MethodTableBuilder::PlaceInterfaceDeclarationOnInterface( MethodImplCompareSignatures( hDecl, bmtMethodHandle(pImpl), + FALSE /* allowCovariantReturn */, IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL); /////////////////////////////// @@ -6600,6 +6655,7 @@ MethodTableBuilder::PlaceParentDeclarationOnClass( MethodImplCompareSignatures( pDecl, pImpl, + TRUE /* allowCovariantReturn */, IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_PARENT_METHOD_IMPL); //////////////////////////////// @@ -7230,7 +7286,7 @@ MethodTableBuilder::PlaceMethodFromParentEquivalentInterfaceIntoInterfaceSlot( // Check to verify that the equivalent slot on the equivalent interface actually matches the method // on the current interface. If not, then the slot is not a match, and we should search other interfaces // for an implementation of the method. - if (!MethodSignature::SignaturesEquivalent(pCurItfMethod->GetMethodSignature(), parentImplementation.GetMethodSignature())) + if (!MethodSignature::SignaturesEquivalent(pCurItfMethod->GetMethodSignature(), parentImplementation.GetMethodSignature(), FALSE)) { continue; } diff --git a/src/coreclr/src/vm/methodtablebuilder.h b/src/coreclr/src/vm/methodtablebuilder.h index 7314c704a1142c..7a07533ab42f59 100644 --- a/src/coreclr/src/vm/methodtablebuilder.h +++ b/src/coreclr/src/vm/methodtablebuilder.h @@ -809,7 +809,8 @@ class MethodTableBuilder static bool SignaturesEquivalent( const MethodSignature & sig1, - const MethodSignature & sig2); + const MethodSignature & sig2, + BOOL allowCovariantReturn); //----------------------------------------------------------------------------------------- // Returns true if the metadata signatures (PCCOR_SIGNATURE) are exactly equal. (No type equivalence permitted) @@ -2739,6 +2740,7 @@ class MethodTableBuilder MethodImplCompareSignatures( bmtMethodHandle hDecl, bmtMethodHandle hImpl, + BOOL allowCovariantReturn, DWORD dwConstraintErrorCode); // -------------------------------------------------------------------------------------------- diff --git a/src/coreclr/src/vm/runtimehandles.cpp b/src/coreclr/src/vm/runtimehandles.cpp index 2b4cad229bb447..a4846515f92c88 100644 --- a/src/coreclr/src/vm/runtimehandles.cpp +++ b/src/coreclr/src/vm/runtimehandles.cpp @@ -2169,7 +2169,8 @@ FCIMPL2(FC_BOOL_RET, SignatureNative::CompareSig, SignatureNative* pLhsUNSAFE, S { ret = MetaSig::CompareMethodSigs( gc.pLhs->GetCorSig(), gc.pLhs->GetCorSigSize(), gc.pLhs->GetModule(), NULL, - gc.pRhs->GetCorSig(), gc.pRhs->GetCorSigSize(), gc.pRhs->GetModule(), NULL); + gc.pRhs->GetCorSig(), gc.pRhs->GetCorSigSize(), gc.pRhs->GetModule(), NULL, + FALSE); } HELPER_METHOD_FRAME_END(); FC_RETURN_BOOL(ret); diff --git a/src/coreclr/src/vm/siginfo.cpp b/src/coreclr/src/vm/siginfo.cpp index 58b8d86f5b5c86..22438a270a8831 100644 --- a/src/coreclr/src/vm/siginfo.cpp +++ b/src/coreclr/src/vm/siginfo.cpp @@ -713,7 +713,7 @@ static BOOL MethodDescMatchesSig(MethodDesc* pMD, PCCOR_SIGNATURE pSig, DWORD cS pMD->GetSig(&pSigOfMD, &cSigOfMD); return MetaSig::CompareMethodSigs(pSig, cSig, pModule, NULL, - pSigOfMD, cSigOfMD, pMD->GetModule(), NULL); + pSigOfMD, cSigOfMD, pMD->GetModule(), NULL, FALSE); } #endif // _DEBUG @@ -3002,7 +3002,7 @@ static BOOL CompareDelegatesForEquivalence(mdToken tk1, mdToken tk2, Module *pMo GetDelegateInvokeMethodSignature(tk1, pModule1, &cbSig1, &pSig1); GetDelegateInvokeMethodSignature(tk2, pModule2, &cbSig2, &pSig2); - return MetaSig::CompareMethodSigs(pSig1, cbSig1, pModule1, NULL, pSig2, cbSig2, pModule2, NULL, pVisited); + return MetaSig::CompareMethodSigs(pSig1, cbSig1, pModule1, NULL, pSig2, cbSig2, pModule2, NULL, FALSE, pVisited); } #endif // FEATURE_TYPEEQUIVALENCE @@ -3562,6 +3562,41 @@ BOOL CompareTypeTokens(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModu #pragma warning(push) #pragma warning(disable:21000) // Suppress PREFast warning about overly large function #endif + +// static +BOOL MetaSig::CompareTypeHandles(TypeHandle hType1, TypeHandle hType2, BOOL allowDerivedClass) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + PRECONDITION(!hType1.IsNull() && !hType2.IsNull()); + } + CONTRACTL_END; + + if (hType1 == hType2) + return TRUE; + + if (!allowDerivedClass) + return FALSE; + + CorElementType et1 = hType1.GetInternalCorElementType(); + CorElementType et2 = hType2.GetInternalCorElementType(); + // TODO: ELEMENT_TYPE_GENERICINST + if ((et1 == ELEMENT_TYPE_OBJECT || et1 == ELEMENT_TYPE_CLASS) && et2 == ELEMENT_TYPE_CLASS) + { + while (!hType2.IsNull()) + { + if (hType1 == hType2) + return TRUE; + hType2 = hType2.GetParent(); + } + } + + return FALSE; +} + //--------------------------------------------------------------------------------------- // // Compare the next elements in two sigs. @@ -3577,6 +3612,7 @@ MetaSig::CompareElementType( Module * pModule2, const Substitution * pSubst1, const Substitution * pSubst2, + BOOL allowDerivedClass, TokenPairList * pVisited) // = NULL { CONTRACTL @@ -3621,6 +3657,7 @@ MetaSig::CompareElementType( pSubst2->GetModule(), pSubst1, pSubst2->GetNext(), + allowDerivedClass, pVisited); } @@ -3648,6 +3685,7 @@ MetaSig::CompareElementType( pModule2, pSubst1->GetNext(), pSubst2, + allowDerivedClass, pVisited); } @@ -3686,21 +3724,21 @@ MetaSig::CompareElementType( { if ((Type1 == ELEMENT_TYPE_INTERNAL) || (Type2 == ELEMENT_TYPE_INTERNAL)) { - TypeHandle hInternal; + TypeHandle hType1, hType2; CorElementType eOtherType; Module * pOtherModule; // One type is already loaded, collect all the necessary information to identify the other type. if (Type1 == ELEMENT_TYPE_INTERNAL) { - IfFailThrow(CorSigUncompressPointer_EndPtr(pSig1, pEndSig1, (void **)&hInternal)); + IfFailThrow(CorSigUncompressPointer_EndPtr(pSig1, pEndSig1, (void **)&hType1)); eOtherType = Type2; pOtherModule = pModule2; } else { - IfFailThrow(CorSigUncompressPointer_EndPtr(pSig2, pEndSig2, (void **)&hInternal)); + IfFailThrow(CorSigUncompressPointer_EndPtr(pSig2, pEndSig2, (void **)&hType2)); eOtherType = Type1; pOtherModule = pModule1; @@ -3711,11 +3749,23 @@ MetaSig::CompareElementType( { case ELEMENT_TYPE_OBJECT: { - return (hInternal.AsMethodTable() == g_pObjectClass); + if (Type1 == ELEMENT_TYPE_INTERNAL) + { + // Type2 is ELEMENT_TYPE_OBJECT. Return true only if Type1 is also type object. + return hType1.AsMethodTable() == g_pObjectClass; + } + else + { + // Type1 is ELEMENT_TYPE_OBJECT. Return true if Type1 is object or any other class deriving + // from object if allowDerivedClass is TRUE + return CompareTypeHandles(TypeHandle(g_pObjectClass), hType2, allowDerivedClass); + } } case ELEMENT_TYPE_STRING: { - return (hInternal.AsMethodTable() == g_pStringClass); + return Type1 == ELEMENT_TYPE_INTERNAL ? + hType1.AsMethodTable() == g_pStringClass : + hType2.AsMethodTable() == g_pStringClass; } case ELEMENT_TYPE_VALUETYPE: case ELEMENT_TYPE_CLASS: @@ -3724,20 +3774,23 @@ MetaSig::CompareElementType( if (Type1 == ELEMENT_TYPE_INTERNAL) { IfFailThrow(CorSigUncompressToken_EndPtr(pSig2, pEndSig2, &tkOther)); + hType2 = ClassLoader::LoadTypeDefOrRefThrowing( + pOtherModule, + tkOther, + ClassLoader::ReturnNullIfNotFound, + ClassLoader::FailIfUninstDefOrRef); } else { IfFailThrow(CorSigUncompressToken_EndPtr(pSig1, pEndSig1, &tkOther)); + hType1 = ClassLoader::LoadTypeDefOrRefThrowing( + pOtherModule, + tkOther, + ClassLoader::ReturnNullIfNotFound, + ClassLoader::FailIfUninstDefOrRef); } - TypeHandle hOtherType; - hOtherType = ClassLoader::LoadTypeDefOrRefThrowing( - pOtherModule, - tkOther, - ClassLoader::ReturnNullIfNotFound, - ClassLoader::FailIfUninstDefOrRef); - - return (hInternal == hOtherType); + return CompareTypeHandles(hType1, hType2, allowDerivedClass); } default: { @@ -3747,7 +3800,14 @@ MetaSig::CompareElementType( } else { - return FALSE; // types must be the same + // Types must be the same, or type2 must derive from type1. + if (allowDerivedClass && Type1 == ELEMENT_TYPE_OBJECT) + { + // TODO: ELEMENT_TYPE_GENERICINST + return Type2 == ELEMENT_TYPE_STRING || Type2 == ELEMENT_TYPE_CLASS; + } + + return FALSE; } } @@ -3831,6 +3891,7 @@ MetaSig::CompareElementType( pModule2, pSubst1, pSubst2, + FALSE, pVisited)) { return FALSE; @@ -3846,7 +3907,18 @@ MetaSig::CompareElementType( IfFailThrow(CorSigUncompressToken_EndPtr(pSig1, pEndSig1, &tk1)); IfFailThrow(CorSigUncompressToken_EndPtr(pSig2, pEndSig2, &tk2)); - return CompareTypeTokens(tk1, tk2, pModule1, pModule2, pVisited); + if (CompareTypeTokens(tk1, tk2, pModule1, pModule2, pVisited)) + { + return TRUE; + } + + if (allowDerivedClass) + { + TypeHandle hType1 = ClassLoader::LoadTypeDefOrRefThrowing(pModule1, tk1, ClassLoader::ReturnNullIfNotFound, ClassLoader::FailIfUninstDefOrRef); + TypeHandle hType2 = ClassLoader::LoadTypeDefOrRefThrowing(pModule2, tk2, ClassLoader::ReturnNullIfNotFound, ClassLoader::FailIfUninstDefOrRef); + return CompareTypeHandles(hType1, hType2, TRUE); + } + return FALSE; } case ELEMENT_TYPE_FNPTR: @@ -3890,6 +3962,7 @@ MetaSig::CompareElementType( pModule2, pSubst1, pSubst2, + FALSE, &newVisited)) { return FALSE; @@ -3918,6 +3991,7 @@ MetaSig::CompareElementType( pModule2, pSubst1, pSubst2, + allowDerivedClass, &newVisitedAlwaysForbidden)) { return FALSE; @@ -3943,6 +4017,7 @@ MetaSig::CompareElementType( pModule2, pSubst1, pSubst2, + FALSE, &newVisited)) { return FALSE; @@ -3971,6 +4046,7 @@ MetaSig::CompareElementType( pModule2, pSubst1, pSubst2, + FALSE, pVisited)) { return FALSE; @@ -4051,7 +4127,7 @@ MetaSig::CompareElementType( IfFailThrow(CorSigUncompressPointer_EndPtr(pSig1, pEndSig1, (void **)&hType1)); IfFailThrow(CorSigUncompressPointer_EndPtr(pSig2, pEndSig2, (void **)&hType2)); - return (hType1 == hType2); + return CompareTypeHandles(hType1, hType2, allowDerivedClass); } } // switch // Unreachable @@ -4125,6 +4201,7 @@ MetaSig::CompareTypeDefsUnderSubstitutions( pSubst2->GetModule(), pSubst1->GetNext(), pSubst2->GetNext(), + FALSE, pVisited)) { return FALSE; @@ -4232,7 +4309,7 @@ MetaSig::CompareMethodSigsNT( HRESULT hr = S_OK; EX_TRY { - if (CompareMethodSigs(pSignature1, cSig1, pModule1, pSubst1, pSignature2, cSig2, pModule2, pSubst2, pVisited)) + if (CompareMethodSigs(pSignature1, cSig1, pModule1, pSubst1, pSignature2, cSig2, pModule2, pSubst2, FALSE, pVisited)) hr = S_OK; else hr = S_FALSE; @@ -4257,6 +4334,7 @@ MetaSig::CompareMethodSigs( DWORD cSig2, Module * pModule2, const Substitution * pSubst2, + BOOL allowCovariantReturn, TokenPairList * pVisited) //= NULL { CONTRACTL @@ -4361,6 +4439,7 @@ MetaSig::CompareMethodSigs( pModule2, pSubst1, pSubst2, + i == 0 && allowCovariantReturn, pVisited)) { return FALSE; @@ -4386,6 +4465,7 @@ MetaSig::CompareMethodSigs( pModule2, pSubst1, pSubst2, + i == 0 && allowCovariantReturn, pVisited)) { return FALSE; @@ -4426,7 +4506,7 @@ BOOL MetaSig::CompareFieldSigs( pEndSig1 = pSig1 + cSig1; pEndSig2 = pSig2 + cSig2; - return(CompareElementType(++pSig1, ++pSig2, pEndSig1, pEndSig2, pModule1, pModule2, NULL, NULL, pVisited)); + return(CompareElementType(++pSig1, ++pSig2, pEndSig1, pEndSig2, pModule1, pModule2, NULL, NULL, FALSE, pVisited)); } #ifndef DACCESS_COMPILE @@ -4668,7 +4748,7 @@ BOOL MetaSig::CompareTypeDefOrRefOrSpec(Module *pModule1, mdToken tok1, ULONG cSig1,cSig2; IfFailThrow(pInternalImport1->GetTypeSpecFromToken(tok1, &pSig1, &cSig1)); IfFailThrow(pInternalImport2->GetTypeSpecFromToken(tok2, &pSig2, &cSig2)); - return MetaSig::CompareElementType(pSig1,pSig2,pSig1+cSig1,pSig2+cSig2,pModule1,pModule2,pSubst1,pSubst2,pVisited); + return MetaSig::CompareElementType(pSig1, pSig2, pSig1 + cSig1, pSig2 + cSig2, pModule1, pModule2, pSubst1, pSubst2, FALSE, pVisited); } // MetaSig::CompareTypeDefOrRefOrSpec /* static */ diff --git a/src/coreclr/src/vm/siginfo.hpp b/src/coreclr/src/vm/siginfo.hpp index e294239670520f..9717364e688cf0 100644 --- a/src/coreclr/src/vm/siginfo.hpp +++ b/src/coreclr/src/vm/siginfo.hpp @@ -970,6 +970,11 @@ class MetaSig //------------------------------------------------------------------ CorElementType GetByRefType(TypeHandle* pTy) const; + // Compare two type handles for equality. If the two types are not equal, and allowDerivedClass + // is TRUE, return true if hType2 derives from hType1. This inheritance check is used to allow + // for covariant return types on MethodImpls. + static BOOL CompareTypeHandles(TypeHandle hType1, TypeHandle hType2, BOOL allowDerivedClass); + // Compare types in two signatures, first applying // - optional substitutions pSubst1 and pSubst2 // to class type parameters (E_T_VAR) in the respective signatures @@ -984,6 +989,7 @@ class MetaSig Module * pModule2, const Substitution * pSubst1, const Substitution * pSubst2, + BOOL allowDerivedClass, TokenPairList * pVisited = NULL); @@ -1002,15 +1008,16 @@ class MetaSig // Compare two complete method signatures, first applying optional substitutions pSubst1 and pSubst2 // to class type parameters (E_T_VAR) in the respective signatures static BOOL CompareMethodSigs( - PCCOR_SIGNATURE pSig1, - DWORD cSig1, - Module* pModule1, + PCCOR_SIGNATURE pSig1, + DWORD cSig1, + Module* pModule1, const Substitution* pSubst1, - PCCOR_SIGNATURE pSig2, - DWORD cSig2, - Module* pModule2, + PCCOR_SIGNATURE pSig2, + DWORD cSig2, + Module* pModule2, const Substitution* pSubst2, - TokenPairList *pVisited = NULL + BOOL allowCovariantReturn, + TokenPairList* pVisited = NULL ); // Nonthrowing version of CompareMethodSigs From a4bc6de2456a1a9cc6633b1e172a6fc5753693c7 Mon Sep 17 00:00:00 2001 From: Fadi Hanna Date: Thu, 26 Mar 2020 22:46:38 -0700 Subject: [PATCH 02/13] Correct handling for generic base types and their substitutions Replace base type hierarchy walking to use metadata instead of loading types, for better performance. --- src/coreclr/src/inc/sigbuilder.h | 2 + src/coreclr/src/utilcode/sigbuilder.cpp | 16 ++ src/coreclr/src/vm/methodtablebuilder.cpp | 71 ++--- src/coreclr/src/vm/siginfo.cpp | 322 ++++++++++++++++++++-- src/coreclr/src/vm/siginfo.hpp | 18 +- 5 files changed, 374 insertions(+), 55 deletions(-) diff --git a/src/coreclr/src/inc/sigbuilder.h b/src/coreclr/src/inc/sigbuilder.h index c1ad67af0f2e34..938e50d8f31346 100644 --- a/src/coreclr/src/inc/sigbuilder.h +++ b/src/coreclr/src/inc/sigbuilder.h @@ -74,6 +74,8 @@ class SigBuilder } void AppendBlob(const PVOID pBlob, SIZE_T cbBlob); + + void AppendSignature(const PCCOR_SIGNATURE pSig, const PCCOR_SIGNATURE pSigEnd); }; #endif // _SIGBUILDER_H_ diff --git a/src/coreclr/src/utilcode/sigbuilder.cpp b/src/coreclr/src/utilcode/sigbuilder.cpp index 922e1613ca3697..58d0c374cf66a0 100644 --- a/src/coreclr/src/utilcode/sigbuilder.cpp +++ b/src/coreclr/src/utilcode/sigbuilder.cpp @@ -119,6 +119,22 @@ void SigBuilder::AppendBlob(const PVOID pBlob, SIZE_T cbBlob) m_dwLength += (DWORD)cbBlob; } +void SigBuilder::AppendSignature(const PCCOR_SIGNATURE pSig, const PCCOR_SIGNATURE pSigEnd) +{ + STANDARD_VM_CONTRACT; + + // Overflow checks + if (pSigEnd < pSig) + ThrowOutOfMemory(); + + DWORD cbSig = (DWORD)(pSigEnd - pSig); + + Ensure(cbSig); + memcpy(&m_pBuffer[m_dwLength], pSig, cbSig); + + m_dwLength += cbSig; +} + void SigBuilder::Grow(SIZE_T cbMin) { STANDARD_VM_CONTRACT; diff --git a/src/coreclr/src/vm/methodtablebuilder.cpp b/src/coreclr/src/vm/methodtablebuilder.cpp index 2a3c8c147da63f..d60d698d765ebb 100644 --- a/src/coreclr/src/vm/methodtablebuilder.cpp +++ b/src/coreclr/src/vm/methodtablebuilder.cpp @@ -2244,6 +2244,11 @@ MethodTableBuilder::EnumerateMethodImpls() if (bmtMethod->dwNumberMethodImpls != 0) { + if (strstr(this->GetHalfBakedClass()->m_szDebugClassName, "Foo") != NULL || strstr(this->GetHalfBakedClass()->m_szDebugClassName, "Bar") != NULL) + { + int a = 0; + } + // // Allocate the structures to keep track of the impl matches // @@ -2368,42 +2373,44 @@ MethodTableBuilder::EnumerateMethodImpls() BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MISSING_SIG_BODY); } - hr = pMDInternalImport->GetParentToken(theDecl, &tkParent); - if (FAILED(hr)) - BuildMethodTableThrowException(hr, *bmtError); - - // Note on covariant return types: right now we only support covariant returns for MethodImpls on - // class, where the MethodDecl is also on a class. Interface methods are not supported. In order to allow - // covariant return type checking in the call to CompareMethodSigs, we need to verify whether the type with - // the MethodDecl is an interface. - // We will also allow covariant return types if both the MethodImpl and MethodDecl are not on the same type. - - BOOL isBodyOnInterface = IsInterface(); - BOOL isDeclOnInterface = FALSE; - BOOL methodImplAndMethodDeclOnSameType = (GetCl() == tkParent); - - if (!isBodyOnInterface && !methodImplAndMethodDeclOnSameType) + BOOL allowCovariantReturn = FALSE; + if (!IsValueClass() && !IsInterface()) { - // Skip checking if the declaring type is an interface if we already know this is a scenario where - // we can't allow for covariant returns - - CONTRACT_VIOLATION(LoadsTypeViolation); - MethodTable* pDeclMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing( - GetModule(), - tkParent, - &bmtGenerics->typeContext, - ClassLoader::ThrowIfNotFound, - ClassLoader::PermitUninstDefOrRef, - ClassLoader::LoadTypes, - CLASS_LOAD_APPROXPARENTS, - TRUE).GetMethodTable()->GetCanonicalMethodTable(); + // Note on covariant return types: right now we only support covariant returns for MethodImpls on + // class, where the MethodDecl is also on a class. Interface methods are not supported. In order to allow + // covariant return type checking in the call to CompareMethodSigs, we need to verify whether the type with + // the MethodDecl is an interface. + // We will also allow covariant return types if both the MethodImpl and MethodDecl are not on the same type. - CONSISTENCY_CHECK(pDeclMT != NULL); + hr = pMDInternalImport->GetParentToken(theDecl, &tkParent); + if (FAILED(hr)) + BuildMethodTableThrowException(hr, *bmtError); - isDeclOnInterface = pDeclMT->IsInterface(); + if (GetCl() != tkParent) + { + // Skip checking if the declaring type is an interface if we already know this is a scenario where + // we can't allow for covariant returns + + CONTRACT_VIOLATION(LoadsTypeViolation); + MethodTable* pDeclMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing( + GetModule(), + tkParent, + &bmtGenerics->typeContext, + ClassLoader::ThrowIfNotFound, + ClassLoader::PermitUninstDefOrRef, + ClassLoader::LoadTypes, + CLASS_LOAD_APPROXPARENTS).GetMethodTable()->GetCanonicalMethodTable(); + + CONSISTENCY_CHECK(pDeclMT != NULL); + + if (!pDeclMT->IsInterface()) + { + allowCovariantReturn = TRUE; + } + } } - if (strstr(this->GetHalfBakedClass()->m_szDebugClassName, "MyFoo") != NULL || strstr(this->GetHalfBakedClass()->m_szDebugClassName, "MyBar") != NULL) + if (strstr(this->GetHalfBakedClass()->m_szDebugClassName, "Foo") != NULL || strstr(this->GetHalfBakedClass()->m_szDebugClassName, "Bar") != NULL) { int a = 0; } @@ -2419,7 +2426,7 @@ MethodTableBuilder::EnumerateMethodImpls() cbSigBody, GetModule(), NULL, - !isBodyOnInterface && !isDeclOnInterface && !methodImplAndMethodDeclOnSameType)) + allowCovariantReturn)) { BuildMethodTableThrowException(IDS_CLASSLOAD_MI_BODY_DECL_MISMATCH); } diff --git a/src/coreclr/src/vm/siginfo.cpp b/src/coreclr/src/vm/siginfo.cpp index 22438a270a8831..e5aac3fdfb0694 100644 --- a/src/coreclr/src/vm/siginfo.cpp +++ b/src/coreclr/src/vm/siginfo.cpp @@ -3563,6 +3563,12 @@ BOOL CompareTypeTokens(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModu #pragma warning(disable:21000) // Suppress PREFast warning about overly large function #endif +//--------------------------------------------------------------------------------------- +// +// Compare two type handles for equality, or that hType2 is a derived class of hType1. +// The derived type check is used by the covariant returns feature, which only supports +// class today (interface types are not supported right now) +// // static BOOL MetaSig::CompareTypeHandles(TypeHandle hType1, TypeHandle hType2, BOOL allowDerivedClass) { @@ -3581,22 +3587,197 @@ BOOL MetaSig::CompareTypeHandles(TypeHandle hType1, TypeHandle hType2, BOOL allo if (!allowDerivedClass) return FALSE; - CorElementType et1 = hType1.GetInternalCorElementType(); - CorElementType et2 = hType2.GetInternalCorElementType(); - // TODO: ELEMENT_TYPE_GENERICINST - if ((et1 == ELEMENT_TYPE_OBJECT || et1 == ELEMENT_TYPE_CLASS) && et2 == ELEMENT_TYPE_CLASS) + if (hType1.IsNull() || hType2.IsValueType() || hType2.IsInterface()) + { + return FALSE; + } + + while (!hType2.IsNull()) + { + if (hType1 == hType2) + return TRUE; + hType2 = hType2.GetParent(); + } + + return FALSE; +} + +// static +BOOL MetaSig::CompareTypeTokensForEqualityOrInheritance(mdToken tk1, Module* pModule1, mdToken tk2, Module* pModule2) +{ + CONTRACTL { - while (!hType2.IsNull()) + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + PRECONDITION(CheckPointer(pModule1)); + PRECONDITION(CheckPointer(pModule2)); + PRECONDITION(TypeFromToken(tk1) == mdtTypeRef || TypeFromToken(tk1) == mdtTypeDef); + PRECONDITION(TypeFromToken(tk2) == mdtTypeRef || TypeFromToken(tk2) == mdtTypeDef); + MODE_ANY; + } + CONTRACTL_END; + + while (pModule2->GetMDImport()->IsValidToken(tk2)) + { + if (CompareTypeTokens(tk1, tk2, pModule1, pModule2, NULL)) + return TRUE; + + // Ensure we are working with the typedef token + mdToken foundToken2; + Module* pFoundModule2; + if (!ClassLoader::ResolveTokenToTypeDefThrowing(pModule2, tk2, &pFoundModule2, &foundToken2)) + return FALSE; + + pModule2 = pFoundModule2; + tk2 = foundToken2; + + DWORD attr; + mdToken tkTypeParent; + IfFailThrow(pModule2->GetMDImport()->GetTypeDefProps(tk2, &attr, &tkTypeParent)); + + if (!pModule2->GetMDImport()->IsValidToken(tkTypeParent)) + break; + + if (TypeFromToken(tkTypeParent) == mdtTypeSpec) { - if (hType1 == hType2) - return TRUE; - hType2 = hType2.GetParent(); + ULONG cbSig; + PCCOR_SIGNATURE pSig; + IfFailThrow(pModule2->GetMDImport()->GetSigFromToken(tkTypeParent, &cbSig, &pSig)); + + PCCOR_SIGNATURE pEndSig = pSig + cbSig; + CorElementType elementType = ELEMENT_TYPE_MAX; + + IfFailThrow(CorSigUncompressElementType_EndPtr(pSig, pEndSig, &elementType)); + if (elementType == ELEMENT_TYPE_GENERICINST) + { + IfFailThrow(CorSigUncompressElementType_EndPtr(pSig, pEndSig, &elementType)); + } + + if (elementType != ELEMENT_TYPE_CLASS) + { + break; + } + + IfFailThrow(CorSigUncompressToken_EndPtr(pSig, pEndSig, &tk2)); + } + else if (TypeFromToken(tkTypeParent) == mdtTypeRef || TypeFromToken(tkTypeParent) == mdtTypeDef) + { + CONSISTENCY_CHECK(tk2 != tkTypeParent); + tk2 = tkTypeParent; + } + else + { + break; } } return FALSE; } +// static +BOOL MetaSig::GetParentSignatureAndSubstitution( + PCCOR_SIGNATURE pSig, + PCCOR_SIGNATURE pEndSig, + Module* pModule, + const Substitution* pSubst, + Module** ppParentTypeModule, + SigBuilder& parentTypeSig, + Substitution& parentTypeSubst) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + PRECONDITION(CheckPointer(pModule)); + PRECONDITION(CheckPointer(ppParentTypeModule)); + MODE_ANY; + } + CONTRACTL_END; + + CorElementType elementType = ELEMENT_TYPE_MAX; + + IfFailThrow(CorSigUncompressElementType_EndPtr(pSig, pEndSig, &elementType)); + + if (elementType == ELEMENT_TYPE_GENERICINST) + { + IfFailThrow(CorSigUncompressElementType_EndPtr(pSig, pEndSig, &elementType)); + } + + // Getting the parent siganture is only applicable to classes, so exclude anything else + if (elementType != ELEMENT_TYPE_CLASS) + { + return FALSE; + } + + mdToken typeRefOrDefToken; + IfFailThrow(CorSigUncompressToken_EndPtr(pSig, pEndSig, &typeRefOrDefToken)); + + // Ensure we are working with the typedef token + mdToken typeDefToken; + Module* pFoundModule; + if (!ClassLoader::ResolveTokenToTypeDefThrowing(pModule, typeRefOrDefToken, &pFoundModule, &typeDefToken)) + return FALSE; + + DWORD attr; + mdToken parentTypeDefOrRefToken; + IfFailThrow(pFoundModule->GetMDImport()->GetTypeDefProps(typeDefToken, &attr, &parentTypeDefOrRefToken)); + + if (!pFoundModule->GetMDImport()->IsValidToken(parentTypeDefOrRefToken)) + { + return FALSE; + } + + if (IsTdInterface(attr)) + { + // Interfaces not supported with covariant return types + return FALSE; + } + + // We load the uninstantiated type here, and we will also return back a valid substitution + // for the caller to use (when applicable) + + if (TypeFromToken(parentTypeDefOrRefToken) == mdtTypeSpec) + { + ULONG cbParentTypeSig; + PCCOR_SIGNATURE pParentTypeSig; + IfFailThrow(pFoundModule->GetMDImport()->GetSigFromToken(parentTypeDefOrRefToken, &cbParentTypeSig, &pParentTypeSig)); + + parentTypeSig.AppendSignature(pParentTypeSig, pParentTypeSig + cbParentTypeSig); + parentTypeSubst = Substitution(parentTypeDefOrRefToken, pFoundModule, pSubst); + *ppParentTypeModule = pFoundModule; + } + else if (TypeFromToken(parentTypeDefOrRefToken) == mdtTypeDef || TypeFromToken(parentTypeDefOrRefToken) == mdtTypeRef) + { + // We need to special case type System.Object since it has its own element type. We don't need to do the same for type String + // because it's a sealed type, and no other class can derive from it. + + Module* pParentModule; + mdTypeDef parentTypeDefToken; + BOOL resolvedToken = ClassLoader::ResolveTokenToTypeDefThrowing(pFoundModule, parentTypeDefOrRefToken, &pParentModule, &parentTypeDefToken); + + if (resolvedToken && pParentModule == g_pObjectClass->GetModule() && parentTypeDefToken == g_pObjectClass->GetCl()) + { + parentTypeSig.AppendElementType(ELEMENT_TYPE_OBJECT); + } + else + { + parentTypeSig.AppendElementType(ELEMENT_TYPE_CLASS); + parentTypeSig.AppendToken(parentTypeDefOrRefToken); + } + + parentTypeSubst = pSubst == NULL ? Substitution() : Substitution(*pSubst); + *ppParentTypeModule = pFoundModule; + } + else + { + return FALSE; + } + + return TRUE; +} + //--------------------------------------------------------------------------------------- // // Compare the next elements in two sigs. @@ -3622,7 +3803,10 @@ MetaSig::CompareElementType( INJECT_FAULT(COMPlusThrowOM()); MODE_ANY; } - CONTRACTL_END + CONTRACTL_END; + + PCCOR_SIGNATURE pSig1Start = pSig1; + PCCOR_SIGNATURE pSig2Start = pSig2; redo: // We jump here if the Type was a ET_CMOD prefix. @@ -3756,9 +3940,16 @@ MetaSig::CompareElementType( } else { - // Type1 is ELEMENT_TYPE_OBJECT. Return true if Type1 is object or any other class deriving - // from object if allowDerivedClass is TRUE - return CompareTypeHandles(TypeHandle(g_pObjectClass), hType2, allowDerivedClass); + // Type1 is ELEMENT_TYPE_OBJECT. Return true if Type2 is type System.Object or any other class + // if allowDerivedClass is TRUE. + if (hType2.AsMethodTable() == g_pObjectClass) + { + return TRUE; + } + else + { + return allowDerivedClass ? CompareTypeHandles(TypeHandle(g_pObjectClass), hType2, TRUE) : FALSE; + } } } case ELEMENT_TYPE_STRING: @@ -3800,11 +3991,36 @@ MetaSig::CompareElementType( } else { - // Types must be the same, or type2 must derive from type1. - if (allowDerivedClass && Type1 == ELEMENT_TYPE_OBJECT) + if (allowDerivedClass) { - // TODO: ELEMENT_TYPE_GENERICINST - return Type2 == ELEMENT_TYPE_STRING || Type2 == ELEMENT_TYPE_CLASS; + if (Type1 == ELEMENT_TYPE_OBJECT && Type2 == ELEMENT_TYPE_STRING) + { + // Obvious case: string derives from object. + return TRUE; + } + else + { + Module* pParentTypeModule; + Substitution parentTypeSubst; + SigBuilder parentTypeSigBuilder; + if (GetParentSignatureAndSubstitution(pSig2Start, pEndSig2, pModule2, pSubst2, &pParentTypeModule, parentTypeSigBuilder, parentTypeSubst)) + { + DWORD cbParentTypeSig; + PCCOR_SIGNATURE pParentTypeSig = (PCCOR_SIGNATURE)parentTypeSigBuilder.GetSignature(&cbParentTypeSig); + PCCOR_SIGNATURE pParentTypeSigEnd = pParentTypeSig + cbParentTypeSig; + + return CompareElementType( + pSig1Start, + pParentTypeSig, + pEndSig1, + pParentTypeSigEnd, + pModule1, + pParentTypeModule, + pSubst1, + parentTypeSubst.GetInst().IsNull() ? NULL : &parentTypeSubst, + allowDerivedClass); + } + } } return FALSE; @@ -3912,12 +4128,53 @@ MetaSig::CompareElementType( return TRUE; } - if (allowDerivedClass) + if (allowDerivedClass && Type1 == ELEMENT_TYPE_CLASS) { - TypeHandle hType1 = ClassLoader::LoadTypeDefOrRefThrowing(pModule1, tk1, ClassLoader::ReturnNullIfNotFound, ClassLoader::FailIfUninstDefOrRef); - TypeHandle hType2 = ClassLoader::LoadTypeDefOrRefThrowing(pModule2, tk2, ClassLoader::ReturnNullIfNotFound, ClassLoader::FailIfUninstDefOrRef); - return CompareTypeHandles(hType1, hType2, TRUE); + // We load the uninstantiated types and check if type2 derives from type1. + // Note that if both Type1 is a generic type, we cannot check for equality here because + // we need to properly keep track of substitutions. + // Here's an example: + // class Class0 { } + // class Class1 : Class0 { } + // class Class2 : class Class1 { } + // class Class3 : class Class2 { } + // class Class4 : Class3{ } + // + // In that example, simply loading the TypeHandles for Class0 and Class4, and traversing the + // parent chain of Class4, we will not end up with a TypeHandle that will be equal to Class0, and + // this is because TypeHandle of Class0 in the parent chain of Class4 is expressed in terms of the + // generic instantiation arguments in the substitutions: + // A -> ARG1 -> T -> int32 + // b -> ARG2 -> int16 + // + // To handle that case, we compute the parent *AND* substitution chain of type2, and recompare that with + // type1 starting from the ELEMENT_TYPE_GENERICINST (see how ELEMENT_TYPE_GENERICINST is handled a few + // lines below). + + mdToken foundToken1; + Module* pFoundModule1; + if (!ClassLoader::ResolveTokenToTypeDefThrowing(pModule1, tk1, &pFoundModule1, &foundToken1)) + return FALSE; + + DWORD attr; + IfFailThrow(pFoundModule1->GetMDImport()->GetTypeDefProps(foundToken1, &attr, NULL)); + if (IsTdInterface(attr)) + { + // Covariant return types are not supported for interfaces today. + return FALSE; + } + + HENUMInternal hEnumGenericPars; + IfFailThrow(pFoundModule1->GetMDImport()->EnumInit(mdtGenericParam, foundToken1, &hEnumGenericPars)); + if (pFoundModule1->GetMDImport()->EnumGetCount(&hEnumGenericPars) > 0) + { + // Type1 is generic. We cannot compare the base type chain of Type2 for inheritance in that case. + return FALSE; + } + + return CompareTypeTokensForEqualityOrInheritance(foundToken1, pFoundModule1, tk2, pModule2); } + return FALSE; } @@ -3994,6 +4251,31 @@ MetaSig::CompareElementType( allowDerivedClass, &newVisitedAlwaysForbidden)) { + if (allowDerivedClass) + { + Module* pParentTypeModule; + Substitution parentTypeSubst; + SigBuilder parentTypeSigBuilder; + if (GetParentSignatureAndSubstitution(pSig2Start, pEndSig2, pModule2, pSubst2, &pParentTypeModule, parentTypeSigBuilder, parentTypeSubst)) + { + DWORD cbParentTypeSig; + PCCOR_SIGNATURE pParentTypeSig = (PCCOR_SIGNATURE)parentTypeSigBuilder.GetSignature(&cbParentTypeSig); + PCCOR_SIGNATURE pParentTypeSigEnd = pParentTypeSig + cbParentTypeSig; + + return CompareElementType( + pSig1Start, + pParentTypeSig, + pEndSig1, + pParentTypeSigEnd, + pModule1, + pParentTypeModule, + pSubst1, + parentTypeSubst.GetInst().IsNull() ? NULL : &parentTypeSubst, + allowDerivedClass, + &newVisitedAlwaysForbidden); + } + } + return FALSE; } diff --git a/src/coreclr/src/vm/siginfo.hpp b/src/coreclr/src/vm/siginfo.hpp index 9717364e688cf0..35b273afdab35c 100644 --- a/src/coreclr/src/vm/siginfo.hpp +++ b/src/coreclr/src/vm/siginfo.hpp @@ -975,12 +975,24 @@ class MetaSig // for covariant return types on MethodImpls. static BOOL CompareTypeHandles(TypeHandle hType1, TypeHandle hType2, BOOL allowDerivedClass); + // Compare two type tokens and check if they are equal, or if the second type token is a + // derived type of the first type token + static BOOL CompareTypeTokensForEqualityOrInheritance(mdToken tk1, Module* pModule1, mdToken tk2, Module* pModule2); + + // Extract the parent type's signature and stubstitution from the input type signature + static BOOL GetParentSignatureAndSubstitution( + PCCOR_SIGNATURE pSig, + PCCOR_SIGNATURE pEndSig, + Module* pModule, + const Substitution* pSubst, + Module** ppParentTypeModule, + SigBuilder& parentTypeSig, + Substitution& parentTypeSubst); + // Compare types in two signatures, first applying // - optional substitutions pSubst1 and pSubst2 // to class type parameters (E_T_VAR) in the respective signatures - static - BOOL - CompareElementType( + static BOOL CompareElementType( PCCOR_SIGNATURE & pSig1, PCCOR_SIGNATURE & pSig2, PCCOR_SIGNATURE pEndSig1, From 5bc0af4134609984aedca708b1e6e111dd450b6e Mon Sep 17 00:00:00 2001 From: Fadi Hanna Date: Fri, 27 Mar 2020 15:15:26 -0700 Subject: [PATCH 03/13] Handling of struct and interface return types --- src/coreclr/src/vm/methodtablebuilder.cpp | 9 ++- src/coreclr/src/vm/siginfo.cpp | 88 +++++++++++++++-------- 2 files changed, 67 insertions(+), 30 deletions(-) diff --git a/src/coreclr/src/vm/methodtablebuilder.cpp b/src/coreclr/src/vm/methodtablebuilder.cpp index d60d698d765ebb..b3370478c2d94d 100644 --- a/src/coreclr/src/vm/methodtablebuilder.cpp +++ b/src/coreclr/src/vm/methodtablebuilder.cpp @@ -2428,7 +2428,14 @@ MethodTableBuilder::EnumerateMethodImpls() NULL, allowCovariantReturn)) { - BuildMethodTableThrowException(IDS_CLASSLOAD_MI_BODY_DECL_MISMATCH); + MetaSig::CompareMethodSigs(pSigDecl, cbSigDecl, GetModule(), &theDeclSubst, pSigBody, cbSigBody, GetModule(), NULL, allowCovariantReturn); + printf("MethodImpl %x with MethodDecl %x failed\n", theBody, theDecl); + //BuildMethodTableThrowException(IDS_CLASSLOAD_MI_BODY_DECL_MISMATCH); + } + else + { + if (strstr(GetModule()->GetSimpleName(), "CovRetInterfaces") != NULL) + printf("MethodImpl %x with MethodDecl %x OK\n", theBody, theDecl); } } else diff --git a/src/coreclr/src/vm/siginfo.cpp b/src/coreclr/src/vm/siginfo.cpp index e5aac3fdfb0694..5c73064037daf2 100644 --- a/src/coreclr/src/vm/siginfo.cpp +++ b/src/coreclr/src/vm/siginfo.cpp @@ -3618,11 +3618,15 @@ BOOL MetaSig::CompareTypeTokensForEqualityOrInheritance(mdToken tk1, Module* pMo } CONTRACTL_END; - while (pModule2->GetMDImport()->IsValidToken(tk2)) + mdToken previousTk2 = mdTokenNil; + + while (previousTk2 != tk2) { if (CompareTypeTokens(tk1, tk2, pModule1, pModule2, NULL)) return TRUE; + previousTk2 = tk2; + // Ensure we are working with the typedef token mdToken foundToken2; Module* pFoundModule2; @@ -3639,6 +3643,10 @@ BOOL MetaSig::CompareTypeTokensForEqualityOrInheritance(mdToken tk1, Module* pMo if (!pModule2->GetMDImport()->IsValidToken(tkTypeParent)) break; + // Interfaces not supported with covariant return types. + if (IsTdInterface(attr)) + break; + if (TypeFromToken(tkTypeParent) == mdtTypeSpec) { ULONG cbSig; @@ -3991,35 +3999,33 @@ MetaSig::CompareElementType( } else { - if (allowDerivedClass) + if (allowDerivedClass && (Type1 == ELEMENT_TYPE_OBJECT || Type1 == ELEMENT_TYPE_CLASS || Type1 == ELEMENT_TYPE_GENERICINST)) { + // Obvious case: string derives from object. if (Type1 == ELEMENT_TYPE_OBJECT && Type2 == ELEMENT_TYPE_STRING) { - // Obvious case: string derives from object. return TRUE; } - else + + Module* pParentTypeModule; + Substitution parentTypeSubst; + SigBuilder parentTypeSigBuilder; + if (GetParentSignatureAndSubstitution(pSig2Start, pEndSig2, pModule2, pSubst2, &pParentTypeModule, parentTypeSigBuilder, parentTypeSubst)) { - Module* pParentTypeModule; - Substitution parentTypeSubst; - SigBuilder parentTypeSigBuilder; - if (GetParentSignatureAndSubstitution(pSig2Start, pEndSig2, pModule2, pSubst2, &pParentTypeModule, parentTypeSigBuilder, parentTypeSubst)) - { - DWORD cbParentTypeSig; - PCCOR_SIGNATURE pParentTypeSig = (PCCOR_SIGNATURE)parentTypeSigBuilder.GetSignature(&cbParentTypeSig); - PCCOR_SIGNATURE pParentTypeSigEnd = pParentTypeSig + cbParentTypeSig; + DWORD cbParentTypeSig; + PCCOR_SIGNATURE pParentTypeSig = (PCCOR_SIGNATURE)parentTypeSigBuilder.GetSignature(&cbParentTypeSig); + PCCOR_SIGNATURE pParentTypeSigEnd = pParentTypeSig + cbParentTypeSig; - return CompareElementType( - pSig1Start, - pParentTypeSig, - pEndSig1, - pParentTypeSigEnd, - pModule1, - pParentTypeModule, - pSubst1, - parentTypeSubst.GetInst().IsNull() ? NULL : &parentTypeSubst, - allowDerivedClass); - } + return CompareElementType( + pSig1Start, + pParentTypeSig, + pEndSig1, + pParentTypeSigEnd, + pModule1, + pParentTypeModule, + pSubst1, + parentTypeSubst.GetInst().IsNull() ? NULL : &parentTypeSubst, + allowDerivedClass); } } @@ -4160,19 +4166,16 @@ MetaSig::CompareElementType( IfFailThrow(pFoundModule1->GetMDImport()->GetTypeDefProps(foundToken1, &attr, NULL)); if (IsTdInterface(attr)) { - // Covariant return types are not supported for interfaces today. + // Interfaces are not currently supported in the derived type checking return FALSE; } HENUMInternal hEnumGenericPars; IfFailThrow(pFoundModule1->GetMDImport()->EnumInit(mdtGenericParam, foundToken1, &hEnumGenericPars)); - if (pFoundModule1->GetMDImport()->EnumGetCount(&hEnumGenericPars) > 0) + if (pFoundModule1->GetMDImport()->EnumGetCount(&hEnumGenericPars) == 0) { - // Type1 is generic. We cannot compare the base type chain of Type2 for inheritance in that case. - return FALSE; + return CompareTypeTokensForEqualityOrInheritance(foundToken1, pFoundModule1, tk2, pModule2); } - - return CompareTypeTokensForEqualityOrInheritance(foundToken1, pFoundModule1, tk2, pModule2); } return FALSE; @@ -4231,6 +4234,8 @@ MetaSig::CompareElementType( case ELEMENT_TYPE_GENERICINST: { + PCCOR_SIGNATURE pCurSig1 = pSig1; + TokenPairList newVisited = TokenPairList::AdjustForTypeSpec( pVisited, pModule1, @@ -4253,6 +4258,31 @@ MetaSig::CompareElementType( { if (allowDerivedClass) { + CorElementType elementType; + IfFailThrow(CorSigUncompressElementType_EndPtr(pCurSig1, pEndSig1, &elementType)); + if (elementType != ELEMENT_TYPE_CLASS) + { + // No point in checking anything other than ELEMENT_TYPE_CLASS for type inheritance + return FALSE; + } + + // Interfaces are not currently supported for derived type checking + { + mdToken tk1; + mdToken foundToken1; + Module* pFoundModule1; + IfFailThrow(CorSigUncompressToken_EndPtr(pCurSig1, pEndSig1, &tk1)); + if (!ClassLoader::ResolveTokenToTypeDefThrowing(pModule1, tk1, &pFoundModule1, &foundToken1)) + { + return FALSE; + } + + DWORD attr; + IfFailThrow(pFoundModule1->GetMDImport()->GetTypeDefProps(foundToken1, &attr, NULL)); + if (IsTdInterface(attr)) + return FALSE; + } + Module* pParentTypeModule; Substitution parentTypeSubst; SigBuilder parentTypeSigBuilder; From 55e9ae8c3add77becf36b2a00fa0c6305c9123a9 Mon Sep 17 00:00:00 2001 From: Fadi Hanna Date: Tue, 31 Mar 2020 10:41:15 -0700 Subject: [PATCH 04/13] Some fixes and refactoring of code --- src/coreclr/src/vm/methodtablebuilder.cpp | 24 +- src/coreclr/src/vm/siginfo.cpp | 336 +++++++++++++--------- src/coreclr/src/vm/siginfo.hpp | 20 +- 3 files changed, 213 insertions(+), 167 deletions(-) diff --git a/src/coreclr/src/vm/methodtablebuilder.cpp b/src/coreclr/src/vm/methodtablebuilder.cpp index b3370478c2d94d..5467a18d2e8e10 100644 --- a/src/coreclr/src/vm/methodtablebuilder.cpp +++ b/src/coreclr/src/vm/methodtablebuilder.cpp @@ -2244,11 +2244,6 @@ MethodTableBuilder::EnumerateMethodImpls() if (bmtMethod->dwNumberMethodImpls != 0) { - if (strstr(this->GetHalfBakedClass()->m_szDebugClassName, "Foo") != NULL || strstr(this->GetHalfBakedClass()->m_szDebugClassName, "Bar") != NULL) - { - int a = 0; - } - // // Allocate the structures to keep track of the impl matches // @@ -2388,9 +2383,6 @@ MethodTableBuilder::EnumerateMethodImpls() if (GetCl() != tkParent) { - // Skip checking if the declaring type is an interface if we already know this is a scenario where - // we can't allow for covariant returns - CONTRACT_VIOLATION(LoadsTypeViolation); MethodTable* pDeclMT = ClassLoader::LoadTypeDefOrRefOrSpecThrowing( GetModule(), @@ -2403,18 +2395,13 @@ MethodTableBuilder::EnumerateMethodImpls() CONSISTENCY_CHECK(pDeclMT != NULL); - if (!pDeclMT->IsInterface()) + if (!pDeclMT->IsInterface() && !pDeclMT->IsValueType()) { allowCovariantReturn = TRUE; } } } - if (strstr(this->GetHalfBakedClass()->m_szDebugClassName, "Foo") != NULL || strstr(this->GetHalfBakedClass()->m_szDebugClassName, "Bar") != NULL) - { - int a = 0; - } - // Can't use memcmp because there may be two AssemblyRefs // in this scope, pointing to the same assembly, etc.). if (!MetaSig::CompareMethodSigs( @@ -2428,14 +2415,7 @@ MethodTableBuilder::EnumerateMethodImpls() NULL, allowCovariantReturn)) { - MetaSig::CompareMethodSigs(pSigDecl, cbSigDecl, GetModule(), &theDeclSubst, pSigBody, cbSigBody, GetModule(), NULL, allowCovariantReturn); - printf("MethodImpl %x with MethodDecl %x failed\n", theBody, theDecl); - //BuildMethodTableThrowException(IDS_CLASSLOAD_MI_BODY_DECL_MISMATCH); - } - else - { - if (strstr(GetModule()->GetSimpleName(), "CovRetInterfaces") != NULL) - printf("MethodImpl %x with MethodDecl %x OK\n", theBody, theDecl); + BuildMethodTableThrowException(IDS_CLASSLOAD_MI_BODY_DECL_MISMATCH); } } else diff --git a/src/coreclr/src/vm/siginfo.cpp b/src/coreclr/src/vm/siginfo.cpp index 5c73064037daf2..69e518b1a871fd 100644 --- a/src/coreclr/src/vm/siginfo.cpp +++ b/src/coreclr/src/vm/siginfo.cpp @@ -3603,81 +3603,130 @@ BOOL MetaSig::CompareTypeHandles(TypeHandle hType1, TypeHandle hType2, BOOL allo } // static -BOOL MetaSig::CompareTypeTokensForEqualityOrInheritance(mdToken tk1, Module* pModule1, mdToken tk2, Module* pModule2) +BOOL MetaSig::IsTypeSignatureEligibleForCovariantReturnType( + PCCOR_SIGNATURE pSig, + PCCOR_SIGNATURE pEndSig, + Module* pModule, + BOOL isBaseTypeSig, + mdToken* pTypeDefToken, /* = NULL */ + Module** ppTypeDefModule, /* = NULL */ + mdToken* pParentTypeDefOrRefOrSpecToken) /* = NULL */ { - CONTRACTL + CorElementType elementType = ELEMENT_TYPE_MAX; + + IfFailThrow(CorSigUncompressElementType_EndPtr(pSig, pEndSig, &elementType)); + + // System.Object is always eligible as a base type since all reference types derive from it + if (isBaseTypeSig && elementType == ELEMENT_TYPE_OBJECT) { - THROWS; - GC_TRIGGERS; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(CheckPointer(pModule1)); - PRECONDITION(CheckPointer(pModule2)); - PRECONDITION(TypeFromToken(tk1) == mdtTypeRef || TypeFromToken(tk1) == mdtTypeDef); - PRECONDITION(TypeFromToken(tk2) == mdtTypeRef || TypeFromToken(tk2) == mdtTypeDef); - MODE_ANY; + return TRUE; } - CONTRACTL_END; - mdToken previousTk2 = mdTokenNil; + if (elementType == ELEMENT_TYPE_GENERICINST) + { + IfFailThrow(CorSigUncompressElementType_EndPtr(pSig, pEndSig, &elementType)); + } - while (previousTk2 != tk2) + // Getting the parent siganture is only applicable to classes, so exclude anything else + if (elementType != ELEMENT_TYPE_CLASS) { - if (CompareTypeTokens(tk1, tk2, pModule1, pModule2, NULL)) - return TRUE; + return FALSE; + } - previousTk2 = tk2; + mdToken typeRefOrDefToken; + IfFailThrow(CorSigUncompressToken_EndPtr(pSig, pEndSig, &typeRefOrDefToken)); - // Ensure we are working with the typedef token - mdToken foundToken2; - Module* pFoundModule2; - if (!ClassLoader::ResolveTokenToTypeDefThrowing(pModule2, tk2, &pFoundModule2, &foundToken2)) - return FALSE; + // Ensure we are working with the typedef token + mdToken typeDefToken; + Module* pFoundModule; + if (!ClassLoader::ResolveTokenToTypeDefThrowing(pModule, typeRefOrDefToken, &pFoundModule, &typeDefToken)) + { + return FALSE; + } - pModule2 = pFoundModule2; - tk2 = foundToken2; + DWORD attr; + mdToken parentTypeDefOrRefOrSpecToken; + IfFailThrow(pFoundModule->GetMDImport()->GetTypeDefProps(typeDefToken, &attr, &parentTypeDefOrRefOrSpecToken)); - DWORD attr; - mdToken tkTypeParent; - IfFailThrow(pModule2->GetMDImport()->GetTypeDefProps(tk2, &attr, &tkTypeParent)); + // Check the validity of the parent type token if this is a signature of a derived type. + if(!isBaseTypeSig && !pFoundModule->GetMDImport()->IsValidToken(parentTypeDefOrRefOrSpecToken)) + { + return FALSE; + } - if (!pModule2->GetMDImport()->IsValidToken(tkTypeParent)) - break; + // Interfaces not supported with covariant return types + if (IsTdInterface(attr)) + { + return FALSE; + } - // Interfaces not supported with covariant return types. - if (IsTdInterface(attr)) - break; + if (ppTypeDefModule != NULL) + *ppTypeDefModule = pFoundModule; + if (pTypeDefToken != NULL) + *pTypeDefToken = typeDefToken; + if (pParentTypeDefOrRefOrSpecToken != NULL) + *pParentTypeDefOrRefOrSpecToken = parentTypeDefOrRefOrSpecToken; + return TRUE; +} - if (TypeFromToken(tkTypeParent) == mdtTypeSpec) - { - ULONG cbSig; - PCCOR_SIGNATURE pSig; - IfFailThrow(pModule2->GetMDImport()->GetSigFromToken(tkTypeParent, &cbSig, &pSig)); +// static +BOOL MetaSig::ComputeBaseTypeTokenAndModule( + mdToken tk, + Module* pModule, + mdToken* baseTypeDefOrRefToken, + Module** ppBaseTypeTokenModule) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + PRECONDITION(CheckPointer(pModule)); + PRECONDITION(TypeFromToken(tk) == mdtTypeRef || TypeFromToken(tk) == mdtTypeDef); + MODE_ANY; + } + CONTRACTL_END; - PCCOR_SIGNATURE pEndSig = pSig + cbSig; - CorElementType elementType = ELEMENT_TYPE_MAX; + // Ensure we are working with the typedef token + mdToken typeDefToken; + Module* pFoundModule; + if (!ClassLoader::ResolveTokenToTypeDefThrowing(pModule, tk, &pFoundModule, &typeDefToken)) + return FALSE; - IfFailThrow(CorSigUncompressElementType_EndPtr(pSig, pEndSig, &elementType)); - if (elementType == ELEMENT_TYPE_GENERICINST) - { - IfFailThrow(CorSigUncompressElementType_EndPtr(pSig, pEndSig, &elementType)); - } + DWORD attr; + mdToken tkTypeParent; + IfFailThrow(pFoundModule->GetMDImport()->GetTypeDefProps(typeDefToken, &attr, &tkTypeParent)); - if (elementType != ELEMENT_TYPE_CLASS) - { - break; - } + if (!pFoundModule->GetMDImport()->IsValidToken(tkTypeParent)) + return FALSE; - IfFailThrow(CorSigUncompressToken_EndPtr(pSig, pEndSig, &tk2)); - } - else if (TypeFromToken(tkTypeParent) == mdtTypeRef || TypeFromToken(tkTypeParent) == mdtTypeDef) - { - CONSISTENCY_CHECK(tk2 != tkTypeParent); - tk2 = tkTypeParent; - } - else + if (TypeFromToken(tkTypeParent) == mdtTypeSpec) + { + ULONG cbSig; + PCCOR_SIGNATURE pSig; + IfFailThrow(pFoundModule->GetMDImport()->GetSigFromToken(tkTypeParent, &cbSig, &pSig)); + + PCCOR_SIGNATURE pEndSig = pSig + cbSig; + CorElementType elementType = ELEMENT_TYPE_MAX; + + IfFailThrow(CorSigUncompressElementType_EndPtr(pSig, pEndSig, &elementType)); + if (elementType == ELEMENT_TYPE_GENERICINST) { - break; + IfFailThrow(CorSigUncompressElementType_EndPtr(pSig, pEndSig, &elementType)); } + + if (elementType != ELEMENT_TYPE_CLASS) + return FALSE; + + IfFailThrow(CorSigUncompressToken_EndPtr(pSig, pEndSig, baseTypeDefOrRefToken)); + *ppBaseTypeTokenModule = pFoundModule; + return TRUE; + } + else if (TypeFromToken(tkTypeParent) == mdtTypeRef || TypeFromToken(tkTypeParent) == mdtTypeDef) + { + *baseTypeDefOrRefToken = tkTypeParent; + *ppBaseTypeTokenModule = pFoundModule; + return TRUE; } return FALSE; @@ -3704,66 +3753,35 @@ BOOL MetaSig::GetParentSignatureAndSubstitution( } CONTRACTL_END; - CorElementType elementType = ELEMENT_TYPE_MAX; - - IfFailThrow(CorSigUncompressElementType_EndPtr(pSig, pEndSig, &elementType)); - - if (elementType == ELEMENT_TYPE_GENERICINST) - { - IfFailThrow(CorSigUncompressElementType_EndPtr(pSig, pEndSig, &elementType)); - } - - // Getting the parent siganture is only applicable to classes, so exclude anything else - if (elementType != ELEMENT_TYPE_CLASS) - { - return FALSE; - } - - mdToken typeRefOrDefToken; - IfFailThrow(CorSigUncompressToken_EndPtr(pSig, pEndSig, &typeRefOrDefToken)); - - // Ensure we are working with the typedef token mdToken typeDefToken; - Module* pFoundModule; - if (!ClassLoader::ResolveTokenToTypeDefThrowing(pModule, typeRefOrDefToken, &pFoundModule, &typeDefToken)) - return FALSE; - - DWORD attr; - mdToken parentTypeDefOrRefToken; - IfFailThrow(pFoundModule->GetMDImport()->GetTypeDefProps(typeDefToken, &attr, &parentTypeDefOrRefToken)); - - if (!pFoundModule->GetMDImport()->IsValidToken(parentTypeDefOrRefToken)) + mdToken parentTypeDefOrRefOrSpecToken; + Module* pTypeDefModule; + if (!IsTypeSignatureEligibleForCovariantReturnType(pSig, pEndSig, pModule, FALSE, &typeDefToken, &pTypeDefModule, &parentTypeDefOrRefOrSpecToken)) { return FALSE; } - if (IsTdInterface(attr)) - { - // Interfaces not supported with covariant return types - return FALSE; - } - // We load the uninstantiated type here, and we will also return back a valid substitution // for the caller to use (when applicable) - if (TypeFromToken(parentTypeDefOrRefToken) == mdtTypeSpec) + if (TypeFromToken(parentTypeDefOrRefOrSpecToken) == mdtTypeSpec) { ULONG cbParentTypeSig; PCCOR_SIGNATURE pParentTypeSig; - IfFailThrow(pFoundModule->GetMDImport()->GetSigFromToken(parentTypeDefOrRefToken, &cbParentTypeSig, &pParentTypeSig)); + IfFailThrow(pTypeDefModule->GetMDImport()->GetSigFromToken(parentTypeDefOrRefOrSpecToken, &cbParentTypeSig, &pParentTypeSig)); parentTypeSig.AppendSignature(pParentTypeSig, pParentTypeSig + cbParentTypeSig); - parentTypeSubst = Substitution(parentTypeDefOrRefToken, pFoundModule, pSubst); - *ppParentTypeModule = pFoundModule; + parentTypeSubst = Substitution(parentTypeDefOrRefOrSpecToken, pTypeDefModule, pSubst); + *ppParentTypeModule = pTypeDefModule; } - else if (TypeFromToken(parentTypeDefOrRefToken) == mdtTypeDef || TypeFromToken(parentTypeDefOrRefToken) == mdtTypeRef) + else if (TypeFromToken(parentTypeDefOrRefOrSpecToken) == mdtTypeDef || TypeFromToken(parentTypeDefOrRefOrSpecToken) == mdtTypeRef) { // We need to special case type System.Object since it has its own element type. We don't need to do the same for type String // because it's a sealed type, and no other class can derive from it. Module* pParentModule; mdTypeDef parentTypeDefToken; - BOOL resolvedToken = ClassLoader::ResolveTokenToTypeDefThrowing(pFoundModule, parentTypeDefOrRefToken, &pParentModule, &parentTypeDefToken); + BOOL resolvedToken = ClassLoader::ResolveTokenToTypeDefThrowing(pTypeDefModule, parentTypeDefOrRefOrSpecToken, &pParentModule, &parentTypeDefToken); if (resolvedToken && pParentModule == g_pObjectClass->GetModule() && parentTypeDefToken == g_pObjectClass->GetCl()) { @@ -3772,11 +3790,11 @@ BOOL MetaSig::GetParentSignatureAndSubstitution( else { parentTypeSig.AppendElementType(ELEMENT_TYPE_CLASS); - parentTypeSig.AppendToken(parentTypeDefOrRefToken); + parentTypeSig.AppendToken(parentTypeDefOrRefOrSpecToken); } parentTypeSubst = pSubst == NULL ? Substitution() : Substitution(*pSubst); - *ppParentTypeModule = pFoundModule; + *ppParentTypeModule = pTypeDefModule; } else { @@ -3999,8 +4017,14 @@ MetaSig::CompareElementType( } else { - if (allowDerivedClass && (Type1 == ELEMENT_TYPE_OBJECT || Type1 == ELEMENT_TYPE_CLASS || Type1 == ELEMENT_TYPE_GENERICINST)) + if (allowDerivedClass) { + // Quick check of Type1 for eligibility before starting to traverse base type chain in Type2 + if (!IsTypeSignatureEligibleForCovariantReturnType(pSig1Start, pEndSig1, pModule1, TRUE)) + { + return FALSE; + } + // Obvious case: string derives from object. if (Type1 == ELEMENT_TYPE_OBJECT && Type2 == ELEMENT_TYPE_STRING) { @@ -4016,8 +4040,22 @@ MetaSig::CompareElementType( PCCOR_SIGNATURE pParentTypeSig = (PCCOR_SIGNATURE)parentTypeSigBuilder.GetSignature(&cbParentTypeSig); PCCOR_SIGNATURE pParentTypeSigEnd = pParentTypeSig + cbParentTypeSig; + // + // Given that we're going to restart the current type comparaison between Type1 and the base type of Type2, and + // given that the signature pointers for both types are passed by reference to get updated during each call to + // CompareElementType(), we need to make some adjustments to the two signature pointers: + // 1) We need to reset pSig1 to the begining of the current signature of Type1 to compare it with the newly + // computed basetype signature. + // 2) Given that we will be using the base type signature as Type2, we also need to skip one element from the + // original signature for Type2. + // + SigParser parser = SigParser(pSig2Start); + IfFailThrow(parser.SkipExactlyOne()); + pSig1 = pSig1Start; + pSig2 = parser.GetPtr(); + return CompareElementType( - pSig1Start, + pSig1, pParentTypeSig, pEndSig1, pParentTypeSigEnd, @@ -4136,45 +4174,64 @@ MetaSig::CompareElementType( if (allowDerivedClass && Type1 == ELEMENT_TYPE_CLASS) { - // We load the uninstantiated types and check if type2 derives from type1. - // Note that if both Type1 is a generic type, we cannot check for equality here because - // we need to properly keep track of substitutions. + // + // We need to check if Type2 derives from Type1. Note that if Type1 is a generic type, + // we cannot check for inheritance here because we need to properly keep track of substitutions. + // // Here's an example: // class Class0 { } // class Class1 : Class0 { } - // class Class2 : class Class1 { } - // class Class3 : class Class2 { } + // class Class2 : Class1 { } + // class Class3 : Class2 { } // class Class4 : Class3{ } // - // In that example, simply loading the TypeHandles for Class0 and Class4, and traversing the - // parent chain of Class4, we will not end up with a TypeHandle that will be equal to Class0, and - // this is because TypeHandle of Class0 in the parent chain of Class4 is expressed in terms of the - // generic instantiation arguments in the substitutions: + // Here, we need to check if Class4 derives from Class0 + // + // In that example, if we just look at the typedef tokens for Class0 and Class4, and traverse the + // parent chain of Class4 to check if it derives from Class0, we would be always returning true, which + // is wrong (ex: if Class2 was declared as 'Class2 : Class1', then Class4 would be + // deriving from Class0, and not from Class0. + // + // Therefore, we need to keep track of the substitutions: // A -> ARG1 -> T -> int32 // b -> ARG2 -> int16 // // To handle that case, we compute the parent *AND* substitution chain of type2, and recompare that with // type1 starting from the ELEMENT_TYPE_GENERICINST (see how ELEMENT_TYPE_GENERICINST is handled a few // lines below). + // - mdToken foundToken1; - Module* pFoundModule1; - if (!ClassLoader::ResolveTokenToTypeDefThrowing(pModule1, tk1, &pFoundModule1, &foundToken1)) - return FALSE; + // First, check if Type1 is eligible for covariant returns - DWORD attr; - IfFailThrow(pFoundModule1->GetMDImport()->GetTypeDefProps(foundToken1, &attr, NULL)); - if (IsTdInterface(attr)) + mdToken typeDefToken1; + Module* pTypeDefModule1; + if (!IsTypeSignatureEligibleForCovariantReturnType(pSig1Start, pEndSig1, pModule1, TRUE, &typeDefToken1, &pTypeDefModule1)) { - // Interfaces are not currently supported in the derived type checking return FALSE; } + // Second, check if Type1 is generic. If so, we'll return FALSE here, and have that handled under ELEMENT_TYPE_GENERICINST + HENUMInternal hEnumGenericPars; - IfFailThrow(pFoundModule1->GetMDImport()->EnumInit(mdtGenericParam, foundToken1, &hEnumGenericPars)); - if (pFoundModule1->GetMDImport()->EnumGetCount(&hEnumGenericPars) == 0) + IfFailThrow(pTypeDefModule1->GetMDImport()->EnumInit(mdtGenericParam, typeDefToken1, &hEnumGenericPars)); + if (pTypeDefModule1->GetMDImport()->EnumGetCount(&hEnumGenericPars) != 0) { - return CompareTypeTokensForEqualityOrInheritance(foundToken1, pFoundModule1, tk2, pModule2); + return FALSE; + } + + // Finally, walk the base type chain of Type2 to check if it derives from Type1. At this point, we don't need to + // worry about generic substitutions because we know that Type1 is non-generic. + + mdToken baseType2Token; + Module* pBaseType2Module; + while (ComputeBaseTypeTokenAndModule(tk2, pModule2, &baseType2Token, &pBaseType2Module) && !(baseType2Token == tk2 && pBaseType2Module == pModule2)) + { + tk2 = baseType2Token; + pModule2 = pBaseType2Module; + if (CompareTypeTokens(tk1, tk2, pModule1, pModule2, pVisited)) + { + return TRUE; + } } } @@ -4258,31 +4315,12 @@ MetaSig::CompareElementType( { if (allowDerivedClass) { - CorElementType elementType; - IfFailThrow(CorSigUncompressElementType_EndPtr(pCurSig1, pEndSig1, &elementType)); - if (elementType != ELEMENT_TYPE_CLASS) + // Quick check of Type1 for eligibility before starting to traverse base type chain in Type2 + if (!IsTypeSignatureEligibleForCovariantReturnType(pSig1Start, pEndSig1, pModule1, TRUE)) { - // No point in checking anything other than ELEMENT_TYPE_CLASS for type inheritance return FALSE; } - // Interfaces are not currently supported for derived type checking - { - mdToken tk1; - mdToken foundToken1; - Module* pFoundModule1; - IfFailThrow(CorSigUncompressToken_EndPtr(pCurSig1, pEndSig1, &tk1)); - if (!ClassLoader::ResolveTokenToTypeDefThrowing(pModule1, tk1, &pFoundModule1, &foundToken1)) - { - return FALSE; - } - - DWORD attr; - IfFailThrow(pFoundModule1->GetMDImport()->GetTypeDefProps(foundToken1, &attr, NULL)); - if (IsTdInterface(attr)) - return FALSE; - } - Module* pParentTypeModule; Substitution parentTypeSubst; SigBuilder parentTypeSigBuilder; @@ -4292,8 +4330,22 @@ MetaSig::CompareElementType( PCCOR_SIGNATURE pParentTypeSig = (PCCOR_SIGNATURE)parentTypeSigBuilder.GetSignature(&cbParentTypeSig); PCCOR_SIGNATURE pParentTypeSigEnd = pParentTypeSig + cbParentTypeSig; + // + // Given that we're going to restart the current type comparaison between Type1 and the base type of Type2, and + // given that the signature pointers for both types are passed by reference to get updated during each call to + // CompareElementType(), we need to make some adjustments to the two signature pointers: + // 1) We need to reset pSig1 to the begining of the current signature of Type1 to compare it with the newly + // computed basetype signature. + // 2) Given that we will be using the base type signature as Type2, we also need to skip one element from the + // original signature for Type2. + // + SigParser parser = SigParser(pSig2Start); + IfFailThrow(parser.SkipExactlyOne()); + pSig1 = pSig1Start; + pSig2 = parser.GetPtr(); + return CompareElementType( - pSig1Start, + pSig1, pParentTypeSig, pEndSig1, pParentTypeSigEnd, diff --git a/src/coreclr/src/vm/siginfo.hpp b/src/coreclr/src/vm/siginfo.hpp index 35b273afdab35c..c2d9912ebb3fd1 100644 --- a/src/coreclr/src/vm/siginfo.hpp +++ b/src/coreclr/src/vm/siginfo.hpp @@ -975,9 +975,23 @@ class MetaSig // for covariant return types on MethodImpls. static BOOL CompareTypeHandles(TypeHandle hType1, TypeHandle hType2, BOOL allowDerivedClass); - // Compare two type tokens and check if they are equal, or if the second type token is a - // derived type of the first type token - static BOOL CompareTypeTokensForEqualityOrInheritance(mdToken tk1, Module* pModule1, mdToken tk2, Module* pModule2); + // Check if a type signature is eligible for covariant return types. + static BOOL IsTypeSignatureEligibleForCovariantReturnType( + PCCOR_SIGNATURE pSig, + PCCOR_SIGNATURE pEndSig, + Module* pModule, + BOOL isBaseTypeSig, + mdToken* pTypeDefToken = NULL, + Module** ppTypeDefModule = NULL, + mdToken* pParentTypeDefOrRefOrSpecToken = NULL); + + // Compute the base type token (it will either be a typedef or typeref token), and returns the + // module where that base type token is declared. + static BOOL ComputeBaseTypeTokenAndModule( + mdToken tk, + Module* pModule, + mdToken* baseTypeDefOrRefToken, + Module** ppBaseTypeTokenModule); // Extract the parent type's signature and stubstitution from the input type signature static BOOL GetParentSignatureAndSubstitution( From df8219e663e49fed2666d32aaf287b84189f95e2 Mon Sep 17 00:00:00 2001 From: Fadi Hanna Date: Tue, 31 Mar 2020 10:41:50 -0700 Subject: [PATCH 05/13] Add some unit tests --- .../InterfaceReturns/InterfaceReturns.il | 311 ++++++++++++++ .../InterfaceReturns/InterfaceReturns.ilproj | 10 + .../InterfaceReturns/InterfaceReturns2.il | 271 ++++++++++++ .../InterfaceReturns/InterfaceReturns2.ilproj | 10 + .../InterfaceReturns/InterfaceReturns3.il | 272 ++++++++++++ .../InterfaceReturns/InterfaceReturns3.ilproj | 10 + .../InterfaceReturns/InterfaceReturns4.il | 272 ++++++++++++ .../InterfaceReturns/InterfaceReturns4.ilproj | 10 + .../StructReturns/StructReturns.il | 276 +++++++++++++ .../StructReturns/StructReturns.ilproj | 10 + .../StructReturns/StructReturns2.il | 276 +++++++++++++ .../StructReturns/StructReturns2.ilproj | 10 + .../CovariantReturns/UnitTest/Modules/A.il | 9 + .../UnitTest/Modules/A.ilproj | 11 + .../CovariantReturns/UnitTest/Modules/B.il | 10 + .../UnitTest/Modules/B.ilproj | 11 + .../CovariantReturns/UnitTest/Modules/C.il | 10 + .../UnitTest/Modules/C.ilproj | 11 + .../UnitTest/Modules/Dictionary.il | 9 + .../UnitTest/Modules/Dictionary.ilproj | 11 + .../UnitTest/Modules/GenBaseType.il | 80 ++++ .../UnitTest/Modules/GenBaseType.ilproj | 11 + .../UnitTest/Modules/GenDerive1.il | 10 + .../UnitTest/Modules/GenDerive1.ilproj | 11 + .../UnitTest/Modules/GenDerive2.il | 11 + .../UnitTest/Modules/GenDerive2.ilproj | 11 + .../UnitTest/Modules/GenDerive3.il | 11 + .../UnitTest/Modules/GenDerive3.ilproj | 11 + .../UnitTest/Modules/GenRetType.il | 9 + .../UnitTest/Modules/GenRetType.ilproj | 11 + .../UnitTest/Modules/GenTestType.il | 101 +++++ .../UnitTest/Modules/GenTestType.ilproj | 11 + .../UnitTest/Modules/GenToNonGen1.il | 10 + .../UnitTest/Modules/GenToNonGen1.ilproj | 11 + .../UnitTest/Modules/GenToNonGen2.il | 11 + .../UnitTest/Modules/GenToNonGen2.ilproj | 11 + .../UnitTest/Modules/GenToNonGen3.il | 12 + .../UnitTest/Modules/GenToNonGen3.ilproj | 11 + .../UnitTest/Modules/NonGenThroughGen1.il | 9 + .../UnitTest/Modules/NonGenThroughGen1.ilproj | 11 + .../UnitTest/Modules/NonGenThroughGen2.il | 11 + .../UnitTest/Modules/NonGenThroughGen2.ilproj | 11 + .../UnitTest/Modules/NonGenThroughGen3.il | 10 + .../UnitTest/Modules/NonGenThroughGen3.ilproj | 11 + .../UnitTest/Modules/NonGenThroughGen4.il | 9 + .../UnitTest/Modules/NonGenThroughGen4.ilproj | 11 + .../UnitTest/Modules/NonGenericDerived1.il | 10 + .../Modules/NonGenericDerived1.ilproj | 11 + .../UnitTest/Modules/NonGenericDerived2.il | 10 + .../Modules/NonGenericDerived2.ilproj | 11 + .../UnitTest/Modules/NonGenericDerived3.il | 9 + .../Modules/NonGenericDerived3.ilproj | 11 + .../UnitTest/Modules/NonGenericDerived4.il | 9 + .../Modules/NonGenericDerived4.ilproj | 11 + .../CovariantReturns/UnitTest/UnitTest.il | 389 ++++++++++++++++++ .../CovariantReturns/UnitTest/UnitTest.ilproj | 10 + .../UnitTest/UnitTestMultiModule.il | 245 +++++++++++ .../UnitTest/UnitTestMultiModule.ilproj | 35 ++ 58 files changed, 3018 insertions(+) create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns2.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns2.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns3.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns3.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns4.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns4.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns2.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns2.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/A.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/A.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/B.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/B.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/C.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/C.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/Dictionary.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/Dictionary.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenBaseType.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenBaseType.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive1.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive1.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive2.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive2.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive3.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive3.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenRetType.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenRetType.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenTestType.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenTestType.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen1.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen1.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen2.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen2.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen3.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen3.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen1.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen1.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen2.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen2.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen3.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen3.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen4.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen4.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived1.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived1.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived2.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived2.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived3.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived3.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived4.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived4.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestMultiModule.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestMultiModule.ilproj diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns.il new file mode 100644 index 00000000000000..53e63da6764013 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns.il @@ -0,0 +1,311 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib { } +.assembly InterfaceReturns { } + +.class interface public auto ansi abstract IA { } +.class interface public auto ansi abstract IB implements IA { } +.class interface public auto ansi abstract IC implements IB { } +.class interface public auto ansi abstract IGenRetType { } + +.class public auto ansi beforefieldinit Dictionary { } + +.class public auto ansi beforefieldinit GenDerive1 implements class IGenRetType { } +.class public auto ansi beforefieldinit GenDerive2 extends class GenDerive1> { } +.class public auto ansi beforefieldinit GenDerive3 extends class GenDerive2 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 implements class IGenRetType { } +.class public auto ansi beforefieldinit NonGenericDerived2 extends class NonGenericDerived1 { } +.class public auto ansi beforefieldinit NonGenericDerived3 extends class NonGenericDerived2 { } +.class public auto ansi beforefieldinit NonGenericDerived4 extends NonGenericDerived3 { } + +.class public auto ansi beforefieldinit GenToNonGen1 implements IC { } +.class public auto ansi beforefieldinit GenToNonGen2 extends class GenToNonGen1> { } +.class public auto ansi beforefieldinit GenToNonGen3 extends class GenToNonGen2 { } + +.class public auto ansi beforefieldinit NonGenThroughGen1 implements class IC { } +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class NonGenThroughGen1> { } +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class NonGenThroughGen2 { } +.class public auto ansi beforefieldinit NonGenThroughGen4 extends NonGenThroughGen3 { } + +.class public auto ansi beforefieldinit BaseTest +{ + .method public hidebysig newslot virtual instance object MyFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class IB MyFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class IB GenToNonGenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class IB NonGenThroughGenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class IGenRetType GenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class IGenRetType> GenFunc() + { + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test1 extends class BaseTest +{ + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenOverride() + { + .override method instance class IB class BaseTest::NonGenThroughGenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test2 extends class BaseTest +{ + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenOverride() + { + .override method instance class IB class BaseTest::GenToNonGenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test3 extends class BaseTest +{ + .method public hidebysig newslot virtual instance class NonGenericDerived4 NewGenFunc1() + { + .override method instance class IGenRetType class BaseTest::GenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test4 extends class BaseTest +{ + .method public hidebysig newslot virtual instance class GenDerive3 NewGenFunc2() + { + .override method instance class IGenRetType> class BaseTest::GenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test5 extends class BaseTest +{ + .method public hidebysig newslot virtual instance class IGenRetType NewFunc1() + { + .override method instance object class BaseTest::MyFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test6 extends class BaseTest +{ + .method public hidebysig newslot virtual instance class IC NewFunc2() + { + .override method instance class IB class BaseTest::MyFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + .method public static void RunTest1() noinlining + { + newobj instance void class Test1::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest2() noinlining + { + newobj instance void class Test2::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest3() noinlining + { + newobj instance void class Test3::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest4() noinlining + { + newobj instance void class Test4::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest5() noinlining + { + newobj instance void class Test5::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest6() noinlining + { + newobj instance void class Test6::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init (bool V_0) + ldc.i4.1 + stloc.0 + + T1: + .try + { + call void CMain::RunTest1() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test1." + call void [System.Console]System.Console::WriteLine(string) + leave.s T2 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T2 + } + + T2: + .try + { + call void CMain::RunTest2() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test2." + call void [System.Console]System.Console::WriteLine(string) + leave.s T3 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T3 + } + + T3: + .try + { + call void CMain::RunTest3() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test3." + call void [System.Console]System.Console::WriteLine(string) + leave.s T4 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T4 + } + + T4: + .try + { + call void CMain::RunTest4() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test4." + call void [System.Console]System.Console::WriteLine(string) + leave.s T5 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T5 + } + + T5: + .try + { + call void CMain::RunTest5() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test5." + call void [System.Console]System.Console::WriteLine(string) + leave.s T6 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T6 + } + + T6: + .try + { + call void CMain::RunTest6() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test6." + call void [System.Console]System.Console::WriteLine(string) + leave.s DONE + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s DONE + } + + DONE: + + ldloc.0 + brtrue.s PASS + + ldc.i4.s 101 + ret + + PASS: + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + } + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method CMain::.ctor + +} // end of class CMain diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns.ilproj new file mode 100644 index 00000000000000..d7bdba968e9fc5 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns.ilproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns2.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns2.il new file mode 100644 index 00000000000000..18615637fa3146 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns2.il @@ -0,0 +1,271 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib { } +.assembly InterfaceReturns { } + +.class interface public auto ansi abstract IA { } +.class interface public auto ansi abstract IB implements IA { } +.class interface public auto ansi abstract IC implements IB { } +.class interface public auto ansi abstract IGenRetType { } + +.class public auto ansi beforefieldinit Dictionary { } + +.class public auto ansi beforefieldinit GenDerive1 implements class IGenRetType { } +.class public auto ansi beforefieldinit GenDerive2 extends class GenDerive1> { } +.class public auto ansi beforefieldinit GenDerive3 extends class GenDerive2 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 implements class IGenRetType { } +.class public auto ansi beforefieldinit NonGenericDerived2 extends class NonGenericDerived1 { } +.class public auto ansi beforefieldinit NonGenericDerived3 extends class NonGenericDerived2 { } +.class public auto ansi beforefieldinit NonGenericDerived4 extends NonGenericDerived3 { } + +.class public auto ansi beforefieldinit GenToNonGen1 implements IC { } +.class public auto ansi beforefieldinit GenToNonGen2 extends class GenToNonGen1> { } +.class public auto ansi beforefieldinit GenToNonGen3 extends class GenToNonGen2 { } + +.class public auto ansi beforefieldinit NonGenThroughGen1 implements class IC { } +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class NonGenThroughGen1> { } +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class NonGenThroughGen2 { } +.class public auto ansi beforefieldinit NonGenThroughGen4 extends NonGenThroughGen3 { } + +.class public auto ansi beforefieldinit BaseTest +{ + .method public hidebysig newslot virtual instance class IGenRetType MyFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class NonGenericDerived4 GenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class GenDerive3 GenFunc() + { + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test1 extends class BaseTest +{ + .method public hidebysig newslot virtual instance class IB NonGenThroughGenOverride() + { + .override method instance class NonGenThroughGen4 class BaseTest::NonGenThroughGenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test2 extends class BaseTest +{ + .method public hidebysig newslot virtual instance class IB GenToNonGenOverride() + { + .override method instance class GenToNonGen3 class BaseTest::GenToNonGenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test3 extends class BaseTest +{ + .method public hidebysig newslot virtual instance class IGenRetType NewGenFunc1() + { + .override method instance class NonGenericDerived4 class BaseTest::GenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test4 extends class BaseTest +{ + .method public hidebysig newslot virtual instance class IGenRetType> NewGenFunc2() + { + .override method instance class GenDerive3 class BaseTest::GenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test5 extends class BaseTest +{ + .method public hidebysig newslot virtual instance object NewFunc1() + { + .override method instance class IGenRetType class BaseTest::MyFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + .method public static void RunTest1() noinlining + { + newobj instance void class Test1::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest2() noinlining + { + newobj instance void class Test2::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest3() noinlining + { + newobj instance void class Test3::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest4() noinlining + { + newobj instance void class Test4::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest5() noinlining + { + newobj instance void class Test5::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init (bool V_0) + ldc.i4.1 + stloc.0 + + T1: + .try + { + call void CMain::RunTest1() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test1." + call void [System.Console]System.Console::WriteLine(string) + leave.s T2 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T2 + } + + T2: + .try + { + call void CMain::RunTest2() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test2." + call void [System.Console]System.Console::WriteLine(string) + leave.s T3 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T3 + } + + T3: + .try + { + call void CMain::RunTest3() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test3." + call void [System.Console]System.Console::WriteLine(string) + leave.s T4 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T4 + } + + T4: + .try + { + call void CMain::RunTest4() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test4." + call void [System.Console]System.Console::WriteLine(string) + leave.s T5 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T5 + } + + T5: + .try + { + call void CMain::RunTest5() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test5." + call void [System.Console]System.Console::WriteLine(string) + leave.s DONE + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s DONE + } + + DONE: + + ldloc.0 + brtrue.s PASS + + ldc.i4.s 101 + ret + + PASS: + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + } + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method CMain::.ctor + +} // end of class CMain diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns2.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns2.ilproj new file mode 100644 index 00000000000000..8516b81f94df5d --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns2.ilproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns3.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns3.il new file mode 100644 index 00000000000000..ad95ca3cdc85af --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns3.il @@ -0,0 +1,272 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib { } +.assembly InterfaceReturns { } + +.class public auto ansi beforefieldinit A { } +.class public auto ansi beforefieldinit B extends A { } +.class public auto ansi beforefieldinit C extends B { } + +.class public auto ansi beforefieldinit GenRetType { } + +.class public auto ansi beforefieldinit Dictionary { } + +.class public auto ansi beforefieldinit GenDerive1 extends class GenRetType { } +.class public auto ansi beforefieldinit GenDerive2 extends class GenDerive1> { } +.class public auto ansi beforefieldinit GenDerive3 extends class GenDerive2 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 extends class GenRetType { } +.class public auto ansi beforefieldinit NonGenericDerived2 extends class NonGenericDerived1 { } +.class public auto ansi beforefieldinit NonGenericDerived3 extends class NonGenericDerived2 { } +.class public auto ansi beforefieldinit NonGenericDerived4 extends NonGenericDerived3 { } + +.class public auto ansi beforefieldinit GenToNonGen1 extends C { } +.class public auto ansi beforefieldinit GenToNonGen2 extends class GenToNonGen1> { } +.class public auto ansi beforefieldinit GenToNonGen3 extends class GenToNonGen2 { } + +.class public auto ansi beforefieldinit NonGenThroughGen1 extends class C { } +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class NonGenThroughGen1> { } +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class NonGenThroughGen2 { } +.class public auto ansi beforefieldinit NonGenThroughGen4 extends NonGenThroughGen3 { } + +.class interface public auto ansi abstract BaseTest +{ + .method public hidebysig newslot virtual instance class GenRetType MyFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class NonGenericDerived4 GenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class GenDerive3 GenFunc() + { + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test1 implements class BaseTest +{ + .method public hidebysig newslot virtual instance class B NonGenThroughGenOverride() + { + .override method instance class NonGenThroughGen4 class BaseTest::NonGenThroughGenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test2 implements class BaseTest +{ + .method public hidebysig newslot virtual instance class B GenToNonGenOverride() + { + .override method instance class GenToNonGen3 class BaseTest::GenToNonGenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test3 implements class BaseTest +{ + .method public hidebysig newslot virtual instance class GenRetType NewGenFunc1() + { + .override method instance class NonGenericDerived4 class BaseTest::GenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test4 implements class BaseTest +{ + .method public hidebysig newslot virtual instance class GenRetType> NewGenFunc2() + { + .override method instance class GenDerive3 class BaseTest::GenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test5 implements class BaseTest +{ + .method public hidebysig newslot virtual instance object NewFunc1() + { + .override method instance class GenRetType class BaseTest::MyFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + .method public static void RunTest1() noinlining + { + newobj instance void class Test1::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest2() noinlining + { + newobj instance void class Test2::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest3() noinlining + { + newobj instance void class Test3::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest4() noinlining + { + newobj instance void class Test4::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest5() noinlining + { + newobj instance void class Test5::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init (bool V_0) + ldc.i4.1 + stloc.0 + + T1: + .try + { + call void CMain::RunTest1() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test1." + call void [System.Console]System.Console::WriteLine(string) + leave.s T2 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T2 + } + + T2: + .try + { + call void CMain::RunTest2() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test2." + call void [System.Console]System.Console::WriteLine(string) + leave.s T3 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T3 + } + + T3: + .try + { + call void CMain::RunTest3() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test3." + call void [System.Console]System.Console::WriteLine(string) + leave.s T4 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T4 + } + + T4: + .try + { + call void CMain::RunTest4() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test4." + call void [System.Console]System.Console::WriteLine(string) + leave.s T5 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T5 + } + + T5: + .try + { + call void CMain::RunTest5() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test5." + call void [System.Console]System.Console::WriteLine(string) + leave.s DONE + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s DONE + } + + DONE: + + ldloc.0 + brtrue.s PASS + + ldc.i4.s 101 + ret + + PASS: + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + } + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method CMain::.ctor + +} // end of class CMain diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns3.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns3.ilproj new file mode 100644 index 00000000000000..3a29ebd99e0676 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns3.ilproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns4.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns4.il new file mode 100644 index 00000000000000..9b1e3358af1efd --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns4.il @@ -0,0 +1,272 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib { } +.assembly InterfaceReturns { } + +.class public auto ansi beforefieldinit A { } +.class public auto ansi beforefieldinit B extends A { } +.class public auto ansi beforefieldinit C extends B { } + +.class public auto ansi beforefieldinit GenRetType { } + +.class public auto ansi beforefieldinit Dictionary { } + +.class public auto ansi beforefieldinit GenDerive1 extends class GenRetType { } +.class public auto ansi beforefieldinit GenDerive2 extends class GenDerive1> { } +.class public auto ansi beforefieldinit GenDerive3 extends class GenDerive2 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 extends class GenRetType { } +.class public auto ansi beforefieldinit NonGenericDerived2 extends class NonGenericDerived1 { } +.class public auto ansi beforefieldinit NonGenericDerived3 extends class NonGenericDerived2 { } +.class public auto ansi beforefieldinit NonGenericDerived4 extends NonGenericDerived3 { } + +.class public auto ansi beforefieldinit GenToNonGen1 extends C { } +.class public auto ansi beforefieldinit GenToNonGen2 extends class GenToNonGen1> { } +.class public auto ansi beforefieldinit GenToNonGen3 extends class GenToNonGen2 { } + +.class public auto ansi beforefieldinit NonGenThroughGen1 extends class C { } +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class NonGenThroughGen1> { } +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class NonGenThroughGen2 { } +.class public auto ansi beforefieldinit NonGenThroughGen4 extends NonGenThroughGen3 { } + +.class interface public auto ansi abstract BaseTest +{ + .method public hidebysig newslot virtual instance class GenRetType MyFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class NonGenericDerived4 GenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class GenDerive3 GenFunc() + { + ldnull + ret + } +} + +.class interface public auto ansi abstract Test1 implements class BaseTest +{ + .method public hidebysig newslot virtual instance class B NonGenThroughGenOverride() + { + .override method instance class NonGenThroughGen4 class BaseTest::NonGenThroughGenFunc() + ldnull + ret + } +} + +.class interface public auto ansi abstract Test2 implements class BaseTest +{ + .method public hidebysig newslot virtual instance class B GenToNonGenOverride() + { + .override method instance class GenToNonGen3 class BaseTest::GenToNonGenFunc() + ldnull + ret + } +} + +.class interface public auto ansi abstract Test3 implements class BaseTest +{ + .method public hidebysig newslot virtual instance class GenRetType NewGenFunc1() + { + .override method instance class NonGenericDerived4 class BaseTest::GenFunc() + ldnull + ret + } +} + +.class interface public auto ansi abstract Test4 implements class BaseTest +{ + .method public hidebysig newslot virtual instance class GenRetType> NewGenFunc2() + { + .override method instance class GenDerive3 class BaseTest::GenFunc() + ldnull + ret + } +} + +.class interface public auto ansi abstract Test5 implements class BaseTest +{ + .method public hidebysig newslot virtual instance object NewFunc1() + { + .override method instance class GenRetType class BaseTest::MyFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + .method public static void RunTest1() noinlining + { + newobj instance void class Test1::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest2() noinlining + { + newobj instance void class Test2::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest3() noinlining + { + newobj instance void class Test3::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest4() noinlining + { + newobj instance void class Test4::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest5() noinlining + { + newobj instance void class Test5::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init (bool V_0) + ldc.i4.1 + stloc.0 + + T1: + .try + { + call void CMain::RunTest1() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test1." + call void [System.Console]System.Console::WriteLine(string) + leave.s T2 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T2 + } + + T2: + .try + { + call void CMain::RunTest2() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test2." + call void [System.Console]System.Console::WriteLine(string) + leave.s T3 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T3 + } + + T3: + .try + { + call void CMain::RunTest3() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test3." + call void [System.Console]System.Console::WriteLine(string) + leave.s T4 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T4 + } + + T4: + .try + { + call void CMain::RunTest4() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test4." + call void [System.Console]System.Console::WriteLine(string) + leave.s T5 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T5 + } + + T5: + .try + { + call void CMain::RunTest5() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test5." + call void [System.Console]System.Console::WriteLine(string) + leave.s DONE + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s DONE + } + + DONE: + + ldloc.0 + brtrue.s PASS + + ldc.i4.s 101 + ret + + PASS: + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + } + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method CMain::.ctor + +} // end of class CMain diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns4.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns4.ilproj new file mode 100644 index 00000000000000..70cebeb5c5c015 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/InterfaceReturns/InterfaceReturns4.ilproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns.il new file mode 100644 index 00000000000000..74807f59f14170 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns.il @@ -0,0 +1,276 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib { } +.assembly StructReturns { } + +.class public sealed auto ansi A extends [mscorlib]System.ValueType { } +.class public sealed auto ansi GenStruct extends [mscorlib]System.ValueType { } + + +.class public auto ansi C { } +.class public auto ansi GenRetType { } +.class public auto ansi beforefieldinit Dictionary { } + +.class public auto ansi beforefieldinit GenDerive1 extends class GenRetType { } +.class public auto ansi beforefieldinit GenDerive2 extends class GenDerive1> { } +.class public auto ansi beforefieldinit GenDerive3 extends class GenDerive2 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 extends class GenRetType { } +.class public auto ansi beforefieldinit NonGenericDerived2 extends class NonGenericDerived1 { } +.class public auto ansi beforefieldinit NonGenericDerived3 extends class NonGenericDerived2 { } +.class public auto ansi beforefieldinit NonGenericDerived4 extends NonGenericDerived3 { } + +.class public auto ansi beforefieldinit GenToNonGen1 extends C { } +.class public auto ansi beforefieldinit GenToNonGen2 extends class GenToNonGen1> { } +.class public auto ansi beforefieldinit GenToNonGen3 extends class GenToNonGen2 { } + +.class public auto ansi beforefieldinit NonGenThroughGen1 extends class C { } +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class NonGenThroughGen1> { } +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class NonGenThroughGen2 { } +.class public auto ansi beforefieldinit NonGenThroughGen4 extends NonGenThroughGen3 { } + + +.class public auto ansi beforefieldinit BaseType +{ + .method public hidebysig newslot virtual instance valuetype A MyFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance valuetype A GenToNonGen() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance valuetype A NonGenThroughGenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance valuetype GenStruct MyGenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance valuetype GenStruct> MyGenFunc() + { + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test1 extends class BaseType +{ + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenOverride() + { + .override method instance valuetype A class BaseType::NonGenThroughGenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test2 extends class BaseType +{ + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenOverride() + { + .override method instance valuetype A class BaseType::GenToNonGen() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test3 extends class BaseType +{ + .method public hidebysig newslot virtual instance class NonGenericDerived4 NewGenFunc1() + { + .override method instance valuetype GenStruct class BaseType::MyGenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test4 extends class BaseType +{ + .method public hidebysig newslot virtual instance class GenDerive3 NewGenFunc1() + { + .override method instance valuetype GenStruct> class BaseType::MyGenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test5 extends class BaseType +{ + .method public hidebysig newslot virtual instance class C NewFunc2() + { + .override method instance valuetype A class BaseType::MyFunc() + ldnull + ret + } +} + + + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + .method public static void RunTest1() noinlining + { + newobj instance void class Test1::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest2() noinlining + { + newobj instance void class Test2::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest3() noinlining + { + newobj instance void class Test3::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest4() noinlining + { + newobj instance void class Test4::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest5() noinlining + { + newobj instance void class Test5::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init (bool V_0) + ldc.i4.1 + stloc.0 + + T1: + .try + { + call void CMain::RunTest1() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test1." + call void [System.Console]System.Console::WriteLine(string) + leave.s T2 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T2 + } + + T2: + .try + { + call void CMain::RunTest2() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test2." + call void [System.Console]System.Console::WriteLine(string) + leave.s T3 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T3 + } + + T3: + .try + { + call void CMain::RunTest3() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test3." + call void [System.Console]System.Console::WriteLine(string) + leave.s T4 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T4 + } + + T4: + .try + { + call void CMain::RunTest4() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test4." + call void [System.Console]System.Console::WriteLine(string) + leave.s T5 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T5 + } + + T5: + .try + { + call void CMain::RunTest5() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test5." + call void [System.Console]System.Console::WriteLine(string) + leave.s DONE + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s DONE + } + + DONE: + + ldloc.0 + brtrue.s PASS + + ldc.i4.s 101 + ret + + PASS: + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method CMain::.ctor + +} // end of class CMain diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns.ilproj new file mode 100644 index 00000000000000..19bd401728977b --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns.ilproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns2.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns2.il new file mode 100644 index 00000000000000..bce446c50b2a3a --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns2.il @@ -0,0 +1,276 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib { } +.assembly StructReturns { } + +.class public sealed auto ansi A extends [mscorlib]System.ValueType { } +.class public sealed auto ansi GenStruct extends [mscorlib]System.ValueType { } + + +.class public auto ansi C { } +.class public auto ansi GenRetType { } +.class public auto ansi beforefieldinit Dictionary { } + +.class public auto ansi beforefieldinit GenDerive1 extends class GenRetType { } +.class public auto ansi beforefieldinit GenDerive2 extends class GenDerive1> { } +.class public auto ansi beforefieldinit GenDerive3 extends class GenDerive2 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 extends class GenRetType { } +.class public auto ansi beforefieldinit NonGenericDerived2 extends class NonGenericDerived1 { } +.class public auto ansi beforefieldinit NonGenericDerived3 extends class NonGenericDerived2 { } +.class public auto ansi beforefieldinit NonGenericDerived4 extends NonGenericDerived3 { } + +.class public auto ansi beforefieldinit GenToNonGen1 extends C { } +.class public auto ansi beforefieldinit GenToNonGen2 extends class GenToNonGen1> { } +.class public auto ansi beforefieldinit GenToNonGen3 extends class GenToNonGen2 { } + +.class public auto ansi beforefieldinit NonGenThroughGen1 extends class C { } +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class NonGenThroughGen1> { } +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class NonGenThroughGen2 { } +.class public auto ansi beforefieldinit NonGenThroughGen4 extends NonGenThroughGen3 { } + + +.class public auto ansi beforefieldinit BaseType +{ + .method public hidebysig newslot virtual instance class C MyFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGen() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class NonGenericDerived4 MyGenFunc() + { + ldnull + ret + } + .method public hidebysig newslot virtual instance class GenDerive3 MyGenFunc() + { + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test1 extends class BaseType +{ + .method public hidebysig newslot virtual instance valuetype A NonGenThroughGenOverride() + { + .override method instance class NonGenThroughGen4 class BaseType::NonGenThroughGenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test2 extends class BaseType +{ + .method public hidebysig newslot virtual instance valuetype A GenToNonGenOverride() + { + .override method instance class GenToNonGen3 class BaseType::GenToNonGen() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test3 extends class BaseType +{ + .method public hidebysig newslot virtual instance valuetype GenStruct NewGenFunc1() + { + .override method instance class NonGenericDerived4 class BaseType::MyGenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test4 extends class BaseType +{ + .method public hidebysig newslot virtual instance valuetype GenStruct> NewGenFunc1() + { + .override method instance class GenDerive3 class BaseType::MyGenFunc() + ldnull + ret + } +} + +.class public auto ansi beforefieldinit Test5 extends class BaseType +{ + .method public hidebysig newslot virtual instance valuetype A NewFunc2() + { + .override method instance class C class BaseType::MyFunc() + ldnull + ret + } +} + + + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + .method public static void RunTest1() noinlining + { + newobj instance void class Test1::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest2() noinlining + { + newobj instance void class Test2::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest3() noinlining + { + newobj instance void class Test3::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest4() noinlining + { + newobj instance void class Test4::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest5() noinlining + { + newobj instance void class Test5::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init (bool V_0) + ldc.i4.1 + stloc.0 + + T1: + .try + { + call void CMain::RunTest1() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test1." + call void [System.Console]System.Console::WriteLine(string) + leave.s T2 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T2 + } + + T2: + .try + { + call void CMain::RunTest2() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test2." + call void [System.Console]System.Console::WriteLine(string) + leave.s T3 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T3 + } + + T3: + .try + { + call void CMain::RunTest3() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test3." + call void [System.Console]System.Console::WriteLine(string) + leave.s T4 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T4 + } + + T4: + .try + { + call void CMain::RunTest4() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test4." + call void [System.Console]System.Console::WriteLine(string) + leave.s T5 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T5 + } + + T5: + .try + { + call void CMain::RunTest5() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Test5." + call void [System.Console]System.Console::WriteLine(string) + leave.s DONE + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s DONE + } + + DONE: + + ldloc.0 + brtrue.s PASS + + ldc.i4.s 101 + ret + + PASS: + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method CMain::.ctor + +} // end of class CMain diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns2.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns2.ilproj new file mode 100644 index 00000000000000..4b89683efdc7ba --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/StructReturns/StructReturns2.ilproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/A.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/A.il new file mode 100644 index 00000000000000..0388370550bc28 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/A.il @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} +.assembly A{} + +.class public auto ansi beforefieldinit A { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/A.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/A.ilproj new file mode 100644 index 00000000000000..5709f614f85279 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/A.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/B.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/B.il new file mode 100644 index 00000000000000..3a49d6fd3f9644 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/B.il @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern A{} +.assembly B{} + + +.class public auto ansi beforefieldinit B extends [A]A { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/B.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/B.ilproj new file mode 100644 index 00000000000000..030302f6445ce4 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/B.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/C.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/C.il new file mode 100644 index 00000000000000..ece5321703e258 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/C.il @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} +.assembly extern B{} +.assembly C{} + +.class public auto ansi beforefieldinit C extends [B]B { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/C.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/C.ilproj new file mode 100644 index 00000000000000..fa878a880b4d6e --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/C.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/Dictionary.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/Dictionary.il new file mode 100644 index 00000000000000..f23cc2e3f2e7f7 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/Dictionary.il @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} +.assembly Dictionary{} + +.class public auto ansi beforefieldinit Dictionary { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/Dictionary.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/Dictionary.ilproj new file mode 100644 index 00000000000000..f73733601e918c --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/Dictionary.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenBaseType.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenBaseType.il new file mode 100644 index 00000000000000..7d70bf4fb86135 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenBaseType.il @@ -0,0 +1,80 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib { } +.assembly extern A { } +.assembly extern B { } +.assembly extern GenRetType { } +.assembly extern Dictionary { } + +.assembly GenBaseType { } + +.class public auto ansi beforefieldinit GenBaseType +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + + .method public hidebysig newslot virtual instance object MyFunc(string& res) + { + ldarg.0 + ldstr "object GenBaseType.MyFunc()" + stind.ref + newobj instance void [A]A::.ctor() + ret + } + .method public hidebysig newslot virtual instance class [B]B MyFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.MyFunc()" + stind.ref + newobj instance void [B]B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class [B]B GenToNonGen(string& res) + { + ldarg.0 + ldstr "B GenBaseType.GenToNonGen()" + stind.ref + newobj instance void [B]B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class [B]B NonGenThroughGenFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.NonGenThroughGenFunc()" + stind.ref + newobj instance void [B]B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class [GenRetType]GenRetType MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class [GenRetType]GenRetType::.ctor() + ret + } + .method public hidebysig newslot virtual instance class [GenRetType]GenRetType> MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType> GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class [GenRetType]GenRetType>::.ctor() + ret + } + .method public hidebysig newslot virtual instance class [GenRetType]GenRetType TestNonGenericDerived(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.TestNonGenericDerived()" + stind.ref + newobj instance void class [GenRetType]GenRetType::.ctor() + ret + } +} diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenBaseType.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenBaseType.ilproj new file mode 100644 index 00000000000000..0ba90cee027431 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenBaseType.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive1.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive1.il new file mode 100644 index 00000000000000..9678d6dda30015 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive1.il @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} +.assembly extern GenRetType{} +.assembly GenDerive1{} + +.class public auto ansi beforefieldinit GenDerive1 extends class [GenRetType]GenRetType { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive1.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive1.ilproj new file mode 100644 index 00000000000000..447fae7b5a25e3 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive1.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive2.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive2.il new file mode 100644 index 00000000000000..b50fbfc783ea66 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive2.il @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} +.assembly extern GenDerive1{} +.assembly extern Dictionary{} +.assembly GenDerive2{} + +.class public auto ansi beforefieldinit GenDerive2 extends class [GenDerive1]GenDerive1> { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive2.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive2.ilproj new file mode 100644 index 00000000000000..67c599a2657d44 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive2.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive3.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive3.il new file mode 100644 index 00000000000000..1d531f3f5db3ed --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive3.il @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} +.assembly extern GenDerive2{} +.assembly GenDerive3{} + +.class public auto ansi beforefieldinit GenDerive3 extends class [GenDerive2]GenDerive2 { } + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive3.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive3.ilproj new file mode 100644 index 00000000000000..4cae55804628b4 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenDerive3.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenRetType.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenRetType.il new file mode 100644 index 00000000000000..094a68b83d0fdb --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenRetType.il @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} +.assembly GenRetType{} + +.class public auto ansi beforefieldinit GenRetType { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenRetType.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenRetType.ilproj new file mode 100644 index 00000000000000..c36b5efac15064 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenRetType.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenTestType.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenTestType.il new file mode 100644 index 00000000000000..1ced09374c2564 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenTestType.il @@ -0,0 +1,101 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} + +.assembly extern A { } +.assembly extern B { } +.assembly extern C { } +.assembly extern Dictionary { } +.assembly extern GenRetType { } +.assembly extern GenDerive1 { } +.assembly extern GenDerive2 { } +.assembly extern GenDerive3 { } +.assembly extern NonGenericDerived1 { } +.assembly extern NonGenericDerived2 { } +.assembly extern NonGenericDerived3 { } +.assembly extern NonGenericDerived4 { } +.assembly extern GenToNonGen1 { } +.assembly extern GenToNonGen2 { } +.assembly extern GenToNonGen3 { } +.assembly extern NonGenThroughGen1 { } +.assembly extern NonGenThroughGen2 { } +.assembly extern NonGenThroughGen3 { } +.assembly extern NonGenThroughGen4 { } + +.assembly extern GenBaseType { } + +.assembly GenTestType { } + +.class public auto ansi beforefieldinit GenTestType extends class [GenBaseType]GenBaseType +{ + .method public hidebysig newslot virtual instance class [NonGenThroughGen4]NonGenThroughGen4 NonGenThroughGenOverride(string& res) + { + .override method instance class [B]B class [GenBaseType]GenBaseType::NonGenThroughGenFunc(string& res) + ldarg.1 + ldstr "NonGenThroughGen4 TestType.NonGenThroughGenFunc()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class [GenToNonGen3]GenToNonGen3 GenToNonGenOverride(string& res) + { + .override method instance class [B]B class [GenBaseType]GenBaseType::GenToNonGen(string& res) + ldarg.1 + ldstr "GenToNonGen3 TestType.GenToNonGenOverride()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class [NonGenericDerived4]NonGenericDerived4 NewGenFunc1(string& res) + { + .override method instance class [GenRetType]GenRetType class [GenBaseType]GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "NonGenericDerived4 TestType.NewGenFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class [GenDerive3]GenDerive3 NewGenFunc2(string& res) + { + .override method instance class [GenRetType]GenRetType> class [GenBaseType]GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "GenDerive3 TestType.NewGenFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class [GenRetType]GenRetType NewFunc1(string& res) + { + .override method instance object class [GenBaseType]GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "GenRetType TestType.NewFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class [C]C NewFunc2(string& res) + { + .override method instance class [B]B class [GenBaseType]GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "C TestType.NewFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class [GenBaseType]GenBaseType::.ctor() + ret + } +} diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenTestType.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenTestType.ilproj new file mode 100644 index 00000000000000..5f1ffa699d6145 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenTestType.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen1.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen1.il new file mode 100644 index 00000000000000..f86b57b3d47fba --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen1.il @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} +.assembly extern C{} +.assembly GenToNonGen1{} + +.class public auto ansi beforefieldinit GenToNonGen1 extends [C]C { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen1.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen1.ilproj new file mode 100644 index 00000000000000..51aef6456c4ade --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen1.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen2.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen2.il new file mode 100644 index 00000000000000..f8f34cb85b0ef1 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen2.il @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} +.assembly extern GenToNonGen1{} +.assembly extern Dictionary{} +.assembly GenToNonGen2{} + +.class public auto ansi beforefieldinit GenToNonGen2 extends class [GenToNonGen1]GenToNonGen1> { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen2.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen2.ilproj new file mode 100644 index 00000000000000..c81e5d4c2422fe --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen2.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen3.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen3.il new file mode 100644 index 00000000000000..741ef9184c2cf2 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen3.il @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} +.assembly extern GenToNonGen2 { } + +.assembly GenToNonGen3{} + + +.class public auto ansi beforefieldinit GenToNonGen3 extends class [GenToNonGen2]GenToNonGen2 { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen3.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen3.ilproj new file mode 100644 index 00000000000000..af288880534b43 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/GenToNonGen3.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen1.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen1.il new file mode 100644 index 00000000000000..581a4275bb6eef --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen1.il @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern C{} +.assembly NonGenThroughGen1{} + +.class public auto ansi beforefieldinit NonGenThroughGen1 extends [C]C { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen1.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen1.ilproj new file mode 100644 index 00000000000000..bc6a5b3ca706e4 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen1.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen2.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen2.il new file mode 100644 index 00000000000000..1dd2d0410e47ef --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen2.il @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} +.assembly extern NonGenThroughGen1{} +.assembly extern Dictionary{} +.assembly NonGenThroughGen2{} + +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class [NonGenThroughGen1]NonGenThroughGen1> { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen2.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen2.ilproj new file mode 100644 index 00000000000000..6b9e08b1060ce6 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen2.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen3.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen3.il new file mode 100644 index 00000000000000..e55a296326bccb --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen3.il @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} +.assembly extern NonGenThroughGen2{} +.assembly NonGenThroughGen3{} + +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class [NonGenThroughGen2]NonGenThroughGen2 { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen3.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen3.ilproj new file mode 100644 index 00000000000000..edab938e925187 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen3.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen4.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen4.il new file mode 100644 index 00000000000000..16a50342681806 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen4.il @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern NonGenThroughGen3{} +.assembly NonGenThroughGen4{} + +.class public auto ansi beforefieldinit NonGenThroughGen4 extends [NonGenThroughGen3]NonGenThroughGen3 { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen4.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen4.ilproj new file mode 100644 index 00000000000000..74e921be626589 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenThroughGen4.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived1.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived1.il new file mode 100644 index 00000000000000..cc4f836083bb74 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived1.il @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib { } +.assembly extern GenRetType { } + +.assembly NonGenericDerived1 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 extends class [GenRetType]GenRetType { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived1.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived1.ilproj new file mode 100644 index 00000000000000..773e2a12982652 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived1.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived2.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived2.il new file mode 100644 index 00000000000000..50fd143311dd5b --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived2.il @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern mscorlib{} +.assembly extern NonGenericDerived1{} +.assembly NonGenericDerived2{} + +.class public auto ansi beforefieldinit NonGenericDerived2 extends class [NonGenericDerived1]NonGenericDerived1 { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived2.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived2.ilproj new file mode 100644 index 00000000000000..19201aa97848bc --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived2.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived3.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived3.il new file mode 100644 index 00000000000000..406a6a013bdfea --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived3.il @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern NonGenericDerived2{} +.assembly NonGenericDerived3{} + +.class public auto ansi beforefieldinit NonGenericDerived3 extends class [NonGenericDerived2]NonGenericDerived2 { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived3.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived3.ilproj new file mode 100644 index 00000000000000..a035dcde822ca9 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived3.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived4.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived4.il new file mode 100644 index 00000000000000..8b803f0adf4cc7 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived4.il @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern NonGenericDerived3{} +.assembly NonGenericDerived4{} + +.class public auto ansi beforefieldinit NonGenericDerived4 extends [NonGenericDerived3]NonGenericDerived3 { } diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived4.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived4.ilproj new file mode 100644 index 00000000000000..a382f20f7c64cf --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/Modules/NonGenericDerived4.ilproj @@ -0,0 +1,11 @@ + + + + Library + BuildOnly + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.il new file mode 100644 index 00000000000000..2e0049efb773d0 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.il @@ -0,0 +1,389 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern System.Runtime { } +.assembly extern mscorlib { } +.assembly UnitTest { } + +.class public auto ansi beforefieldinit A { } +.class public auto ansi beforefieldinit B extends A { } +.class public auto ansi beforefieldinit C extends B { } + +.class public auto ansi beforefieldinit GenRetType { } +.class public auto ansi beforefieldinit Dictionary { } + +.class public auto ansi beforefieldinit GenDerive1 extends class GenRetType { } +.class public auto ansi beforefieldinit GenDerive2 extends class GenDerive1> { } +.class public auto ansi beforefieldinit GenDerive3 extends class GenDerive2 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 extends class GenRetType { } +.class public auto ansi beforefieldinit NonGenericDerived2 extends class NonGenericDerived1 { } +.class public auto ansi beforefieldinit NonGenericDerived3 extends class NonGenericDerived2 { } +.class public auto ansi beforefieldinit NonGenericDerived4 extends NonGenericDerived3 { } + +.class public auto ansi beforefieldinit GenToNonGen1 extends C { } +.class public auto ansi beforefieldinit GenToNonGen2 extends class GenToNonGen1> { } +.class public auto ansi beforefieldinit GenToNonGen3 extends class GenToNonGen2 { } + + +.class public auto ansi beforefieldinit NonGenThroughGen1 extends C { } +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class NonGenThroughGen1> { } +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class NonGenThroughGen2 { } +.class public auto ansi beforefieldinit NonGenThroughGen4 extends NonGenThroughGen3 { } + +.class public auto ansi beforefieldinit GenBaseType +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + + .method public hidebysig newslot virtual instance object MyFunc(string& res) + { + ldarg.0 + ldstr "object GenBaseType.MyFunc()" + stind.ref + newobj instance void A::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B MyFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.MyFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B GenToNonGen(string& res) + { + ldarg.0 + ldstr "B GenBaseType.GenToNonGen()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B NonGenThroughGenFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.NonGenThroughGenFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType> MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType> GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType>::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType TestNonGenericDerived(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.TestNonGenericDerived()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } +} + + +// ======================================================================================== + +.class public auto ansi beforefieldinit GenTestType extends class GenBaseType +{ + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenOverride(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + ldarg.1 + ldstr "NonGenThroughGen4 TestType.NonGenThroughGenFunc()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenOverride(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen(string& res) + ldarg.1 + ldstr "GenToNonGen3 TestType.GenToNonGenOverride()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class NonGenericDerived4 NewGenFunc1(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "NonGenericDerived4 TestType.NewGenFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenDerive3 NewGenFunc2(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "GenDerive3 TestType.NewGenFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenRetType NewFunc1(string& res) + { + .override method instance object class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "GenRetType TestType.NewFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class C NewFunc2(string& res) + { + .override method instance class B class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "C TestType.NewFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenBaseType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + .method public static bool RunTest1() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenRetType TestType.NewFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + ldloca.s 0 + callvirt instance object class GenBaseType::MyFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenRetType TestType.NewFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest2() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: C TestType.NewFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::MyFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "C TestType.NewFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest3() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenDerive3 TestType.NewGenFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + ldloca.s 0 + callvirt instance class GenRetType> class GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenDerive3 TestType.NewGenFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest4() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenericDerived4 TestType.NewGenFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + ldloca.s 0 + callvirt instance class GenRetType class GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenericDerived4 TestType.NewGenFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest5() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenToNonGen3 TestType.GenToNonGenOverride()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::GenToNonGen(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenToNonGen3 TestType.GenToNonGenOverride()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest6() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenThroughGen4 TestType.NonGenThroughGenFunc()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenThroughGen4 TestType.NonGenThroughGenFunc()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init ( bool result ) + + ldc.i4.1 + stloc.0 + + T1: + call bool CMain::RunTest1() + brtrue.s T2 + ldc.i4.0 + stloc.0 + + T2: + call bool CMain::RunTest2() + brtrue.s T3 + ldc.i4.0 + stloc.0 + + T3: + call bool CMain::RunTest3() + brtrue.s T4 + ldc.i4.0 + stloc.0 + + T4: + call bool CMain::RunTest4() + brtrue.s T5 + ldc.i4.0 + stloc.0 + + T5: + call bool CMain::RunTest5() + brtrue.s T6 + ldc.i4.0 + stloc.0 + + T6: + call bool CMain::RunTest6() + brtrue.s DONE + ldc.i4.0 + stloc.0 + + DONE: + ldloc.0 + brtrue.s PASS + + ldstr "Test FAILED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 101 + ret + + PASS: + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + + ldc.i4.s 100 + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.ilproj new file mode 100644 index 00000000000000..8f3457cf99bda9 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.ilproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestMultiModule.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestMultiModule.il new file mode 100644 index 00000000000000..3a0b2f40158488 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestMultiModule.il @@ -0,0 +1,245 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern System.Runtime { } +.assembly extern mscorlib { } + +.assembly extern A { } +.assembly extern B { } +.assembly extern C { } +.assembly extern Dictionary { } +.assembly extern GenRetType { } +.assembly extern GenDerive1 { } +.assembly extern GenDerive2 { } +.assembly extern GenDerive3 { } +.assembly extern NonGenericDerived1 { } +.assembly extern NonGenericDerived2 { } +.assembly extern NonGenericDerived3 { } +.assembly extern NonGenericDerived4 { } +.assembly extern GenToNonGen1 { } +.assembly extern GenToNonGen2 { } +.assembly extern GenToNonGen3 { } +.assembly extern NonGenThroughGen1 { } +.assembly extern NonGenThroughGen2 { } +.assembly extern NonGenThroughGen3 { } +.assembly extern NonGenThroughGen4 { } + +.assembly extern GenBaseType { } +.assembly extern GenTestType { } + +.assembly UnitTestMultiModule { } + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + .method public static bool RunTest1() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenRetType TestType.NewFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class [GenTestType]GenTestType::.ctor() + ldloca.s 0 + callvirt instance object class [GenBaseType]GenBaseType::MyFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenRetType TestType.NewFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest2() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: C TestType.NewFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class [GenTestType]GenTestType::.ctor() + ldloca.s 0 + callvirt instance class [B]B class [GenBaseType]GenBaseType::MyFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "C TestType.NewFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest3() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenDerive3 TestType.NewGenFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class [GenTestType]GenTestType::.ctor() + ldloca.s 0 + callvirt instance class [GenRetType]GenRetType> class [GenBaseType]GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenDerive3 TestType.NewGenFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest4() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenericDerived4 TestType.NewGenFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class [GenTestType]GenTestType::.ctor() + ldloca.s 0 + callvirt instance class [GenRetType]GenRetType class [GenBaseType]GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenericDerived4 TestType.NewGenFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest5() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenToNonGen3 TestType.GenToNonGenOverride()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class [GenTestType]GenTestType::.ctor() + ldloca.s 0 + callvirt instance class [B]B class [GenBaseType]GenBaseType::GenToNonGen(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenToNonGen3 TestType.GenToNonGenOverride()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest6() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenThroughGen4 TestType.NonGenThroughGenFunc()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class [GenTestType]GenTestType::.ctor() + ldloca.s 0 + callvirt instance class [B]B class [GenBaseType]GenBaseType::NonGenThroughGenFunc(string& res) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenThroughGen4 TestType.NonGenThroughGenFunc()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init ( bool result ) + + ldc.i4.1 + stloc.0 + + T1: + call bool CMain::RunTest1() + brtrue.s T2 + ldc.i4.0 + stloc.0 + + T2: + call bool CMain::RunTest2() + brtrue.s T3 + ldc.i4.0 + stloc.0 + + T3: + call bool CMain::RunTest3() + brtrue.s T4 + ldc.i4.0 + stloc.0 + + T4: + call bool CMain::RunTest4() + brtrue.s T5 + ldc.i4.0 + stloc.0 + + T5: + call bool CMain::RunTest5() + brtrue.s T6 + ldc.i4.0 + stloc.0 + + T6: + call bool CMain::RunTest6() + brtrue.s DONE + ldc.i4.0 + stloc.0 + + DONE: + ldloc.0 + brtrue.s PASS + + ldstr "Test FAILED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 101 + ret + + PASS: + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + + ldc.i4.s 100 + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestMultiModule.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestMultiModule.ilproj new file mode 100644 index 00000000000000..990f46ff75f4ca --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestMultiModule.ilproj @@ -0,0 +1,35 @@ + + + Exe + BuildAndRun + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 6e5921847b51ed243332b520af818d631146d394 Mon Sep 17 00:00:00 2001 From: Fadi Hanna Date: Tue, 31 Mar 2020 11:14:21 -0700 Subject: [PATCH 06/13] Remove some debug code and fix some comments text --- src/coreclr/src/vm/methodtablebuilder.cpp | 10 ++---- src/coreclr/src/vm/siginfo.cpp | 39 +++++++++++++++-------- src/coreclr/src/vm/siginfo.hpp | 2 +- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/coreclr/src/vm/methodtablebuilder.cpp b/src/coreclr/src/vm/methodtablebuilder.cpp index 5467a18d2e8e10..bbcf4e5183be85 100644 --- a/src/coreclr/src/vm/methodtablebuilder.cpp +++ b/src/coreclr/src/vm/methodtablebuilder.cpp @@ -5606,11 +5606,6 @@ MethodTableBuilder::ProcessMethodImpls() HRESULT hr = S_OK; - if (strstr(this->GetHalfBakedClass()->m_szDebugClassName, "MyFoo") != NULL || strstr(this->GetHalfBakedClass()->m_szDebugClassName, "MyBar") != NULL) - { - int a = 0; - } - DeclaredMethodIterator it(*this); while (it.Next()) { @@ -5826,9 +5821,8 @@ MethodTableBuilder::ProcessMethodImpls() bmtRTType *pCurDeclType = pDeclType; do { - // Two pass algorithm: - // 1: Search for exact matches - // 2: Search for equivalent matches. + // two pass algorithm. search for exact matches followed + // by equivalent matches. for (int iPass = 0; (iPass < 2) && (declMethod.IsNull()); iPass++) { MethodTable *pCurDeclMT = pCurDeclType->GetMethodTable(); diff --git a/src/coreclr/src/vm/siginfo.cpp b/src/coreclr/src/vm/siginfo.cpp index 69e518b1a871fd..eed1f31163aa93 100644 --- a/src/coreclr/src/vm/siginfo.cpp +++ b/src/coreclr/src/vm/siginfo.cpp @@ -3567,7 +3567,7 @@ BOOL CompareTypeTokens(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModu // // Compare two type handles for equality, or that hType2 is a derived class of hType1. // The derived type check is used by the covariant returns feature, which only supports -// class today (interface types are not supported right now) +// classes today (interface types are not supported right now) // // static BOOL MetaSig::CompareTypeHandles(TypeHandle hType1, TypeHandle hType2, BOOL allowDerivedClass) @@ -3602,6 +3602,10 @@ BOOL MetaSig::CompareTypeHandles(TypeHandle hType1, TypeHandle hType2, BOOL allo return FALSE; } +//--------------------------------------------------------------------------------------- +// +// Check if a type signature is eligible for covariant return types. +// // static BOOL MetaSig::IsTypeSignatureEligibleForCovariantReturnType( PCCOR_SIGNATURE pSig, @@ -3669,11 +3673,16 @@ BOOL MetaSig::IsTypeSignatureEligibleForCovariantReturnType( return TRUE; } +//--------------------------------------------------------------------------------------- +// +// Compute the base type token (it will either be a typedef or typeref token), and returns the +// module where that base type token is declared. +// // static BOOL MetaSig::ComputeBaseTypeTokenAndModule( mdToken tk, Module* pModule, - mdToken* baseTypeDefOrRefToken, + mdToken* pBaseTypeDefOrRefToken, Module** ppBaseTypeTokenModule) { CONTRACTL @@ -3718,13 +3727,13 @@ BOOL MetaSig::ComputeBaseTypeTokenAndModule( if (elementType != ELEMENT_TYPE_CLASS) return FALSE; - IfFailThrow(CorSigUncompressToken_EndPtr(pSig, pEndSig, baseTypeDefOrRefToken)); + IfFailThrow(CorSigUncompressToken_EndPtr(pSig, pEndSig, pBaseTypeDefOrRefToken)); *ppBaseTypeTokenModule = pFoundModule; return TRUE; } else if (TypeFromToken(tkTypeParent) == mdtTypeRef || TypeFromToken(tkTypeParent) == mdtTypeDef) { - *baseTypeDefOrRefToken = tkTypeParent; + *pBaseTypeDefOrRefToken = tkTypeParent; *ppBaseTypeTokenModule = pFoundModule; return TRUE; } @@ -3732,6 +3741,10 @@ BOOL MetaSig::ComputeBaseTypeTokenAndModule( return FALSE; } +//--------------------------------------------------------------------------------------- +// +// Extract the parent type's signature and stubstitution from the input type signature +// // static BOOL MetaSig::GetParentSignatureAndSubstitution( PCCOR_SIGNATURE pSig, @@ -3761,8 +3774,8 @@ BOOL MetaSig::GetParentSignatureAndSubstitution( return FALSE; } - // We load the uninstantiated type here, and we will also return back a valid substitution - // for the caller to use (when applicable) + // If the parent type token is a TypeSpec token, we need to load the substitution from the signature and + // chain it to the existing substitution (if there is one) if (TypeFromToken(parentTypeDefOrRefOrSpecToken) == mdtTypeSpec) { @@ -4189,16 +4202,16 @@ MetaSig::CompareElementType( // // In that example, if we just look at the typedef tokens for Class0 and Class4, and traverse the // parent chain of Class4 to check if it derives from Class0, we would be always returning true, which - // is wrong (ex: if Class2 was declared as 'Class2 : Class1', then Class4 would be - // deriving from Class0, and not from Class0. + // is wrong. Here's a counter example: if Class2 was declared as 'Class2 : Class1', + // then Class4 would be deriving from Class0, and not from Class0. // // Therefore, we need to keep track of the substitutions: // A -> ARG1 -> T -> int32 - // b -> ARG2 -> int16 + // B -> ARG2 -> int16 // - // To handle that case, we compute the parent *AND* substitution chain of type2, and recompare that with - // type1 starting from the ELEMENT_TYPE_GENERICINST (see how ELEMENT_TYPE_GENERICINST is handled a few - // lines below). + // To handle that case, we need to compute the base type *AND* base type substitution chain of type2, and + // recompare that with type1. If type1 is generic, we'll return return FALSE here, so that we can properly + // handle this scenario correctly under ELEMENT_TYPE_GENERICINST. // // First, check if Type1 is eligible for covariant returns @@ -4291,8 +4304,6 @@ MetaSig::CompareElementType( case ELEMENT_TYPE_GENERICINST: { - PCCOR_SIGNATURE pCurSig1 = pSig1; - TokenPairList newVisited = TokenPairList::AdjustForTypeSpec( pVisited, pModule1, diff --git a/src/coreclr/src/vm/siginfo.hpp b/src/coreclr/src/vm/siginfo.hpp index c2d9912ebb3fd1..cb51cba1e4f94e 100644 --- a/src/coreclr/src/vm/siginfo.hpp +++ b/src/coreclr/src/vm/siginfo.hpp @@ -990,7 +990,7 @@ class MetaSig static BOOL ComputeBaseTypeTokenAndModule( mdToken tk, Module* pModule, - mdToken* baseTypeDefOrRefToken, + mdToken* pBaseTypeDefOrRefToken, Module** ppBaseTypeTokenModule); // Extract the parent type's signature and stubstitution from the input type signature From 8720cec2b8a4df72421f544693f16b5bccdc5355 Mon Sep 17 00:00:00 2001 From: Fadi Hanna Date: Tue, 31 Mar 2020 12:16:01 -0700 Subject: [PATCH 07/13] Add unit test using delegates --- .../UnitTest/UnitTestDelegates.il | 425 ++++++++++++++++++ .../UnitTest/UnitTestDelegates.ilproj | 10 + 2 files changed, 435 insertions(+) create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestDelegates.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestDelegates.ilproj diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestDelegates.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestDelegates.il new file mode 100644 index 00000000000000..6d26c58e02d19b --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestDelegates.il @@ -0,0 +1,425 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern System.Runtime { } +.assembly extern mscorlib { } +.assembly UnitTestDelegates { } + +.class public auto ansi beforefieldinit A { } +.class public auto ansi beforefieldinit B extends A { } +.class public auto ansi beforefieldinit C extends B { } + +.class public auto ansi beforefieldinit GenRetType { } +.class public auto ansi beforefieldinit Dictionary { } + +.class public auto ansi beforefieldinit GenDerive1 extends class GenRetType { } +.class public auto ansi beforefieldinit GenDerive2 extends class GenDerive1> { } +.class public auto ansi beforefieldinit GenDerive3 extends class GenDerive2 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 extends class GenRetType { } +.class public auto ansi beforefieldinit NonGenericDerived2 extends class NonGenericDerived1 { } +.class public auto ansi beforefieldinit NonGenericDerived3 extends class NonGenericDerived2 { } +.class public auto ansi beforefieldinit NonGenericDerived4 extends NonGenericDerived3 { } + +.class public auto ansi beforefieldinit GenToNonGen1 extends C { } +.class public auto ansi beforefieldinit GenToNonGen2 extends class GenToNonGen1> { } +.class public auto ansi beforefieldinit GenToNonGen3 extends class GenToNonGen2 { } + + +.class public auto ansi beforefieldinit NonGenThroughGen1 extends C { } +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class NonGenThroughGen1> { } +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class NonGenThroughGen2 { } +.class public auto ansi beforefieldinit NonGenThroughGen4 extends NonGenThroughGen3 { } + +.class public auto ansi beforefieldinit GenBaseType +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + + .method public hidebysig newslot virtual instance object MyFunc(string& res) + { + ldarg.0 + ldstr "object GenBaseType.MyFunc()" + stind.ref + newobj instance void A::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B MyFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.MyFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B GenToNonGen(string& res) + { + ldarg.0 + ldstr "B GenBaseType.GenToNonGen()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B NonGenThroughGenFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.NonGenThroughGenFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType> MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType> GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType>::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType TestNonGenericDerived(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.TestNonGenericDerived()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } +} + + + +.class public auto ansi beforefieldinit GenTestType extends class GenBaseType +{ + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenOverride(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + ldarg.1 + ldstr "NonGenThroughGen4 TestType.NonGenThroughGenFunc()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenOverride(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen(string& res) + ldarg.1 + ldstr "GenToNonGen3 TestType.GenToNonGenOverride()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class NonGenericDerived4 NewGenFunc1(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "NonGenericDerived4 TestType.NewGenFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenDerive3 NewGenFunc2(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "GenDerive3 TestType.NewGenFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenRetType NewFunc1(string& res) + { + .override method instance object class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "GenRetType TestType.NewFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class C NewFunc2(string& res) + { + .override method instance class B class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "C TestType.NewFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenBaseType::.ctor() + ret + } +} + + + + +.class public auto ansi sealed ReturnObjDel extends [System.Runtime]System.MulticastDelegate +{ + // We can use a delegate with signature 'object Invoke(string&)' for all methods here since they all return a reference type + + .method public hidebysig specialname rtspecialname instance void .ctor (object 'object', native int 'method') runtime managed { } + .method public hidebysig newslot virtual instance class [System.Runtime]System.IAsyncResult BeginInvoke (string& res, class [System.Runtime]System.AsyncCallback callback, object 'object') runtime managed { } + .method public hidebysig newslot virtual instance object Invoke (string& res) runtime managed { } + .method public hidebysig newslot virtual instance object EndInvoke (string& res, class [System.Runtime]System.IAsyncResult result) runtime managed { } +} + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + .method public static bool RunTest1() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenRetType TestType.NewFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + dup + ldvirtftn instance object class GenBaseType::MyFunc(string&) + newobj instance void class ReturnObjDel::.ctor(object, native int) + + ldloca.s 0 + callvirt instance object class ReturnObjDel::Invoke(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenRetType TestType.NewFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest2() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: C TestType.NewFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + dup + ldvirtftn instance class B class GenBaseType::MyFunc(string&) + newobj instance void class ReturnObjDel::.ctor(object, native int) + + ldloca.s 0 + callvirt instance object class ReturnObjDel::Invoke(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "C TestType.NewFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest3() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenDerive3 TestType.NewGenFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + dup + ldvirtftn instance class GenRetType> class GenBaseType::MyGenFunc(string&) + newobj instance void class ReturnObjDel::.ctor(object, native int) + + ldloca.s 0 + callvirt instance object class ReturnObjDel::Invoke(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenDerive3 TestType.NewGenFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest4() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenericDerived4 TestType.NewGenFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + dup + ldvirtftn instance class GenRetType class GenBaseType::MyGenFunc(string&) + newobj instance void class ReturnObjDel::.ctor(object, native int) + + ldloca.s 0 + callvirt instance object class ReturnObjDel::Invoke(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenericDerived4 TestType.NewGenFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest5() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenToNonGen3 TestType.GenToNonGenOverride()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + dup + ldvirtftn instance class B class GenBaseType::GenToNonGen(string&) + newobj instance void class ReturnObjDel::.ctor(object, native int) + + ldloca.s 0 + callvirt instance object class ReturnObjDel::Invoke(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenToNonGen3 TestType.GenToNonGenOverride()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest6() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenThroughGen4 TestType.NonGenThroughGenFunc()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + dup + ldvirtftn instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + newobj instance void class ReturnObjDel::.ctor(object, native int) + + ldloca.s 0 + callvirt instance object class ReturnObjDel::Invoke(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenThroughGen4 TestType.NonGenThroughGenFunc()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init ( bool result ) + + ldc.i4.1 + stloc.0 + + T1: + call bool CMain::RunTest1() + brtrue.s T2 + ldc.i4.0 + stloc.0 + + T2: + call bool CMain::RunTest2() + brtrue.s T3 + ldc.i4.0 + stloc.0 + + T3: + call bool CMain::RunTest3() + brtrue.s T4 + ldc.i4.0 + stloc.0 + + T4: + call bool CMain::RunTest4() + brtrue.s T5 + ldc.i4.0 + stloc.0 + + T5: + call bool CMain::RunTest5() + brtrue.s T6 + ldc.i4.0 + stloc.0 + + T6: + call bool CMain::RunTest6() + brtrue.s DONE + ldc.i4.0 + stloc.0 + + DONE: + ldloc.0 + brtrue.s PASS + + ldstr "Test FAILED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 101 + ret + + PASS: + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + + ldc.i4.s 100 + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestDelegates.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestDelegates.ilproj new file mode 100644 index 00000000000000..baa0fd4674967e --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTestDelegates.ilproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + + From 2edbc7ff06b477e2b3853a37f794ccdff7c140a7 Mon Sep 17 00:00:00 2001 From: Fadi Hanna Date: Thu, 9 Apr 2020 17:28:23 -0700 Subject: [PATCH 08/13] Add design doc --- .../features/covariant-return-methods.md | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 docs/design/features/covariant-return-methods.md diff --git a/docs/design/features/covariant-return-methods.md b/docs/design/features/covariant-return-methods.md new file mode 100644 index 00000000000000..a481884bbdc599 --- /dev/null +++ b/docs/design/features/covariant-return-methods.md @@ -0,0 +1,74 @@ +# Covariant Return Methods + +Covariant return methods is a runtime feature designed to support the [covariant return types](https://github.com/dotnet/csharplang/blob/master/proposals/covariant-returns.md) and [records](https://github.com/dotnet/csharplang/blob/master/proposals/records.md) C# language features posed for C# 9.0. + +This feature allows an overriding method to have a more derived reference type than the method it overrides. Covariant return methods can only be described through MethodImpl records, and as an initial implementation, will have the following limitations: +1. Covariant return methods will only be applicable to methods on reference types: the MethodDecl and MethodImpl records can only be on reference types. Methods on interfaces will not be supported. +2. Return types in covariant return methods can only be reference types: covariant interface return types are not supported. + +Supporting interfaces comes with many complications (ex: interface equivalence, default interface methods, variance on generic interfaces, etc...), which is why the feature will initially only support classes. + +MethodImpl checking will allow a return type to vary as long as the override is compatible with the return type of the method overriden (i.e. a derived type). + +If a language wishes for the override to be semantically visible such that users of the more derived type may rely on the covariant return type it shall make the override a newslot method with appropriate visibility AND name to be used outside of the class. + +For virtual method slot MethodImpl overrides, each slot shall be checked for compatible signature on type load. (Implementation note: This behavior can be triggered only if the type has a covariant return type override in its hierarchy, so as to make this pay for play.) + +A new `ValidateMethodImplRemainsInEffectAttribute` shall be added. The presence of this attribute is to require the type loader to ensure that the MethodImpl records specified on the method have not lost their slot unifying behavior due to other actions. In other words, when a MethodImpl on type A overrides some method using a derived return type in the signature, any type deriving from A will be allowed to have a MethodImpl record that overrides the same method as long as the return type used in the signature is the same or more derived than the return type used in the MethodImpl signature on type A. This is used to allow the C# language to require that overrides have the consistent behaviors expected. The expectation is that C# would place this attribute on covariant override methods in classes. + +## Implementation Notes + +### Signature Checking + +Signature checking for MethodImpl is done through the `MetaSig::CompareElementType` method, which is called from various places in the runtime when comparing method signatures. This method compares the signatures of two types, and will now take a boolean flag that would allow for derived type checking behavior. The boolean flag will be set to `TRUE` appropriately during comparison of the return type signatures between a MethodImpl and MethodDecl records. + +The type signature checking algorithm will perform the following: +1. Traverse and compare the signatures for `type1` and `type2` recursively. +2. If the signatures mismatch at any given point, and the current element type for `type2` is `ELEMENT_TYPE_CLASS` or `ELEMENT_TYPE_GENERICINST`: +2.a. Check for covariant return eligibility +2.b. Compute the parent type's signature and parent type's generic substitution of `type2` +2.c. Perform a recursive call to re-compare `type1` with the new parent type signature of `type2`. + +Note: if `ELEMENT_TYPE_INTERNAL` is encountered in either of the type signatures, both types will be fully loaded and compared for compatibility. + +### VTable Slot Checking + +This will be done during the call to `SetupMethodTable2` where we propagate inheritance (see methodtablebuilder.cpp around line 10642). TODO: add algorithm description here. + +### [Future] Interface Support + +An interface method may be both non-final and have a MethodImpl that declares that it overrides another interface method. If it does, NO other interface method may .override it. Instead further overrides must override the method that it overrode. Also the overriding method may only override 1 method. + +The default interface method resolution algorithm shall change from: + +``` console +Given interface method M and type T. +Let MSearch = M +Let MFound = Most specific implementation within the interfaces for MSearch within type T. If multiple implementations are found, throw Ambiguous match exception. +Return MFound +``` + +To: + +``` console +Given interface method M and type T. +Let MSearch = M + +If (MSearch overrides another method MBase) + Let MSearch = MBase + +Let MFound = Most specific implementation within the interfaces for MSearch within type T. If multiple implementations are found, throw Ambiguous match exception. +Let M Code = NULL + +If ((MFound != Msearch) and (MFound is not final)) + Let M ClassVirtual = ResolveInterfaceMethod for MFound to virtual override on class T without using Default interface method implementation or return NULL if not found. + If (M ClassVirtual != NULL) + Let M Code= ResolveVirtualMethod for MFound on class T to implementation method + +If (M Code != NULL) + Let M Code = MFound + +Check M Code For signature interface method M. + +Return M Code +``` From 135f4951ac7f81e36fd20716fdb6602f62011955 Mon Sep 17 00:00:00 2001 From: Fadi Hanna Date: Thu, 9 Apr 2020 17:35:32 -0700 Subject: [PATCH 09/13] Fix formatting issue --- docs/design/features/covariant-return-methods.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/design/features/covariant-return-methods.md b/docs/design/features/covariant-return-methods.md index a481884bbdc599..817af3eaea377b 100644 --- a/docs/design/features/covariant-return-methods.md +++ b/docs/design/features/covariant-return-methods.md @@ -25,9 +25,9 @@ Signature checking for MethodImpl is done through the `MetaSig::CompareElementTy The type signature checking algorithm will perform the following: 1. Traverse and compare the signatures for `type1` and `type2` recursively. 2. If the signatures mismatch at any given point, and the current element type for `type2` is `ELEMENT_TYPE_CLASS` or `ELEMENT_TYPE_GENERICINST`: -2.a. Check for covariant return eligibility -2.b. Compute the parent type's signature and parent type's generic substitution of `type2` -2.c. Perform a recursive call to re-compare `type1` with the new parent type signature of `type2`. + + Check for covariant return eligibility + + Compute the parent type's signature and parent type's generic substitution of `type2` + + Perform a recursive call to re-compare `type1` with the new parent type signature of `type2`. Note: if `ELEMENT_TYPE_INTERNAL` is encountered in either of the type signatures, both types will be fully loaded and compared for compatibility. From 13d6297e9a91c1b48f2d3fb872b5df03a0145bf3 Mon Sep 17 00:00:00 2001 From: Fadi Hanna Date: Fri, 10 Apr 2020 15:23:49 -0700 Subject: [PATCH 10/13] Add more unit tests and fix #ifdef causing build error --- src/coreclr/src/vm/siginfo.cpp | 3 +- .../UnitTest/ReOverrideMoreDerivedReturn.il | 469 ++++++++++++++++++ .../ReOverrideMoreDerivedReturn.ilproj | 10 + .../UnitTest/ReOverrideSameReturn.il | 462 +++++++++++++++++ .../UnitTest/ReOverrideSameReturn.ilproj | 10 + 5 files changed, 952 insertions(+), 2 deletions(-) create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideMoreDerivedReturn.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideMoreDerivedReturn.ilproj create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideSameReturn.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideSameReturn.ilproj diff --git a/src/coreclr/src/vm/siginfo.cpp b/src/coreclr/src/vm/siginfo.cpp index eed1f31163aa93..3802d321105401 100644 --- a/src/coreclr/src/vm/siginfo.cpp +++ b/src/coreclr/src/vm/siginfo.cpp @@ -5708,6 +5708,7 @@ MetaSig::GetUnmanagedCallingConvention( *pPinvokeMapOut = (CorPinvokeMap)0; return TRUE; } +#endif // #ifndef DACCESS_COMPILE //--------------------------------------------------------------------------------------- // @@ -5808,8 +5809,6 @@ void Substitution::DeleteChain() delete this; } -#endif // #ifndef DACCESS_COMPILE - //--------------------------------------------------------------------------------------- // // static diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideMoreDerivedReturn.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideMoreDerivedReturn.il new file mode 100644 index 00000000000000..bc43bcafb0254a --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideMoreDerivedReturn.il @@ -0,0 +1,469 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern System.Runtime { } +.assembly extern mscorlib { } +.assembly ReOverrideMoreDerivedReturn { } + +.class public auto ansi beforefieldinit A { } +.class public auto ansi beforefieldinit B extends A { } +.class public auto ansi beforefieldinit C extends B { } +.class public auto ansi beforefieldinit D extends C { } + +.class public auto ansi beforefieldinit GenRetType { } +.class public auto ansi beforefieldinit GenDerivedRetType extends class GenRetType { } +.class public auto ansi beforefieldinit Dictionary { } + +.class public auto ansi beforefieldinit GenDerive1 extends class GenRetType { } +.class public auto ansi beforefieldinit GenDerive2 extends class GenDerive1> { } +.class public auto ansi beforefieldinit GenDerive3 extends class GenDerive2 { } +.class public auto ansi beforefieldinit GenDerive4 extends class GenDerive3 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 extends class GenRetType { } +.class public auto ansi beforefieldinit NonGenericDerived2 extends class NonGenericDerived1 { } +.class public auto ansi beforefieldinit NonGenericDerived3 extends class NonGenericDerived2 { } +.class public auto ansi beforefieldinit NonGenericDerived4 extends NonGenericDerived3 { } +.class public auto ansi beforefieldinit NonGenericDerived5 extends NonGenericDerived4 { } + +.class public auto ansi beforefieldinit GenToNonGen1 extends C { } +.class public auto ansi beforefieldinit GenToNonGen2 extends class GenToNonGen1> { } +.class public auto ansi beforefieldinit GenToNonGen3 extends class GenToNonGen2 { } +.class public auto ansi beforefieldinit GenToNonGen4 extends class GenToNonGen3 { } + + +.class public auto ansi beforefieldinit NonGenThroughGen1 extends C { } +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class NonGenThroughGen1> { } +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class NonGenThroughGen2 { } +.class public auto ansi beforefieldinit NonGenThroughGen4 extends NonGenThroughGen3 { } +.class public auto ansi beforefieldinit NonGenThroughGen5 extends NonGenThroughGen4 { } + +.class public auto ansi beforefieldinit GenBaseType +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + + .method public hidebysig newslot virtual instance object MyFunc(string& res) + { + ldarg.0 + ldstr "object GenBaseType.MyFunc()" + stind.ref + newobj instance void A::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B MyFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.MyFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B GenToNonGen(string& res) + { + ldarg.0 + ldstr "B GenBaseType.GenToNonGen()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B NonGenThroughGenFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.NonGenThroughGenFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType> MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType> GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType>::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType TestNonGenericDerived(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.TestNonGenericDerived()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } +} + + +// ======================================================================================== + +.class public auto ansi beforefieldinit GenTestType extends class GenBaseType +{ + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenOverride(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + ldarg.1 + ldstr "NonGenThroughGen4 TestType.NonGenThroughGenFunc()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenOverride(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen(string& res) + ldarg.1 + ldstr "GenToNonGen3 TestType.GenToNonGenOverride()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class NonGenericDerived4 NewGenFunc1(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "NonGenericDerived4 TestType.NewGenFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenDerive3 NewGenFunc2(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "GenDerive3 TestType.NewGenFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenDerivedRetType NewFunc1(string& res) + { + .override method instance object class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "GenDerivedRetType TestType.NewFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class C NewFunc2(string& res) + { + .override method instance class B class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "C TestType.NewFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenBaseType::.ctor() + ret + } +} + +// ======================================================================================== + +.class public auto ansi beforefieldinit GenDerivedTestType extends class GenTestType +{ + .method public hidebysig newslot virtual instance class NonGenThroughGen5 NonGenThroughGenOverride(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + ldarg.1 + ldstr "NonGenThroughGen5 DerivedTestType.NonGenThroughGenFunc()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenToNonGen4 GenToNonGenOverride(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen(string& res) + ldarg.1 + ldstr "GenToNonGen4 DerivedTestType.GenToNonGenOverride()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class NonGenericDerived5 NewGenFunc1(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "NonGenericDerived5 DerivedTestType.NewGenFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenDerive4 NewGenFunc2(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "GenDerive4 DerivedTestType.NewGenFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenDerivedRetType NewFunc1(string& res) + { + .override method instance object class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "GenDerivedRetType DerivedTestType.NewFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class D NewFunc2(string& res) + { + .override method instance class B class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "D DerivedTestType.NewFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + .method public static bool RunTest1() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenDerivedRetType DerivedTestType.NewFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenDerivedTestType::.ctor() + ldloca.s 0 + callvirt instance object class GenBaseType::MyFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenDerivedRetType DerivedTestType.NewFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest2() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: D DerivedTestType.NewFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenDerivedTestType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::MyFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "D DerivedTestType.NewFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest3() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenDerive4 DerivedTestType.NewGenFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenDerivedTestType::.ctor() + ldloca.s 0 + callvirt instance class GenRetType> class GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenDerive4 DerivedTestType.NewGenFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest4() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenericDerived5 DerivedTestType.NewGenFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenDerivedTestType::.ctor() + ldloca.s 0 + callvirt instance class GenRetType class GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenericDerived5 DerivedTestType.NewGenFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest5() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenToNonGen4 DerivedTestType.GenToNonGenOverride()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenDerivedTestType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::GenToNonGen(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenToNonGen4 DerivedTestType.GenToNonGenOverride()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest6() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenThroughGen5 DerivedTestType.NonGenThroughGenFunc()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenDerivedTestType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenThroughGen5 DerivedTestType.NonGenThroughGenFunc()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init ( bool result ) + + ldc.i4.1 + stloc.0 + + T1: + call bool CMain::RunTest1() + brtrue.s T2 + ldc.i4.0 + stloc.0 + + T2: + call bool CMain::RunTest2() + brtrue.s T3 + ldc.i4.0 + stloc.0 + + T3: + call bool CMain::RunTest3() + brtrue.s T4 + ldc.i4.0 + stloc.0 + + T4: + call bool CMain::RunTest4() + brtrue.s T5 + ldc.i4.0 + stloc.0 + + T5: + call bool CMain::RunTest5() + brtrue.s T6 + ldc.i4.0 + stloc.0 + + T6: + call bool CMain::RunTest6() + brtrue.s DONE + ldc.i4.0 + stloc.0 + + DONE: + ldloc.0 + brtrue.s PASS + + ldstr "Test FAILED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 101 + ret + + PASS: + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + + ldc.i4.s 100 + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideMoreDerivedReturn.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideMoreDerivedReturn.ilproj new file mode 100644 index 00000000000000..31b7d301228e9a --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideMoreDerivedReturn.ilproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideSameReturn.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideSameReturn.il new file mode 100644 index 00000000000000..044215d4630e80 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideSameReturn.il @@ -0,0 +1,462 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern System.Runtime { } +.assembly extern mscorlib { } +.assembly ReOverrideSameReturn { } + +.class public auto ansi beforefieldinit A { } +.class public auto ansi beforefieldinit B extends A { } +.class public auto ansi beforefieldinit C extends B { } + +.class public auto ansi beforefieldinit GenRetType { } +.class public auto ansi beforefieldinit Dictionary { } + +.class public auto ansi beforefieldinit GenDerive1 extends class GenRetType { } +.class public auto ansi beforefieldinit GenDerive2 extends class GenDerive1> { } +.class public auto ansi beforefieldinit GenDerive3 extends class GenDerive2 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 extends class GenRetType { } +.class public auto ansi beforefieldinit NonGenericDerived2 extends class NonGenericDerived1 { } +.class public auto ansi beforefieldinit NonGenericDerived3 extends class NonGenericDerived2 { } +.class public auto ansi beforefieldinit NonGenericDerived4 extends NonGenericDerived3 { } + +.class public auto ansi beforefieldinit GenToNonGen1 extends C { } +.class public auto ansi beforefieldinit GenToNonGen2 extends class GenToNonGen1> { } +.class public auto ansi beforefieldinit GenToNonGen3 extends class GenToNonGen2 { } + + +.class public auto ansi beforefieldinit NonGenThroughGen1 extends C { } +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class NonGenThroughGen1> { } +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class NonGenThroughGen2 { } +.class public auto ansi beforefieldinit NonGenThroughGen4 extends NonGenThroughGen3 { } + +.class public auto ansi beforefieldinit GenBaseType +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + + .method public hidebysig newslot virtual instance object MyFunc(string& res) + { + ldarg.0 + ldstr "object GenBaseType.MyFunc()" + stind.ref + newobj instance void A::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B MyFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.MyFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B GenToNonGen(string& res) + { + ldarg.0 + ldstr "B GenBaseType.GenToNonGen()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B NonGenThroughGenFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.NonGenThroughGenFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType> MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType> GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType>::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType TestNonGenericDerived(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.TestNonGenericDerived()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } +} + + +// ======================================================================================== + +.class public auto ansi beforefieldinit GenTestType extends class GenBaseType +{ + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenOverride(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + ldarg.1 + ldstr "NonGenThroughGen4 TestType.NonGenThroughGenFunc()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenOverride(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen(string& res) + ldarg.1 + ldstr "GenToNonGen3 TestType.GenToNonGenOverride()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class NonGenericDerived4 NewGenFunc1(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "NonGenericDerived4 TestType.NewGenFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenDerive3 NewGenFunc2(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "GenDerive3 TestType.NewGenFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenRetType NewFunc1(string& res) + { + .override method instance object class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "GenRetType TestType.NewFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class C NewFunc2(string& res) + { + .override method instance class B class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "C TestType.NewFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenBaseType::.ctor() + ret + } +} + +// ======================================================================================== + +.class public auto ansi beforefieldinit GenDerivedTestType extends class GenTestType +{ + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenOverride(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + ldarg.1 + ldstr "NonGenThroughGen4 DerivedTestType.NonGenThroughGenFunc()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenOverride(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen(string& res) + ldarg.1 + ldstr "GenToNonGen3 DerivedTestType.GenToNonGenOverride()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class NonGenericDerived4 NewGenFunc1(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "NonGenericDerived4 DerivedTestType.NewGenFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenDerive3 NewGenFunc2(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "GenDerive3 DerivedTestType.NewGenFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenRetType NewFunc1(string& res) + { + .override method instance object class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "GenRetType DerivedTestType.NewFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class C NewFunc2(string& res) + { + .override method instance class B class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "C DerivedTestType.NewFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + .method public static bool RunTest1() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenRetType DerivedTestType.NewFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenDerivedTestType::.ctor() + ldloca.s 0 + callvirt instance object class GenBaseType::MyFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenRetType DerivedTestType.NewFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest2() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: C DerivedTestType.NewFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenDerivedTestType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::MyFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "C DerivedTestType.NewFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest3() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenDerive3 DerivedTestType.NewGenFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenDerivedTestType::.ctor() + ldloca.s 0 + callvirt instance class GenRetType> class GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenDerive3 DerivedTestType.NewGenFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest4() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenericDerived4 DerivedTestType.NewGenFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenDerivedTestType::.ctor() + ldloca.s 0 + callvirt instance class GenRetType class GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenericDerived4 DerivedTestType.NewGenFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest5() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenToNonGen3 DerivedTestType.GenToNonGenOverride()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenDerivedTestType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::GenToNonGen(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenToNonGen3 DerivedTestType.GenToNonGenOverride()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest6() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenThroughGen4 DerivedTestType.NonGenThroughGenFunc()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenDerivedTestType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenThroughGen4 DerivedTestType.NonGenThroughGenFunc()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init ( bool result ) + + ldc.i4.1 + stloc.0 + + T1: + call bool CMain::RunTest1() + brtrue.s T2 + ldc.i4.0 + stloc.0 + + T2: + call bool CMain::RunTest2() + brtrue.s T3 + ldc.i4.0 + stloc.0 + + T3: + call bool CMain::RunTest3() + brtrue.s T4 + ldc.i4.0 + stloc.0 + + T4: + call bool CMain::RunTest4() + brtrue.s T5 + ldc.i4.0 + stloc.0 + + T5: + call bool CMain::RunTest5() + brtrue.s T6 + ldc.i4.0 + stloc.0 + + T6: + call bool CMain::RunTest6() + brtrue.s DONE + ldc.i4.0 + stloc.0 + + DONE: + ldloc.0 + brtrue.s PASS + + ldstr "Test FAILED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 101 + ret + + PASS: + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + + ldc.i4.s 100 + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideSameReturn.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideSameReturn.ilproj new file mode 100644 index 00000000000000..9b917476d9a184 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideSameReturn.ilproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + + From ee7c507753d5547c599c6f4e19146d1426492a8e Mon Sep 17 00:00:00 2001 From: Fadi Hanna Date: Tue, 14 Apr 2020 18:16:39 -0700 Subject: [PATCH 11/13] Add ValidateMethodImplRemainsInEffectAttribute validation Fix generic substitution bug and add more tests --- src/coreclr/src/dlls/mscorrc/mscorrc.rc | 1 + src/coreclr/src/dlls/mscorrc/resource.h | 1 + src/coreclr/src/vm/class.cpp | 74 +++ src/coreclr/src/vm/clsload.hpp | 4 +- src/coreclr/src/vm/siginfo.cpp | 78 ++- src/coreclr/src/vm/wellknownattributes.h | 3 + .../Negative/OverrideSameSigAsDecl.il | 483 ++++++++++++++++++ .../OverrideSameSigAsDecl.ilproj} | 2 +- .../IncompatibleReturnNoValidation.il | 366 +++++++++++++ .../IncompatibleReturnNoValidation.ilproj | 10 + ...Return.il => OverrideMoreDerivedReturn.il} | 0 .../UnitTest/OverrideMoreDerivedReturn.ilproj | 10 + ...ideSameReturn.il => OverrideSameReturn.il} | 0 ...eturn.ilproj => OverrideSameReturn.ilproj} | 2 +- .../CovariantReturns/UnitTest/UnitTest.il | 183 ++++++- .../System.Private.CoreLib.Shared.projitems | 1 + ...idateMethodImplRemainsInEffectAttribute.cs | 11 + 17 files changed, 1215 insertions(+), 14 deletions(-) create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Negative/OverrideSameSigAsDecl.il rename src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/{UnitTest/ReOverrideMoreDerivedReturn.ilproj => Negative/OverrideSameSigAsDecl.ilproj} (80%) create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/NoValidation/IncompatibleReturnNoValidation.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/NoValidation/IncompatibleReturnNoValidation.ilproj rename src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/{ReOverrideMoreDerivedReturn.il => OverrideMoreDerivedReturn.il} (100%) create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/OverrideMoreDerivedReturn.ilproj rename src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/{ReOverrideSameReturn.il => OverrideSameReturn.il} (100%) rename src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/{ReOverrideSameReturn.ilproj => OverrideSameReturn.ilproj} (82%) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValidateMethodImplRemainsInEffectAttribute.cs diff --git a/src/coreclr/src/dlls/mscorrc/mscorrc.rc b/src/coreclr/src/dlls/mscorrc/mscorrc.rc index 8a7410ef25b2d5..9337b473d7aac6 100644 --- a/src/coreclr/src/dlls/mscorrc/mscorrc.rc +++ b/src/coreclr/src/dlls/mscorrc/mscorrc.rc @@ -421,6 +421,7 @@ BEGIN IDS_CLASSLOAD_MI_BODY_DECL_MISMATCH "Signature of the body and declaration in a method implementation do not match. Type: '%1'. Assembly: '%2'." IDS_CLASSLOAD_MI_MISSING_SIG_BODY "Signature for the body in a method implementation cannot be found. Type: '%1'. Assembly: '%2'." IDS_CLASSLOAD_MI_MISSING_SIG_DECL "Signature for the declaration in a method implementation cannot be found. Type: '%1'. Assembly: '%2'." + IDS_CLASSLOAD_MI_BADRETURNTYPE "Return type in method '%1' on type '%2' from assembly '%3' is not compatible with base type method '%4'." IDS_CLASSLOAD_EQUIVALENTSTRUCTMETHODS "Could not load the structure '%1' from assembly '%2'. The structure is marked as eligible for type equivalence, but it has a method." IDS_CLASSLOAD_EQUIVALENTSTRUCTFIELDS "Could not load the structure '%1' from assembly '%2'. The structure is marked as eligible for type equivalence, but it has a static or non-public field." diff --git a/src/coreclr/src/dlls/mscorrc/resource.h b/src/coreclr/src/dlls/mscorrc/resource.h index 342c0570d493bb..a75aa00afe1d3a 100644 --- a/src/coreclr/src/dlls/mscorrc/resource.h +++ b/src/coreclr/src/dlls/mscorrc/resource.h @@ -167,6 +167,7 @@ #define IDS_CLASSLOAD_MI_BODY_DECL_MISMATCH 0x17a5 #define IDS_CLASSLOAD_MI_MISSING_SIG_BODY 0x17a6 #define IDS_CLASSLOAD_MI_MISSING_SIG_DECL 0x17a7 +#define IDS_CLASSLOAD_MI_BADRETURNTYPE 0x17a8 #define IDS_CLASSLOAD_TOOMANYGENERICARGS 0x17ab #define IDS_ERROR 0x17b0 diff --git a/src/coreclr/src/vm/class.cpp b/src/coreclr/src/vm/class.cpp index c87c21d1515952..3f085f9122726c 100644 --- a/src/coreclr/src/vm/class.cpp +++ b/src/coreclr/src/vm/class.cpp @@ -967,12 +967,86 @@ void ClassLoader::LoadExactParents(MethodTable *pMT) MethodTableBuilder::CopyExactParentSlots(pMT, pApproxParentMT); + if (!pMT->IsInterface() && !pMT->IsValueType()) + { + ValidateMethodImplRemainsInEffect(pMT); + } + // We can now mark this type as having exact parents pMT->SetHasExactParent(); RETURN; } +/*static*/ +void ClassLoader::ValidateMethodImplRemainsInEffect(MethodTable* pMT) +{ + CONTRACT_VOID + { + STANDARD_VM_CHECK; + PRECONDITION(CheckPointer(pMT)); + PRECONDITION(!pMT->IsInterface() && !pMT->IsValueType()); + } + CONTRACT_END; + + MethodTable* pParentMT = pMT->GetParentMethodTable(); + if (pParentMT == NULL) + RETURN; + + BYTE* pVal = NULL; + ULONG cbVal = 0; + HRESULT hr = pMT->GetCustomAttribute(WellKnownAttribute::ValidateMethodImplRemainsInEffectAttribute, (const void**)&pVal, &cbVal); + if (hr != S_OK) + RETURN; + + for (WORD i = 0; i < pParentMT->GetNumVirtuals(); i++) + { + MethodDesc* pMD = pMT->GetMethodDescForSlot(i); + MethodDesc* pParentMD = pParentMT->GetMethodDescForSlot(i); + + DWORD originalIndex = pMD->GetSlot(); + if (originalIndex == i) + continue; + + DWORD originalIndexParent = pParentMD->GetSlot(); + if (originalIndex == originalIndexParent) + continue; + + SigTypeContext context1(pParentMD); + TypeHandle hType1 = pParentMD->GetSigPointer().GetTypeHandleThrowing(pParentMD->GetModule(), &context1, ClassLoader::LoadTypesFlag::LoadTypes, CLASS_LOAD_EXACTPARENTS); + + SigTypeContext context2(pMD); + TypeHandle hType2 = pMD->GetSigPointer().GetTypeHandleThrowing(pMD->GetModule(), &context2, ClassLoader::LoadTypesFlag::LoadTypes, CLASS_LOAD_EXACTPARENTS); + + // Type1 has to be equal to Type2, or a base type of Type2 (covariant returns) + + if (!MetaSig::CompareTypeHandles(hType1, hType2, TRUE /* allowDerivedClass */ )) + { + SString strAssemblyName; + pMD->GetAssembly()->GetDisplayName(strAssemblyName); + + SString strInvalidTypeName; + TypeString::AppendType(strInvalidTypeName, TypeHandle(pMD->GetMethodTable())); + + SString strInvalidMethodName; + TypeString::AppendMethod(strInvalidMethodName, pMD, pMD->GetMethodInstantiation()); + + SString strParentMethodName; + TypeString::AppendMethod(strParentMethodName, pParentMD, pParentMD->GetMethodInstantiation()); + + COMPlusThrow( + kTypeLoadException, + IDS_CLASSLOAD_MI_BADRETURNTYPE, + strInvalidMethodName, + strInvalidTypeName, + strAssemblyName, + strParentMethodName); + } + } + + RETURN; +} + //******************************************************************************* // This is the routine that computes the internal type of a given type. It normalizes // structs that have only one field (of int/ptr sized values), to be that underlying type. diff --git a/src/coreclr/src/vm/clsload.hpp b/src/coreclr/src/vm/clsload.hpp index 23a051f6aeef45..fb569e93c7c130 100644 --- a/src/coreclr/src/vm/clsload.hpp +++ b/src/coreclr/src/vm/clsload.hpp @@ -969,10 +969,12 @@ class ClassLoader // Phase CLASS_LOAD_EXACTPARENTS of class loading // Load exact parents and interfaces and dependent structures (generics dictionary, vtable fixes) - static void LoadExactParents(MethodTable *pMT); + static void LoadExactParents(MethodTable* pMT); static void LoadExactParentAndInterfacesTransitively(MethodTable *pMT); + static void ValidateMethodImplRemainsInEffect(MethodTable* pMT); + // Create a non-canonical instantiation of a generic type based off the canonical instantiation // (For example, MethodTable for List is based on the MethodTable for List<__Canon>) static TypeHandle CreateTypeHandleForNonCanonicalGenericInstantiation(TypeKey *pTypeKey, diff --git a/src/coreclr/src/vm/siginfo.cpp b/src/coreclr/src/vm/siginfo.cpp index 3802d321105401..cd7dbedd274dde 100644 --- a/src/coreclr/src/vm/siginfo.cpp +++ b/src/coreclr/src/vm/siginfo.cpp @@ -3566,8 +3566,7 @@ BOOL CompareTypeTokens(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModu //--------------------------------------------------------------------------------------- // // Compare two type handles for equality, or that hType2 is a derived class of hType1. -// The derived type check is used by the covariant returns feature, which only supports -// classes today (interface types are not supported right now) +// The derived type check is used by the covariant returns feature. // // static BOOL MetaSig::CompareTypeHandles(TypeHandle hType1, TypeHandle hType2, BOOL allowDerivedClass) @@ -3587,7 +3586,7 @@ BOOL MetaSig::CompareTypeHandles(TypeHandle hType1, TypeHandle hType2, BOOL allo if (!allowDerivedClass) return FALSE; - if (hType1.IsNull() || hType2.IsValueType() || hType2.IsInterface()) + if (hType1.IsNull() || hType2.IsValueType()) { return FALSE; } @@ -3658,18 +3657,13 @@ BOOL MetaSig::IsTypeSignatureEligibleForCovariantReturnType( return FALSE; } - // Interfaces not supported with covariant return types - if (IsTdInterface(attr)) - { - return FALSE; - } - if (ppTypeDefModule != NULL) *ppTypeDefModule = pFoundModule; if (pTypeDefToken != NULL) *pTypeDefToken = typeDefToken; if (pParentTypeDefOrRefOrSpecToken != NULL) *pParentTypeDefOrRefOrSpecToken = parentTypeDefOrRefOrSpecToken; + return TRUE; } @@ -4729,6 +4723,8 @@ MetaSig::CompareMethodSigs( DWORD ArgCount2; DWORD i; + const Substitution* pOrigSubst2 = pSubst2; + // If scopes are the same, and sigs are same, can return. // If the sigs aren't the same, but same scope, can't return yet, in // case there are two AssemblyRefs pointing to the same assembly or such. @@ -4804,6 +4800,38 @@ MetaSig::CompareMethodSigs( // This would be a breaking change to make this throw... see comment above _ASSERT(*pSig2 != ELEMENT_TYPE_SENTINEL); + pSubst2 = pOrigSubst2; + + // + // If we are comparing the return type signatures and allow for covariant returns, + // we need to check if the return type on the second signature is a generic type, + // and if so, chain its generic instantiation arguments to the substitution chain. + // This is necessary in case we need to compute the base type signature of the second + // type's signature, and compare that to the first type's signature, to allow for + // derived types. + // + SigPointer instArgSignature; + Substitution instArgsSubstitution; + if (i == 0 && allowCovariantReturn) + { + SigParser parser(pSig2, (DWORD)(pEndSig2 - pSig2)); + + CorElementType returnElementType; + IfFailThrow(parser.GetElemType(&returnElementType)); + + if (returnElementType == ELEMENT_TYPE_GENERICINST) + { + IfFailThrow(parser.SkipExactlyOne()); // Skip generic type definition signature + IfFailThrow(parser.GetData(NULL)); // Skip number of generic arguments + instArgSignature = SigPointer(parser.GetPtr()); + instArgsSubstitution = Substitution(pModule2, instArgSignature, pSubst2); + + // Temporarily chain the generic instantiation to the substitution chain of the + // second type's signature + pSubst2 = &instArgsSubstitution; + } + } + // We are in bounds on both sides. Compare the element. if (!CompareElementType( pSig1, @@ -4831,6 +4859,38 @@ MetaSig::CompareMethodSigs( // do return type as well for (i = 0; i <= ArgCount1; i++) { + pSubst2 = pOrigSubst2; + + // + // If we are comparing the return type signatures and allow for covariant returns, + // we need to check if the return type on the second signature is a generic type, + // and if so, chain its generic instantiation arguments to the substitution chain. + // This is necessary in case we need to compute the base type signature of the second + // type's signature, and compare that to the first type's signature, to allow for + // derived types. + // + SigPointer instArgSignature; + Substitution instArgsSubstitution; + if (i == 0 && allowCovariantReturn) + { + SigParser parser(pSig2, (DWORD)(pEndSig2 - pSig2)); + + CorElementType returnElementType; + IfFailThrow(parser.GetElemType(&returnElementType)); + + if (returnElementType == ELEMENT_TYPE_GENERICINST) + { + IfFailThrow(parser.SkipExactlyOne()); // Skip generic type definition signature + IfFailThrow(parser.GetData(NULL)); // Skip number of generic arguments + instArgSignature = SigPointer(parser.GetPtr()); + instArgsSubstitution = Substitution(pModule2, instArgSignature, pSubst2); + + // Temporarily chain the generic instantiation to the substitution chain of the + // second type's signature + pSubst2 = &instArgsSubstitution; + } + } + if (!CompareElementType( pSig1, pSig2, diff --git a/src/coreclr/src/vm/wellknownattributes.h b/src/coreclr/src/vm/wellknownattributes.h index de71eb459f90cf..8401f233cd0c56 100644 --- a/src/coreclr/src/vm/wellknownattributes.h +++ b/src/coreclr/src/vm/wellknownattributes.h @@ -35,6 +35,7 @@ enum class WellKnownAttribute : DWORD UnmanagedFunctionPointer, ThreadStatic, WinRTMarshalingBehaviorAttribute, + ValidateMethodImplRemainsInEffectAttribute, CountOfWellKnownAttributes }; @@ -99,6 +100,8 @@ inline const char *GetWellKnownAttributeName(WellKnownAttribute attribute) return "System.ThreadStaticAttribute"; case WellKnownAttribute::WinRTMarshalingBehaviorAttribute: return "Windows.Foundation.Metadata.MarshalingBehaviorAttribute"; + case WellKnownAttribute::ValidateMethodImplRemainsInEffectAttribute: + return "System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute"; case WellKnownAttribute::CountOfWellKnownAttributes: default: break; // Silence compiler warnings diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Negative/OverrideSameSigAsDecl.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Negative/OverrideSameSigAsDecl.il new file mode 100644 index 00000000000000..857bb81acf8040 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Negative/OverrideSameSigAsDecl.il @@ -0,0 +1,483 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern System.Private.CoreLib { } +.assembly extern System.Runtime { } +.assembly extern mscorlib { } +.assembly OverrideSameSigAsDecl { } + +.class public auto ansi beforefieldinit A { } +.class public auto ansi beforefieldinit B extends A { } +.class public auto ansi beforefieldinit C extends B { } + +.class public auto ansi beforefieldinit GenRetType { } +.class public auto ansi beforefieldinit Dictionary { } + +.class public auto ansi beforefieldinit GenDerive1 extends class GenRetType { } +.class public auto ansi beforefieldinit GenDerive2 extends class GenDerive1> { } +.class public auto ansi beforefieldinit GenDerive3 extends class GenDerive2 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 extends class GenRetType { } +.class public auto ansi beforefieldinit NonGenericDerived2 extends class NonGenericDerived1 { } +.class public auto ansi beforefieldinit NonGenericDerived3 extends class NonGenericDerived2 { } +.class public auto ansi beforefieldinit NonGenericDerived4 extends NonGenericDerived3 { } + +.class public auto ansi beforefieldinit GenToNonGen1 extends C { } +.class public auto ansi beforefieldinit GenToNonGen2 extends class GenToNonGen1> { } +.class public auto ansi beforefieldinit GenToNonGen3 extends class GenToNonGen2 { } + + +.class public auto ansi beforefieldinit NonGenThroughGen1 extends C { } +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class NonGenThroughGen1> { } +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class NonGenThroughGen2 { } +.class public auto ansi beforefieldinit NonGenThroughGen4 extends NonGenThroughGen3 { } + +.class public auto ansi beforefieldinit GenBaseType +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + + .method public hidebysig newslot virtual instance object MyFunc(string& res) + { + ldarg.0 + ldstr "object GenBaseType.MyFunc()" + stind.ref + newobj instance void A::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B MyFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.MyFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B GenToNonGen(string& res) + { + ldarg.0 + ldstr "B GenBaseType.GenToNonGen()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B NonGenThroughGenFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.NonGenThroughGenFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType> MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType> GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType>::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType TestNonGenericDerived(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.TestNonGenericDerived()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } +} + + +// ======================================================================================== + +.class public auto ansi beforefieldinit GenTestType extends class GenBaseType +{ + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenOverride(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + ldarg.1 + ldstr "NonGenThroughGen4 TestType.NonGenThroughGenFunc()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenOverride(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen(string& res) + ldarg.1 + ldstr "GenToNonGen3 TestType.GenToNonGenOverride()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class NonGenericDerived4 NewGenFunc1(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "NonGenericDerived4 TestType.NewGenFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenDerive3 NewGenFunc2(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "GenDerive3 TestType.NewGenFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenRetType NewFunc1(string& res) + { + .override method instance object class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "GenRetType TestType.NewFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class C NewFunc2(string& res) + { + .override method instance class B class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "C TestType.NewFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenBaseType::.ctor() + ret + } +} + +// ======================================================================================== + +.class public auto ansi beforefieldinit Invalid1 extends class GenTestType +{ + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + + .method public hidebysig newslot virtual instance class B NonGenThroughGenOverride_Invalid(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit Invalid2 extends class GenTestType +{ + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + + .method public hidebysig newslot virtual instance class B GenToNonGenOverride_Invalid(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen(string& res) + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit Invalid3 extends class GenTestType +{ + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + + .method public hidebysig newslot virtual instance class GenRetType NewGenFunc1_Invalid(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc(string& res) + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit Invalid4 extends class GenTestType +{ + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + + .method public hidebysig newslot virtual instance class GenRetType> NewGenFunc2_Invalid(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc(string& res) + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit Invalid5 extends class GenTestType +{ + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + + .method public hidebysig newslot virtual instance object NewFunc1_Invalid(string& res) + { + .override method instance object class GenBaseType::MyFunc(string& res) + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit Invalid6 extends class GenTestType +{ + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + + .method public hidebysig newslot virtual instance class B NewFunc2_Invalid(string& res) + { + .override method instance class B class GenBaseType::MyFunc(string& res) + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + .method public static void RunTest1() noinlining + { + newobj instance void class Invalid1::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest2() noinlining + { + newobj instance void class Invalid2::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest3() noinlining + { + newobj instance void class Invalid3::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest4() noinlining + { + newobj instance void class Invalid4::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest5() noinlining + { + newobj instance void class Invalid5::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest6() noinlining + { + newobj instance void class Invalid6::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init (bool V_0) + ldc.i4.1 + stloc.0 + + T1: + .try + { + call void CMain::RunTest1() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Invalid1." + call void [System.Console]System.Console::WriteLine(string) + leave.s T2 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T2 + } + + T2: + .try + { + call void CMain::RunTest2() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Invalid2." + call void [System.Console]System.Console::WriteLine(string) + leave.s T3 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T3 + } + + T3: + .try + { + call void CMain::RunTest3() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Invalid3." + call void [System.Console]System.Console::WriteLine(string) + leave.s T4 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T4 + } + + T4: + .try + { + call void CMain::RunTest4() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Invalid4." + call void [System.Console]System.Console::WriteLine(string) + leave.s T5 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T5 + } + + T5: + .try + { + call void CMain::RunTest5() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Invalid5." + call void [System.Console]System.Console::WriteLine(string) + leave.s T6 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s T6 + } + + T6: + .try + { + call void CMain::RunTest6() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Invalid6." + call void [System.Console]System.Console::WriteLine(string) + leave.s DONE + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s DONE + } + + DONE: + + ldloc.0 + brtrue.s PASS + + ldc.i4.s 101 + ret + + PASS: + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideMoreDerivedReturn.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Negative/OverrideSameSigAsDecl.ilproj similarity index 80% rename from src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideMoreDerivedReturn.ilproj rename to src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Negative/OverrideSameSigAsDecl.ilproj index 31b7d301228e9a..7bf8afb159d367 100644 --- a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideMoreDerivedReturn.ilproj +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Negative/OverrideSameSigAsDecl.ilproj @@ -5,6 +5,6 @@ 1 - + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/NoValidation/IncompatibleReturnNoValidation.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/NoValidation/IncompatibleReturnNoValidation.il new file mode 100644 index 00000000000000..1dea0cc7577e3a --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/NoValidation/IncompatibleReturnNoValidation.il @@ -0,0 +1,366 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern System.Private.CoreLib { } +.assembly extern System.Runtime { } +.assembly extern mscorlib { } +.assembly IncompatibleReturnNoValidation { } + +.class public auto ansi beforefieldinit A { } +.class public auto ansi beforefieldinit B extends A { } +.class public auto ansi beforefieldinit C extends B { } + +.class public auto ansi beforefieldinit GenRetType { } +.class public auto ansi beforefieldinit Dictionary { } + +.class public auto ansi beforefieldinit GenDerive1 extends class GenRetType { } +.class public auto ansi beforefieldinit GenDerive2 extends class GenDerive1> { } +.class public auto ansi beforefieldinit GenDerive3 extends class GenDerive2 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 extends class GenRetType { } +.class public auto ansi beforefieldinit NonGenericDerived2 extends class NonGenericDerived1 { } +.class public auto ansi beforefieldinit NonGenericDerived3 extends class NonGenericDerived2 { } +.class public auto ansi beforefieldinit NonGenericDerived4 extends NonGenericDerived3 { } + +.class public auto ansi beforefieldinit GenToNonGen1 extends C { } +.class public auto ansi beforefieldinit GenToNonGen2 extends class GenToNonGen1> { } +.class public auto ansi beforefieldinit GenToNonGen3 extends class GenToNonGen2 { } + + +.class public auto ansi beforefieldinit NonGenThroughGen1 extends C { } +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class NonGenThroughGen1> { } +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class NonGenThroughGen2 { } +.class public auto ansi beforefieldinit NonGenThroughGen4 extends NonGenThroughGen3 { } + +.class public auto ansi beforefieldinit GenBaseType +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + + .method public hidebysig newslot virtual instance object MyFunc(string& res) + { + ldarg.0 + ldstr "object GenBaseType.MyFunc()" + stind.ref + newobj instance void A::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B MyFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.MyFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B GenToNonGen(string& res) + { + ldarg.0 + ldstr "B GenBaseType.GenToNonGen()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B NonGenThroughGenFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.NonGenThroughGenFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType> MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType> GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType>::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType TestNonGenericDerived(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.TestNonGenericDerived()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } +} + + +// ======================================================================================== + +.class public auto ansi beforefieldinit GenTestType extends class GenBaseType +{ + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenOverride(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + ldarg.1 + ldstr "NonGenThroughGen4 TestType.NonGenThroughGenFunc()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenOverride(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen(string& res) + ldarg.1 + ldstr "GenToNonGen3 TestType.GenToNonGenOverride()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class NonGenericDerived4 NewGenFunc1(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "NonGenericDerived4 TestType.NewGenFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenDerive3 NewGenFunc2(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "GenDerive3 TestType.NewGenFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenRetType NewFunc1(string& res) + { + .override method instance object class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "GenRetType TestType.NewFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class C NewFunc2(string& res) + { + .override method instance class B class GenBaseType::MyFunc(string& res) + ldarg.1 + ldstr "C TestType.NewFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenBaseType::.ctor() + ret + } +} + +// ======================================================================================== + +// ======================================================================================== +// The following types are overriding base type methods that have already been overridden +// with covariant return types, but the return type here is not compatible (return type is +// a base type of the covariant return type of existing overrides). Validation is only +// triggered by the presense of the ValidateMethodImplRemainsInEffect attribute, so the +// following types should successfully load since they do not have the attribute. +// ======================================================================================== +.class public auto ansi beforefieldinit IncompatibleButValid1 extends class GenTestType +{ + .method public hidebysig newslot virtual instance class B NonGenThroughGenOverride_IncompatibleButValid(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit IncompatibleButValid2 extends class GenTestType +{ + .method public hidebysig newslot virtual instance class B GenToNonGenOverride_IncompatibleButValid(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen(string& res) + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit IncompatibleButValid3 extends class GenTestType +{ + .method public hidebysig newslot virtual instance class GenRetType NewGenFunc1_IncompatibleButValid(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc(string& res) + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit IncompatibleButValid4 extends class GenTestType +{ + .method public hidebysig newslot virtual instance class GenRetType> NewGenFunc2_IncompatibleButValid(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc(string& res) + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit IncompatibleButValid5 extends class GenTestType +{ + .method public hidebysig newslot virtual instance object NewFunc1_IncompatibleButValid(string& res) + { + .override method instance object class GenBaseType::MyFunc(string& res) + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit IncompatibleButValid6 extends class GenTestType +{ + .method public hidebysig newslot virtual instance class B NewFunc2_IncompatibleButValid(string& res) + { + .override method instance class B class GenBaseType::MyFunc(string& res) + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenTestType::.ctor() + ret + } +} + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + .method public static void RunTest1() noinlining + { + newobj instance void class IncompatibleButValid1::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest2() noinlining + { + newobj instance void class IncompatibleButValid2::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest3() noinlining + { + newobj instance void class IncompatibleButValid3::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest4() noinlining + { + newobj instance void class IncompatibleButValid4::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest5() noinlining + { + newobj instance void class IncompatibleButValid5::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunTest6() noinlining + { + newobj instance void class IncompatibleButValid6::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + + // No exception should be thrown here. + call void CMain::RunTest1() + call void CMain::RunTest2() + call void CMain::RunTest3() + call void CMain::RunTest4() + call void CMain::RunTest5() + call void CMain::RunTest6() + + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/NoValidation/IncompatibleReturnNoValidation.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/NoValidation/IncompatibleReturnNoValidation.ilproj new file mode 100644 index 00000000000000..3d2e01fb5d250d --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/NoValidation/IncompatibleReturnNoValidation.ilproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideMoreDerivedReturn.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/OverrideMoreDerivedReturn.il similarity index 100% rename from src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideMoreDerivedReturn.il rename to src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/OverrideMoreDerivedReturn.il diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/OverrideMoreDerivedReturn.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/OverrideMoreDerivedReturn.ilproj new file mode 100644 index 00000000000000..919060123e065a --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/OverrideMoreDerivedReturn.ilproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideSameReturn.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/OverrideSameReturn.il similarity index 100% rename from src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideSameReturn.il rename to src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/OverrideSameReturn.il diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideSameReturn.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/OverrideSameReturn.ilproj similarity index 82% rename from src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideSameReturn.ilproj rename to src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/OverrideSameReturn.ilproj index 9b917476d9a184..c2be2cd6a5b067 100644 --- a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/ReOverrideSameReturn.ilproj +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/OverrideSameReturn.ilproj @@ -5,6 +5,6 @@ 1 - + diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.il index 2e0049efb773d0..53e7a1fb2bf9d8 100644 --- a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.il +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest.il @@ -4,6 +4,7 @@ .assembly extern System.Console { } .assembly extern System.Runtime { } +.assembly extern System.Private.CoreLib { } .assembly extern mscorlib { } .assembly UnitTest { } @@ -104,8 +105,66 @@ // ======================================================================================== -.class public auto ansi beforefieldinit GenTestType extends class GenBaseType +.class public auto ansi beforefieldinit GenMiddleType extends class GenBaseType { + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenBaseType::.ctor() + ret + } + + .method public hidebysig newslot virtual instance class NonGenThroughGen2 NonGenThroughGenOverride_Middle(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + ldarg.1 + ldstr "NonGenThroughGen2 GenMiddleType.NonGenThroughGenFunc()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenToNonGen1> GenToNonGenOverride_Middle(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen(string& res) + ldarg.1 + ldstr "GenToNonGen1> GenMiddleType.GenToNonGenOverride()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class NonGenericDerived1 NewGenFunc1_Middle(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "NonGenericDerived1 GenMiddleType.NewGenFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenDerive1> NewGenFunc2_Middle(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc(string& res) + ldarg.1 + ldstr "GenDerive1> GenMiddleType.NewGenFunc2()" + stind.ref + ldnull + ret + } + +} + + +// ======================================================================================== +.class public auto ansi beforefieldinit GenTestType extends class GenMiddleType +{ + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenOverride(string& res) { .override method instance class B class GenBaseType::NonGenThroughGenFunc(string& res) @@ -170,13 +229,14 @@ { .maxstack 8 ldarg.0 - call instance void class GenBaseType::.ctor() + call instance void class GenMiddleType::.ctor() ret } } .class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object { + // ============== Test using GenTestType ============== // .method public static bool RunTest1() noinlining { .locals init (string res, bool flag) @@ -315,6 +375,101 @@ ret } + // ============== Test using GenMiddleType ============== // + .method public static bool RunTest_Middle1() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenDerive1> GenMiddleType.NewGenFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenMiddleType::.ctor() + ldloca.s 0 + callvirt instance class GenRetType> class GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenDerive1> GenMiddleType.NewGenFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest_Middle2() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenericDerived1 GenMiddleType.NewGenFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenMiddleType::.ctor() + ldloca.s 0 + callvirt instance class GenRetType class GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenericDerived1 GenMiddleType.NewGenFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest_Middle3() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenToNonGen1> GenMiddleType.GenToNonGenOverride()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenMiddleType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::GenToNonGen(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenToNonGen1> GenMiddleType.GenToNonGenOverride()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest_Middle4() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenThroughGen2 GenMiddleType.NonGenThroughGenFunc()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenMiddleType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenThroughGen2 GenMiddleType.NonGenThroughGenFunc()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + // ===================================================================================== // + .method public hidebysig static int32 Main( string[] args) cil managed { .entrypoint @@ -356,6 +511,30 @@ T6: call bool CMain::RunTest6() + brtrue.s M1 + ldc.i4.0 + stloc.0 + + M1: + call bool CMain::RunTest_Middle1() + brtrue.s M2 + ldc.i4.0 + stloc.0 + + M2: + call bool CMain::RunTest_Middle2() + brtrue.s M3 + ldc.i4.0 + stloc.0 + + M3: + call bool CMain::RunTest_Middle3() + brtrue.s M4 + ldc.i4.0 + stloc.0 + + M4: + call bool CMain::RunTest_Middle4() brtrue.s DONE ldc.i4.0 stloc.0 diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 4e8a39bf297b81..a952df253606ce 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -631,6 +631,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValidateMethodImplRemainsInEffectAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValidateMethodImplRemainsInEffectAttribute.cs new file mode 100644 index 00000000000000..2da77ceb45fe9f --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValidateMethodImplRemainsInEffectAttribute.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public sealed class ValidateMethodImplRemainsInEffectAttribute : Attribute + { + } +} From 06cdc5ebfc3f7ee0eb1c7c2a5088c96249daab02 Mon Sep 17 00:00:00 2001 From: Fadi Hanna Date: Tue, 14 Apr 2020 22:09:28 -0700 Subject: [PATCH 12/13] Small refactor --- src/coreclr/src/vm/siginfo.cpp | 95 ++++++------------- .../IncompatibleReturnNoValidation.il | 0 .../IncompatibleReturnNoValidation.ilproj | 0 .../OverrideSameSigAsDecl.il | 0 .../OverrideSameSigAsDecl.ilproj | 0 5 files changed, 29 insertions(+), 66 deletions(-) rename src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/{NoValidation => Validation}/IncompatibleReturnNoValidation.il (100%) rename src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/{NoValidation => Validation}/IncompatibleReturnNoValidation.ilproj (100%) rename src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/{Negative => Validation}/OverrideSameSigAsDecl.il (100%) rename src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/{Negative => Validation}/OverrideSameSigAsDecl.ilproj (100%) diff --git a/src/coreclr/src/vm/siginfo.cpp b/src/coreclr/src/vm/siginfo.cpp index cd7dbedd274dde..d1a602b26caa90 100644 --- a/src/coreclr/src/vm/siginfo.cpp +++ b/src/coreclr/src/vm/siginfo.cpp @@ -4742,6 +4742,33 @@ MetaSig::CompareMethodSigs( return FALSE; } + // + // If we are comparing the return type signatures and allow for covariant returns, + // we need to check if the return type on the second signature is a generic type, + // and if so, chain its generic instantiation arguments to the substitution chain. + // This is necessary in case we need to compute the base type signature of the second + // type's signature, and compare that to the first type's signature, to allow for + // derived types. + // + SigPointer instArgSignature; + Substitution instArgsSubstitution; + if (allowCovariantReturn) + { + MetaSig metaSig2(pSig2, (DWORD)(pEndSig2 - pSig2), pModule2, NULL); + SigParser parser(metaSig2.GetReturnProps()); + + CorElementType returnElementType; + IfFailThrow(parser.GetElemType(&returnElementType)); + + if (returnElementType == ELEMENT_TYPE_GENERICINST) + { + IfFailThrow(parser.SkipExactlyOne()); // Skip generic type definition signature + IfFailThrow(parser.GetData(NULL)); // Skip number of generic arguments + instArgSignature = SigPointer(parser.GetPtr()); + instArgsSubstitution = Substitution(pModule2, instArgSignature, pSubst2); + } + } + __int8 callConv = *pSig1; pSig1++; @@ -4800,38 +4827,6 @@ MetaSig::CompareMethodSigs( // This would be a breaking change to make this throw... see comment above _ASSERT(*pSig2 != ELEMENT_TYPE_SENTINEL); - pSubst2 = pOrigSubst2; - - // - // If we are comparing the return type signatures and allow for covariant returns, - // we need to check if the return type on the second signature is a generic type, - // and if so, chain its generic instantiation arguments to the substitution chain. - // This is necessary in case we need to compute the base type signature of the second - // type's signature, and compare that to the first type's signature, to allow for - // derived types. - // - SigPointer instArgSignature; - Substitution instArgsSubstitution; - if (i == 0 && allowCovariantReturn) - { - SigParser parser(pSig2, (DWORD)(pEndSig2 - pSig2)); - - CorElementType returnElementType; - IfFailThrow(parser.GetElemType(&returnElementType)); - - if (returnElementType == ELEMENT_TYPE_GENERICINST) - { - IfFailThrow(parser.SkipExactlyOne()); // Skip generic type definition signature - IfFailThrow(parser.GetData(NULL)); // Skip number of generic arguments - instArgSignature = SigPointer(parser.GetPtr()); - instArgsSubstitution = Substitution(pModule2, instArgSignature, pSubst2); - - // Temporarily chain the generic instantiation to the substitution chain of the - // second type's signature - pSubst2 = &instArgsSubstitution; - } - } - // We are in bounds on both sides. Compare the element. if (!CompareElementType( pSig1, @@ -4841,7 +4836,7 @@ MetaSig::CompareMethodSigs( pModule1, pModule2, pSubst1, - pSubst2, + (i == 0 && allowCovariantReturn) ? &instArgsSubstitution : pSubst2, i == 0 && allowCovariantReturn, pVisited)) { @@ -4859,38 +4854,6 @@ MetaSig::CompareMethodSigs( // do return type as well for (i = 0; i <= ArgCount1; i++) { - pSubst2 = pOrigSubst2; - - // - // If we are comparing the return type signatures and allow for covariant returns, - // we need to check if the return type on the second signature is a generic type, - // and if so, chain its generic instantiation arguments to the substitution chain. - // This is necessary in case we need to compute the base type signature of the second - // type's signature, and compare that to the first type's signature, to allow for - // derived types. - // - SigPointer instArgSignature; - Substitution instArgsSubstitution; - if (i == 0 && allowCovariantReturn) - { - SigParser parser(pSig2, (DWORD)(pEndSig2 - pSig2)); - - CorElementType returnElementType; - IfFailThrow(parser.GetElemType(&returnElementType)); - - if (returnElementType == ELEMENT_TYPE_GENERICINST) - { - IfFailThrow(parser.SkipExactlyOne()); // Skip generic type definition signature - IfFailThrow(parser.GetData(NULL)); // Skip number of generic arguments - instArgSignature = SigPointer(parser.GetPtr()); - instArgsSubstitution = Substitution(pModule2, instArgSignature, pSubst2); - - // Temporarily chain the generic instantiation to the substitution chain of the - // second type's signature - pSubst2 = &instArgsSubstitution; - } - } - if (!CompareElementType( pSig1, pSig2, @@ -4899,7 +4862,7 @@ MetaSig::CompareMethodSigs( pModule1, pModule2, pSubst1, - pSubst2, + (i == 0 && allowCovariantReturn) ? &instArgsSubstitution : pSubst2, i == 0 && allowCovariantReturn, pVisited)) { diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/NoValidation/IncompatibleReturnNoValidation.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Validation/IncompatibleReturnNoValidation.il similarity index 100% rename from src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/NoValidation/IncompatibleReturnNoValidation.il rename to src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Validation/IncompatibleReturnNoValidation.il diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/NoValidation/IncompatibleReturnNoValidation.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Validation/IncompatibleReturnNoValidation.ilproj similarity index 100% rename from src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/NoValidation/IncompatibleReturnNoValidation.ilproj rename to src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Validation/IncompatibleReturnNoValidation.ilproj diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Negative/OverrideSameSigAsDecl.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Validation/OverrideSameSigAsDecl.il similarity index 100% rename from src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Negative/OverrideSameSigAsDecl.il rename to src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Validation/OverrideSameSigAsDecl.il diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Negative/OverrideSameSigAsDecl.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Validation/OverrideSameSigAsDecl.ilproj similarity index 100% rename from src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Negative/OverrideSameSigAsDecl.ilproj rename to src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/Validation/OverrideSameSigAsDecl.ilproj From 49730222fac1d5319a845af9fbd56244ddb5915f Mon Sep 17 00:00:00 2001 From: Fadi Hanna Date: Wed, 15 Apr 2020 12:42:01 -0700 Subject: [PATCH 13/13] Add coverage for GVMs, and fix a validation bug with GVM instantiations --- src/coreclr/src/vm/class.cpp | 10 +- src/coreclr/src/vm/siginfo.cpp | 2 - .../CovariantReturns/UnitTest/UnitTest_GVM.il | 723 ++++++++++++++++++ .../UnitTest/UnitTest_GVM.ilproj | 10 + 4 files changed, 740 insertions(+), 5 deletions(-) create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest_GVM.il create mode 100644 src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest_GVM.ilproj diff --git a/src/coreclr/src/vm/class.cpp b/src/coreclr/src/vm/class.cpp index 3f085f9122726c..53233207379e28 100644 --- a/src/coreclr/src/vm/class.cpp +++ b/src/coreclr/src/vm/class.cpp @@ -1012,11 +1012,15 @@ void ClassLoader::ValidateMethodImplRemainsInEffect(MethodTable* pMT) if (originalIndex == originalIndexParent) continue; - SigTypeContext context1(pParentMD); - TypeHandle hType1 = pParentMD->GetSigPointer().GetTypeHandleThrowing(pParentMD->GetModule(), &context1, ClassLoader::LoadTypesFlag::LoadTypes, CLASS_LOAD_EXACTPARENTS); + // The context used to load the return type of the parent method has to use the generic method arguments + // of the overriding method, otherwise the type comparison below will not work correctly + SigTypeContext context1(pParentMD->GetClassInstantiation(), pMD->GetMethodInstantiation()); + MetaSig methodSig1(pParentMD); + TypeHandle hType1 = methodSig1.GetReturnProps().GetTypeHandleThrowing(pParentMD->GetModule(), &context1, ClassLoader::LoadTypesFlag::LoadTypes, CLASS_LOAD_EXACTPARENTS); SigTypeContext context2(pMD); - TypeHandle hType2 = pMD->GetSigPointer().GetTypeHandleThrowing(pMD->GetModule(), &context2, ClassLoader::LoadTypesFlag::LoadTypes, CLASS_LOAD_EXACTPARENTS); + MetaSig methodSig2(pMD); + TypeHandle hType2 = methodSig2.GetReturnProps().GetTypeHandleThrowing(pMD->GetModule(), &context2, ClassLoader::LoadTypesFlag::LoadTypes, CLASS_LOAD_EXACTPARENTS); // Type1 has to be equal to Type2, or a base type of Type2 (covariant returns) diff --git a/src/coreclr/src/vm/siginfo.cpp b/src/coreclr/src/vm/siginfo.cpp index d1a602b26caa90..7d8ade1d3b628f 100644 --- a/src/coreclr/src/vm/siginfo.cpp +++ b/src/coreclr/src/vm/siginfo.cpp @@ -4723,8 +4723,6 @@ MetaSig::CompareMethodSigs( DWORD ArgCount2; DWORD i; - const Substitution* pOrigSubst2 = pSubst2; - // If scopes are the same, and sigs are same, can return. // If the sigs aren't the same, but same scope, can't return yet, in // case there are two AssemblyRefs pointing to the same assembly or such. diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest_GVM.il b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest_GVM.il new file mode 100644 index 00000000000000..a1f5a598025dda --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest_GVM.il @@ -0,0 +1,723 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern System.Console { } +.assembly extern System.Runtime { } +.assembly extern System.Private.CoreLib { } +.assembly extern mscorlib { } +.assembly UnitTest_GVM { } + +.class public auto ansi beforefieldinit A { } +.class public auto ansi beforefieldinit B extends A { } +.class public auto ansi beforefieldinit C extends B { } + +.class public auto ansi beforefieldinit GenRetType { } +.class public auto ansi beforefieldinit Dictionary { } + +.class public auto ansi beforefieldinit GenDerive1 extends class GenRetType { } +.class public auto ansi beforefieldinit GenDerive2 extends class GenDerive1> { } +.class public auto ansi beforefieldinit GenDerive3 extends class GenDerive2 { } + +.class public auto ansi beforefieldinit NonGenericDerived1 extends class GenRetType { } +.class public auto ansi beforefieldinit NonGenericDerived2 extends class NonGenericDerived1 { } +.class public auto ansi beforefieldinit NonGenericDerived3 extends class NonGenericDerived2 { } +.class public auto ansi beforefieldinit NonGenericDerived4 extends NonGenericDerived3 { } +.class public auto ansi beforefieldinit NonGenericDerived5 extends class NonGenericDerived1 { } + +.class public auto ansi beforefieldinit GenToNonGen1 extends C { } +.class public auto ansi beforefieldinit GenToNonGen2 extends class GenToNonGen1> { } +.class public auto ansi beforefieldinit GenToNonGen3 extends class GenToNonGen2 { } + + +.class public auto ansi beforefieldinit NonGenThroughGen1 extends C { } +.class public auto ansi beforefieldinit NonGenThroughGen2 extends class NonGenThroughGen1> { } +.class public auto ansi beforefieldinit NonGenThroughGen3 extends class NonGenThroughGen2 { } +.class public auto ansi beforefieldinit NonGenThroughGen4 extends NonGenThroughGen3 { } +.class public auto ansi beforefieldinit NonGenThroughGen5 extends class NonGenThroughGen2 { } + + +.class public auto ansi beforefieldinit GenBaseType +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + + .method public hidebysig newslot virtual instance object MyFunc(string& res) + { + ldarg.0 + ldstr "object GenBaseType.MyFunc()" + stind.ref + newobj instance void A::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B MyFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.MyFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B GenToNonGen(string& res) + { + ldarg.0 + ldstr "B GenBaseType.GenToNonGen()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class B NonGenThroughGenFunc(string& res) + { + ldarg.0 + ldstr "B GenBaseType.NonGenThroughGenFunc()" + stind.ref + newobj instance void B::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType> MyGenFunc(string& res) + { + ldarg.0 + ldstr "GenRetType> GenBaseType.MyGenFunc()" + stind.ref + newobj instance void class GenRetType>::.ctor() + ret + } + .method public hidebysig newslot virtual instance class GenRetType TestNonGenericDerived(string& res) + { + ldarg.0 + ldstr "GenRetType GenBaseType.TestNonGenericDerived()" + stind.ref + newobj instance void class GenRetType::.ctor() + ret + } +} + + +// ======================================================================================== + +.class public auto ansi beforefieldinit GenMiddleType extends class GenBaseType +{ + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenBaseType::.ctor() + ret + } + + .method public hidebysig newslot virtual instance class NonGenThroughGen2 NonGenThroughGenOverride_Middle(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc<[1]>(string& res) + ldarg.1 + ldstr "NonGenThroughGen2 GenMiddleType.NonGenThroughGenFunc()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenToNonGen1> GenToNonGenOverride_Middle(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen<[1]>(string& res) + ldarg.1 + ldstr "GenToNonGen1> GenMiddleType.GenToNonGenOverride()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class NonGenericDerived1 NewGenFunc1_Middle(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc<[1]>(string& res) + ldarg.1 + ldstr "NonGenericDerived1 GenMiddleType.NewGenFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenDerive2 NewGenFunc2_Middle(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc<[1]>(string& res) + ldarg.1 + ldstr "GenDerive2 GenMiddleType.NewGenFunc2()" + stind.ref + ldnull + ret + } +} + +// ======================================================================================== + +.class public auto ansi beforefieldinit GenTestType extends class GenMiddleType +{ + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + + .method public hidebysig newslot virtual instance class NonGenThroughGen5 NonGenThroughGenOverride(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc<[1]>(string& res) + ldarg.1 + ldstr "NonGenThroughGen5 TestType.NonGenThroughGenFunc()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenOverride(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen<[1]>(string& res) + ldarg.1 + ldstr "GenToNonGen3 TestType.GenToNonGenOverride()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class NonGenericDerived5 NewGenFunc1(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc<[1]>(string& res) + ldarg.1 + ldstr "NonGenericDerived5 TestType.NewGenFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenDerive2 NewGenFunc2(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc<[1]>(string& res) + ldarg.1 + ldstr "GenDerive2 TestType.NewGenFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class GenRetType NewFunc1(string& res) + { + .override method instance object class GenBaseType::MyFunc<[1]>(string& res) + ldarg.1 + ldstr "GenRetType TestType.NewFunc1()" + stind.ref + ldnull + ret + } + + .method public hidebysig newslot virtual instance class C NewFunc2(string& res) + { + .override method instance class B class GenBaseType::MyFunc<[1]>(string& res) + ldarg.1 + ldstr "C TestType.NewFunc2()" + stind.ref + ldnull + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void class GenMiddleType::.ctor() + ret + } +} + +// ======================================================================================== + +.class public auto ansi beforefieldinit Invalid1 extends class GenMiddleType +{ + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + + // Invalid: when comparing 'object' with !!Y in the instantiation of NonGenericDerived1 in the base type chain + .method public hidebysig newslot virtual instance class NonGenThroughGen4 NonGenThroughGenOverride(string& res) + { + .override method instance class B class GenBaseType::NonGenThroughGenFunc<[1]>(string& res) + ldnull + ret + } +} +.class public auto ansi beforefieldinit Invalid2 extends class GenMiddleType +{ + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + + // Invalid: when comparing 'object' with !!Y in the instantiation + .method public hidebysig newslot virtual instance class GenToNonGen3 GenToNonGenOverride(string& res) + { + .override method instance class B class GenBaseType::GenToNonGen<[1]>(string& res) + ldnull + ret + } +} +.class public auto ansi beforefieldinit Invalid3 extends class GenMiddleType +{ + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + + // Invalid when comparing !!Y and 'object' in instantiation of GenRetType + .method public hidebysig newslot virtual instance class NonGenericDerived4 NewGenFunc1(string& res) + { + .override method instance class GenRetType class GenBaseType::MyGenFunc<[1]>(string& res) + ldnull + ret + } +} +.class public auto ansi beforefieldinit Invalid4 extends class GenMiddleType +{ + .custom instance void [System.Private.CoreLib]System.Runtime.CompilerServices.ValidateMethodImplRemainsInEffectAttribute::.ctor() = (01 00 00 00) + + // Invalid when comparing !!Y and 'string' in instantiation of Dictionary + .method public hidebysig newslot virtual instance class GenDerive3 NewGenFunc2(string& res) + { + .override method instance class GenRetType> class GenBaseType::MyGenFunc<[1]>(string& res) + ldnull + ret + } +} + +// ======================================================================================== + +.class public auto ansi beforefieldinit CMain extends [mscorlib]System.Object +{ + // ============== Test using GenTestType ============== // + .method public static bool RunTest1() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenRetType TestType.NewFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + ldloca.s 0 + callvirt instance object class GenBaseType::MyFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenRetType TestType.NewFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest2() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: C TestType.NewFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::MyFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "C TestType.NewFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest3() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenDerive2 TestType.NewGenFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + ldloca.s 0 + callvirt instance class GenRetType> class GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenDerive2 TestType.NewGenFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest4() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenericDerived5 TestType.NewGenFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + ldloca.s 0 + callvirt instance class GenRetType class GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenericDerived5 TestType.NewGenFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest5() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenToNonGen3 TestType.GenToNonGenOverride()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::GenToNonGen(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenToNonGen3 TestType.GenToNonGenOverride()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest6() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenThroughGen5 TestType.NonGenThroughGenFunc()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenTestType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenThroughGen5 TestType.NonGenThroughGenFunc()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + // ============== Test using GenMiddleType ============== // + .method public static bool RunTest_Middle1() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenDerive2 GenMiddleType.NewGenFunc2()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenMiddleType::.ctor() + ldloca.s 0 + callvirt instance class GenRetType> class GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenDerive2 GenMiddleType.NewGenFunc2()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest_Middle2() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenericDerived1 GenMiddleType.NewGenFunc1()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenMiddleType::.ctor() + ldloca.s 0 + callvirt instance class GenRetType class GenBaseType::MyGenFunc(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenericDerived1 GenMiddleType.NewGenFunc1()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest_Middle3() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: GenToNonGen1> GenMiddleType.GenToNonGenOverride()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenMiddleType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::GenToNonGen(string&) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "GenToNonGen1> GenMiddleType.GenToNonGenOverride()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + .method public static bool RunTest_Middle4() noinlining + { + .locals init (string res, bool flag) + + ldstr "EXPECTED: NonGenThroughGen2 GenMiddleType.NonGenThroughGenFunc()" + call void [System.Console]System.Console::WriteLine(object) + ldstr "ACTUAL : " + call void [System.Console]System.Console::Write(object) + + newobj instance void class GenMiddleType::.ctor() + ldloca.s 0 + callvirt instance class B class GenBaseType::NonGenThroughGenFunc(string& res) + pop + + ldloc.0 + call void [System.Console]System.Console::WriteLine(object) + + ldloc.0 + ldstr "NonGenThroughGen2 GenMiddleType.NonGenThroughGenFunc()" + call bool [System.Runtime]System.String::op_Equality(string, string) + ret + } + + // ===================================================================================== // + .method public static void RunInvalidTest1() noinlining + { + newobj instance void class Invalid1::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunInvalidTest2() noinlining + { + newobj instance void class Invalid2::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunInvalidTest3() noinlining + { + newobj instance void class Invalid3::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + .method public static void RunInvalidTest4() noinlining + { + newobj instance void class Invalid4::.ctor() + call void [System.Console]System.Console::WriteLine(object) + ret + } + + // ===================================================================================== // + .method public hidebysig static int32 Main( string[] args) cil managed + { + .entrypoint + .maxstack 2 + .locals init ( bool result ) + + ldc.i4.1 + stloc.0 + + T1: + call bool CMain::RunTest1() + brtrue.s T2 + ldc.i4.0 + stloc.0 + + T2: + call bool CMain::RunTest2() + brtrue.s T3 + ldc.i4.0 + stloc.0 + + T3: + call bool CMain::RunTest3() + brtrue.s T4 + ldc.i4.0 + stloc.0 + + T4: + call bool CMain::RunTest4() + brtrue.s T5 + ldc.i4.0 + stloc.0 + + T5: + call bool CMain::RunTest5() + brtrue.s T6 + ldc.i4.0 + stloc.0 + + T6: + call bool CMain::RunTest6() + brtrue.s M1 + ldc.i4.0 + stloc.0 + + M1: + call bool CMain::RunTest_Middle1() + brtrue.s M2 + ldc.i4.0 + stloc.0 + + M2: + call bool CMain::RunTest_Middle2() + brtrue.s M3 + ldc.i4.0 + stloc.0 + + M3: + call bool CMain::RunTest_Middle3() + brtrue.s M4 + ldc.i4.0 + stloc.0 + + M4: + call bool CMain::RunTest_Middle4() + brtrue.s INVALID1 + ldc.i4.0 + stloc.0 + + INVALID1: + .try + { + call void CMain::RunInvalidTest1() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Invalid1." + call void [System.Console]System.Console::WriteLine(string) + leave.s INVALID2 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s INVALID2 + } + + INVALID2: + .try + { + call void CMain::RunInvalidTest2() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Invalid2." + call void [System.Console]System.Console::WriteLine(string) + leave.s INVALID3 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s INVALID3 + } + + INVALID3: + .try + { + call void CMain::RunInvalidTest3() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Invalid3." + call void [System.Console]System.Console::WriteLine(string) + leave.s INVALID4 + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s INVALID4 + } + + INVALID4: + .try + { + call void CMain::RunInvalidTest4() + ldc.i4.0 + stloc.0 + ldstr "FAIL: did not catch expected TypeLoadException when loading Invalid4." + call void [System.Console]System.Console::WriteLine(string) + leave.s DONE + } + catch [mscorlib]System.TypeLoadException + { + ldstr "Caught expected TypeLoadException:" + call void [System.Console]System.Console::WriteLine(string) + call void [System.Console]System.Console::WriteLine(object) + leave.s DONE + } + + DONE: + ldloc.0 + brtrue.s PASS + + ldstr "Test FAILED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 101 + ret + + PASS: + ldstr "Test PASSED" + call void [System.Console]System.Console::WriteLine(string) + ldc.i4.s 100 + ret + + ldc.i4.s 100 + ret + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} diff --git a/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest_GVM.ilproj b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest_GVM.ilproj new file mode 100644 index 00000000000000..4d57a6f1c738b4 --- /dev/null +++ b/src/coreclr/tests/src/Loader/classloader/MethodImpl/CovariantReturns/UnitTest/UnitTest_GVM.ilproj @@ -0,0 +1,10 @@ + + + Exe + BuildAndRun + 1 + + + + +