Browse Source

Improved pointer generic constraints

Brian Fiete 4 months ago
parent
commit
195463cb77

+ 9 - 0
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -23498,6 +23498,15 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
 	case BfUnaryOp_Dereference:
 		{
 			CheckResultForReading(mResult);
+			if (mResult.mType->IsGenericParam())
+			{
+				auto genericParamInstance = mModule->GetGenericParamInstance((BfGenericParamType*)mResult.mType);
+				if ((genericParamInstance->mTypeConstraint != NULL) && (genericParamInstance->mTypeConstraint->IsPointer()))
+				{
+					mResult = mModule->GetDefaultTypedValue(genericParamInstance->mTypeConstraint->GetUnderlyingType(), false, BfDefaultValueKind_Addr);
+					break;
+				}
+			}
 			if (!mResult.mType->IsPointer())
 			{
 				mResult = BfTypedValue();

+ 10 - 9
IDEHelper/Compiler/BfModule.cpp

@@ -8859,17 +8859,18 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
 		}
 	}
 
-	if (checkArgType->IsPointer())
-	{
-		auto ptrType = (BfPointerType*)checkArgType;
-		checkArgType = ptrType->mElementType;
-	}
+	auto checkArgElementType = checkArgType;
+ 	if (checkArgElementType->IsPointer())
+ 	{
+ 		auto ptrType = (BfPointerType*)checkArgElementType;
+		checkArgElementType = ptrType->mElementType;
+ 	}
 
 	if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_New) != 0)
 	{
 		bool canAlloc = false;
 
-		if (auto checkTypeInst = checkArgType->ToTypeInstance())
+		if (auto checkTypeInst = checkArgElementType->ToTypeInstance())
 		{
 			if (checkTypeInst->IsObjectOrStruct())
 			{
@@ -8910,11 +8911,11 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
 					canAlloc = TypeIsSubTypeOf(mCurTypeInstance, checkTypeInst, false);
 			}
 		}
-		else if (checkArgType->IsGenericParam())
+		else if (checkArgElementType->IsGenericParam())
 		{
 			canAlloc = (checkGenericParamFlags & (BfGenericParamFlag_New | BfGenericParamFlag_Var)) != 0;
 		}
-		else if (checkArgType->IsPrimitiveType())
+		else if (checkArgElementType->IsPrimitiveType())
 		{
 			// Any primitive types and stuff can be allocated
 			canAlloc = true;
@@ -8975,7 +8976,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
 						}
 
 						if (doError)
-						{
+						{ 
 							if ((!ignoreErrors) && (PreFail()))
 								*errorOut = Fail(StrFormat("Const generic argument '%s', declared with '%s', is not compatible with const constraint '%s' for '%s'", genericParamInst->GetName().c_str(),
 									_TypeToString(constExprValueType).c_str(), _TypeToString(genericParamInst->mTypeConstraint).c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef);

+ 8 - 0
IDEHelper/Tests/src/Generics.bf

@@ -199,6 +199,11 @@ namespace Tests
 			delete val2;
 		}
 
+		public static int IntPtrTest<T>(T val) where T : int*
+		{
+			return *val;
+		}
+
 		public class ClassE
 		{
 		    public static Self Instance = new ClassE() ~ delete _;
@@ -513,6 +518,9 @@ namespace Tests
 
 			var innerC = OuterA<int, float>.InnerC.this<int32>(123);
 			Test.Assert(innerC.mVal == 123);
+
+			int iVal = 123;
+			Test.Assert(IntPtrTest(&iVal) == 123);
 		}
 	}