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:
parent
36e0a3a375
commit
06f4eb9576
8 changed files with 113 additions and 61 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()))
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue