1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-09 20:12:21 +02:00

Improved extern type constraints

This commit is contained in:
Brian Fiete 2020-08-10 13:29:05 -07:00
parent 99989d5472
commit 32cd6d8841
8 changed files with 280 additions and 85 deletions

View file

@ -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++)
{ {
@ -18802,8 +18803,6 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
bool invertResult = false; bool invertResult = false;
BfBinaryOp oppositeBinaryOp = BfGetOppositeBinaryOp(findBinaryOp);
while (true) while (true)
{ {
auto entry = baseClassWalker.Next(); auto entry = baseClassWalker.Next();
@ -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 (_CheckBinaryOp(genericParam))
{ return;
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;
}
}
}
} }
} }
// 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; SizedArray<BfGenericParamInstance*, 4> genericParams;
for (int genericParamIdx = 0; genericParamIdx < genericTypeInst->mGenericTypeInfo->mGenericParams.size(); genericParamIdx++) mModule->GetActiveTypeGenericParamInstances(genericParams);
for (auto genericParam : genericParams)
{ {
auto genericParam = mModule->GetGenericTypeParamInstance(genericParamIdx); if (_CheckBinaryOp(genericParam))
for (auto& opConstraint : genericParam->mOperatorConstraints) return;
{
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;
}
}
}
} }
} }
@ -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 if (resultType->IsInterface())
resultType = mModule->mContext->mBfObjectType;
*resultTypedValue = mModule->Cast(resultTypeSrc, *resultTypedValue, resultType);
}
if (otherType->IsNull())
{
if (resultType->IsFunction())
{ {
if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) // Compare as objects instead
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 0), resultTypedValue->mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); 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 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())

View file

@ -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
@ -587,11 +592,6 @@ public:
} }
BfIRType(const BfIRValue& val) { mKind = TypeKind_Stream; mId = val.mId; } BfIRType(const BfIRValue& val) { mKind = TypeKind_Stream; mId = val.mId; }
operator bool()
{
return (mId != -1);
}
}; };
struct BfIRBlock : public BfIRValue struct BfIRBlock : public BfIRValue

View file

@ -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()

View file

@ -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);

View file

@ -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++) for (int paramIdx = startDefGenericParamIdx; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mGenericParams.size(); paramIdx++)
{ {
auto genericParamDef = typeDef->mGenericParamDefs[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);
@ -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; SizedArray<BfGenericParamInstance*, 4> genericParams;
for (int genericParamIdx = 0; genericParamIdx < genericTypeInst->mGenericTypeInfo->mGenericParams.size(); genericParamIdx++) 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();
} }
} }

View file

@ -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]))

View file

@ -2759,8 +2759,8 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co
typeDef->mTypeDeclaration = partialTypeDef->mTypeDeclaration; typeDef->mTypeDeclaration = partialTypeDef->mTypeDeclaration;
} }
for (auto& externConstraint : partialTypeDef->mExternalConstraints) // for (auto& externConstraint : partialTypeDef->mExternalConstraints)
typeDef->mExternalConstraints.Add(externConstraint); // typeDef->mExternalConstraints.Add(externConstraint);
} }
// Merge attributes together // Merge attributes together

View file

@ -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()
{ {