mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-09 03:52:19 +02:00
Made method mutability part of signature and method selection
This commit is contained in:
parent
f795215b44
commit
c49d92b779
7 changed files with 129 additions and 14 deletions
|
@ -738,6 +738,8 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CanModify() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BF_AST_TYPE(name, TBase) \
|
#define BF_AST_TYPE(name, TBase) \
|
||||||
|
|
|
@ -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();
|
||||||
|
@ -4200,7 +4208,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
|
||||||
{
|
{
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -15777,7 +15824,7 @@ void BfExprEvaluator::PopulateDeferrredTupleAssignData(BfTupleExpression* tupleE
|
||||||
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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue