Browse Source

Added 'concrete' constraint

Brian Fiete 4 years ago
parent
commit
e3f51e39ed

+ 2 - 2
BeefLibs/corlib/src/Collections/IEnumerator.bf

@@ -17,12 +17,12 @@ namespace System.Collections
 		Result<T> GetNextRef() mut;
 	}
 
-    concrete interface IEnumerable<T>
+    interface IEnumerable<T>
     {
         concrete IEnumerator<T> GetEnumerator();
     }
 
-	concrete interface IRefEnumerable<T>
+	interface IRefEnumerable<T>
 	{
 	    concrete IRefEnumerator<T> GetEnumerator();
 	}

+ 1 - 1
IDE/mintest/minlib/src/System/Collections/IEnumerator.bf

@@ -28,7 +28,7 @@ namespace System.Collections
         Result<T*> GetNextRef() mut;
 	}
     
-    concrete interface IEnumerable<T>
+    interface IEnumerable<T>
     {
         concrete IEnumerator<T> GetEnumerator();
     }

+ 6 - 17
IDEHelper/Compiler/BfDefBuilder.cpp

@@ -286,7 +286,7 @@ void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsD
 
 			if (!name.empty())
 			{
-				if ((name == "class") || (name == "struct") || (name == "struct*") || (name == "const") || (name == "var") || (name == "interface") || (name == "enum"))
+				if ((name == "class") || (name == "struct") || (name == "struct*") || (name == "const") || (name == "var") || (name == "concrete") || (name == "interface") || (name == "enum"))
 				{
 					int prevFlags = constraintDef->mGenericParamFlags & 
 						(BfGenericParamFlag_Class | BfGenericParamFlag_Struct | BfGenericParamFlag_StructPtr | BfGenericParamFlag_Interface | BfGenericParamFlag_Enum);
@@ -319,6 +319,8 @@ void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsD
 						constraintDef->mGenericParamFlags = (BfGenericParamFlags)(constraintDef->mGenericParamFlags | BfGenericParamFlag_StructPtr);
 					else if (name == "const")
 						constraintDef->mGenericParamFlags = (BfGenericParamFlags)(constraintDef->mGenericParamFlags | BfGenericParamFlag_Const);
+					else if (name == "concrete")
+						constraintDef->mGenericParamFlags = (BfGenericParamFlags)(constraintDef->mGenericParamFlags | BfGenericParamFlag_Concrete);
 					else if (name == "interface")
 						constraintDef->mGenericParamFlags = (BfGenericParamFlags)(constraintDef->mGenericParamFlags | BfGenericParamFlag_Interface);
 					else if (name == "enum")
@@ -459,10 +461,7 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
 
 		if (mCurTypeDef->mTypeCode == BfTypeCode_Interface)
 		{
-			if ((methodDef->mIsConcrete) && (!mCurTypeDef->mIsConcrete))
-				Fail("Only interfaces declared as 'concrete' can be declare methods as 'concrete'. Consider adding 'concrete' to the interface declaration.", methodDeclaration->mVirtualSpecifier);
-			//if (!methodDef->mIsConcrete)
-				//Fail(StrFormat("Interfaces methods cannot be declared as '%s'", methodDeclaration->mVirtualSpecifier->ToString().c_str()), methodDeclaration->mVirtualSpecifier);
+			//
 		}
 		else
 		{
@@ -1654,8 +1653,7 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 	mCurTypeDef->mSource = mCurSource;
 	mCurTypeDef->mSource->mRefCount++;
 	mCurTypeDef->mTypeDeclaration = typeDeclaration;
-	mCurTypeDef->mIsAbstract = (typeDeclaration->mAbstractSpecifier != NULL) && (typeDeclaration->mAbstractSpecifier->GetToken() == BfToken_Abstract);
-	mCurTypeDef->mIsConcrete = (typeDeclaration->mAbstractSpecifier != NULL) && (typeDeclaration->mAbstractSpecifier->GetToken() == BfToken_Concrete);
+	mCurTypeDef->mIsAbstract = (typeDeclaration->mAbstractSpecifier != NULL) && (typeDeclaration->mAbstractSpecifier->GetToken() == BfToken_Abstract);	
 	mCurTypeDef->mIsStatic = typeDeclaration->mStaticSpecifier != NULL;
 	mCurTypeDef->mIsDelegate = false;
 	mCurTypeDef->mIsFunction = false;
@@ -1720,16 +1718,7 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 			mCurTypeDef->mIsAbstract = false;
 		}
 	}
-
-	if (mCurTypeDef->mIsConcrete)
-	{
-		if (mCurTypeDef->mTypeCode != BfTypeCode_Interface)
-		{
-			mPassInstance->Warn(0, StrFormat("Types declared as '%s' cannot be 'concrete'", BfTokenToString(typeToken)).c_str(), typeDeclaration->mAbstractSpecifier);
-			mCurTypeDef->mIsConcrete = false;
-		}
-	}
-
+	
 	int outerGenericSize = 0;
 	if (mCurTypeDef->mOuterType != NULL)
 		outerGenericSize = (int)mCurTypeDef->mOuterType->mGenericParamDefs.size();

+ 11 - 18
IDEHelper/Compiler/BfModule.cpp

@@ -1350,6 +1350,8 @@ void BfModule::StartExtension()
 	mStaticFieldRefs.Clear();
 	for (auto& kv : mInterfaceSlotRefs)
 		kv.mValue = BfIRValue();
+	for (auto& pairVal : mDeferredMethodCallData)
+		delete pairVal.mValue;
 	mDeferredMethodCallData.Clear();
 	mDeferredMethodIds.Clear();
 
@@ -5142,11 +5144,6 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 		BfMangler::Mangle(typeDataName, mCompiler->GetMangleKind(), type, mContext->mScratchModule);
 	}
 
