mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-14 14:24:10 +02:00
Fixed readonly issues, particularly with statics
This commit is contained in:
parent
90e4cf8825
commit
f041caaeb8
3 changed files with 62 additions and 38 deletions
|
@ -2107,6 +2107,7 @@ BfExprEvaluator::BfExprEvaluator(BfModule* module)
|
||||||
mResolveGenericParam = true;
|
mResolveGenericParam = true;
|
||||||
mNoBind = false;
|
mNoBind = false;
|
||||||
mResultLocalVar = NULL;
|
mResultLocalVar = NULL;
|
||||||
|
mResultFieldInstance = NULL;
|
||||||
mResultLocalVarField = 0;
|
mResultLocalVarField = 0;
|
||||||
mResultLocalVarFieldCount = 0;
|
mResultLocalVarFieldCount = 0;
|
||||||
mResultLocalVarRefNode = NULL;
|
mResultLocalVarRefNode = NULL;
|
||||||
|
@ -2932,6 +2933,7 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI
|
||||||
if (!isMixinOuterVariablePass)
|
if (!isMixinOuterVariablePass)
|
||||||
{
|
{
|
||||||
mResultLocalVar = varDecl;
|
mResultLocalVar = varDecl;
|
||||||
|
mResultFieldInstance = NULL;
|
||||||
mResultLocalVarRefNode = identifierNode;
|
mResultLocalVarRefNode = identifierNode;
|
||||||
}
|
}
|
||||||
return localResult;
|
return localResult;
|
||||||
|
@ -2988,6 +2990,7 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI
|
||||||
result = mModule->LoadValue(result);
|
result = mModule->LoadValue(result);
|
||||||
|
|
||||||
mResultLocalVar = localVar;
|
mResultLocalVar = localVar;
|
||||||
|
mResultFieldInstance = &field;
|
||||||
mResultLocalVarField = -(field.mMergedDataIdx + 1);
|
mResultLocalVarField = -(field.mMergedDataIdx + 1);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -3077,6 +3080,7 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI
|
||||||
if (!mModule->mCurMethodState->HasNonStaticMixin())
|
if (!mModule->mCurMethodState->HasNonStaticMixin())
|
||||||
{
|
{
|
||||||
mResultLocalVar = mModule->GetThisVariable();
|
mResultLocalVar = mModule->GetThisVariable();
|
||||||
|
mResultFieldInstance = NULL;
|
||||||
mResultLocalVarRefNode = identifierNode;
|
mResultLocalVarRefNode = identifierNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3357,6 +3361,8 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
|
||||||
return BfTypedValue();
|
return BfTypedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mResultFieldInstance = fieldInstance;
|
||||||
|
|
||||||
// Are we accessing a 'var' field that has not yet been resolved?
|
// Are we accessing a 'var' field that has not yet been resolved?
|
||||||
if (fieldInstance->mResolvedType->IsVar())
|
if (fieldInstance->mResolvedType->IsVar())
|
||||||
{
|
{
|
||||||
|
@ -3393,7 +3399,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
|
||||||
|
|
||||||
// Target must be an implicit 'this', or an error (accessing a static with a non-static target).
|
// Target must be an implicit 'this', or an error (accessing a static with a non-static target).
|
||||||
// Not actually needed in either case since this is a static lookup.
|
// Not actually needed in either case since this is a static lookup.
|
||||||
mResultLocalVar = NULL;
|
mResultLocalVar = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isConst = false;
|
bool isConst = false;
|
||||||
|
@ -3463,7 +3469,9 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
|
||||||
{
|
{
|
||||||
mModule->CheckStaticAccess(curCheckType);
|
mModule->CheckStaticAccess(curCheckType);
|
||||||
auto retVal = mModule->ReferenceStaticField(fieldInstance);
|
auto retVal = mModule->ReferenceStaticField(fieldInstance);
|
||||||
if (field->mIsReadOnly)
|
bool isStaticCtor = (mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mMethodDef->mMethodType == BfMethodType_Ctor) &&
|
||||||
|
(mModule->mCurMethodInstance->mMethodDef->mIsStatic);
|
||||||
|
if ((field->mIsReadOnly) && (!isStaticCtor))
|
||||||
retVal = mModule->LoadValue(retVal, NULL, mIsVolatileReference);
|
retVal = mModule->LoadValue(retVal, NULL, mIsVolatileReference);
|
||||||
else
|
else
|
||||||
mIsHeapReference = true;
|
mIsHeapReference = true;
|
||||||
|
@ -6683,7 +6691,8 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
||||||
}
|
}
|
||||||
|
|
||||||
mResultLocalVar = NULL;
|
mResultLocalVar = NULL;
|
||||||
mResultLocalVarRefNode = NULL;
|
mResultFieldInstance = NULL;
|
||||||
|
mResultLocalVarRefNode = NULL;
|
||||||
MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, false);
|
MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, false);
|
||||||
mModule->ValidateAllocation(resolvedTypeInstance, targetSrc);
|
mModule->ValidateAllocation(resolvedTypeInstance, targetSrc);
|
||||||
|
|
||||||
|
@ -7687,6 +7696,7 @@ void BfExprEvaluator::Visit(BfThisExpression* thisExpr)
|
||||||
{
|
{
|
||||||
|
|
||||||
mResultLocalVar = mModule->GetThisVariable();
|
mResultLocalVar = mModule->GetThisVariable();
|
||||||
|
mResultFieldInstance = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7732,6 +7742,7 @@ void BfExprEvaluator::Visit(BfMixinExpression* mixinExpr)
|
||||||
BfTypedValue localResult = LoadLocal(varDecl);
|
BfTypedValue localResult = LoadLocal(varDecl);
|
||||||
mResult = localResult;
|
mResult = localResult;
|
||||||
mResultLocalVar = varDecl;
|
mResultLocalVar = varDecl;
|
||||||
|
mResultFieldInstance = NULL;
|
||||||
mResultLocalVarRefNode = mixinExpr;
|
mResultLocalVarRefNode = mixinExpr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -8635,6 +8646,7 @@ BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfIdentif
|
||||||
if (!isMixinOuterVariablePass)
|
if (!isMixinOuterVariablePass)
|
||||||
{
|
{
|
||||||
mResultLocalVar = varDecl;
|
mResultLocalVar = varDecl;
|
||||||
|
mResultFieldInstance = NULL;
|
||||||
mResultLocalVarRefNode = identifierNode;
|
mResultLocalVarRefNode = identifierNode;
|
||||||
}
|
}
|
||||||
return localResult;
|
return localResult;
|
||||||
|
@ -8684,6 +8696,7 @@ BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfIdentif
|
||||||
result = mModule->LoadValue(result);
|
result = mModule->LoadValue(result);
|
||||||
|
|
||||||
mResultLocalVar = localVar;
|
mResultLocalVar = localVar;
|
||||||
|
mResultFieldInstance = &field;
|
||||||
mResultLocalVarField = -(field.mMergedDataIdx + 1);
|
mResultLocalVarField = -(field.mMergedDataIdx + 1);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -14016,6 +14029,7 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp
|
||||||
mPropDefBypassVirtual = false;
|
mPropDefBypassVirtual = false;
|
||||||
mIndexerValues.clear();
|
mIndexerValues.clear();
|
||||||
mResultLocalVar = NULL;
|
mResultLocalVar = NULL;
|
||||||
|
mResultFieldInstance = NULL;
|
||||||
}
|
}
|
||||||
if (resolveGenericType)
|
if (resolveGenericType)
|
||||||
ResolveGenericType();
|
ResolveGenericType();
|
||||||
|
@ -14126,6 +14140,7 @@ void BfExprEvaluator::FinishExpressionResult()
|
||||||
{
|
{
|
||||||
CheckResultForReading(mResult);
|
CheckResultForReading(mResult);
|
||||||
mResultLocalVar = NULL;
|
mResultLocalVar = NULL;
|
||||||
|
mResultFieldInstance = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BfExprEvaluator::CheckAllowValue(const BfTypedValue& typedValue, BfAstNode* refNode)
|
bool BfExprEvaluator::CheckAllowValue(const BfTypedValue& typedValue, BfAstNode* refNode)
|
||||||
|
@ -14171,6 +14186,7 @@ void BfExprEvaluator::MakeResultAsValue()
|
||||||
{
|
{
|
||||||
// Expressions like parens will turn a variable reference into a simple value
|
// Expressions like parens will turn a variable reference into a simple value
|
||||||
mResultLocalVar = NULL;
|
mResultLocalVar = NULL;
|
||||||
|
mResultFieldInstance = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNode, const char* modifyType, bool onlyNeedsMut)
|
bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNode, const char* modifyType, bool onlyNeedsMut)
|
||||||
|
@ -14208,10 +14224,12 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool canModify = (((typedVal.IsAddr()) || (typedVal.mType->IsValuelessType())) &&
|
||||||
|
(!typedVal.IsReadOnly()));
|
||||||
|
|
||||||
if (localVar != NULL)
|
if (localVar != NULL)
|
||||||
{
|
{
|
||||||
if (((!typedVal.IsAddr()) && (!typedVal.mType->IsValuelessType())) ||
|
if (!canModify)
|
||||||
(typedVal.IsReadOnly()))
|
|
||||||
{
|
{
|
||||||
BfError* error = NULL;
|
BfError* error = NULL;
|
||||||
if (localVar->mIsThis)
|
if (localVar->mIsThis)
|
||||||
|
@ -14253,40 +14271,35 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else if (mResultFieldInstance != NULL)
|
||||||
{
|
{
|
||||||
while (checkTypeInst != NULL)
|
if (isCapturedLocal)
|
||||||
{
|
{
|
||||||
for (auto& checkFieldInstance : checkTypeInst->mFieldInstances)
|
error = mModule->Fail(StrFormat("Cannot %s read-only captured local variable '%s'. Consider adding by-reference capture specifier [&] to lambda and ensuring that captured value is not read-only.", modifyType,
|
||||||
{
|
mResultFieldInstance->GetFieldDef()->mName.c_str()), refNode);
|
||||||
if (checkFieldInstance.mMergedDataIdx == fieldIdx)
|
|
||||||
{
|
|
||||||
if (isCapturedLocal)
|
|
||||||
{
|
|
||||||
error = mModule->Fail(StrFormat("Cannot %s read-only captured local variable '%s'. Consider adding by-reference capture specifier [&] to lambda and ensuring that captured value is not read-only.", modifyType,
|
|
||||||
checkFieldInstance.GetFieldDef()->mName.c_str()), refNode);
|
|
||||||
}
|
|
||||||
else if (isClosure)
|
|
||||||
{
|
|
||||||
if (!mModule->mCurMethodState->mClosureState->mDeclaringMethodIsMutating)
|
|
||||||
error = mModule->Fail(StrFormat("Cannot %s field '%s.%s' within struct lambda. Consider adding 'mut' specifier to this method.", modifyType,
|
|
||||||
mModule->TypeToString(checkFieldInstance.mOwner).c_str(), checkFieldInstance.GetFieldDef()->mName.c_str()), refNode);
|
|
||||||
else
|
|
||||||
error = mModule->Fail(StrFormat("Cannot %s field '%s.%s' within struct lambda. Consider adding by-reference capture specifier [&] to lambda.", modifyType,
|
|
||||||
mModule->TypeToString(checkFieldInstance.mOwner).c_str(), checkFieldInstance.GetFieldDef()->mName.c_str()), refNode);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
error = mModule->Fail(StrFormat("Cannot %s field '%s.%s' within struct method '%s'. Consider adding 'mut' specifier to this method.", modifyType,
|
|
||||||
mModule->TypeToString(checkFieldInstance.mOwner).c_str(), checkFieldInstance.GetFieldDef()->mName.c_str(),
|
|
||||||
mModule->MethodToString(mModule->mCurMethodInstance).c_str()), refNode);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkTypeInst = checkTypeInst->mBaseType;
|
|
||||||
}
|
}
|
||||||
|
else if (isClosure)
|
||||||
|
{
|
||||||
|
if (!mModule->mCurMethodState->mClosureState->mDeclaringMethodIsMutating)
|
||||||
|
error = mModule->Fail(StrFormat("Cannot %s field '%s.%s' within struct lambda. Consider adding 'mut' specifier to this method.", modifyType,
|
||||||
|
mModule->TypeToString(mResultFieldInstance->mOwner).c_str(), mResultFieldInstance->GetFieldDef()->mName.c_str()), refNode);
|
||||||
|
else
|
||||||
|
error = mModule->Fail(StrFormat("Cannot %s field '%s.%s' within struct lambda. Consider adding by-reference capture specifier [&] to lambda.", modifyType,
|
||||||
|
mModule->TypeToString(mResultFieldInstance->mOwner).c_str(), mResultFieldInstance->GetFieldDef()->mName.c_str()), refNode);
|
||||||
|
}
|
||||||
|
else if (mResultFieldInstance->GetFieldDef()->mIsReadOnly)
|
||||||
|
{
|
||||||
|
error = mModule->Fail(StrFormat("Cannot %s readonly field '%s.%s' within method '%s'", modifyType,
|
||||||
|
mModule->TypeToString(mResultFieldInstance->mOwner).c_str(), mResultFieldInstance->GetFieldDef()->mName.c_str(),
|
||||||
|
mModule->MethodToString(mModule->mCurMethodInstance).c_str()), refNode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error = mModule->Fail(StrFormat("Cannot %s field '%s.%s' within struct method '%s'. Consider adding 'mut' specifier to this method.", modifyType,
|
||||||
|
mModule->TypeToString(mResultFieldInstance->mOwner).c_str(), mResultFieldInstance->GetFieldDef()->mName.c_str(),
|
||||||
|
mModule->MethodToString(mModule->mCurMethodInstance).c_str()), refNode);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (localVar->IsParam())
|
else if (localVar->IsParam())
|
||||||
|
@ -14315,6 +14328,15 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
|
||||||
localVar->mWrittenToId = mModule->mCurMethodState->GetRootMethodState()->mCurAccessId++;
|
localVar->mWrittenToId = mModule->mCurMethodState->GetRootMethodState()->mCurAccessId++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((mResultFieldInstance != NULL) && (mResultFieldInstance->GetFieldDef()->mIsReadOnly) && (!canModify))
|
||||||
|
{
|
||||||
|
auto error = mModule->Fail(StrFormat("Cannot %s static readonly field '%s.%s' within method '%s'", modifyType,
|
||||||
|
mModule->TypeToString(mResultFieldInstance->mOwner).c_str(), mResultFieldInstance->GetFieldDef()->mName.c_str(),
|
||||||
|
mModule->MethodToString(mModule->mCurMethodInstance).c_str()), refNode);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return mModule->CheckModifyValue(typedVal, refNode, modifyType);
|
return mModule->CheckModifyValue(typedVal, refNode, modifyType);
|
||||||
|
|
|
@ -283,6 +283,7 @@ public:
|
||||||
BfTypedValue mResult;
|
BfTypedValue mResult;
|
||||||
BfEvalExprFlags mBfEvalExprFlags;
|
BfEvalExprFlags mBfEvalExprFlags;
|
||||||
BfLocalVariable* mResultLocalVar;
|
BfLocalVariable* mResultLocalVar;
|
||||||
|
BfFieldInstance* mResultFieldInstance;
|
||||||
int mResultLocalVarField;
|
int mResultLocalVarField;
|
||||||
int mResultLocalVarFieldCount; // > 1 for structs with multiple members
|
int mResultLocalVarFieldCount; // > 1 for structs with multiple members
|
||||||
BfAstNode* mResultLocalVarRefNode;
|
BfAstNode* mResultLocalVarRefNode;
|
||||||
|
|
|
@ -1022,9 +1022,10 @@ public:
|
||||||
|
|
||||||
BfMethodState* GetNonCaptureState()
|
BfMethodState* GetNonCaptureState()
|
||||||
{
|
{
|
||||||
|
//TODO: Why did this require mLocalMethod to not be null? That means lambda captures we're not crossed over
|
||||||
auto checkMethodState = this;
|
auto checkMethodState = this;
|
||||||
while ((checkMethodState->mPrevMethodState != NULL) && (checkMethodState->mClosureState != NULL) &&
|
while ((checkMethodState->mPrevMethodState != NULL) && (checkMethodState->mClosureState != NULL) &&
|
||||||
(checkMethodState->mClosureState->mCapturing) && (checkMethodState->mClosureState->mLocalMethod != NULL))
|
(checkMethodState->mClosureState->mCapturing) /*&& (checkMethodState->mClosureState->mLocalMethod != NULL)*/)
|
||||||
checkMethodState = checkMethodState->mPrevMethodState;
|
checkMethodState = checkMethodState->mPrevMethodState;
|
||||||
return checkMethodState;
|
return checkMethodState;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue