2
0
Эх сурвалжийг харах

Improved extern type constraints

Brian Fiete 5 жил өмнө
parent
commit
32cd6d8841

+ 90 - 57
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -18774,6 +18774,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
 			BfBinaryOp findBinaryOp = binaryOp;
 			BfBinaryOp findBinaryOp = binaryOp;
 
 
 			bool isComparison = (binaryOp >= BfBinaryOp_Equality) && (binaryOp <= BfBinaryOp_LessThanOrEqual);
 			bool isComparison = (binaryOp >= BfBinaryOp_Equality) && (binaryOp <= BfBinaryOp_LessThanOrEqual);
+			BfBinaryOp oppositeBinaryOp = BfGetOppositeBinaryOp(findBinaryOp);
 
 
 			for (int pass = 0; pass < 2; pass++)
 			for (int pass = 0; pass < 2; pass++)
 			{
 			{
@@ -18800,9 +18801,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
 				BfMethodMatcher methodMatcher(opToken, mModule, "", args, NULL);
 				BfMethodMatcher methodMatcher(opToken, mModule, "", args, NULL);
 				BfBaseClassWalker baseClassWalker(leftValue.mType, rightValue.mType, mModule);
 				BfBaseClassWalker baseClassWalker(leftValue.mType, rightValue.mType, mModule);
 
 
-				bool invertResult = false;				
-				
-				BfBinaryOp oppositeBinaryOp = BfGetOppositeBinaryOp(findBinaryOp);				
+				bool invertResult = false;												
 
 
 				while (true)
 				while (true)
 				{
 				{
@@ -18930,47 +18929,78 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
 					return;
 					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
 				// Check method generic constraints
 				if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized) && (mModule->mCurMethodInstance->mMethodInfoEx != NULL))
 				if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized) && (mModule->mCurMethodInstance->mMethodInfoEx != NULL))
 				{
 				{
 					for (int genericParamIdx = 0; genericParamIdx < mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++)
 					for (int genericParamIdx = 0; genericParamIdx < mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++)
 					{
 					{
 						auto genericParam = mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams[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
 				// Check type generic constraints
 				if ((mModule->mCurTypeInstance->IsGenericTypeInstance()) && (mModule->mCurTypeInstance->IsUnspecializedType()))
 				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<BfGenericParamInstance*, 4> genericParams;
+					mModule->GetActiveTypeGenericParamInstances(genericParams);
+					for (auto genericParam : genericParams)
+					{						
+						if (_CheckBinaryOp(genericParam))
+							return;						
 					}
 					}
 				}
 				}
 
 
@@ -19129,42 +19159,45 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
 			return;
 			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 (resultType->IsInterface())
+			{
+				// Compare as objects instead
+				resultType = mModule->mContext->mBfObjectType;
+					*resultTypedValue = mModule->Cast(resultTypeSrc, *resultTypedValue, resultType);
+			}
 
 
-		if (otherType->IsNull())
-		{
-			if (resultType->IsFunction())
+			if (otherType->IsNull())
 			{
 			{
-				if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality))
-					mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean));
+				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
 				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
 			else
 			{
 			{
+				auto convertedValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox);
+				if (!convertedValue)
+					return;
 				if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality))
 				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
 				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())
 	if (resultType->IsTypedPrimitive())

+ 6 - 6
IDEHelper/Compiler/BfIRBuilder.h

@@ -569,6 +569,11 @@ struct BfIRTypeData
 
 
 	TypeKind mKind;
 	TypeKind mKind;
 	int mId;
 	int mId;
+
+	operator bool()
+	{
+		return (mId != -1);
+	}
 };
 };
 
 
 struct BfIRType : public BfIRTypeData
 struct BfIRType : public BfIRTypeData
@@ -586,12 +591,7 @@ public:
 		mId = typeData.mId;
 		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
 struct BfIRBlock : public BfIRValue

+ 1 - 1
IDEHelper/Compiler/BfModule.cpp

@@ -12773,7 +12773,7 @@ BfLocalVariable* BfModule::GetThisVariable()
 
 
 bool BfModule::IsInGeneric()
 bool BfModule::IsInGeneric()
 {	
 {	
-	return (mCurMethodInstance->GetNumGenericArguments() != 0) || (mCurTypeInstance->IsGenericTypeInstance());
+	return ((mCurMethodInstance != NULL) && (mCurMethodInstance->GetNumGenericArguments() != 0)) || (mCurTypeInstance->IsGenericTypeInstance());
 }
 }
 
 
 bool BfModule::InDefinitionSection()
 bool BfModule::InDefinitionSection()

+ 1 - 0
IDEHelper/Compiler/BfModule.h

