Sfoglia il codice sorgente

Fixed method selection by extern constraint specificity

Brian Fiete 4 anni fa
parent
commit
56bcb6ecd1
2 ha cambiato i file con 93 aggiunte e 3 eliminazioni
  1. 43 3
      IDEHelper/Compiler/BfExprEvaluator.cpp
  2. 50 0
      IDEHelper/Tests/src/Generics2.bf

+ 43 - 3
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -993,13 +993,53 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
 		{
 		{
 			SET_BETTER_OR_WORSE(newMethodInstance->HasExternConstraints(), prevMethodInstance->HasExternConstraints());
 			SET_BETTER_OR_WORSE(newMethodInstance->HasExternConstraints(), prevMethodInstance->HasExternConstraints());
 		}
 		}
-	}		
-
+	}
+	
 	if ((isBetter) || (isWorse))
 	if ((isBetter) || (isWorse))
 	{
 	{
 		RETURN_RESULTS;
 		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<BfType*, GenericParamPair> 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!	
 	// Does one have a body and one doesn't?  Obvious!	
 	isBetter = prevMethodDef->IsEmptyPartial();
 	isBetter = prevMethodDef->IsEmptyPartial();
 	isWorse = newMethodDef->IsEmptyPartial();
 	isWorse = newMethodDef->IsEmptyPartial();
@@ -1389,7 +1429,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
 		
 		
 	mMethodCheckCount++;
 	mMethodCheckCount++;
 	
 	
-	BfMethodInstance* methodInstance = mModule->GetRawMethodInstance(typeInstance, checkMethod);	
+	BfMethodInstance* methodInstance = mModule->GetRawMethodInstance(typeInstance, checkMethod);
 	if (methodInstance == NULL)
 	if (methodInstance == NULL)
 	{		
 	{		
 		BFMODULE_FATAL(mModule, "Failed to get raw method in BfMethodMatcher::CheckMethod");
 		BFMODULE_FATAL(mModule, "Failed to get raw method in BfMethodMatcher::CheckMethod");

+ 50 - 0
IDEHelper/Tests/src/Generics2.bf

@@ -0,0 +1,50 @@
+using System;
+
+namespace Tests
+{
+	class Generics2
+	{
+		struct TestFunc<T, Del>
+		{
+			private int mId;
+			private Del mComparer;
+
+			public static TestFunc<T, Del> 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<String, delegate bool(String)>.Create(10, scope (s) => s == "Str");
+			Test.Assert(testF.CallCheck("Str"));
+			Test.Assert(!testF.CallCheck("Str2"));
+		}
+	}
+}