diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 01291c77..93253681 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -993,13 +993,53 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp { SET_BETTER_OR_WORSE(newMethodInstance->HasExternConstraints(), prevMethodInstance->HasExternConstraints()); } - } - + } + if ((isBetter) || (isWorse)) { RETURN_RESULTS; } + if ((newMethodInstance->mMethodDef->mExternalConstraints.size() != 0) || (prevMethodInstance->mMethodDef->mExternalConstraints.size() != 0)) + { + struct GenericParamPair + { + BfGenericMethodParamInstance* mParams[2]; + GenericParamPair() + { + mParams[0] = NULL; + mParams[1] = NULL; + } + }; + + Dictionary externConstraints; + + auto _GetParams = [&](int idx, BfMethodInstance* methodInstance) + { + for (int externConstraintIdx = 0; externConstraintIdx < (int)methodInstance->mMethodDef->mExternalConstraints.size(); externConstraintIdx++) + { + auto genericParam = methodInstance->mMethodInfoEx->mGenericParams[methodInstance->mMethodDef->mGenericParams.size() + externConstraintIdx]; + BF_ASSERT(genericParam->mExternType != NULL); + GenericParamPair* pairPtr = NULL; + externConstraints.TryAdd(genericParam->mExternType, NULL, &pairPtr); + pairPtr->mParams[idx] = genericParam; + } + }; + + _GetParams(0, newMethodInstance); + _GetParams(0, prevMethodInstance); + + for (auto kv : externConstraints) + { + SET_BETTER_OR_WORSE(mModule->AreConstraintsSubset(kv.mValue.mParams[1], kv.mValue.mParams[0]), mModule->AreConstraintsSubset(kv.mValue.mParams[0], kv.mValue.mParams[1])); + } + + if ((isBetter) || (isWorse)) + { + RETURN_RESULTS; + } + } + // Does one have a body and one doesn't? Obvious! isBetter = prevMethodDef->IsEmptyPartial(); isWorse = newMethodDef->IsEmptyPartial(); @@ -1389,7 +1429,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst mMethodCheckCount++; - BfMethodInstance* methodInstance = mModule->GetRawMethodInstance(typeInstance, checkMethod); + BfMethodInstance* methodInstance = mModule->GetRawMethodInstance(typeInstance, checkMethod); if (methodInstance == NULL) { BFMODULE_FATAL(mModule, "Failed to get raw method in BfMethodMatcher::CheckMethod"); diff --git a/IDEHelper/Tests/src/Generics2.bf b/IDEHelper/Tests/src/Generics2.bf new file mode 100644 index 00000000..48513f50 --- /dev/null +++ b/IDEHelper/Tests/src/Generics2.bf @@ -0,0 +1,50 @@ +using System; + +namespace Tests +{ + class Generics2 + { + struct TestFunc + { + private int mId; + private Del mComparer; + + public static TestFunc Create(int id, Del comparer) + { + return .() + { + mId = id, + mComparer = comparer + }; + } + + public bool CheckDlg(T item) + { + return false; + } + + public bool CheckDlg(T item) where Del : delegate bool(T) + { + return mComparer(item); + } + + public bool CheckDlg(T item) where Del : delegate bool(int, T) + { + return mComparer(mId, item); + } + + public bool CallCheck(T val) + { + return CheckDlg(val); + } + } + + [Test] + public static void TestBasics() + { + let testF = TestFunc.Create(10, scope (s) => s == "Str"); + Test.Assert(testF.CallCheck("Str")); + Test.Assert(!testF.CallCheck("Str2")); + } + } +}