1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 04:22:20 +02:00

Improvements to auto-impl properties

This commit is contained in:
Brian Fiete 2022-03-01 09:49:02 -08:00
parent 36e0a3a375
commit 06f4eb9576
8 changed files with 113 additions and 61 deletions

View file

@ -1,3 +1,5 @@
#pragma warning disable 168
using System; using System;
namespace IDETest namespace IDETest
{ {
@ -49,7 +51,7 @@ namespace IDETest
{ {
parent = test; parent = test;
mInnerInt = parent.mA; mInnerInt = parent.mA;
mSA.mA = 123; mSA.mA = 123;
int a = mSA.mA; int a = mSA.mA;
int b = mSA.mB; //FAIL int b = mSA.mB; //FAIL

View file

@ -19,6 +19,9 @@ namespace IDETest
struct StructB struct StructB
{ {
public StructA B { get; } public StructA B { get; }
public StructA B2 { get; set mut; }
public ref StructA B3 { get; } //FAIL
public ref StructA B4 { get mut; }
int mZ = 9; int mZ = 9;
@ -29,6 +32,7 @@ namespace IDETest
public void Yoop() mut public void Yoop() mut
{ {
B = .(); //FAIL B = .(); //FAIL
B2.mA = .(); //WARN
} }
} }
} }

View file

@ -2428,51 +2428,62 @@ namespace IDE
ewc.GetLineText(lineIdx, lineText); ewc.GetLineText(lineIdx, lineText);
ewc.GetLinePosition(lineIdx, var lineStart, var lineEnd); ewc.GetLinePosition(lineIdx, var lineStart, var lineEnd);
bool hasError = false;
for (int i = lineStart; i < lineEnd; i++) void FindError(bool warning)
{ {
var flags = (SourceElementFlags)ewc.mData.mText[i].mDisplayFlags; bool hasError = false;
if (flags.HasFlag(.Error)) for (int i = lineStart; i < lineEnd; i++)
hasError = true;
}
int failIdx = lineText.IndexOf("//FAIL");
bool expectedError = failIdx != -1;
if (hasError == expectedError)
{
if (expectedError)
{ {
String wantsError = scope String(lineText, failIdx + "//FAIL".Length); var flags = (SourceElementFlags)ewc.mData.mText[i].mDisplayFlags;
wantsError.Trim(); if (flags.HasFlag(warning ? .Warning : .Error))
if (!wantsError.IsEmpty) hasError = true;
}
String kind = warning ? "warning" : "error";
int failIdx = lineText.IndexOf(warning ? "//WARN" : "//FAIL");
bool expectedError = failIdx != -1;
if (hasError == expectedError)
{
if (expectedError)
{ {
bool foundErrorText = false; String wantsError = scope String(lineText, failIdx + "//FAIL".Length);
if (var error = FindError(lineIdx)) wantsError.Trim();
if (!wantsError.IsEmpty)
{ {
if (error.mError.Contains(wantsError)) bool foundErrorText = false;
foundErrorText = true; if (var error = FindError(lineIdx))
if (error.mMoreInfo != null)
{ {
for (var moreInfo in error.mMoreInfo) if (error.mIsWarning == warning)
if (moreInfo.mError.Contains(wantsError)) {
if (error.mError.Contains(wantsError))
foundErrorText = true; foundErrorText = true;
if (error.mMoreInfo != null)
{
for (var moreInfo in error.mMoreInfo)
if (moreInfo.mError.Contains(wantsError))
foundErrorText = true;
}
}
}
if (!foundErrorText)
{
mScriptManager.Fail($"Line {lineIdx + 1} {kind} in {textPanel.mFilePath} did not contain {kind} text '{wantsError}'\n\t");
} }
}
if (!foundErrorText)
{
mScriptManager.Fail("Error at line {0} in {1} did not contain error text '{2}'\n\t", lineIdx + 1, textPanel.mFilePath, wantsError);
} }
} }
} }
}
else
{
if (hasError)
mScriptManager.Fail("Unexpected error at line {0} in {1}\n\t", lineIdx + 1, textPanel.mFilePath);
else else
mScriptManager.Fail("Expected error but didn't encounter one at line {0} in {1}\n\t", lineIdx + 1, textPanel.mFilePath); {
return; if (hasError)
mScriptManager.Fail($"Unexpected {kind} at line {lineIdx + 1} in {textPanel.mFilePath}\n\t");
else
mScriptManager.Fail($"Expected {kind} but didn't encounter one at line {lineIdx + 1} in {textPanel.mFilePath}\n\t");
return;
}
} }
FindError(false);
FindError(true);
} }
} }

View file

@ -569,6 +569,7 @@ enum BfTypedValueKind
{ {
BfTypedValueKind_Addr, BfTypedValueKind_Addr,
BfTypedValueKind_CopyOnMutateAddr, BfTypedValueKind_CopyOnMutateAddr,
BfTypedValueKind_CopyOnMutateAddr_Derived,
BfTypedValueKind_ReadOnlyAddr, BfTypedValueKind_ReadOnlyAddr,
BfTypedValueKind_TempAddr, BfTypedValueKind_TempAddr,
BfTypedValueKind_RestrictedTempAddr, BfTypedValueKind_RestrictedTempAddr,
@ -688,7 +689,7 @@ public:
bool IsCopyOnMutate() const bool IsCopyOnMutate() const
{ {
return (mKind == BfTypedValueKind_CopyOnMutateAddr); return (mKind == BfTypedValueKind_CopyOnMutateAddr) || (mKind == BfTypedValueKind_CopyOnMutateAddr_Derived);
} }
bool IsReadOnly() const bool IsReadOnly() const

View file

@ -4591,22 +4591,29 @@ BfTypedValue BfExprEvaluator::LoadProperty(BfAstNode* targetSrc, BfTypedValue ta
{ {
bool needsCopy = true; bool needsCopy = true;
if (setter == NULL) if (BfNodeIsA<BfRefTypeRef>(prop->mTypeRef))
{ {
if (((mModule->mCurMethodInstance->mMethodDef->mMethodType == BfMethodType_Ctor)) && // Allow full ref
(target.mType == mModule->mCurTypeInstance))
{
// Allow writing inside ctor
}
else
{
result.MakeReadOnly();
needsCopy = false;
}
} }
else
{
if (setter == NULL)
{
if (((mModule->mCurMethodInstance->mMethodDef->mMethodType == BfMethodType_Ctor)) &&
(target.mType == mModule->mCurTypeInstance))
{
// Allow writing inside ctor
}
else
{
result.MakeReadOnly();
needsCopy = false;
}
}
if (result.mKind == BfTypedValueKind_Addr) if (result.mKind == BfTypedValueKind_Addr)
result.mKind = BfTypedValueKind_CopyOnMutateAddr; result.mKind = BfTypedValueKind_CopyOnMutateAddr;
}
mPropDef = NULL; mPropDef = NULL;
mPropSrc = NULL; mPropSrc = NULL;
@ -4890,10 +4897,7 @@ BfTypedValue BfExprEvaluator::LoadField(BfAstNode* targetSrc, BfTypedValue targe
mModule->mBfIRBuilder->CreateStore(target.mValue, elementAddr); mModule->mBfIRBuilder->CreateStore(target.mValue, elementAddr);
target = BfTypedValue(allocaInst, primStructType, true); target = BfTypedValue(allocaInst, primStructType, true);
} }
if (target.IsCopyOnMutate())
target = mModule->CopyValue(target);
BfTypedValue targetValue; BfTypedValue targetValue;
if ((target.mType != typeInstance) && (!target.IsSplat())) if ((target.mType != typeInstance) && (!target.IsSplat()))
{ {
@ -4972,6 +4976,9 @@ BfTypedValue BfExprEvaluator::LoadField(BfAstNode* targetSrc, BfTypedValue targe
{ {
if ((wantsReadOnly) && (retVal.IsAddr()) && (!retVal.IsReadOnly())) if ((wantsReadOnly) && (retVal.IsAddr()) && (!retVal.IsReadOnly()))
retVal.mKind = BfTypedValueKind_ReadOnlyAddr; retVal.mKind = BfTypedValueKind_ReadOnlyAddr;
else if ((target.IsCopyOnMutate()) && (retVal.IsAddr()))
retVal.mKind = BfTypedValueKind_CopyOnMutateAddr_Derived;
mIsHeapReference = true; mIsHeapReference = true;
} }
@ -6803,6 +6810,9 @@ void BfExprEvaluator::PushThis(BfAstNode* targetSrc, BfTypedValue argVal, BfMeth
if (((argVal.mType->IsComposite()) || (argVal.mType->IsTypedPrimitive()))) if (((argVal.mType->IsComposite()) || (argVal.mType->IsTypedPrimitive())))
{ {
if (argVal.IsCopyOnMutate())
argVal = mModule->CopyValue(argVal);
if ((argVal.IsReadOnly()) || (!argVal.IsAddr())) if ((argVal.IsReadOnly()) || (!argVal.IsAddr()))
{ {
if (!skipMutCheck) if (!skipMutCheck)
@ -18297,11 +18307,8 @@ bool BfExprEvaluator::CheckIsBase(BfAstNode* checkNode)
return true; return true;
} }
bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNode, const char* modifyType, bool onlyNeedsMut, bool emitWarning, bool skipCopyOnMutate) bool BfExprEvaluator::CheckModifyResult(BfTypedValue& typedVal, BfAstNode* refNode, const char* modifyType, bool onlyNeedsMut, bool emitWarning, bool skipCopyOnMutate)
{ {
if ((!skipCopyOnMutate) && (typedVal.IsCopyOnMutate()))
typedVal = mModule->CopyValue(typedVal);
BfLocalVariable* localVar = NULL; BfLocalVariable* localVar = NULL;
bool isCapturedLocal = false; bool isCapturedLocal = false;
if (mResultLocalVar != NULL) if (mResultLocalVar != NULL)
@ -18336,6 +18343,9 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
} }
bool canModify = typedVal.CanModify(); bool canModify = typedVal.CanModify();
if (((typedVal.mKind == BfTypedValueKind_TempAddr) || (typedVal.mKind == BfTypedValueKind_CopyOnMutateAddr_Derived)) &&
(strcmp(modifyType, "assign to") == 0))
mModule->Warn(0, "Assigning to temporary copy of a value. Consider using 'ref' in value source declaration.", refNode);
auto _Fail = [&](const StringImpl& error, BfAstNode* refNode) auto _Fail = [&](const StringImpl& error, BfAstNode* refNode)
{ {
@ -18497,6 +18507,9 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
return false; return false;
} }
if ((!skipCopyOnMutate) && (typedVal.IsCopyOnMutate()))
typedVal = mModule->CopyValue(typedVal);
return mModule->CheckModifyValue(typedVal, refNode, modifyType); return mModule->CheckModifyValue(typedVal, refNode, modifyType);
} }
@ -19250,6 +19263,11 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
return; return;
} }
if (ptr.mKind == BfTypedValueKind_CopyOnMutateAddr)
ptr.mKind = BfTypedValueKind_Addr;
else if (ptr.IsCopyOnMutate())
ptr = mModule->CopyValue(ptr);
BF_ASSERT(convVal); BF_ASSERT(convVal);
if ((convVal) && (convVal.mType->IsNull()) && (ptr.mType->IsNullable())) if ((convVal) && (convVal.mType->IsNull()) && (ptr.mType->IsNullable()))
{ {

View file

@ -449,7 +449,7 @@ public:
void MarkResultAssigned(); void MarkResultAssigned();
void MakeResultAsValue(); void MakeResultAsValue();
bool CheckIsBase(BfAstNode* checkNode); bool CheckIsBase(BfAstNode* checkNode);
bool CheckModifyResult(BfTypedValue typeValue, BfAstNode* refNode, const char* modifyType, bool onlyNeedsMut = false, bool emitWarning = false, bool skipCopyOnMutate = false); bool CheckModifyResult(BfTypedValue& typeValue, BfAstNode* refNode, const char* modifyType, bool onlyNeedsMut = false, bool emitWarning = false, bool skipCopyOnMutate = false);
bool CheckGenericCtor(BfGenericParamType* genericParamType, BfResolvedArgs& argValues, BfAstNode* targetSrc); bool CheckGenericCtor(BfGenericParamType* genericParamType, BfResolvedArgs& argValues, BfAstNode* targetSrc);
BfTypedValue LoadProperty(BfAstNode* targetSrc, BfTypedValue target, BfTypeInstance* typeInstance, BfPropertyDef* prop, BfLookupFieldFlags flags, BfCheckedKind checkedKind, bool isInline); BfTypedValue LoadProperty(BfAstNode* targetSrc, BfTypedValue target, BfTypeInstance* typeInstance, BfPropertyDef* prop, BfLookupFieldFlags flags, BfCheckedKind checkedKind, bool isInline);
BfTypedValue LoadField(BfAstNode* targetSrc, BfTypedValue target, BfTypeInstance* typeInstance, BfFieldDef* fieldDef, BfLookupFieldFlags flags); BfTypedValue LoadField(BfAstNode* targetSrc, BfTypedValue target, BfTypeInstance* typeInstance, BfFieldDef* fieldDef, BfLookupFieldFlags flags);

View file

@ -20710,6 +20710,9 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup,
} }
else if (methodDef->mMethodType == BfMethodType_PropertyGetter) else if (methodDef->mMethodType == BfMethodType_PropertyGetter)
{ {
if ((methodInstance->mReturnType->IsRef()) && (!methodDef->mIsMutating))
Fail("Auto-implemented ref property getters must declare 'mut'", methodInstance->mMethodDef->GetRefNode());
if (methodInstance->mReturnType->IsValuelessType()) if (methodInstance->mReturnType->IsValuelessType())
{ {
mBfIRBuilder->CreateRetVoid(); mBfIRBuilder->CreateRetVoid();
@ -20736,8 +20739,14 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup,
lookupValue = BfTypedValue(mBfIRBuilder->CreateInBoundsGEP(GetThis().mValue, 0, fieldInstance->mDataIdx), fieldInstance->mResolvedType, true); lookupValue = BfTypedValue(mBfIRBuilder->CreateInBoundsGEP(GetThis().mValue, 0, fieldInstance->mDataIdx), fieldInstance->mResolvedType, true);
else else
lookupValue = ExtractValue(GetThis(), fieldInstance, fieldInstance->mDataIdx); lookupValue = ExtractValue(GetThis(), fieldInstance, fieldInstance->mDataIdx);
if (!methodInstance->mReturnType->IsRef()) if (methodInstance->mReturnType->IsRef())
{
if ((!lookupValue.IsAddr()) && (!lookupValue.mType->IsValuelessType()))
lookupValue = MakeAddressable(lookupValue);
}
else
lookupValue = LoadOrAggregateValue(lookupValue); lookupValue = LoadOrAggregateValue(lookupValue);
CreateReturn(lookupValue.mValue); CreateReturn(lookupValue.mValue);
EmitLifetimeEnds(&mCurMethodState->mHeadScope); EmitLifetimeEnds(&mCurMethodState->mHeadScope);
} }

View file

@ -23,13 +23,20 @@ namespace Tests
struct StructB struct StructB
{ {
public StructA B { get; set mut; } public StructA B { get; set mut; }
public ref StructA B2 { get mut; set mut; }
int mZ = 9; int mZ = 9;
public this() public this()
{ {
B = .(); B = .();
#unwarn
B.mA += 1000; B.mA += 1000;
StructA sa = .();
sa.mA += 2000;
B2 = sa;
B2.mA += 3000;
} }
} }
@ -72,8 +79,6 @@ namespace Tests
} }
} }
class ClassB class ClassB
{ {
public StructA B { get; set; } public StructA B { get; set; }
@ -118,10 +123,12 @@ namespace Tests
{ {
StructB sb = .(); StructB sb = .();
StructA sa = sb.B; StructA sa = sb.B;
StructA sa2 = sb.B2;
Test.Assert(sa.mA == 111); Test.Assert(sa.mA == 111);
sb.B = .(222); sb.B = .(222);
sa = sb.B; sa = sb.B;
Test.Assert(sa.mA == 222); Test.Assert(sa.mA == 222);
Test.Assert(sa2.mA == 5111);
StructC sc = default; StructC sc = default;
Test.Assert(sc.C == 123); Test.Assert(sc.C == 123);