From e3f51e39edc909e1d66af2f9f99e7cb5340df77a Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 13 Jan 2021 09:24:15 -0800 Subject: [PATCH] Added 'concrete' constraint --- .../corlib/src/Collections/IEnumerator.bf | 4 +- .../src/System/Collections/IEnumerator.bf | 2 +- IDEHelper/Compiler/BfDefBuilder.cpp | 23 +++-------- IDEHelper/Compiler/BfModule.cpp | 29 ++++++-------- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 2 +- IDEHelper/Compiler/BfReducer.cpp | 6 +-- IDEHelper/Compiler/BfStmtEvaluator.cpp | 39 ++++++++++++++++--- IDEHelper/Compiler/BfSystem.cpp | 9 ++--- IDEHelper/Compiler/BfSystem.h | 23 ++++++----- IDEHelper/Compiler/CeMachine.cpp | 2 +- IDEHelper/Tests/src/Generics.bf | 21 ++++++++-- IDEHelper/Tests/src/Interfaces.bf | 2 +- 12 files changed, 90 insertions(+), 72 deletions(-) diff --git a/BeefLibs/corlib/src/Collections/IEnumerator.bf b/BeefLibs/corlib/src/Collections/IEnumerator.bf index 61f02f8d..016a5eb7 100644 --- a/BeefLibs/corlib/src/Collections/IEnumerator.bf +++ b/BeefLibs/corlib/src/Collections/IEnumerator.bf @@ -17,12 +17,12 @@ namespace System.Collections Result GetNextRef() mut; } - concrete interface IEnumerable + interface IEnumerable { concrete IEnumerator GetEnumerator(); } - concrete interface IRefEnumerable + interface IRefEnumerable { concrete IRefEnumerator GetEnumerator(); } diff --git a/IDE/mintest/minlib/src/System/Collections/IEnumerator.bf b/IDE/mintest/minlib/src/System/Collections/IEnumerator.bf index ae4ef97b..df4efe4e 100644 --- a/IDE/mintest/minlib/src/System/Collections/IEnumerator.bf +++ b/IDE/mintest/minlib/src/System/Collections/IEnumerator.bf @@ -28,7 +28,7 @@ namespace System.Collections Result GetNextRef() mut; } - concrete interface IEnumerable + interface IEnumerable { concrete IEnumerator GetEnumerator(); } diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index 346e7e6a..48d6d03b 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/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(); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 8837efc6..77d53d12 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/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& 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; diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index f895b42c..e6aec8c3 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/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; diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 34185ff8..d1898633 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/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: diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index 1e70fecf..c5350e93 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/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 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) diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 04b7a6b4..098a58be 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/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; diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 4a094206..9ddcd141 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/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; diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index b07fe695..0d52829e 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/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; diff --git a/IDEHelper/Tests/src/Generics.bf b/IDEHelper/Tests/src/Generics.bf index 9d093740..d65b9197 100644 --- a/IDEHelper/Tests/src/Generics.bf +++ b/IDEHelper/Tests/src/Generics.bf @@ -226,9 +226,14 @@ namespace Tests } - static int MethodE(T val) where T : IEnumerable + static T2 MethodE(T val) where T : concrete, IEnumerable where T2 : operator T2 + T2 { - return 0; + T2 total = default; + for (var v in val) + { + total += v; + } + return total; } static int MethodF(IEnumerable val) @@ -243,6 +248,7 @@ namespace Tests List list = scope .(); list.Sort(); + List floatList = scope .() {1, 2, 3}; ClassA ca = scope .(); ClassB cb = scope .(); @@ -278,8 +284,15 @@ namespace Tests Test.Assert(ClassE.Instance.CreateSystem() == 999); - MethodE(list); - MethodF(list); + /*IEnumerable ie = floatList; + Test.Assert( + [IgnoreErrors(true)] + { + Test.Assert(MethodE(ie) == 8); + true + } == false);*/ + Test.Assert(MethodE(floatList) == 6); + Test.Assert(MethodF(floatList) == 0); } } diff --git a/IDEHelper/Tests/src/Interfaces.bf b/IDEHelper/Tests/src/Interfaces.bf index 41af1514..bd2c8751 100644 --- a/IDEHelper/Tests/src/Interfaces.bf +++ b/IDEHelper/Tests/src/Interfaces.bf @@ -23,7 +23,7 @@ namespace Tests } } - concrete interface IFaceC + interface IFaceC { concrete IFaceA GetConcreteIA(); }