diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index c357890a..aec4b23b 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -549,6 +549,13 @@ void BfAutoComplete::AddCurrentTypes(BfTypeInstance* typeInst, const StringImpl& auto typeDef = typeInst->mTypeDef; for (auto nestedTypeDef : typeDef->mNestedTypes) { + if (nestedTypeDef->mIsPartial) + { + nestedTypeDef = mSystem->GetCombinedPartial(nestedTypeDef); + if (nestedTypeDef == NULL) + continue; + } + if (CheckProtection(nestedTypeDef->mProtection, allowProtected, allowPrivate)) AddTypeDef(nestedTypeDef, filter, onlyAttribute); } diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 481df8bf..4083e862 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -745,6 +745,18 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp int prevArgIdx = argIdx + prevImplicitParamCount; _CompareParamTypes(newMethodInstance->GetParamType(newArgIdx), prevMethodInstance->GetParamType(prevArgIdx)); } + + // Do generic constraint subset test directly to handle cases like "NotDisposed()" vs "NOtDisposed() where T : IDisposable" + if ((newMethodInstance->GetNumGenericArguments() > 0) && (newMethodInstance->GetNumGenericArguments() == prevMethodInstance->GetNumGenericArguments())) + { + for (int genericParamIdx = 0; genericParamIdx < (int)newMethodInstance->GetNumGenericArguments(); genericParamIdx++) + { + auto newMethodGenericParam = newMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; + auto prevMethodGenericParam = prevMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; + SET_BETTER_OR_WORSE(mModule->AreConstraintsSubset(prevMethodGenericParam, newMethodGenericParam), mModule->AreConstraintsSubset(newMethodGenericParam, prevMethodGenericParam)); + } + } + if ((isBetter) || (isWorse)) { RETURN_RESULTS; @@ -782,7 +794,37 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp } } - RETURN_BETTER_OR_WORSE(newMethodDef->mCheckedKind == mCheckedKind, prevMethodDef->mCheckedKind == mCheckedKind); + // If we have conditional type extensions that both define an implementation for a method, use the most-specific conditional extension constraints + auto owner = newMethodInstance->GetOwner(); + if ((newMethodDef->mDeclaringType != prevMethodDef->mDeclaringType) && (owner->IsGenericTypeInstance())) + { + auto genericOwner = (BfGenericTypeInstance*)owner; + if (genericOwner->mGenericExtensionInfo != NULL) + { + BfGenericExtensionEntry* newGenericExtesionEntry = NULL; + BfGenericExtensionEntry* prevGenericExtesionEntry = NULL; + if ((genericOwner->mGenericExtensionInfo->mExtensionMap.TryGetValue(newMethodDef->mDeclaringType, &newGenericExtesionEntry)) && + (genericOwner->mGenericExtensionInfo->mExtensionMap.TryGetValue(prevMethodDef->mDeclaringType, &prevGenericExtesionEntry))) + { + if ((newGenericExtesionEntry->mGenericParams.size() == prevGenericExtesionEntry->mGenericParams.size())) + { + for (int genericParamIdx = 0; genericParamIdx < (int)newGenericExtesionEntry->mGenericParams.size(); genericParamIdx++) + { + auto newMethodGenericParam = newGenericExtesionEntry->mGenericParams[genericParamIdx]; + auto prevMethodGenericParam = prevGenericExtesionEntry->mGenericParams[genericParamIdx]; + SET_BETTER_OR_WORSE(mModule->AreConstraintsSubset(prevMethodGenericParam, newMethodGenericParam), mModule->AreConstraintsSubset(newMethodGenericParam, prevMethodGenericParam)); + } + } + + if ((isBetter) || (isWorse)) + { + RETURN_RESULTS; + } + } + } + } + + RETURN_BETTER_OR_WORSE(newMethodDef->mCheckedKind == mCheckedKind, prevMethodDef->mCheckedKind == mCheckedKind); RETURN_RESULTS; } diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 80d10c61..189deb6a 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -1502,6 +1502,10 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy for (auto baseTypeRef : typeDef->mBaseTypes) { + SetAndRestoreValue prevTypeRef(mContext->mCurTypeState->mCurBaseTypeRef, baseTypeRef); + SetAndRestoreValue prevIgnoreError(mIgnoreErrors, true); + SetAndRestoreValue prevSkipTypeProtectionChecks(typeInstance->mSkipTypeProtectionChecks, true); + auto baseType = ResolveTypeRef(baseTypeRef, BfPopulateType_Declaration); if (baseType != NULL) { @@ -3811,6 +3815,10 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) if (ifaceMethodInst == NULL) continue; + // Don't even try to match generics + if (!ifaceMethodInst->mMethodDef->mGenericParams.IsEmpty()) + continue; + auto iReturnType = ifaceMethodInst->mReturnType; if (iReturnType->IsSelf()) iReturnType = typeInstance; @@ -3931,7 +3939,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) } } - if ((bestMethodInst->mMethodDef->HasBody()) && (matchedMethod == NULL)) + if ((bestMethodInst->mMethodDef->HasBody()) && (bestMethodInst->mMethodDef->mGenericParams.size() == 0) && (matchedMethod == NULL)) { auto methodDef = bestMethodInst->mMethodDef; BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_ForeignMethodDef; @@ -3939,10 +3947,10 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) flags = (BfGetMethodInstanceFlags)(flags | BfGetMethodInstanceFlag_UnspecializedPass); auto methodInst = GetMethodInstance(typeInstance, methodDef, BfTypeVector(), flags, ifaceInst); if (methodInst) - { + { *matchedMethodRef = methodInst.mMethodInstance; - BfMethodInstance* newMethodInstance = *matchedMethodRef; + BfMethodInstance* newMethodInstance = methodInst.mMethodInstance; BF_ASSERT(newMethodInstance->mIsForeignMethodDef); if (newMethodInstance->mMethodInstanceGroup->mOnDemandKind == BfMethodOnDemandKind_Decl_AwaitingReference) mOnDemandMethodCount++; @@ -4053,7 +4061,7 @@ void BfModule::AddMethodToWorkList(BfMethodInstance* methodInstance) return; BF_ASSERT(mCompiler->mCompileState != BfCompiler::CompileState_VData); - if (methodInstance->mIsReified) + if ((methodInstance->mIsReified) && (!methodInstance->mIsUnspecialized)) { BF_ASSERT(mCompiler->mCompileState != BfCompiler::CompileState_Unreified); } diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index ce5d819f..fa41e383 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -2925,21 +2925,28 @@ void BfSystem::FinishCompositePartial(BfTypeDef* compositeTypeDef) VerifyTypeDef(nextRevision); } +BfTypeDef* BfSystem::GetCombinedPartial(BfTypeDef* typeDef) +{ + if ((!typeDef->mIsPartial) || (typeDef->mIsCombinedPartial)) + return typeDef; + + auto itr = mTypeDefs.TryGet(typeDef->mFullName); + do + { + BF_ASSERT(typeDef->mIsPartial); + typeDef = *itr; + itr.MoveToNextHashMatch(); + } while (!typeDef->mIsCombinedPartial); + return typeDef; +} + BfTypeDef* BfSystem::GetOuterTypeNonPartial(BfTypeDef* typeDef) { auto checkType = typeDef->mOuterType; if ((checkType == NULL) || (!checkType->mIsPartial)) return checkType; - auto itr = mTypeDefs.TryGet(checkType->mFullName); - do - { - BF_ASSERT(checkType->mIsPartial); - checkType = *itr; - itr.MoveToNextHashMatch(); - } - while (!checkType->mIsCombinedPartial); - return checkType; + return GetCombinedPartial(checkType); } int BfSystem::GetGenericParamIdx(const Array& genericParams, const StringImpl& name) diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 1c6f3ce4..c237daff 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -1300,8 +1300,10 @@ public: bool ContainsNamespace(const BfAtomComposite& namespaceStr, BfProject* bfProject); void InjectNewRevision(BfTypeDef* typeDef); void AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* compositeTypeDef, BfTypeDef* partialTypeDef); - void FinishCompositePartial(BfTypeDef* compositeTypeDef); + void FinishCompositePartial(BfTypeDef* compositeTypeDef); + BfTypeDef* GetCombinedPartial(BfTypeDef* typeDef); BfTypeDef* GetOuterTypeNonPartial(BfTypeDef* typeDef); + int GetGenericParamIdx(const Array& genericParams, const StringImpl& name); int GetGenericParamIdx(const Array& genericParams, BfTypeReference* typeRef);