From c3bc2bc67c668c14016505a906ede4a3338eb9e2 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 5 Aug 2020 05:34:32 -0700 Subject: [PATCH] Added extern constraints to types --- IDEHelper/Compiler/BfCompiler.cpp | 2 + IDEHelper/Compiler/BfDefBuilder.cpp | 2 +- IDEHelper/Compiler/BfExprEvaluator.cpp | 2 +- IDEHelper/Compiler/BfModule.cpp | 46 +++++++++++----- IDEHelper/Compiler/BfModule.h | 2 +- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 70 +++++++++++++++++++----- IDEHelper/Compiler/BfResolvedTypeUtils.h | 6 +- IDEHelper/Compiler/BfSystem.cpp | 7 ++- IDEHelper/Compiler/BfSystem.h | 1 + IDEHelper/Tests/src/Operators.bf | 21 ++++++- 10 files changed, 121 insertions(+), 38 deletions(-) diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 2b406e44..c7eb7f75 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -4012,6 +4012,8 @@ void BfCompiler::ProcessAutocompleteTempType() module->HandleTypeGenericParamRef(nameNode, tempTypeDef, genericParamIdx); } + //TODO: Do extern constraint stuff here + for (auto fieldDef : tempTypeDef->mFields) { BP_ZONE("ProcessAutocompleteTempType.CheckField"); diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index 620585f5..d88efdab 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -1629,7 +1629,7 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration) int outerGenericSize = 0; if (mCurTypeDef->mOuterType != NULL) outerGenericSize = (int)mCurTypeDef->mOuterType->mGenericParamDefs.size(); - ParseGenericParams(typeDeclaration->mGenericParams, typeDeclaration->mGenericConstraintsDeclaration, mCurTypeDef->mGenericParamDefs, NULL, outerGenericSize); + ParseGenericParams(typeDeclaration->mGenericParams, typeDeclaration->mGenericConstraintsDeclaration, mCurTypeDef->mGenericParamDefs, &mCurTypeDef->mExternalConstraints, outerGenericSize); BF_ASSERT(mCurTypeDef->mNameEx == NULL); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 46ac24d1..3fa31bdb 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -13034,7 +13034,7 @@ BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfAstNode* targetSrc, BfTypeVector* typeGenericArguments = NULL; if (owner->mGenericTypeInfo != NULL) typeGenericArguments = &owner->mGenericTypeInfo->mTypeGenericArguments; - genericArg = mModule->ResolveGenericType(genericArg, typeGenericArguments, checkMethodGenericArgs); + //genericArg = mModule->ResolveGenericType(genericArg, typeGenericArguments, checkMethodGenericArgs); } if (genericArg->IsVar()) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index a4adbcec..bc8df4e3 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -3892,16 +3892,24 @@ void BfModule::FindSubTypes(BfTypeInstance* classType, SizedArrayImpl* outV continue; if (outVals->Contains(ifaceInst.mInterfaceType->mTypeId)) continue; - + if (ifaceInst.mDeclaringType->IsExtension()) { bool needsExCheck = false; if (ifaceInst.mDeclaringType->mProject != classType->mTypeDef->mProject) { - exChecks->push_back(ifaceInst.mInterfaceType); - continue; + PopulateType(ifaceInst.mInterfaceType, BfPopulateType_DataAndMethods); + if (ifaceInst.mInterfaceType->mVirtualMethodTableSize > 0) + { + exChecks->push_back(ifaceInst.mInterfaceType); + continue; + } + else + { + // We can only do an 'exCheck' if we're actually going to slot this interface + } } - } + } outVals->push_back(ifaceInst.mInterfaceType->mTypeId); } @@ -6878,8 +6886,9 @@ String BfModule::GenericParamSourceToString(const BfGenericParamSource & generic { if (genericParamSource.mMethodInstance != NULL) { - auto methodInst = GetUnspecializedMethodInstance(genericParamSource.mMethodInstance); - return MethodToString(methodInst); + auto methodInst = GetUnspecializedMethodInstance(genericParamSource.mMethodInstance, false); + SetAndRestoreValue prevMethodInst(methodInst, NULL); + return MethodToString(genericParamSource.mMethodInstance); } else { @@ -9264,12 +9273,16 @@ BfMethodInstance* BfModule::GetRawMethodByName(BfTypeInstance* typeInstance, con return NULL; } -BfMethodInstance* BfModule::GetUnspecializedMethodInstance(BfMethodInstance* methodInstance) +BfMethodInstance* BfModule::GetUnspecializedMethodInstance(BfMethodInstance* methodInstance, bool useUnspecializedType) { if ((methodInstance->mMethodInfoEx != NULL) && (methodInstance->mMethodInfoEx->mMethodGenericArguments.size() != 0)) methodInstance = methodInstance->mMethodInstanceGroup->mDefault; auto owner = methodInstance->mMethodInstanceGroup->mOwner; + + if (!useUnspecializedType) + return GetRawMethodInstanceAtIdx(owner, methodInstance->mMethodDef->mIdx); + if (!owner->IsGenericTypeInstance()) return methodInstance; @@ -19861,15 +19874,18 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool } else { - if (unspecializedTypeInstance == NULL) - unspecializedTypeInstance = GetUnspecializedTypeInstance(mCurTypeInstance); - auto externConstraintDef = genericParam->GetExternConstraintDef(); - // Resolve in the unspecialized type, then resolve the generic later. This fixes ambiguity where the type is specialized by a method generic arg - { - SetAndRestoreValue prevTypeInstance(mCurTypeInstance, unspecializedTypeInstance); - genericParam->mExternType = ResolveTypeRef(externConstraintDef->mTypeRef); - } + +// if (unspecializedTypeInstance == NULL) +// unspecializedTypeInstance = GetUnspecializedTypeInstance(mCurTypeInstance); +// +// // Resolve in the unspecialized type, then resolve the generic later. This fixes ambiguity where the type is specialized by a method generic arg +// { +// SetAndRestoreValue prevTypeInstance(mCurTypeInstance, unspecializedTypeInstance); +// genericParam->mExternType = ResolveTypeRef(externConstraintDef->mTypeRef); +// } + + genericParam->mExternType = ResolveTypeRef(externConstraintDef->mTypeRef); auto autoComplete = mCompiler->GetAutoComplete(); if (autoComplete != NULL) diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 6270ecf3..7ea6231e 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1768,7 +1768,7 @@ public: BfMethodInstance* GetRawMethodInstanceAtIdx(BfTypeInstance* typeInstance, int methodIdx, const char* assertName = NULL); BfMethodInstance* GetRawMethodInstance(BfTypeInstance* typeInstance, BfMethodDef* methodDef); BfMethodInstance* GetRawMethodByName(BfTypeInstance* typeInstance, const StringImpl& methodName, int paramCount = -1, bool checkBase = false, bool allowMixin = false); - BfMethodInstance* GetUnspecializedMethodInstance(BfMethodInstance* methodInstance); // Unspecialized owner type and unspecialized method type + BfMethodInstance* GetUnspecializedMethodInstance(BfMethodInstance* methodInstance, bool useUnspecializedType = true); // Unspecialized owner type and unspecialized method type int GetGenericParamAndReturnCount(BfMethodInstance* methodInstance); BfModule* GetSpecializedMethodModule(const SizedArrayImpl& projectList); BfModuleMethodInstance GetMethodInstanceAtIdx(BfTypeInstance* typeInstance, int methodIdx, const char* assertName = NULL, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index e9b6834c..474b2040 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -75,6 +75,12 @@ BfGenericExtensionEntry* BfModule::BuildGenericExtensionInfo(BfTypeInstance* gen genericExEntry->mGenericParams.push_back(genericParamInstance); } + for (int externConstraintIdx = 0; externConstraintIdx < (int)partialTypeDef->mExternalConstraints.size(); externConstraintIdx++) + { + auto genericParamInstance = new BfGenericTypeParamInstance(partialTypeDef, externConstraintIdx + (int)partialTypeDef->mGenericParamDefs.size()); + genericExEntry->mGenericParams.push_back(genericParamInstance); + } + for (int paramIdx = startDefGenericParamIdx; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.size(); paramIdx++) { auto genericParamInstance = genericExEntry->mGenericParams[paramIdx]; @@ -124,6 +130,12 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef) genericTypeInst->mGenericTypeInfo->mGenericParams.push_back(genericParamInstance); } + for (int externConstraintIdx = 0; externConstraintIdx < (int)typeDef->mExternalConstraints.size(); externConstraintIdx++) + { + auto genericParamInstance = new BfGenericTypeParamInstance(typeDef, externConstraintIdx + (int)typeDef->mGenericParamDefs.size()); + genericTypeInst->mGenericTypeInfo->mGenericParams.push_back(genericParamInstance); + } + if (!typeDef->mPartials.empty()) { for (auto partialTypeDef : typeDef->mPartials) @@ -170,8 +182,30 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef) else { for (int paramIdx = startDefGenericParamIdx; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mGenericParams.size(); paramIdx++) - { + { auto genericParamInstance = genericTypeInst->mGenericTypeInfo->mGenericParams[paramIdx]; + + if (paramIdx < (int)typeDef->mGenericParamDefs.size()) + { + genericParamInstance->mExternType = GetGenericParamType(BfGenericParamKind_Type, paramIdx); + } + else + { + auto externConstraintDef = genericParamInstance->GetExternConstraintDef(); + genericParamInstance->mExternType = ResolveTypeRef(externConstraintDef->mTypeRef); + + auto autoComplete = mCompiler->GetAutoComplete(); + if (autoComplete != NULL) + autoComplete->CheckTypeRef(externConstraintDef->mTypeRef, false); + + if (genericParamInstance->mExternType != NULL) + { + // + } + else + genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var); + } + ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType()); auto genericParamDef = genericParamInstance->GetGenericParamDef(); if (genericParamDef != NULL) @@ -223,20 +257,30 @@ bool BfModule::ValidateGenericConstraints(BfTypeReference* typeRef, BfTypeInstan } auto typeDef = genericTypeInst->mTypeDef; - for (int paramIdx = 0; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.size(); paramIdx++) + //for (int paramIdx = 0; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.size(); paramIdx++) + + for (int paramIdx = 0; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mGenericParams.size(); paramIdx++) { auto genericParamInstance = genericTypeInst->mGenericTypeInfo->mGenericParams[paramIdx]; - // Why did we remove this line? This breaks determining compatibility of one unspecialized type to another unspecialized type, called from ResolveTypeResult - //if (!genericTypeInst->mIsUnspecialized) + + BfType* genericArg; + if (paramIdx < (int)genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.size()) { - BfError* error = NULL; - if (!CheckGenericConstraints(BfGenericParamSource(genericTypeInst), genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[paramIdx], typeRef, genericParamInstance, NULL, &error)) - { - genericTypeInst->mGenericTypeInfo->mHadValidateErrors = true; - return false; - } + genericArg = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[paramIdx]; } - } + else + { + genericArg = genericParamInstance->mExternType; + } + + BfError* error = NULL; + if (!CheckGenericConstraints(BfGenericParamSource(genericTypeInst), genericArg, typeRef, genericParamInstance, NULL, &error)) + { + genericTypeInst->mGenericTypeInfo->mHadValidateErrors = true; + return false; + } + } + return true; } @@ -10394,11 +10438,11 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp ((explicitCast) && (opConstraint.mCastToken == BfToken_Explicit))) { // If we can convert OUR fromVal to the constraint's fromVal then we may match - if (CanCast(typedVal, opConstraint.mRightType)) + if (CanCast(typedVal, opConstraint.mRightType, BfCastFlags_NoConversionOperator)) { // .. and we can convert the constraint's toType to OUR toType then we're good auto opToVal = genericParam->mExternType; - if (CanCast(BfTypedValue(BfIRValue::sValueless, opToVal), toType)) + if (CanCast(BfTypedValue(BfIRValue::sValueless, opToVal), toType, BfCastFlags_NoConversionOperator)) return mBfIRBuilder->GetFakeVal(); } } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 0f48bf21..263d3bde 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -1091,7 +1091,7 @@ public: { if (mGenericIdx < (int)mTypeDef->mGenericParamDefs.size()) return mTypeDef->mGenericParamDefs[mGenericIdx]; - return NULL; + return &mTypeDef->mExternalConstraints[mGenericIdx - (int)mTypeDef->mGenericParamDefs.size()]; } virtual BfGenericParamDef* GetGenericParamDef() override @@ -1105,14 +1105,14 @@ public: { if (mGenericIdx < (int)mTypeDef->mGenericParamDefs.size()) return NULL; - return NULL; + return &mTypeDef->mExternalConstraints[mGenericIdx - (int)mTypeDef->mGenericParamDefs.size()]; } virtual String GetName() override { if (mGenericIdx < (int)mTypeDef->mGenericParamDefs.size()) return mTypeDef->mGenericParamDefs[mGenericIdx]->mName; - return "???"; + return mTypeDef->mExternalConstraints[mGenericIdx - (int)mTypeDef->mGenericParamDefs.size()].mTypeRef->ToString(); } }; diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 14486496..7f095892 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -2662,6 +2662,7 @@ void BfSystem::InjectNewRevision(BfTypeDef* typeDef) typeDef->mGenericParamDefs.Clear(); typeDef->mGenericParamDefs = nextTypeDef->mGenericParamDefs; + typeDef->mExternalConstraints = nextTypeDef->mExternalConstraints; nextTypeDef->mGenericParamDefs.Clear(); typeDef->mBaseTypes = nextTypeDef->mBaseTypes; @@ -2738,7 +2739,8 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co BfGenericParamDef* newGeneric = new BfGenericParamDef(); *newGeneric = *generic; typeDef->mGenericParamDefs.push_back(newGeneric); - } + } + typeDef->mExternalConstraints = partialTypeDef->mExternalConstraints; typeDef->mBaseTypes = partialTypeDef->mBaseTypes; @@ -2756,6 +2758,9 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co typeDef->mTypeCode = partialTypeDef->mTypeCode; typeDef->mTypeDeclaration = partialTypeDef->mTypeDeclaration; } + + for (auto& externConstraint : partialTypeDef->mExternalConstraints) + typeDef->mExternalConstraints.Add(externConstraint); } // Merge attributes together diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index a9fedc0e..128e08e3 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -880,6 +880,7 @@ public: Array mOperators; BfMethodDef* mDtorDef; Array mGenericParamDefs; + Array mExternalConstraints; Array mBaseTypes; Array mNestedTypes; Array mDirectAllocNodes; diff --git a/IDEHelper/Tests/src/Operators.bf b/IDEHelper/Tests/src/Operators.bf index e10e9569..9063f38f 100644 --- a/IDEHelper/Tests/src/Operators.bf +++ b/IDEHelper/Tests/src/Operators.bf @@ -176,17 +176,28 @@ namespace Tests return val + val2; } - public static T Complex(T val, T2 val2) - where T : operator T + T2 + public static T Complex(T val, T2 val2, T3 val3) where T : operator -T where T : operator implicit T2 + where T : operator T + T2 + where int32 : operator T + T3 { T conv = val2; T result = val + val2; result = -result; + int32 iRes = val + val3; return result; } + struct StructOp3 where float : operator T + T2 + { + public float Use(T lhs, T2 rhs) + { + float f = lhs + rhs; + return f; + } + } + [Test] public static void TestBasics() { @@ -212,7 +223,7 @@ namespace Tests float val = Op((int32)100, (int16)23); Test.Assert(val == 123); - int32 i32res = Complex((int32)100, (int16)23); + int32 i32res = Complex((int32)100, (int16)23, (int8)4); Test.Assert(i32res == -123); StructOp sOp; @@ -231,6 +242,10 @@ namespace Tests Test.Assert(rsc == rsc2); Test.Assert(rsc !== rsc2); + StructOp3 so3 = .(); + float f = so3.Use(1, 2); + Test.Assert(f == 3); + /*let oai = OuterOp.InnerOp.Op(1.0f, 100); Test.Assert(oai == 101.0f);