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:
parent
93f5890d6d
commit
e4892af4c9
3 changed files with 95 additions and 62 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue