1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 19:48:20 +02:00

Made method mutability part of signature and method selection

This commit is contained in:
Brian Fiete 2020-08-29 14:18:05 -07:00
parent f795215b44
commit c49d92b779
7 changed files with 129 additions and 14 deletions

View file

@ -738,6 +738,8 @@ public:
break; break;
} }
} }
bool CanModify() const;
}; };
#define BF_AST_TYPE(name, TBase) \ #define BF_AST_TYPE(name, TBase) \

View file

@ -1015,6 +1015,7 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
auto activeDef = mModule->GetActiveTypeDef(); auto activeDef = mModule->GetActiveTypeDef();
RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType == activeDef, prevMethodDef->mDeclaringType == activeDef); RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType == activeDef, prevMethodDef->mDeclaringType == activeDef);
RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType->IsExtension(), prevMethodDef->mDeclaringType->IsExtension()); RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType->IsExtension(), prevMethodDef->mDeclaringType->IsExtension());
RETURN_BETTER_OR_WORSE(newMethodDef->mIsMutating, prevMethodDef->mIsMutating);
RETURN_RESULTS; RETURN_RESULTS;
} }
@ -1437,6 +1438,13 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
else if (needInferGenericParams) else if (needInferGenericParams)
genericArgumentsSubstitute = &mCheckMethodGenericArguments; genericArgumentsSubstitute = &mCheckMethodGenericArguments;
if ((checkMethod->mIsMutating) && (targetTypeInstance != NULL) && (targetTypeInstance->IsValueType()) &&
((mTarget.IsReadOnly()) || (!mTarget.IsAddr())) &&
(!targetTypeInstance->IsValuelessType()))
{
goto NoMatch;
}
if (mSkipImplicitParams) if (mSkipImplicitParams)
{ {
//paramOfs = methodInstance->GetImplicitParamCount(); //paramOfs = methodInstance->GetImplicitParamCount();
@ -4199,8 +4207,8 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
if (auto propertyDeclaration = BfNodeDynCast<BfPropertyDeclaration>(mPropDef->mFieldDeclaration)) if (auto propertyDeclaration = BfNodeDynCast<BfPropertyDeclaration>(mPropDef->mFieldDeclaration))
{ {
if (curCheckType->mTypeDef->HasAutoProperty(propertyDeclaration)) if (curCheckType->mTypeDef->HasAutoProperty(propertyDeclaration))
{ {
bool hasSetter = GetPropertyMethodDef(mPropDef, BfMethodType_PropertySetter, BfCheckedKind_NotSet) != NULL; bool hasSetter = GetPropertyMethodDef(mPropDef, BfMethodType_PropertySetter, BfCheckedKind_NotSet, mPropTarget) != NULL;
auto autoFieldName = curCheckType->mTypeDef->GetAutoPropertyName(propertyDeclaration); auto autoFieldName = curCheckType->mTypeDef->GetAutoPropertyName(propertyDeclaration);
auto result = LookupField(targetSrc, target, autoFieldName, BfLookupFieldFlag_IgnoreProtection); auto result = LookupField(targetSrc, target, autoFieldName, BfLookupFieldFlag_IgnoreProtection);
if (result) if (result)
@ -14845,14 +14853,54 @@ void BfExprEvaluator::Visit(BfInvocationExpression* invocationExpr)
mResult = cascadeValue; mResult = cascadeValue;
} }
BfMethodDef* BfExprEvaluator::GetPropertyMethodDef(BfPropertyDef* propDef, BfMethodType methodType, BfCheckedKind checkedKind) BfMethodDef* BfExprEvaluator::GetPropertyMethodDef(BfPropertyDef* propDef, BfMethodType methodType, BfCheckedKind checkedKind, BfTypedValue propTarget)
{ {
bool allowMut = (propTarget) && (!propTarget.mType->IsValueType() || propTarget.CanModify());
int bestPri = -1000;
BfMethodDef* matchedMethod = NULL; BfMethodDef* matchedMethod = NULL;
for (auto methodDef : propDef->mMethods)
{
if (methodDef->mMethodType != methodType)
continue;
int curPri = 0;
if (methodDef->mCheckedKind == checkedKind)
{
curPri = 5;
}
else if ((checkedKind == BfCheckedKind_NotSet) && (methodDef->mCheckedKind == mModule->GetDefaultCheckedKind()))
curPri = 3;
else
curPri = 1;
if (methodDef->mIsMutating)
{
if (allowMut)
curPri++;
else
curPri -= 10;
}
if (curPri > bestPri)
{
bestPri = curPri;
matchedMethod = methodDef;
}
}
return matchedMethod;
/*BfMethodDef* matchedMethod = NULL;
BfMethodDef* backupMethod = NULL; BfMethodDef* backupMethod = NULL;
for (auto methodDef : propDef->mMethods) for (auto methodDef : propDef->mMethods)
{ {
if (methodDef->mMethodType != methodType) if (methodDef->mMethodType != methodType)
continue; continue;
if (methodDef->mCheckedKind == checkedKind) if (methodDef->mCheckedKind == checkedKind)
{ {
matchedMethod = methodDef; matchedMethod = methodDef;
@ -14865,7 +14913,7 @@ BfMethodDef* BfExprEvaluator::GetPropertyMethodDef(BfPropertyDef* propDef, BfMet
} }
if (matchedMethod == NULL) if (matchedMethod == NULL)
matchedMethod = backupMethod; matchedMethod = backupMethod;
return matchedMethod; return matchedMethod;*/
} }
BfModuleMethodInstance BfExprEvaluator::GetPropertyMethodInstance(BfMethodDef* methodDef) BfModuleMethodInstance BfExprEvaluator::GetPropertyMethodInstance(BfMethodDef* methodDef)
@ -15084,7 +15132,7 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp
SetAndRestoreValue<BfFunctionBindResult*> prevFunctionBindResult(mFunctionBindResult, NULL); SetAndRestoreValue<BfFunctionBindResult*> prevFunctionBindResult(mFunctionBindResult, NULL);
SetAndRestoreValue<BfAstNode*> prevDeferCallRef(mDeferCallRef, NULL); SetAndRestoreValue<BfAstNode*> prevDeferCallRef(mDeferCallRef, NULL);
BfMethodDef* matchedMethod = GetPropertyMethodDef(mPropDef, BfMethodType_PropertyGetter, mPropCheckedKind); BfMethodDef* matchedMethod = GetPropertyMethodDef(mPropDef, BfMethodType_PropertyGetter, mPropCheckedKind, mPropTarget);
if (matchedMethod == NULL) if (matchedMethod == NULL)
{ {
mModule->Fail("Property has no getter", mPropSrc); mModule->Fail("Property has no getter", mPropSrc);
@ -15404,8 +15452,7 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
return true; return true;
} }
bool canModify = (((typedVal.IsAddr()) || (typedVal.mType->IsValuelessType())) && bool canModify = typedVal.CanModify();
(!typedVal.IsReadOnly()));
if (localVar != NULL) if (localVar != NULL)
{ {
@ -15776,8 +15823,8 @@ void BfExprEvaluator::PopulateDeferrredTupleAssignData(BfTupleExpression* tupleE
BfPointerType* pointerType = (BfPointerType*)exprEvaluator->mPropTarget.mType; BfPointerType* pointerType = (BfPointerType*)exprEvaluator->mPropTarget.mType;
propTypeInst = pointerType->mElementType->ToTypeInstance(); propTypeInst = pointerType->mElementType->ToTypeInstance();
} }
auto setMethod = GetPropertyMethodDef(exprEvaluator->mPropDef, BfMethodType_PropertySetter, mPropCheckedKind); auto setMethod = GetPropertyMethodDef(exprEvaluator->mPropDef, BfMethodType_PropertySetter, mPropCheckedKind, mPropTarget);
if (setMethod != NULL) if (setMethod != NULL)
{ {
auto methodInstance = mModule->GetMethodInstance(propTypeInst, setMethod, BfTypeVector()); auto methodInstance = mModule->GetMethodInstance(propTypeInst, setMethod, BfTypeVector());
@ -15785,7 +15832,7 @@ void BfExprEvaluator::PopulateDeferrredTupleAssignData(BfTupleExpression* tupleE
} }
else else
{ {
auto getMethod = GetPropertyMethodDef(exprEvaluator->mPropDef, BfMethodType_PropertyGetter, mPropCheckedKind); auto getMethod = GetPropertyMethodDef(exprEvaluator->mPropDef, BfMethodType_PropertyGetter, mPropCheckedKind, mPropTarget);
if (getMethod != NULL) if (getMethod != NULL)
{ {
auto methodInstance = mModule->GetMethodInstance(propTypeInst, getMethod, BfTypeVector()); auto methodInstance = mModule->GetMethodInstance(propTypeInst, getMethod, BfTypeVector());
@ -15948,7 +15995,7 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
auto propDef = mPropDef; auto propDef = mPropDef;
auto propTarget = mPropTarget; auto propTarget = mPropTarget;
auto setMethod = GetPropertyMethodDef(mPropDef, BfMethodType_PropertySetter, mPropCheckedKind); auto setMethod = GetPropertyMethodDef(mPropDef, BfMethodType_PropertySetter, mPropCheckedKind, mPropTarget);
if (setMethod == NULL) if (setMethod == NULL)
{ {
// Allow for a ref return on the getter to be used if a setter is not available // Allow for a ref return on the getter to be used if a setter is not available
@ -17306,6 +17353,7 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
continue; continue;
methodMatcher.mCheckedKind = checkedKind; methodMatcher.mCheckedKind = checkedKind;
methodMatcher.mTarget = target;
methodMatcher.CheckMethod(startCheckTypeInst, curCheckType, checkMethod, false); methodMatcher.CheckMethod(startCheckTypeInst, curCheckType, checkMethod, false);
if ((methodMatcher.mBestMethodDef == checkMethod) || if ((methodMatcher.mBestMethodDef == checkMethod) ||
@ -18191,7 +18239,7 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
if (writeToProp) if (writeToProp)
{ {
auto setMethod = GetPropertyMethodDef(propDef, BfMethodType_PropertySetter, mPropCheckedKind); auto setMethod = GetPropertyMethodDef(propDef, BfMethodType_PropertySetter, mPropCheckedKind, mPropTarget);
if (setMethod == NULL) if (setMethod == NULL)
{ {
mModule->Fail("Property has no setter", propSrc); mModule->Fail("Property has no setter", propSrc);

View file

@ -348,7 +348,7 @@ public:
void ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveArgFlags flags = BfResolveArgFlag_None); void ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveArgFlags flags = BfResolveArgFlag_None);
BfAllocTarget ResolveAllocTarget(BfAstNode* newNode, BfTokenNode*& newToken, BfCustomAttributes** outCustomAttributes = NULL); BfAllocTarget ResolveAllocTarget(BfAstNode* newNode, BfTokenNode*& newToken, BfCustomAttributes** outCustomAttributes = NULL);
BfTypedValue ResolveArgValue(BfResolvedArg& resolvedArg, BfType* wantType, BfTypedValue* receivingValue = NULL, BfParamKind paramKind = BfParamKind_Normal); BfTypedValue ResolveArgValue(BfResolvedArg& resolvedArg, BfType* wantType, BfTypedValue* receivingValue = NULL, BfParamKind paramKind = BfParamKind_Normal);
BfMethodDef* GetPropertyMethodDef(BfPropertyDef* propDef, BfMethodType methodType, BfCheckedKind checkedKind); BfMethodDef* GetPropertyMethodDef(BfPropertyDef* propDef, BfMethodType methodType, BfCheckedKind checkedKind, BfTypedValue propTarget);
BfModuleMethodInstance GetPropertyMethodInstance(BfMethodDef* methodDef); BfModuleMethodInstance GetPropertyMethodInstance(BfMethodDef* methodDef);
void CheckPropFail(BfMethodDef* propMethodDef, BfMethodInstance* methodInstance, bool checkProt); void CheckPropFail(BfMethodDef* propMethodDef, BfMethodInstance* methodInstance, bool checkProt);
bool HasResult(); bool HasResult();

View file

@ -11385,7 +11385,7 @@ bool BfModule::CompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstan
else if (methodA->mMethodDef->mName != methodB->mMethodDef->mName) else if (methodA->mMethodDef->mName != methodB->mMethodDef->mName)
return false; return false;
if (methodA->mMethodDef->mCheckedKind != methodB->mMethodDef->mCheckedKind) if (methodA->mMethodDef->mCheckedKind != methodB->mMethodDef->mCheckedKind)
return false; return false;
if ((methodA->mMethodDef->mMethodType == BfMethodType_Mixin) != (methodB->mMethodDef->mMethodType == BfMethodType_Mixin)) if ((methodA->mMethodDef->mMethodType == BfMethodType_Mixin) != (methodB->mMethodDef->mMethodType == BfMethodType_Mixin))
return false; return false;
@ -20846,6 +20846,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
if (((checkMethodInstance->mChainType == BfMethodChainType_None) || (checkMethodInstance->mChainType == BfMethodChainType_ChainHead)) && if (((checkMethodInstance->mChainType == BfMethodChainType_None) || (checkMethodInstance->mChainType == BfMethodChainType_ChainHead)) &&
(checkMethodInstance->GetExplicitInterface() == methodInstance->GetExplicitInterface()) && (checkMethodInstance->GetExplicitInterface() == methodInstance->GetExplicitInterface()) &&
(checkMethod->mIsMutating == methodDef->mIsMutating) &&
(CompareMethodSignatures(checkMethodInstance, mCurMethodInstance))) (CompareMethodSignatures(checkMethodInstance, mCurMethodInstance)))
{ {
bool canChain = false; bool canChain = false;

View file

@ -56,6 +56,11 @@ bool BfTypedValue::IsValuelessType() const
return mType->IsValuelessType(); return mType->IsValuelessType();
} }
bool BfTypedValue::CanModify() const
{
return (((IsAddr()) || (mType->IsValuelessType())) && (!IsReadOnly()));
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
bool BfDependencyMap::AddUsedBy(BfType* dependentType, BfDependencyMap::DependencyFlags flags) bool BfDependencyMap::AddUsedBy(BfType* dependentType, BfDependencyMap::DependencyFlags flags)

View file

@ -31,6 +31,24 @@ namespace Tests
} }
struct StructA
{
int mA;
public int this[int index]
{
get
{
return 1;
}
get mut
{
return 2;
}
}
}
[Test] [Test]
public static void Hey() public static void Hey()
{ {
@ -43,6 +61,11 @@ namespace Tests
Test.Assert(value == 234); Test.Assert(value == 234);
value = ca[0]; value = ca[0];
Test.Assert(value == 234); Test.Assert(value == 234);
StructA sa = default;
let sa2 = sa;
Test.Assert(sa[0] == 2);
Test.Assert(sa2[0] == 1);
} }
} }
} }

View file

@ -36,8 +36,35 @@ namespace Tests
{ {
public StructA B { get; } public StructA B { get; }
public int C => 123;
[SkipCall]
public int D => 123;
public int E
{
get
{
return 1;
}
get mut
{
return 2;
}
}
int mZ = 9; int mZ = 9;
public int GetVal()
{
return 3;
}
public int GetVal() mut
{
return 4;
}
public this() public this()
{ {
B = .(); B = .();
@ -73,6 +100,15 @@ namespace Tests
sa = sb.B; sa = sb.B;
Test.Assert(sa.mA == 222); Test.Assert(sa.mA == 222);
StructC sc = default;
Test.Assert(sc.C == 123);
Test.Assert(sc.D == 0);
let sc2 = sc;
Test.Assert(sc.E == 2);
Test.Assert(sc.GetVal() == 4);
Test.Assert(sc2.E == 1);
Test.Assert(sc2.GetVal() == 3);
ClassB cb = scope .(); ClassB cb = scope .();
sa = cb.B; sa = cb.B;
Test.Assert(sa.mA == 0); Test.Assert(sa.mA == 0);