-	if (typeDataName == "?sBfTypeData@@bf@@2HA")
-	{
-		NOP;
-	}
-
 	int typeCode = BfTypeCode_None;		
 				
 	if (typeInstance != NULL)
@@ -7482,6 +7479,15 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
 		}
 	}
 
+	if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Concrete) &&
+		((checkGenericParamFlags & (BfGenericParamFlag_Interface | BfGenericParamFlag_Var)) == 0) && (checkArgType->IsInterface()))
+	{
+		if (!ignoreErrors)
+			*errorOut = Fail(StrFormat("The type '%s' must be an concrete type in order to use it as parameter '%s' for '%s'",
+				TypeToString(origCheckArgType).c_str(), genericParamInst->GetName().c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef);
+		return false;
+	}
+
 	if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Interface) &&
 		((checkGenericParamFlags & (BfGenericParamFlag_Interface | BfGenericParamFlag_Var)) == 0) && (!checkArgType->IsInterface()))
 	{
@@ -7711,19 +7717,6 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
 		}
 	}
 
-	if ((genericParamInst->mInterfaceConstraints.size() > 0) && (origCheckArgType->IsInterface()))
-	{	
-		PopulateType(origCheckArgType);
-		auto checkTypeInst = origCheckArgType->ToTypeInstance();
-		if (checkTypeInst->mTypeDef->mIsConcrete)
-		{
-			if (!ignoreErrors)
-				*errorOut = Fail(StrFormat("Generic argument '%s', declared to be concrete interface '%s' for '%s', must be a concrete type", genericParamInst->GetName().c_str(),
-					TypeToString(origCheckArgType).c_str()), checkArgTypeRef);
-			return false;
-		}
-	}
-
 	for (auto checkConstraint : genericParamInst->mInterfaceConstraints)
 	{
 		BfType* convCheckConstraint = checkConstraint;

+ 1 - 1
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -7678,7 +7678,7 @@ BfGenericParamInstance* BfModule::GetGenericParamInstance(BfGenericParamType* ty
 
 BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTypeRef, BfPopulateType populateType, BfResolveTypeRefFlags resolveFlags)
 {
-	if (mCompiler->mIsResolveOnly)
+	if ((mCompiler->mIsResolveOnly) && (!IsInSpecializedSection()))
 	{
 		bool isGetDefinition = false;
 		BfAutoComplete* autoComplete = NULL;

+ 3 - 3
IDEHelper/Compiler/BfReducer.cpp

@@ -8162,8 +8162,7 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi
 	break;
 
 	case BfToken_Sealed:
-	case BfToken_Abstract:
-	case BfToken_Concrete:
+	case BfToken_Abstract:	
 	case BfToken_Public:
 	case BfToken_Private:
 	case BfToken_Protected:
@@ -8241,7 +8240,7 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi
 			MEMBER_SET(typeDeclaration, mSealedSpecifier, tokenNode);
 		}
 
-		if ((token == BfToken_Abstract) || (token == BfToken_Concrete))
+		if (token == BfToken_Abstract)
 		{
 			if (typeDeclaration->mAbstractSpecifier != NULL)
 			{
@@ -9618,6 +9617,7 @@ BfGenericConstraintsDeclaration* BfReducer::CreateGenericConstraintsDeclaration(
 				case BfToken_Class:
 				case BfToken_Struct:
 				case BfToken_Const:
+				case BfToken_Concrete:
 				case BfToken_Var:
 				case BfToken_New:
 				case BfToken_Delete:

+ 33 - 6
IDEHelper/Compiler/BfStmtEvaluator.cpp

@@ -6000,6 +6000,22 @@ void BfModule::Visit(BfForEachStatement* forEachStmt)
 		itr = target;
 		bool hadGetEnumeratorType = false;
 
+		if (genericParamInst != NULL)
+		{			
+			for (auto ifaceConstraint : genericParamInst->mInterfaceConstraints)
+			{
+				if (ifaceConstraint->IsInstanceOf(mCompiler->mGenericIEnumerableTypeDef))
+				{
+					if (targetTypeInstance != NULL)
+					{
+						targetTypeInstance = NULL;
+						break;
+					}
+					targetTypeInstance = ifaceConstraint->ToTypeInstance();					
+				}
+			}
+		}
+
 		if (targetTypeInstance != NULL)
 		{
 			PopulateType(targetTypeInstance, BfPopulateType_DataAndMethods);
@@ -6012,20 +6028,30 @@ void BfModule::Visit(BfForEachStatement* forEachStmt)
 			{
 				hadGetEnumeratorType = true;
 				Fail(StrFormat("Type '%s' does not contain a non-static 'GetEnumerator' method", TypeToString(targetTypeInstance).c_str()), forEachStmt->mCollectionExpression);
-			}
-			else if (getEnumeratorMethod.mMethodInstance->mMethodDef->mIsConcrete)
-			{
-				hadGetEnumeratorType = true;
-				Fail(StrFormat("Iteration requires a concrete implementation of '%s'", TypeToString(targetTypeInstance).c_str()), forEachStmt->mCollectionExpression);
-			}
+			}			
 			else
 			{
+				if (getEnumeratorMethod.mMethodInstance->mMethodDef->mIsConcrete)
+				{
+					hadGetEnumeratorType = true;
+					if (genericParamInst != NULL)
+					{
+						if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Concrete) == 0)
+							Fail(StrFormat("Iteration requires a concrete implementation of '%s', consider adding 'concrete' constraint to '%s'", TypeToString(targetTypeInstance).c_str(), genericParamInst->GetName().c_str()), forEachStmt->mCollectionExpression);
+					}
+					else
+						Fail(StrFormat("Iteration requires a concrete implementation of '%s'", TypeToString(targetTypeInstance).c_str()), forEachStmt->mCollectionExpression);
+				}
+
 				hadGetEnumeratorType = true;
 				BfExprEvaluator exprEvaluator(this);
 				SizedArray<BfIRValue, 1> args;
 				auto castedTarget = Cast(forEachStmt->mCollectionExpression, target, getEnumeratorMethod.mMethodInstance->GetOwner());
 				exprEvaluator.PushThis(forEachStmt->mCollectionExpression, castedTarget, getEnumeratorMethod.mMethodInstance, args);
 				itr = exprEvaluator.CreateCall(forEachStmt->mCollectionExpression, getEnumeratorMethod.mMethodInstance, IsSkippingExtraResolveChecks() ? BfIRValue() : getEnumeratorMethod.mFunc, false, args);
+
+				if (itr.mType->IsConcreteInterfaceType())
+					itr.mType = itr.mType->GetUnderlyingType();
 			}
 		}
 
@@ -6060,6 +6086,7 @@ void BfModule::Visit(BfForEachStatement* forEachStmt)
 			};
 
 			auto enumeratorTypeInst = itr.mType->ToTypeInstance();
+
 			if (enumeratorTypeInst != NULL)
 			{
 				for (auto& interfaceRef : enumeratorTypeInst->mInterfaces)

+ 3 - 6
IDEHelper/Compiler/BfSystem.cpp

@@ -2733,8 +2733,7 @@ void BfSystem::InjectNewRevision(BfTypeDef* typeDef)
 	typeDef->mIsDelegate = nextTypeDef->mIsDelegate;
 	typeDef->mIsFunction = nextTypeDef->mIsFunction;
 	typeDef->mIsClosure = nextTypeDef->mIsClosure;
-	typeDef->mIsAbstract = nextTypeDef->mIsAbstract;
-	typeDef->mIsConcrete = nextTypeDef->mIsConcrete;
+	typeDef->mIsAbstract = nextTypeDef->mIsAbstract;	
 	typeDef->mIsStatic = nextTypeDef->mIsStatic;
 	typeDef->mHasAppendCtor = nextTypeDef->mHasAppendCtor;
 	typeDef->mHasCEOnCompile = nextTypeDef->mHasCEOnCompile;
@@ -2839,8 +2838,7 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co
 		typeDef->mFullNameEx = partialTypeDef->mFullNameEx;
 		typeDef->mProtection = partialTypeDef->mProtection;		
 		typeDef->mIsDelegate = partialTypeDef->mIsDelegate;
-		typeDef->mIsAbstract = partialTypeDef->mIsAbstract;
-		typeDef->mIsConcrete = partialTypeDef->mIsConcrete;
+		typeDef->mIsAbstract = partialTypeDef->mIsAbstract;		
 		typeDef->mIsStatic = partialTypeDef->mIsStatic;
 		typeDef->mHasAppendCtor = partialTypeDef->mHasAppendCtor;		
 		typeDef->mHasCtorNoBody = partialTypeDef->mHasCtorNoBody;
@@ -2879,8 +2877,7 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co
 	}	
 
 	// Merge attributes together
-	typeDef->mIsAbstract |= partialTypeDef->mIsAbstract;
-	typeDef->mIsConcrete |= partialTypeDef->mIsConcrete;
+	typeDef->mIsAbstract |= partialTypeDef->mIsAbstract;	
 	typeDef->mIsStatic |= partialTypeDef->mIsStatic;
 	typeDef->mHasAppendCtor |= partialTypeDef->mHasAppendCtor;	
 	typeDef->mHasCEOnCompile |= partialTypeDef->mHasCEOnCompile;

+ 11 - 12
IDEHelper/Compiler/BfSystem.h

@@ -629,14 +629,15 @@ enum BfGenericParamFlags : uint16
 	BfGenericParamFlag_StructPtr	= 4,
 	BfGenericParamFlag_Enum			= 8,
 	BfGenericParamFlag_Interface	= 0x10,	
-	BfGenericParamFlag_New			= 0x20,
-	BfGenericParamFlag_Delete		= 0x40,
-	BfGenericParamFlag_Var			= 0x80,
-	BfGenericParamFlag_Const		= 0x100,
-	BfGenericParamFlag_Equals		= 0x200,
-	BfGenericParamFlag_Equals_Op    = 0x400,
-	BfGenericParamFlag_Equals_Type  = 0x800,
-	BfGenericParamFlag_Equals_IFace = 0x1000
+	BfGenericParamFlag_Concrete		= 0x20,
+	BfGenericParamFlag_New			= 0x40,
+	BfGenericParamFlag_Delete		= 0x80,
+	BfGenericParamFlag_Var			= 0x100,
+	BfGenericParamFlag_Const		= 0x200,
+	BfGenericParamFlag_Equals		= 0x400,
+	BfGenericParamFlag_Equals_Op    = 0x800,
+	BfGenericParamFlag_Equals_Type  = 0x1000,
+	BfGenericParamFlag_Equals_IFace = 0x2000
 };
 
 class BfConstraintDef
