1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-11 04:52:21 +02:00

Check operator overloads for assignments on properties

This commit is contained in:
Brian Fiete 2022-02-14 16:07:11 -05:00
parent c887a69e7d
commit 9872ce989b
3 changed files with 178 additions and 87 deletions

View file

@ -18607,6 +18607,69 @@ void BfExprEvaluator::DoTupleAssignment(BfAssignmentExpression* assignExpr)
mResult = rightValue; mResult = rightValue;
} }
BfTypedValue BfExprEvaluator::PerformAssignment_CheckOp(BfAssignmentExpression* assignExpr, bool deferBinop, BfTypedValue& leftValue, BfTypedValue& rightValue, bool& evaluatedRight)
{
BfResolvedArgs argValues;
auto checkTypeInst = leftValue.mType->ToTypeInstance();
while (checkTypeInst != NULL)
{
for (auto operatorDef : checkTypeInst->mTypeDef->mOperators)
{
if (operatorDef->mOperatorDeclaration->mAssignOp != assignExpr->mOp)
continue;
auto methodInst = mModule->GetRawMethodInstanceAtIdx(checkTypeInst, operatorDef->mIdx);
if (methodInst->GetParamCount() != 1)
continue;
auto paramType = methodInst->GetParamType(0);
if (deferBinop)
{
if (argValues.mArguments == NULL)
{
SizedArray<BfExpression*, 2> argExprs;
argExprs.push_back(assignExpr->mRight);
BfSizedArray<BfExpression*> sizedArgExprs(argExprs);
argValues.Init(&sizedArgExprs);
ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval);
}
evaluatedRight = true;
rightValue = ResolveArgValue(argValues.mResolvedArgs[0], paramType);
if (!rightValue)
continue;
}
else
{
if (!mModule->CanCast(rightValue, paramType))
continue;
}
mModule->SetElementType(assignExpr->mOpToken, BfSourceElementType_Method);
auto autoComplete = GetAutoComplete();
if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(assignExpr->mOpToken)))
{
if (operatorDef->mOperatorDeclaration != NULL)
autoComplete->SetDefinitionLocation(operatorDef->mOperatorDeclaration->mOpTypeToken);
}
auto moduleMethodInstance = mModule->GetMethodInstance(checkTypeInst, operatorDef, BfTypeVector());
BfExprEvaluator exprEvaluator(mModule);
SizedArray<BfIRValue, 1> args;
exprEvaluator.PushThis(assignExpr->mLeft, leftValue, moduleMethodInstance.mMethodInstance, args);
exprEvaluator.PushArg(rightValue, args);
exprEvaluator.CreateCall(assignExpr, moduleMethodInstance.mMethodInstance, moduleMethodInstance.mFunc, false, args);
return leftValue;
}
checkTypeInst = mModule->GetBaseType(checkTypeInst);
}
return BfTypedValue();
}
void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool evaluatedLeft, BfTypedValue rightValue, BfTypedValue* outCascadeValue) void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool evaluatedLeft, BfTypedValue rightValue, BfTypedValue* outCascadeValue)
{ {
auto binaryOp = BfAssignOpToBinaryOp(assignExpr->mOp); auto binaryOp = BfAssignOpToBinaryOp(assignExpr->mOp);
@ -18718,16 +18781,39 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
autoComplete->mResultString += mPropDef->mName; autoComplete->mResultString += mPropDef->mName;
} }
bool handled = false;
BfTypedValue convVal; BfTypedValue convVal;
if (binaryOp != BfBinaryOp_None) if (binaryOp != BfBinaryOp_None)
{ {
PerformBinaryOperation(assignExpr->mLeft, assignExpr->mRight, binaryOp, assignExpr->mOpToken, BfBinOpFlag_ForceLeftType); BfTypedValue leftValue = mModule->CreateValueFromExpression(assignExpr->mLeft, mExpectingType, (BfEvalExprFlags)((mBfEvalExprFlags & BfEvalExprFlags_InheritFlags) | BfEvalExprFlags_NoCast | BfEvalExprFlags_AllowIntUnknown));
if (!mResult) if (!leftValue)
return; return;
convVal = mResult;
mResult = BfTypedValue(); bool evaluatedRight = false;
if (!convVal) auto opResult = PerformAssignment_CheckOp(assignExpr, true, leftValue, rightValue, evaluatedRight);
if (opResult)
{
mResult = opResult;
return; return;
}
else
{
if (evaluatedRight)
{
if (!rightValue)
return;
PerformBinaryOperation(assignExpr->mLeft, assignExpr->mRight, binaryOp, assignExpr->mOpToken, BfBinOpFlag_ForceLeftType, leftValue, rightValue);
}
else
PerformBinaryOperation(assignExpr->mLeft, assignExpr->mRight, binaryOp, assignExpr->mOpToken, BfBinOpFlag_ForceLeftType, leftValue);
if (!mResult)
return;
convVal = mResult;
mResult = BfTypedValue();
if (!convVal)
return;
}
} }
else else
{ {
@ -18755,37 +18841,40 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
} }
} }
if (mPropSrc != NULL) if (!handled)
mModule->UpdateExprSrcPos(mPropSrc);
BfResolvedArg valueArg;
valueArg.mTypedValue = convVal;
mIndexerValues.Insert(0, valueArg);
if (!setMethod->mIsStatic)
{ {
auto owner = methodInstance.mMethodInstance->GetOwner(); if (mPropSrc != NULL)
if ((mPropTarget.mType != owner) || mModule->UpdateExprSrcPos(mPropSrc);
((mPropTarget.mValue.IsFake()) && (!mOrigPropTarget.mValue.IsFake())))
BfResolvedArg valueArg;
valueArg.mTypedValue = convVal;
mIndexerValues.Insert(0, valueArg);
if (!setMethod->mIsStatic)
{ {
if ((mPropDefBypassVirtual) || (!mPropTarget.mType->IsInterface())) auto owner = methodInstance.mMethodInstance->GetOwner();
if ((mPropTarget.mType != owner) ||
((mPropTarget.mValue.IsFake()) && (!mOrigPropTarget.mValue.IsFake())))
{ {
mPropTarget = mModule->Cast(mPropSrc, mOrigPropTarget, owner); if ((mPropDefBypassVirtual) || (!mPropTarget.mType->IsInterface()))
if (!mPropTarget)
{ {
mModule->Fail("Internal property error", mPropSrc); mPropTarget = mModule->Cast(mPropSrc, mOrigPropTarget, owner);
return; if (!mPropTarget)
{
mModule->Fail("Internal property error", mPropSrc);
return;
}
} }
} }
} }
}
auto callFlags = mPropDefBypassVirtual ? BfCreateCallFlags_BypassVirtual : BfCreateCallFlags_None; auto callFlags = mPropDefBypassVirtual ? BfCreateCallFlags_BypassVirtual : BfCreateCallFlags_None;
mResult = CreateCall(mPropSrc, mPropTarget, mOrigPropTarget, setMethod, methodInstance, callFlags, mIndexerValues, NULL); mResult = CreateCall(mPropSrc, mPropTarget, mOrigPropTarget, setMethod, methodInstance, callFlags, mIndexerValues, NULL);
mPropDef = NULL; mPropDef = NULL;
mResult = convVal; mResult = convVal;
mIndexerValues.Clear(); mIndexerValues.Clear();
return; return;
}
} }
} }
@ -18842,65 +18931,14 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
if ((rightValue) || (deferBinop)) if ((rightValue) || (deferBinop))
{ {
auto checkTypeInst = leftValue.mType->ToTypeInstance(); bool evaluatedRight = false;
while (checkTypeInst != NULL) auto opResult = PerformAssignment_CheckOp(assignExpr, deferBinop, leftValue, rightValue, evaluatedRight);
if (opResult)
{ {
for (auto operatorDef : checkTypeInst->mTypeDef->mOperators) handled = true;
{ convVal = opResult;
if (operatorDef->mOperatorDeclaration->mAssignOp != assignExpr->mOp)
continue;
auto methodInst = mModule->GetRawMethodInstanceAtIdx(checkTypeInst, operatorDef->mIdx);
if (methodInst->GetParamCount() != 1)
continue;
auto paramType = methodInst->GetParamType(0);
if (deferBinop)
{
if (argValues.mArguments == NULL)
{
SizedArray<BfExpression*, 2> argExprs;
argExprs.push_back(assignExpr->mRight);
BfSizedArray<BfExpression*> sizedArgExprs(argExprs);
argValues.Init(&sizedArgExprs);
ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval);
}
rightValue = ResolveArgValue(argValues.mResolvedArgs[0], paramType);
if (!rightValue)
continue;
}
else
{
if (!mModule->CanCast(rightValue, paramType))
continue;
}
mModule->SetElementType(assignExpr->mOpToken, BfSourceElementType_Method);
if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(assignExpr->mOpToken)))
{
if (operatorDef->mOperatorDeclaration != NULL)
autoComplete->SetDefinitionLocation(operatorDef->mOperatorDeclaration->mOpTypeToken);
}
auto moduleMethodInstance = mModule->GetMethodInstance(checkTypeInst, operatorDef, BfTypeVector());
BfExprEvaluator exprEvaluator(mModule);
SizedArray<BfIRValue, 1> args;
exprEvaluator.PushThis(assignExpr->mLeft, leftValue, moduleMethodInstance.mMethodInstance, args);
exprEvaluator.PushArg(rightValue, args);
exprEvaluator.CreateCall(assignExpr, moduleMethodInstance.mMethodInstance, moduleMethodInstance.mFunc, false, args);
convVal = leftValue;
handled = true;
break;
}
if (handled)
break;
checkTypeInst = mModule->GetBaseType(checkTypeInst);
} }
else
if (!handled)
{ {
auto flags = BfBinOpFlag_ForceLeftType; auto flags = BfBinOpFlag_ForceLeftType;
if (deferBinop) if (deferBinop)

View file

@ -501,7 +501,8 @@ public:
void FixitAddMember(BfTypeInstance* typeInst, BfType* fieldType, const StringImpl& fieldName, bool isStatic); void FixitAddMember(BfTypeInstance* typeInst, BfType* fieldType, const StringImpl& fieldName, bool isStatic);
void PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags); void PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags);
BfTypedValue PerformUnaryOperation_TryOperator(const BfTypedValue& inValue, BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags); BfTypedValue PerformUnaryOperation_TryOperator(const BfTypedValue& inValue, BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags);
void PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags); void PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags);
BfTypedValue PerformAssignment_CheckOp(BfAssignmentExpression* assignExpr, bool deferBinop, BfTypedValue& leftValue, BfTypedValue& rightValue, bool& evaluatedRight);
void PerformAssignment(BfAssignmentExpression* assignExpr, bool evaluatedLeft, BfTypedValue rightValue, BfTypedValue* outCascadeValue = NULL); void PerformAssignment(BfAssignmentExpression* assignExpr, bool evaluatedLeft, BfTypedValue rightValue, BfTypedValue* outCascadeValue = NULL);
void PopulateDeferrredTupleAssignData(BfTupleExpression* tupleExr, DeferredTupleAssignData& deferredTupleAssignData); void PopulateDeferrredTupleAssignData(BfTupleExpression* tupleExr, DeferredTupleAssignData& deferredTupleAssignData);
void AssignDeferrredTupleAssignData(BfAssignmentExpression* assignExpr, DeferredTupleAssignData& deferredTupleAssignData, BfTypedValue rightValue); void AssignDeferrredTupleAssignData(BfAssignmentExpression* assignExpr, DeferredTupleAssignData& deferredTupleAssignData, BfTypedValue rightValue);

