| 15483 | } |
| 15484 | |
| 15485 | bool BfModule::TypeIsSubTypeOf(BfTypeInstance* srcType, BfTypeInstance* wantType, bool checkAccessibility) |
| 15486 | { |
| 15487 | if ((srcType == NULL) || (wantType == NULL)) |
| 15488 | return false; |
| 15489 | if (srcType == wantType) |
| 15490 | return true; |
| 15491 | |
| 15492 | if (srcType->mDefineState < BfTypeDefineState_HasInterfaces_Direct) |
| 15493 | { |
| 15494 | if (srcType->mDefineState == BfTypeDefineState_ResolvingBaseType) |
| 15495 | { |
| 15496 | auto typeState = mContext->mCurTypeState; |
| 15497 | while (typeState != NULL) |
| 15498 | { |
| 15499 | if ((typeState->mType == srcType) && (typeState->mCurBaseType != NULL)) |
| 15500 | { |
| 15501 | return TypeIsSubTypeOf(typeState->mCurBaseType, wantType, checkAccessibility); |
| 15502 | } |
| 15503 | typeState = typeState->mPrevState; |
| 15504 | } |
| 15505 | } |
| 15506 | |
| 15507 | // Type is incomplete. We don't do the IsIncomplete check here because of re-entry |
| 15508 | // While handling 'var' resolution, we don't want to force a PopulateType reentry |
| 15509 | // but we do have enough information for TypeIsSubTypeOf |
| 15510 | PopulateType(srcType, BfPopulateType_Interfaces_Direct); |
| 15511 | } |
| 15512 | |
| 15513 | if (wantType->IsInterface()) |
| 15514 | { |
| 15515 | if (wantType->mDefineState < BfTypeDefineState_HasInterfaces_All) |
| 15516 | PopulateType(srcType, BfPopulateType_Interfaces_All); |
| 15517 | |
| 15518 | BfTypeDef* checkActiveTypeDef = NULL; |
| 15519 | bool checkAccessibility = true; |
| 15520 | if (IsInSpecializedSection()) |
| 15521 | { |
| 15522 | // When we have a specialized section, the generic params may not be considered "included" |
| 15523 | // in the module that contains the generic type definition. We rely on any casting errors |
| 15524 | // to be thrown on the unspecialized type pass. We have a similar issue with injecting mixins. |
| 15525 | checkAccessibility = false; |
| 15526 | } |
| 15527 | |
| 15528 | auto checkType = srcType; |
| 15529 | while (checkType != NULL) |
| 15530 | { |
| 15531 | for (auto ifaceInst : checkType->mInterfaces) |
| 15532 | { |
| 15533 | if (ifaceInst.mInterfaceType == wantType) |
| 15534 | { |
| 15535 | if (checkAccessibility) |
| 15536 | { |
| 15537 | if (checkActiveTypeDef == NULL) |
| 15538 | checkActiveTypeDef = GetActiveTypeDef(NULL, false, true); |
| 15539 | |
| 15540 | // We need to be lenient when validating generic constraints |
| 15541 | // Otherwise "T<A> where T : IB" declared in a lib won't be able to match a type B in a using project 'C', |
| 15542 | // because this check will see the lib using 'C', which it won't consider visible |
no test coverage detected