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

Added constraint test for casting

This commit is contained in:
Brian Fiete 2020-09-19 06:41:36 -07:00
parent 93f5890d6d
commit e4892af4c9
3 changed files with 95 additions and 62 deletions

View file

@ -17943,9 +17943,12 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal
} }
if (isConstraintCheck) if (isConstraintCheck)
{ {
operatorConstraintReturnType = mModule->CheckOperator(checkType, operatorDef, inValue, BfTypedValue()); auto returnType = mModule->CheckOperator(checkType, operatorDef, inValue, BfTypedValue());
if (operatorConstraintReturnType != NULL) if (returnType != NULL)
{
operatorConstraintReturnType = returnType;
methodMatcher.mBestMethodDef = operatorDef; methodMatcher.mBestMethodDef = operatorDef;
}
} }
else else
{ {
@ -17969,7 +17972,7 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal
{ {
if (opConstraint.mUnaryOp == findOp) if (opConstraint.mUnaryOp == findOp)
{ {
if (mModule->CanCast(args[0].mTypedValue, opConstraint.mRightType, isConstraintCheck ? BfCastFlags_NoConversionOperator : BfCastFlags_None)) if (mModule->CanCast(args[0].mTypedValue, opConstraint.mRightType, isConstraintCheck ? BfCastFlags_IsConstraintCheck : BfCastFlags_None))
{ {
return BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType); return BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType);
} }
@ -17989,7 +17992,7 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal
{ {
if (opConstraint.mUnaryOp == findOp) if (opConstraint.mUnaryOp == findOp)
{ {
if (mModule->CanCast(args[0].mTypedValue, opConstraint.mRightType, isConstraintCheck ? BfCastFlags_NoConversionOperator : BfCastFlags_None)) if (mModule->CanCast(args[0].mTypedValue, opConstraint.mRightType, isConstraintCheck ? BfCastFlags_IsConstraintCheck : BfCastFlags_None))
{ {
return BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType); return BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType);
} }
@ -19329,9 +19332,10 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
{ {
// We can't do CheckMethod because circular referencing means we may have to evaluate this before our type is complete, // We can't do CheckMethod because circular referencing means we may have to evaluate this before our type is complete,
// which means before method processing has occurred // which means before method processing has occurred
operatorConstraintReturnType = mModule->CheckOperator(checkType, operatorDef, leftValue, rightValue); auto returnType = mModule->CheckOperator(checkType, operatorDef, args[0].mTypedValue, args[1].mTypedValue);
if (operatorConstraintReturnType != NULL) if (returnType != NULL)
{ {
operatorConstraintReturnType = returnType;
methodMatcher.mBestMethodDef = operatorDef; methodMatcher.mBestMethodDef = operatorDef;
foundExactMatch = true; foundExactMatch = true;
} }
@ -19357,9 +19361,10 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
{ {
if ((flags & BfBinOpFlag_IsConstraintCheck) != 0) if ((flags & BfBinOpFlag_IsConstraintCheck) != 0)
{ {
operatorConstraintReturnType = mModule->CheckOperator(checkType, oppositeOperatorDef, leftValue, rightValue); auto returnType = mModule->CheckOperator(checkType, oppositeOperatorDef, args[0].mTypedValue, args[1].mTypedValue);
if (operatorConstraintReturnType != NULL) if (returnType != NULL)
{ {
operatorConstraintReturnType = returnType;
methodMatcher.mBestMethodDef = oppositeOperatorDef; methodMatcher.mBestMethodDef = oppositeOperatorDef;
methodMatcher.mSelfType = entry.mSrcType; methodMatcher.mSelfType = entry.mSrcType;
} }

View file

@ -9685,17 +9685,15 @@ BfType* BfModule::CheckOperator(BfTypeInstance* typeInstance, BfOperatorDef* ope
if (lhs) if (lhs)
{ {
if (operatorInfo->mLHSType == NULL) if (operatorInfo->mLHSType == NULL)
return NULL; return NULL;
// TODO: Make this be a special flag to do CheckOperator conversion checks? if (!CanCast(lhs, operatorInfo->mLHSType, BfCastFlags_IsConstraintCheck))
if (!CanCast(lhs, operatorInfo->mLHSType, BfCastFlags_NoConversionOperator))
return NULL; return NULL;
} }
if (rhs) if (rhs)
{ {
if (operatorInfo->mRHSType == NULL) if (operatorInfo->mRHSType == NULL)
return NULL; return NULL;
// TODO: Make this be a special flag to do CheckOperator conversion checks? if (!CanCast(rhs, operatorInfo->mRHSType, BfCastFlags_IsConstraintCheck))
if (!CanCast(rhs, operatorInfo->mRHSType, BfCastFlags_NoConversionOperator))
return NULL; return NULL;
} }
return operatorInfo->mReturnType; return operatorInfo->mReturnType;

View file

@ -10557,6 +10557,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
BfIRValue conversionResult; BfIRValue conversionResult;
BfMethodInstance* opMethodInstance = NULL; BfMethodInstance* opMethodInstance = NULL;
BfType* opMethodSrcType = NULL; BfType* opMethodSrcType = NULL;
BfOperatorInfo* constraintOperatorInfo = NULL;
// Normal, lifted, execute // Normal, lifted, execute
for (int pass = 0; pass < 3; pass++) for (int pass = 0; pass < 3; pass++)
@ -10580,6 +10581,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
break; break;
} }
bool isConstraintCheck = ((castFlags & BfCastFlags_IsConstraintCheck) != 0);
BfBaseClassWalker baseClassWalker(fromType, toType, this); BfBaseClassWalker baseClassWalker(fromType, toType, this);
while (true) while (true)
@ -10597,16 +10599,29 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
(operatorDef->mOperatorDeclaration->mExplicitToken->GetToken() == BfToken_Explicit)) (operatorDef->mOperatorDeclaration->mExplicitToken->GetToken() == BfToken_Explicit))
continue; continue;
auto methodInst = GetRawMethodInstanceAtIdx(checkInstance, operatorDef->mIdx); BfType* methodFromType = NULL;
BfType* methodToType = NULL;
if (methodInst->GetParamCount() != 1) if (isConstraintCheck)
{ {
AssertErrorState(); auto operatorInfo = GetOperatorInfo(checkInstance, operatorDef);
continue; methodFromType = operatorInfo->mLHSType;
methodToType = operatorInfo->mReturnType;
if ((methodFromType == NULL) || (methodToType == NULL))
continue;
} }
else
{
auto methodInst = GetRawMethodInstanceAtIdx(checkInstance, operatorDef->mIdx);
if (methodInst->GetParamCount() != 1)
{
AssertErrorState();
continue;
}
auto methodFromType = methodInst->GetParamType(0); methodFromType = methodInst->GetParamType(0);
auto methodToType = methodInst->mReturnType; methodToType = methodInst->mReturnType;
}
if (methodFromType->IsSelf()) if (methodFromType->IsSelf())
methodFromType = entry.mSrcType; methodFromType = entry.mSrcType;
@ -10672,7 +10687,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
if ((toDist >= 0) && (toDist < bestNegToDist)) if ((toDist >= 0) && (toDist < bestNegToDist))
{ {
bestNegToDist = toDist; bestNegToDist = toDist;
bestNegToType = methodInst->mReturnType; bestNegToType = methodToType;
} }
} }
} }
@ -10680,36 +10695,43 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
{ {
if ((methodFromType == bestFromType) && (methodToType == bestToType)) if ((methodFromType == bestFromType) && (methodToType == bestToType))
{ {
// Get in native module so our module doesn't get a reference to it - we may not end up calling it at all! if (isConstraintCheck)
//BfModuleMethodInstance methodInstance = checkInstance->mModule->GetMethodInstanceAtIdx(checkInstance, operatorDef->mIdx);
BfMethodInstance* methodInstance = GetRawMethodInstanceAtIdx(checkInstance, operatorDef->mIdx);
if (opMethodInstance != NULL)
{ {
int prevGenericCount = GetGenericParamAndReturnCount(opMethodInstance); auto operatorInfo = GetOperatorInfo(checkInstance, operatorDef);
int newGenericCount = GetGenericParamAndReturnCount(methodInstance); constraintOperatorInfo = operatorInfo;
if (newGenericCount > prevGenericCount) }
else
{
// Get in native module so our module doesn't get a reference to it - we may not end up calling it at all!
BfMethodInstance* methodInstance = GetRawMethodInstanceAtIdx(checkInstance, operatorDef->mIdx);
if (opMethodInstance != NULL)
{ {
// Prefer generic match int prevGenericCount = GetGenericParamAndReturnCount(opMethodInstance);
opMethodInstance = methodInstance; int newGenericCount = GetGenericParamAndReturnCount(methodInstance);
opMethodSrcType = entry.mSrcType; if (newGenericCount > prevGenericCount)
} {
else if (newGenericCount < prevGenericCount) // Prefer generic match
{ opMethodInstance = methodInstance;
// Previous was a generic match opMethodSrcType = entry.mSrcType;
continue; }
else if (newGenericCount < prevGenericCount)
{
// Previous was a generic match
continue;
}
else
{
isAmbiguousCast = true;
break;
}
} }
else else
{ {
isAmbiguousCast = true; opMethodInstance = methodInstance;
break; opMethodSrcType = entry.mSrcType;
} }
} }
else
{
opMethodInstance = methodInstance;
opMethodSrcType = entry.mSrcType;
}
} }
} }
} }
@ -10718,7 +10740,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
if (isAmbiguousCast) if (isAmbiguousCast)
break; break;
if (opMethodInstance != NULL) if ((opMethodInstance != NULL) || (constraintOperatorInfo != NULL))
{ {
if (mayBeBox) if (mayBeBox)
{ {
@ -10731,22 +10753,30 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
SetFail(); SetFail();
} }
BfMethodInstance* methodInstance = GetRawMethodInstance(opMethodInstance->GetOwner(), opMethodInstance->mMethodDef); BfType* returnType;
if (isConstraintCheck)
auto methodDeclaration = methodInstance->mMethodDef->GetMethodDeclaration(); {
if (methodDeclaration->mBody == NULL) returnType = constraintOperatorInfo->mReturnType;
{ }
// Handle the typedPrim<->underlying part implicitly else
if (fromType->IsTypedPrimitive()) {
returnType = opMethodInstance->mReturnType;
BfMethodInstance* methodInstance = GetRawMethodInstance(opMethodInstance->GetOwner(), opMethodInstance->mMethodDef);
auto methodDeclaration = methodInstance->mMethodDef->GetMethodDeclaration();
if (methodDeclaration->mBody == NULL)
{ {
auto convTypedValue = BfTypedValue(typedVal.mValue, fromType->GetUnderlyingType()); // Handle the typedPrim<->underlying part implicitly
return CastToValue(srcNode, convTypedValue, toType, (BfCastFlags)(castFlags & ~BfCastFlags_Explicit), NULL); if (fromType->IsTypedPrimitive())
{
auto convTypedValue = BfTypedValue(typedVal.mValue, fromType->GetUnderlyingType());
return CastToValue(srcNode, convTypedValue, toType, (BfCastFlags)(castFlags & ~BfCastFlags_Explicit), NULL);
}
else if (toType->IsTypedPrimitive())
{
auto castedVal = CastToValue(srcNode, typedVal, toType->GetUnderlyingType(), (BfCastFlags)(castFlags & ~BfCastFlags_Explicit), NULL);
return castedVal;
}
} }
else if (toType->IsTypedPrimitive())
{
auto castedVal = CastToValue(srcNode, typedVal, toType->GetUnderlyingType(), (BfCastFlags)(castFlags & ~BfCastFlags_Explicit), NULL);
return castedVal;
}
} }
// Actually perform conversion // Actually perform conversion
@ -10757,10 +10787,10 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
BfTypedValue operatorOut; BfTypedValue operatorOut;
if (ignoreWrites) if (ignoreWrites)
{ {
if (opMethodInstance->mReturnType == toType) if (returnType == toType)
return mBfIRBuilder->GetFakeVal(); return mBfIRBuilder->GetFakeVal();
operatorOut = GetDefaultTypedValue(opMethodInstance->mReturnType); operatorOut = GetDefaultTypedValue(returnType);
} }
else else
{ {