@@ -994,8 +995,7 @@ public:
 	bool mIsDelegate;
 	bool mIsFunction;
 	bool mIsClosure;
-	bool mIsAbstract;
-	bool mIsConcrete;
+	bool mIsAbstract;	
 	bool mIsStatic;	
 	bool mHasCEOnCompile;
 	bool mHasAppendCtor;
@@ -1033,8 +1033,7 @@ public:
 		mDefState = DefState_New;
 		mHash = 0;		
 		mPartialIdx = -1;
-		mIsAbstract = false;
-		mIsConcrete = false;
+		mIsAbstract = false;		
 		mIsDelegate = false;
 		mIsFunction = false;
 		mIsClosure = false;

+ 1 - 1
IDEHelper/Compiler/CeMachine.cpp

@@ -287,7 +287,7 @@ void CeDumpContext::DumpOperandInfo(CeOperandInfoKind operandInfoKind)
 		{
 			int64 val = CE_GET(int64);
 			char str[64];
-			sprintf(str, "%lld", val);
+			sprintf(str, "%lld", (long long)val);
 			mStr += str;
 		}
 		break;

+ 17 - 4
IDEHelper/Tests/src/Generics.bf

@@ -226,9 +226,14 @@ namespace Tests
 
 		}
 
-		static int MethodE<T, T2>(T val) where T : IEnumerable<T2>
+		static T2 MethodE<T, T2>(T val) where T : concrete, IEnumerable<T2> where T2 : operator T2 + T2
 		{
-			return 0;
+			T2 total = default;
+			for (var v in val)
+			{
+				total += v;
+			}
+			return total;
 		}
 
 		static int MethodF<T>(IEnumerable<T> val)
@@ -243,6 +248,7 @@ namespace Tests
 
 			List<Entry> list = scope .();
 			list.Sort();
+			List<float> floatList = scope .() {1, 2, 3};
 
 			ClassA ca = scope .();
 			ClassB cb = scope .();
@@ -278,8 +284,15 @@ namespace Tests
 
 			Test.Assert(ClassE.Instance.CreateSystem<int>() == 999);
 
-			MethodE(list);
-			MethodF(list);
+			/*IEnumerable<float> ie = floatList;
+			Test.Assert(
+				[IgnoreErrors(true)]
+				{
+					Test.Assert(MethodE(ie) == 8);
+					true
+				} == false);*/
+			Test.Assert(MethodE(floatList) == 6);
+			Test.Assert(MethodF(floatList) == 0);
 		}
 	}
 

+ 1 - 1
IDEHelper/Tests/src/Interfaces.bf

@@ -23,7 +23,7 @@ namespace Tests
 			}
 		}
 
-		concrete interface IFaceC
+		interface IFaceC
 		{
 			concrete IFaceA GetConcreteIA();
 		}