@@ -1681,6 +1681,7 @@ public:
 	bool IsUnboundGeneric(BfType* type);
 	bool IsUnboundGeneric(BfType* type);
 	BfGenericParamInstance* GetGenericTypeParamInstance(int paramIdx);
 	BfGenericParamInstance* GetGenericTypeParamInstance(int paramIdx);
 	BfGenericParamInstance* GetGenericParamInstance(BfGenericParamType* type);	
 	BfGenericParamInstance* GetGenericParamInstance(BfGenericParamType* type);	
+	void GetActiveTypeGenericParamInstances(SizedArray<BfGenericParamInstance*, 4>& genericParamInstance);
 	BfTypeInstance* GetBaseType(BfTypeInstance* typeInst);
 	BfTypeInstance* GetBaseType(BfTypeInstance* typeInst);
 	void HandleTypeGenericParamRef(BfAstNode* refNode, BfTypeDef* typeDef, int typeGenericParamIdx);
 	void HandleTypeGenericParamRef(BfAstNode* refNode, BfTypeDef* typeDef, int typeGenericParamIdx);
 	void HandleMethodGenericParamRef(BfAstNode* refNode, BfTypeDef* typeDef, BfMethodDef* methodDef, int typeGenericParamIdx);
 	void HandleMethodGenericParamRef(BfAstNode* refNode, BfTypeDef* typeDef, BfMethodDef* methodDef, int typeGenericParamIdx);

+ 121 - 15
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -77,7 +77,19 @@ BfGenericExtensionEntry* BfModule::BuildGenericExtensionInfo(BfTypeInstance* gen
 
 
 	for (int externConstraintIdx = 0; externConstraintIdx < (int)partialTypeDef->mExternalConstraints.size(); externConstraintIdx++)
 	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());
 		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);
 		genericExEntry->mGenericParams.push_back(genericParamInstance);
 	}
 	}
 
 
@@ -143,15 +155,31 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef)
 			if (!partialTypeDef->IsExtension())
 			if (!partialTypeDef->IsExtension())
 			{
 			{
 				typeState.mCurTypeDef = partialTypeDef;
 				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 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());
 					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.mCheckAccessibility = false;
 						genericParamSource.mTypeInstance = genericTypeInst;
 						genericParamSource.mTypeInstance = genericTypeInst;
 						BfError* error = NULL;
 						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;
 							genericExEntry->mConstraintsPassed = false;
 						}
 						}
@@ -274,7 +313,7 @@ bool BfModule::ValidateGenericConstraints(BfTypeReference* typeRef, BfTypeInstan
 		}
 		}
 
 
 		BfError* error = NULL;
 		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;
 			genericTypeInst->mGenericTypeInfo->mHadValidateErrors = true;
 			return false;
 			return false;
