1
0
Fork 0
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:
Brian Fiete 2020-02-19 06:35:52 -08:00
parent 90e4cf8825
commit f041caaeb8
3 changed files with 62 additions and 38 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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;
} }