From 32cd6d8841992430be602333bd3a4deecb4aee6c Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 10 Aug 2020 13:29:05 -0700 Subject: [PATCH] Improved extern type constraints --- IDEHelper/Compiler/BfExprEvaluator.cpp | 149 +++++++++++++-------- IDEHelper/Compiler/BfIRBuilder.h | 12 +- IDEHelper/Compiler/BfModule.cpp | 2 +- IDEHelper/Compiler/BfModule.h | 1 + IDEHelper/Compiler/BfModuleTypeUtils.cpp | 136 ++++++++++++++++--- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 17 ++- IDEHelper/Compiler/BfSystem.cpp | 4 +- IDEHelper/Tests/src/Constraints.bf | 44 ++++++ 8 files changed, 280 insertions(+), 85 deletions(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index a80511c8..6d04048b 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -18774,6 +18774,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod BfBinaryOp findBinaryOp = binaryOp; bool isComparison = (binaryOp >= BfBinaryOp_Equality) && (binaryOp <= BfBinaryOp_LessThanOrEqual); + BfBinaryOp oppositeBinaryOp = BfGetOppositeBinaryOp(findBinaryOp); for (int pass = 0; pass < 2; pass++) { @@ -18800,9 +18801,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod BfMethodMatcher methodMatcher(opToken, mModule, "", args, NULL); BfBaseClassWalker baseClassWalker(leftValue.mType, rightValue.mType, mModule); - bool invertResult = false; - - BfBinaryOp oppositeBinaryOp = BfGetOppositeBinaryOp(findBinaryOp); + bool invertResult = false; while (true) { @@ -18930,47 +18929,78 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod return; } + auto _CheckBinaryOp = [&](BfGenericParamInstance* genericParam) + { + for (auto& opConstraint : genericParam->mOperatorConstraints) + { + BfType* returnType = genericParam->mExternType; + bool works = false; + if (opConstraint.mBinaryOp == findBinaryOp) + { + if ((mModule->CanCast(args[0].mTypedValue, opConstraint.mLeftType)) && + (mModule->CanCast(args[1].mTypedValue, opConstraint.mRightType))) + { + works = true; + } + } + else if (opConstraint.mBinaryOp == oppositeBinaryOp) + { + if ((mModule->CanCast(args[0].mTypedValue, opConstraint.mRightType)) && + (mModule->CanCast(args[1].mTypedValue, opConstraint.mLeftType))) + { + works = true; + } + } + else if ((isComparison) && (opConstraint.mBinaryOp == BfBinaryOp_Compare)) + { + if ((mModule->CanCast(args[0].mTypedValue, opConstraint.mLeftType)) && + (mModule->CanCast(args[1].mTypedValue, opConstraint.mRightType))) + { + works = true; + } + else if ((mModule->CanCast(args[0].mTypedValue, opConstraint.mRightType)) && + (mModule->CanCast(args[1].mTypedValue, opConstraint.mLeftType))) + { + works = true; + } + + if (works) + { + returnType = mModule->GetPrimitiveType(BfTypeCode_Boolean); + } + } + + if (works) + { + BF_ASSERT(genericParam->mExternType != NULL); + mResult = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), returnType); + return true; + } + } + + return false; + }; + // Check method generic constraints if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized) && (mModule->mCurMethodInstance->mMethodInfoEx != NULL)) { for (int genericParamIdx = 0; genericParamIdx < mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++) { auto genericParam = mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; - for (auto& opConstraint : genericParam->mOperatorConstraints) - { - if (opConstraint.mBinaryOp == findBinaryOp) - { - if ((mModule->CanCast(args[0].mTypedValue, opConstraint.mLeftType)) && - (mModule->CanCast(args[1].mTypedValue, opConstraint.mRightType))) - { - BF_ASSERT(genericParam->mExternType != NULL); - mResult = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType); - return; - } - } - } + if (_CheckBinaryOp(genericParam)) + return; } } // Check type generic constraints if ((mModule->mCurTypeInstance->IsGenericTypeInstance()) && (mModule->mCurTypeInstance->IsUnspecializedType())) { - auto genericTypeInst = (BfTypeInstance*)mModule->mCurTypeInstance; - for (int genericParamIdx = 0; genericParamIdx < genericTypeInst->mGenericTypeInfo->mGenericParams.size(); genericParamIdx++) - { - auto genericParam = mModule->GetGenericTypeParamInstance(genericParamIdx); - for (auto& opConstraint : genericParam->mOperatorConstraints) - { - if (opConstraint.mBinaryOp == findBinaryOp) - { - if ((mModule->CanCast(args[0].mTypedValue, opConstraint.mLeftType)) && - (mModule->CanCast(args[1].mTypedValue, opConstraint.mRightType))) - { - mResult = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType); - return; - } - } - } + SizedArray genericParams; + mModule->GetActiveTypeGenericParamInstances(genericParams); + for (auto genericParam : genericParams) + { + if (_CheckBinaryOp(genericParam)) + return; } } @@ -19129,42 +19159,45 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod return; } - if (resultType->IsInterface()) + if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality) || (binaryOp == BfBinaryOp_InEquality) || (binaryOp == BfBinaryOp_StrictInEquality)) { - // Compare as objects instead - resultType = mModule->mContext->mBfObjectType; - *resultTypedValue = mModule->Cast(resultTypeSrc, *resultTypedValue, resultType); - } - - if (otherType->IsNull()) - { - if (resultType->IsFunction()) + if (resultType->IsInterface()) { - if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) - mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); + // Compare as objects instead + resultType = mModule->mContext->mBfObjectType; + *resultTypedValue = mModule->Cast(resultTypeSrc, *resultTypedValue, resultType); + } + + if (otherType->IsNull()) + { + if (resultType->IsFunction()) + { + if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) + mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); + else + mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); + } else - mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); + { + if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) + mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); + else + mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNotNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); + } } else { + auto convertedValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox); + if (!convertedValue) + return; if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) - mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); + mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); else - mResult = BfTypedValue(mModule->mBfIRBuilder->CreateIsNotNull(resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); + mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); } - } - else - { - auto convertedValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox); - if (!convertedValue) - return; - if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) - mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); - else - mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); - } - return; + return; + } } if (resultType->IsTypedPrimitive()) diff --git a/IDEHelper/Compiler/BfIRBuilder.h b/IDEHelper/Compiler/BfIRBuilder.h index a64378e0..de302da8 100644 --- a/IDEHelper/Compiler/BfIRBuilder.h +++ b/IDEHelper/Compiler/BfIRBuilder.h @@ -569,6 +569,11 @@ struct BfIRTypeData TypeKind mKind; int mId; + + operator bool() + { + return (mId != -1); + } }; struct BfIRType : public BfIRTypeData @@ -586,12 +591,7 @@ public: mId = typeData.mId; } - BfIRType(const BfIRValue& val) { mKind = TypeKind_Stream; mId = val.mId; } - - operator bool() - { - return (mId != -1); - } + BfIRType(const BfIRValue& val) { mKind = TypeKind_Stream; mId = val.mId; } }; struct BfIRBlock : public BfIRValue diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 6648e6a7..90ea91a3 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -12773,7 +12773,7 @@ BfLocalVariable* BfModule::GetThisVariable() bool BfModule::IsInGeneric() { - return (mCurMethodInstance->GetNumGenericArguments() != 0) || (mCurTypeInstance->IsGenericTypeInstance()); + return ((mCurMethodInstance != NULL) && (mCurMethodInstance->GetNumGenericArguments() != 0)) || (mCurTypeInstance->IsGenericTypeInstance()); } bool BfModule::InDefinitionSection() diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 7ea6231e..d1ca1a3a 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1681,6 +1681,7 @@ public: bool IsUnboundGeneric(BfType* type); BfGenericParamInstance* GetGenericTypeParamInstance(int paramIdx); BfGenericParamInstance* GetGenericParamInstance(BfGenericParamType* type); + void GetActiveTypeGenericParamInstances(SizedArray& genericParamInstance); BfTypeInstance* GetBaseType(BfTypeInstance* typeInst); void HandleTypeGenericParamRef(BfAstNode* refNode, BfTypeDef* typeDef, int typeGenericParamIdx); void HandleMethodGenericParamRef(BfAstNode* refNode, BfTypeDef* typeDef, BfMethodDef* methodDef, int typeGenericParamIdx); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 474b2040..78a6b1b6 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -77,7 +77,19 @@ BfGenericExtensionEntry* BfModule::BuildGenericExtensionInfo(BfTypeInstance* gen for (int externConstraintIdx = 0; externConstraintIdx < (int)partialTypeDef->mExternalConstraints.size(); externConstraintIdx++) { + auto& genericConstraint = partialTypeDef->mExternalConstraints[externConstraintIdx]; + auto genericParamInstance = new BfGenericTypeParamInstance(partialTypeDef, externConstraintIdx + (int)partialTypeDef->mGenericParamDefs.size()); + genericParamInstance->mExternType = ResolveTypeRef(genericConstraint.mTypeRef); + + auto autoComplete = mCompiler->GetAutoComplete(); + if (autoComplete != NULL) + autoComplete->CheckTypeRef(genericConstraint.mTypeRef, false); + + if (genericParamInstance->mExternType == NULL) + genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var); + + ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType()); genericExEntry->mGenericParams.push_back(genericParamInstance); } @@ -143,15 +155,31 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef) if (!partialTypeDef->IsExtension()) { typeState.mCurTypeDef = partialTypeDef; - for (int paramIdx = startDefGenericParamIdx; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.size(); paramIdx++) - { - auto genericParamDef = typeDef->mGenericParamDefs[paramIdx]; + for (int paramIdx = startDefGenericParamIdx; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mGenericParams.size(); paramIdx++) + { auto genericParamInstance = genericTypeInst->mGenericTypeInfo->mGenericParams[paramIdx]; + auto genericParamDef = genericParamInstance->GetGenericParamDef(); + + if (paramIdx < (int)typeDef->mGenericParamDefs.size()) + { + genericParamInstance->mExternType = GetGenericParamType(BfGenericParamKind_Type, paramIdx); + } + else + { + auto externConstraintDef = genericParamInstance->GetExternConstraintDef(); + genericParamInstance->mExternType = ResolveTypeRef(externConstraintDef->mTypeRef); + if (genericParamInstance->mExternType == NULL) + genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var); + } + ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType()); - for (auto nameNode : genericParamDef->mNameNodes) + if (genericParamDef != NULL) { - HandleTypeGenericParamRef(nameNode, typeDef, paramIdx); + for (auto nameNode : genericParamDef->mNameNodes) + { + HandleTypeGenericParamRef(nameNode, typeDef, paramIdx); + } } } } @@ -170,7 +198,18 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef) genericParamSource.mCheckAccessibility = false; genericParamSource.mTypeInstance = genericTypeInst; BfError* error = NULL; - if (!CheckGenericConstraints(genericParamSource, genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[paramIdx], NULL, genericParamInstance, NULL, &error)) + + BfType* genericArg; + if (paramIdx < (int)genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.size()) + { + genericArg = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[paramIdx]; + } + else + { + genericArg = genericParamInstance->mExternType; + } + + if ((genericArg == NULL) || (!CheckGenericConstraints(genericParamSource, genericArg, NULL, genericParamInstance, NULL, &error))) { genericExEntry->mConstraintsPassed = false; } @@ -274,7 +313,7 @@ bool BfModule::ValidateGenericConstraints(BfTypeReference* typeRef, BfTypeInstan } BfError* error = NULL; - if (!CheckGenericConstraints(BfGenericParamSource(genericTypeInst), genericArg, typeRef, genericParamInstance, NULL, &error)) + if ((genericArg == NULL) || (!CheckGenericConstraints(BfGenericParamSource(genericTypeInst), genericArg, typeRef, genericParamInstance, NULL, &error))) { genericTypeInst->mGenericTypeInfo->mHadValidateErrors = true; return false; @@ -6511,6 +6550,12 @@ BfGenericParamInstance* BfModule::GetGenericTypeParamInstance(int genericParamId PopulateType(genericTypeInst, BfPopulateType_Declaration); } + if (genericParamIdx >= (int)genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.size()) + { + // Extern constraints should always be directly used - they don't get extended + return genericTypeInst->mGenericTypeInfo->mGenericParams[genericParamIdx]; + } + if (genericTypeInst->mGenericTypeInfo->mGenericExtensionInfo != NULL) { auto activeTypeDef = GetActiveTypeDef(NULL, true); @@ -6522,8 +6567,8 @@ BfGenericParamInstance* BfModule::GetGenericTypeParamInstance(int genericParamId BfGenericExtensionEntry* genericExEntry; if (genericTypeInst->mGenericTypeInfo->mGenericExtensionInfo->mExtensionMap.TryGetValue(lookupTypeDef, &genericExEntry)) - { - return genericExEntry->mGenericParams[genericParamIdx]; + { + return genericExEntry->mGenericParams[genericParamIdx]; } else { @@ -6539,6 +6584,58 @@ BfGenericParamInstance* BfModule::GetGenericTypeParamInstance(int genericParamId return genericTypeInst->mGenericTypeInfo->mGenericParams[genericParamIdx]; } +void BfModule::GetActiveTypeGenericParamInstances(SizedArray& genericParamInstances) +{ + // When we're evaluating a method, make sure the params refer back to that method context + auto curTypeInstance = mCurTypeInstance; + if (mCurMethodInstance != NULL) + curTypeInstance = mCurMethodInstance->mMethodInstanceGroup->mOwner; + + BfTypeInstance* genericTypeInst = curTypeInstance->ToGenericTypeInstance(); + if ((genericTypeInst->IsIncomplete()) && (genericTypeInst->mGenericTypeInfo->mGenericParams.size() == 0)) + { + // Set this to NULL so we don't recurse infinitely + SetAndRestoreValue prevTypeInst(mCurTypeInstance, NULL); + PopulateType(genericTypeInst, BfPopulateType_Declaration); + } + + if (genericTypeInst->mGenericTypeInfo->mGenericExtensionInfo != NULL) + { + auto activeTypeDef = GetActiveTypeDef(NULL, true); + if ((activeTypeDef->mTypeDeclaration != genericTypeInst->mTypeDef->mTypeDeclaration) && (activeTypeDef->IsExtension())) + { + BfTypeDef* lookupTypeDef = activeTypeDef; + while (lookupTypeDef->mNestDepth > genericTypeInst->mTypeDef->mNestDepth) + lookupTypeDef = lookupTypeDef->mOuterType; + + BfGenericExtensionEntry* genericExEntry; + if (genericTypeInst->mGenericTypeInfo->mGenericExtensionInfo->mExtensionMap.TryGetValue(lookupTypeDef, &genericExEntry)) + { + for (auto entry : genericExEntry->mGenericParams) + genericParamInstances.Add(entry); + + auto genericTypeInfo = genericTypeInst->mGenericTypeInfo; + + // Add root extern constraints - they don't get extended + for (int genericParamIdx = (int)genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.size(); genericParamIdx < genericTypeInst->mGenericTypeInfo->mGenericParams.size(); genericParamIdx++) + genericParamInstances.Add(genericTypeInst->mGenericTypeInfo->mGenericParams[genericParamIdx]); + return; + } + else + { + if ((mCompiler->mResolvePassData == NULL) || (mCompiler->mResolvePassData->mAutoComplete == NULL)) + { + BFMODULE_FATAL(this, "Invalid GetGenericParamInstance with extension"); + } + } + } + } + + BF_ASSERT(genericTypeInst != NULL); + for (auto entry : genericTypeInst->mGenericTypeInfo->mGenericParams) + genericParamInstances.Add(entry); +} + BfGenericParamInstance* BfModule::GetGenericParamInstance(BfGenericParamType* type) { if (type->mGenericParamKind == BfGenericParamKind_Method) @@ -8939,7 +9036,15 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula constExprType->mValue = result; resolvedEntry->mValue = constExprType; - BF_ASSERT(BfResolvedTypeSet::Hash(constExprType, &lookupCtx) == resolvedEntry->mHash); +#ifdef _DEBUG + if (BfResolvedTypeSet::Hash(constExprType, &lookupCtx) != resolvedEntry->mHash) + { + int refHash = BfResolvedTypeSet::Hash(typeRef, &lookupCtx); + int typeHash = BfResolvedTypeSet::Hash(constExprType, &lookupCtx); + BF_ASSERT(refHash == typeHash); + } + BF_ASSERT(BfResolvedTypeSet::Equals(constExprType, typeRef, &lookupCtx)); +#endif populateModule->InitType(constExprType, populateType); return constExprType; @@ -9534,6 +9639,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp if (allowCast) { + PopulateType(toType); if (toType->IsValuelessType()) return BfIRValue::sValueless; if (ignoreWrites) @@ -10453,21 +10559,21 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp // Check type generic constraints if ((mCurTypeInstance != NULL) && (mCurTypeInstance->IsGenericTypeInstance()) && (mCurTypeInstance->IsUnspecializedType())) { - auto genericTypeInst = (BfTypeInstance*)mCurTypeInstance; - for (int genericParamIdx = 0; genericParamIdx < genericTypeInst->mGenericTypeInfo->mGenericParams.size(); genericParamIdx++) + SizedArray genericParams; + GetActiveTypeGenericParamInstances(genericParams); + for (auto genericParam : genericParams) { - auto genericParam = GetGenericTypeParamInstance(genericParamIdx); for (auto& opConstraint : genericParam->mOperatorConstraints) { if ((opConstraint.mCastToken == BfToken_Implicit) || ((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.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index c499a717..9d0a78e1 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -2023,10 +2023,21 @@ bool BfTypeInstance::IsTypeMemberIncluded(BfTypeDef* typeDef, BfTypeDef* activeT for (int genericIdx = 0; genericIdx < (int)declConstraints->size(); genericIdx++) { - auto genericType = mGenericTypeInfo->mTypeGenericArguments[genericIdx]; - auto declGenericParam = (*declConstraints)[genericIdx]; - if (!module->CheckGenericConstraints(BfGenericParamSource(), genericType, NULL, declGenericParam)) + + BfType* genericArg; + if (genericIdx < (int)mGenericTypeInfo->mTypeGenericArguments.size()) + { + genericArg = mGenericTypeInfo->mTypeGenericArguments[genericIdx]; + } + else + { + genericArg = declGenericParam->mExternType; + } + + //auto genericType = mGenericTypeInfo->mTypeGenericArguments[genericIdx]; + + if ((genericArg == NULL) || (!module->CheckGenericConstraints(BfGenericParamSource(), genericArg, NULL, declGenericParam))) return false; //if (!mModule->AreConstraintsSubset((*declConstraints)[genericIdx], (*activeConstraints)[genericIdx])) diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 7f095892..f6ecc233 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -2759,8 +2759,8 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co typeDef->mTypeDeclaration = partialTypeDef->mTypeDeclaration; } - for (auto& externConstraint : partialTypeDef->mExternalConstraints) - typeDef->mExternalConstraints.Add(externConstraint); +// for (auto& externConstraint : partialTypeDef->mExternalConstraints) +// typeDef->mExternalConstraints.Add(externConstraint); } // Merge attributes together diff --git a/IDEHelper/Tests/src/Constraints.bf b/IDEHelper/Tests/src/Constraints.bf index d1bd4045..04ddc3af 100644 --- a/IDEHelper/Tests/src/Constraints.bf +++ b/IDEHelper/Tests/src/Constraints.bf @@ -1,3 +1,5 @@ +#pragma warning disable 168 + using System; using System.Collections; @@ -32,6 +34,48 @@ namespace Tests return Method2.Enumerator, (K key, V value)>(param1.GetEnumerator()); } + struct StructA + { + + } + + class ClassA where float : operator T * T where char8 : operator implicit T + { + public static float DoMul(T lhs, T rhs) + { + char8 val = lhs; + return lhs * rhs; + } + } + + extension ClassA where double : operator T - T where StructA : operator explicit T + { + public static double DoSub(T lhs, T rhs) + { + StructA sa = (StructA)lhs; + return lhs - rhs; + } + } + + extension ClassA where int16 : operator T + T where int8 : operator implicit T + { + public static double DoAdd(T lhs, T rhs) + { + int8 val = lhs; + double d = lhs * rhs; + return lhs + rhs; + } + } + + public static void Test0(T val) + where float : operator T * T where char8 : operator implicit T + where int16 : operator T + T where int8 : operator implicit T + { + ClassA ca = scope .(); + ClassA.DoMul(val, val); + ClassA.DoAdd(val, val); + } + [Test] public static void TestBasics() {