@@ -6511,6 +6550,12 @@ BfGenericParamInstance* BfModule::GetGenericTypeParamInstance(int genericParamId
 		PopulateType(genericTypeInst, BfPopulateType_Declaration);
 		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)
 	if (genericTypeInst->mGenericTypeInfo->mGenericExtensionInfo != NULL)
 	{
 	{
 		auto activeTypeDef = GetActiveTypeDef(NULL, true);
 		auto activeTypeDef = GetActiveTypeDef(NULL, true);
@@ -6522,8 +6567,8 @@ BfGenericParamInstance* BfModule::GetGenericTypeParamInstance(int genericParamId
 
 
 			BfGenericExtensionEntry* genericExEntry;
 			BfGenericExtensionEntry* genericExEntry;
 			if (genericTypeInst->mGenericTypeInfo->mGenericExtensionInfo->mExtensionMap.TryGetValue(lookupTypeDef, &genericExEntry))
 			if (genericTypeInst->mGenericTypeInfo->mGenericExtensionInfo->mExtensionMap.TryGetValue(lookupTypeDef, &genericExEntry))
-			{
-				return genericExEntry->mGenericParams[genericParamIdx];
+			{				
+				return genericExEntry->mGenericParams[genericParamIdx];				
 			}
 			}
 			else
 			else
 			{
 			{
@@ -6539,6 +6584,58 @@ BfGenericParamInstance* BfModule::GetGenericTypeParamInstance(int genericParamId
 	return genericTypeInst->mGenericTypeInfo->mGenericParams[genericParamIdx];
 	return genericTypeInst->mGenericTypeInfo->mGenericParams[genericParamIdx];
 }
 }
 
 
+void BfModule::GetActiveTypeGenericParamInstances(SizedArray<BfGenericParamInstance*, 4>& 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<BfTypeInstance*> 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)
 BfGenericParamInstance* BfModule::GetGenericParamInstance(BfGenericParamType* type)
 {
 {
 	if (type->mGenericParamKind == BfGenericParamKind_Method)
 	if (type->mGenericParamKind == BfGenericParamKind_Method)
@@ -8939,7 +9036,15 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		constExprType->mValue = result;
 		constExprType->mValue = result;
 
 
 		resolvedEntry->mValue = constExprType;
 		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);
 		populateModule->InitType(constExprType, populateType);
 		return constExprType;
 		return constExprType;
@@ -9534,6 +9639,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 
 
 			if (allowCast)
 			if (allowCast)
 			{
 			{
+				PopulateType(toType);
 				if (toType->IsValuelessType())
 				if (toType->IsValuelessType())
 					return BfIRValue::sValueless;
 					return BfIRValue::sValueless;
 				if (ignoreWrites)
 				if (ignoreWrites)
@@ -10453,21 +10559,21 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 		// Check type generic constraints
 		// Check type generic constraints
 		if ((mCurTypeInstance != NULL) && (mCurTypeInstance->IsGenericTypeInstance()) && (mCurTypeInstance->IsUnspecializedType()))
 		if ((mCurTypeInstance != NULL) && (mCurTypeInstance->IsGenericTypeInstance()) && (mCurTypeInstance->IsUnspecializedType()))
 		{
 		{
-			auto genericTypeInst = (BfTypeInstance*)mCurTypeInstance;
-			for (int genericParamIdx = 0; genericParamIdx < genericTypeInst->mGenericTypeInfo->mGenericParams.size(); genericParamIdx++)
+			SizedArray<BfGenericParamInstance*, 4> genericParams;
+			GetActiveTypeGenericParamInstances(genericParams);
+			for (auto genericParam : genericParams)
 			{
 			{
-				auto genericParam = GetGenericTypeParamInstance(genericParamIdx);
 				for (auto& opConstraint : genericParam->mOperatorConstraints)
 				for (auto& opConstraint : genericParam->mOperatorConstraints)
 				{
 				{
 					if ((opConstraint.mCastToken == BfToken_Implicit) ||
 					if ((opConstraint.mCastToken == BfToken_Implicit) ||
 						((explicitCast) && (opConstraint.mCastToken == BfToken_Explicit)))
 						((explicitCast) && (opConstraint.mCastToken == BfToken_Explicit)))
 					{
 					{
 						// If we can convert OUR fromVal to the constraint's fromVal then we may match
 						// 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
 							// .. and we can convert the constraint's toType to OUR toType then we're good
 							auto opToVal = genericParam->mExternType;
 							auto opToVal = genericParam->mExternType;
-							if (CanCast(BfTypedValue(BfIRValue::sValueless, opToVal), toType))
+							if (CanCast(BfTypedValue(BfIRValue::sValueless, opToVal), toType, BfCastFlags_NoConversionOperator))
 								return mBfIRBuilder->GetFakeVal();
 								return mBfIRBuilder->GetFakeVal();
 						}
 						}
 					}
 					}

+ 14 - 3
IDEHelper/Compiler/BfResolvedTypeUtils.cpp

@@ -2023,10 +2023,21 @@ bool BfTypeInstance::IsTypeMemberIncluded(BfTypeDef* typeDef, BfTypeDef* activeT
 
 
 		for (int genericIdx = 0; genericIdx < (int)declConstraints->size(); genericIdx++)
 		for (int genericIdx = 0; genericIdx < (int)declConstraints->size(); genericIdx++)
 		{
 		{
-			auto genericType = mGenericTypeInfo->mTypeGenericArguments[genericIdx];
-
 			auto declGenericParam = (*declConstraints)[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;
 				return false;
 
 
 			//if (!mModule->AreConstraintsSubset((*declConstraints)[genericIdx], (*activeConstraints)[genericIdx]))
 			//if (!mModule->AreConstraintsSubset((*declConstraints)[genericIdx], (*activeConstraints)[genericIdx]))

+ 2 - 2
IDEHelper/Compiler/BfSystem.cpp

@@ -2759,8 +2759,8 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co
 			typeDef->mTypeDeclaration = partialTypeDef->mTypeDeclaration;		
 			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
 	// Merge attributes together

+ 44 - 0
IDEHelper/Tests/src/Constraints.bf

@@ -1,3 +1,5 @@
+#pragma warning disable 168
+
 using System;
 using System;
 using System.Collections;
 using System.Collections;
 
 
@@ -32,6 +34,48 @@ namespace Tests
 		    return Method2<Dictionary<K, V>.Enumerator, (K key, V value)>(param1.GetEnumerator());
 		    return Method2<Dictionary<K, V>.Enumerator, (K key, V value)>(param1.GetEnumerator());
 		}
 		}
 
 
+		struct StructA
+		{
+
+		}
+
+		class ClassA<T> 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<T> 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<T> 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>(T val)
+			where float : operator T * T where char8 : operator implicit T
+			where int16 : operator T + T where int8 : operator implicit T
+		{
+			ClassA<T> ca = scope .();
+			ClassA<T>.DoMul(val, val);
+ 			ClassA<T>.DoAdd(val, val);
+		}
+
 		[Test]
 		[Test]
 		public static void TestBasics()
 		public static void TestBasics()
 		{
 		{