View file

@ -2,6 +2,22 @@
using System; using System;
namespace System
{
public extension Event<T>
{
public implicit void operator+=(T action) mut
{
Add(action);
}
public implicit void operator-=(T action) mut
{
Remove(action, true);
}
}
}
namespace Tests namespace Tests
{ {
class Operators class Operators
@ -457,6 +473,26 @@ namespace Tests
public struct Vector2 : this(float x, float y); public struct Vector2 : this(float x, float y);
public static Event<Action> sEvent ~ _.Dispose(); // Workaround for the lack of auto-destructor in properties
public static ref Event<Action> EventProp { get => ref sEvent; set => sEvent = value; };
static int sA = 123;
public static ref int RefVal => ref sA;
public static int Val
{
get
{
return sA;
}
set
{
sA = value;
}
}
[Test] [Test]
public static void TestBasics() public static void TestBasics()
{ {
@ -657,6 +693,22 @@ namespace Tests
StructK sk = (.)123; StructK sk = (.)123;
uint64 sku32 = sk; uint64 sku32 = sk;
Test.Assert(sku32 == 123); Test.Assert(sku32 == 123);
int val2 = 10;
void Set()
{
val2 += 200;
}
EventProp += new => Set;
EventProp();
Test.Assert(val2 == 210);
RefVal += 99;
Test.Assert(sA == 222);
Val += 1000;
Test.Assert(sA == 1222);
} }
struct IntStruct struct IntStruct