mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-14 14:24:10 +02:00
Fixed erroneous 'this' ctor assignment detection in struct extensions
This commit is contained in:
parent
b341b6d3b4
commit
fd4ec25e7b
4 changed files with 89 additions and 42 deletions
|
@ -2262,47 +2262,65 @@ void BfModule::LocalVariableDone(BfLocalVariable* localVar, bool isMethodExit)
|
||||||
{
|
{
|
||||||
for (auto& fieldInstance : checkTypeInstance->mFieldInstances)
|
for (auto& fieldInstance : checkTypeInstance->mFieldInstances)
|
||||||
{
|
{
|
||||||
if (fieldInstance.mMergedDataIdx != -1)
|
if (fieldInstance.mMergedDataIdx == -1)
|
||||||
{
|
continue;
|
||||||
int checkMask = 1 << fieldInstance.mMergedDataIdx;
|
|
||||||
if ((localVar->mUnassignedFieldFlags & checkMask) != 0)
|
|
||||||
{
|
|
||||||
auto fieldDef = fieldInstance.GetFieldDef();
|
|
||||||
if (auto propertyDeclaration = BfNodeDynCast<BfPropertyDeclaration>(fieldDef->mFieldDeclaration))
|
|
||||||
{
|
|
||||||
String propName;
|
|
||||||
if (propertyDeclaration->mNameNode != NULL)
|
|
||||||
propertyDeclaration->mNameNode->ToString(propName);
|
|
||||||
|
|
||||||
if (checkTypeInstance == mCurTypeInstance)
|
int checkMask = 1 << fieldInstance.mMergedDataIdx;
|
||||||
{
|
if ((localVar->mUnassignedFieldFlags & checkMask) != 0)
|
||||||
Fail(StrFormat("Auto-implemented property '%s' must be fully assigned before control is returned to the caller",
|
{
|
||||||
propName.c_str()), localNameNode, deferFullAnalysis); // 0171
|
auto fieldDef = fieldInstance.GetFieldDef();
|
||||||
}
|
|
||||||
else
|
if (mCurMethodInstance->mMethodDef->mDeclaringType->mIsPartial)
|
||||||
{
|
{
|
||||||
Fail(StrFormat("Auto-implemented property '%s.%s' must be fully assigned before control is returned to the caller",
|
if (mCurMethodInstance->mMethodDef->mDeclaringType != fieldInstance.GetFieldDef()->mDeclaringType)
|
||||||
TypeToString(checkTypeInstance).c_str(),
|
{
|
||||||
propName.c_str()), localNameNode, deferFullAnalysis); // 0171
|
// This extension is only responsible for its own fields
|
||||||
}
|
foundFields = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fieldDef->mFieldDeclaration != NULL) && (fieldDef->mFieldDeclaration->mInitializer != NULL))
|
||||||
|
{
|
||||||
|
// This initializer was handled in CtorNoBody
|
||||||
|
foundFields = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto propertyDeclaration = BfNodeDynCast<BfPropertyDeclaration>(fieldDef->mFieldDeclaration))
|
||||||
|
{
|
||||||
|
String propName;
|
||||||
|
if (propertyDeclaration->mNameNode != NULL)
|
||||||
|
propertyDeclaration->mNameNode->ToString(propName);
|
||||||
|
|
||||||
|
if (checkTypeInstance == mCurTypeInstance)
|
||||||
|
{
|
||||||
|
Fail(StrFormat("Auto-implemented property '%s' must be fully assigned before control is returned to the caller",
|
||||||
|
propName.c_str()), localNameNode, deferFullAnalysis); // 0171
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (checkTypeInstance == mCurTypeInstance)
|
Fail(StrFormat("Auto-implemented property '%s.%s' must be fully assigned before control is returned to the caller",
|
||||||
{
|
TypeToString(checkTypeInstance).c_str(),
|
||||||
Fail(StrFormat("Field '%s' must be fully assigned before control is returned to the caller",
|
propName.c_str()), localNameNode, deferFullAnalysis); // 0171
|
||||||
fieldDef->mName.c_str()), localNameNode, deferFullAnalysis); // 0171
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Fail(StrFormat("Field '%s.%s' must be fully assigned before control is returned to the caller",
|
|
||||||
TypeToString(checkTypeInstance).c_str(),
|
|
||||||
fieldDef->mName.c_str()), localNameNode, deferFullAnalysis); // 0171
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (checkTypeInstance == mCurTypeInstance)
|
||||||
|
{
|
||||||
|
Fail(StrFormat("Field '%s' must be fully assigned before control is returned to the caller",
|
||||||
|
fieldDef->mName.c_str()), localNameNode, deferFullAnalysis); // 0171
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Fail(StrFormat("Field '%s.%s' must be fully assigned before control is returned to the caller",
|
||||||
|
TypeToString(checkTypeInstance).c_str(),
|
||||||
|
fieldDef->mName.c_str()), localNameNode, deferFullAnalysis); // 0171
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foundFields = true;
|
foundFields = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkTypeInstance = checkTypeInstance->mBaseType;
|
checkTypeInstance = checkTypeInstance->mBaseType;
|
||||||
|
@ -10087,8 +10105,10 @@ void BfModule::EmitDynamicCastCheck(BfTypedValue typedVal, BfType* type, bool al
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BfTypedValue BfModule::BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfType* toType, const BfAllocTarget& allocTarget, bool callDtor)
|
BfTypedValue BfModule::BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfType* toType, const BfAllocTarget& allocTarget, BfCastFlags castFlags)
|
||||||
{
|
{
|
||||||
|
bool callDtor = (castFlags & BfCastFlags_NoBoxDtor) == 0;
|
||||||
|
|
||||||
if (mBfIRBuilder->mIgnoreWrites)
|
if (mBfIRBuilder->mIgnoreWrites)
|
||||||
{
|
{
|
||||||
if (toType == mContext->mBfObjectType)
|
if (toType == mContext->mBfObjectType)
|
||||||
|
@ -10160,7 +10180,7 @@ BfTypedValue BfModule::BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
||||||
loadedVal = mBfIRBuilder->CreateLoad(nullableValueAddr);
|
loadedVal = mBfIRBuilder->CreateLoad(nullableValueAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto boxedVal = BoxValue(srcNode, BfTypedValue(loadedVal, fromStructTypeInstance->GetUnderlyingType()), resultType, allocTarget, callDtor);
|
auto boxedVal = BoxValue(srcNode, BfTypedValue(loadedVal, fromStructTypeInstance->GetUnderlyingType()), resultType, allocTarget, callDtor ? BfCastFlags_None : BfCastFlags_NoBoxDtor);
|
||||||
RestoreScopeState();
|
RestoreScopeState();
|
||||||
if (!boxedVal)
|
if (!boxedVal)
|
||||||
return BfTypedValue();
|
return BfTypedValue();
|
||||||
|
@ -17067,7 +17087,7 @@ void BfModule::EmitCtorBody(bool& skipBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zero out memory for default ctor
|
// Zero out memory for default ctor
|
||||||
if ((methodDeclaration == NULL) && (mCurTypeInstance->IsStruct()))
|
if ((methodDeclaration == NULL) && (mCurTypeInstance->IsStruct()) && (methodInstance->mChainType != BfMethodChainType_ChainMember))
|
||||||
{
|
{
|
||||||
if (mCurTypeInstance->IsTypedPrimitive())
|
if (mCurTypeInstance->IsTypedPrimitive())
|
||||||
{
|
{
|
||||||
|
@ -17075,7 +17095,7 @@ void BfModule::EmitCtorBody(bool& skipBody)
|
||||||
mBfIRBuilder->CreateStore(GetDefaultValue(mCurTypeInstance), thisRef);
|
mBfIRBuilder->CreateStore(GetDefaultValue(mCurTypeInstance), thisRef);
|
||||||
}
|
}
|
||||||
else if (mCurTypeInstance->mInstSize > 0)
|
else if (mCurTypeInstance->mInstSize > 0)
|
||||||
{
|
{
|
||||||
BfIRValue fillValue = GetConstValue8(0);
|
BfIRValue fillValue = GetConstValue8(0);
|
||||||
BfIRValue sizeValue = GetConstValue(mCurTypeInstance->mInstSize);
|
BfIRValue sizeValue = GetConstValue(mCurTypeInstance->mInstSize);
|
||||||
auto thisRef = mCurMethodState->mLocals[0]->mValue;
|
auto thisRef = mCurMethodState->mLocals[0]->mValue;
|
||||||
|
|
|
@ -1626,7 +1626,7 @@ public:
|
||||||
void EmitDeferredCallProcessor(SLIList<BfDeferredCallEntry*>& callEntries, BfIRValue callTail);
|
void EmitDeferredCallProcessor(SLIList<BfDeferredCallEntry*>& callEntries, BfIRValue callTail);
|
||||||
bool CanCast(BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags = BfCastFlags_None);
|
bool CanCast(BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags = BfCastFlags_None);
|
||||||
bool AreSplatsCompatible(BfType* fromType, BfType* toType, bool* outNeedsMemberCasting);
|
bool AreSplatsCompatible(BfType* fromType, BfType* toType, bool* outNeedsMemberCasting);
|
||||||
BfTypedValue BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfType* toType /*Can be System.Object or interface*/, const BfAllocTarget& allocTarget, bool callDtor = true);
|
BfTypedValue BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfType* toType /*Can be System.Object or interface*/, const BfAllocTarget& allocTarget, BfCastFlags castFlags = BfCastFlags_None);
|
||||||
BfIRValue CastToFunction(BfAstNode* srcNode, const BfTypedValue& targetValue, BfMethodInstance* methodInstance, BfType* toType, BfCastFlags castFlags = BfCastFlags_None, BfIRValue irFunc = BfIRValue());
|
BfIRValue CastToFunction(BfAstNode* srcNode, const BfTypedValue& targetValue, BfMethodInstance* methodInstance, BfType* toType, BfCastFlags castFlags = BfCastFlags_None, BfIRValue irFunc = BfIRValue());
|
||||||
BfIRValue CastToValue(BfAstNode* srcNode, BfTypedValue val, BfType* toType, BfCastFlags castFlags = BfCastFlags_None, BfCastResultFlags* resultFlags = NULL);
|
BfIRValue CastToValue(BfAstNode* srcNode, BfTypedValue val, BfType* toType, BfCastFlags castFlags = BfCastFlags_None, BfCastResultFlags* resultFlags = NULL);
|
||||||
BfTypedValue Cast(BfAstNode* srcNode, const BfTypedValue& val, BfType* toType, BfCastFlags castFlags = BfCastFlags_None);
|
BfTypedValue Cast(BfAstNode* srcNode, const BfTypedValue& val, BfType* toType, BfCastFlags castFlags = BfCastFlags_None);
|
||||||
|
|
|
@ -11906,7 +11906,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
||||||
|
|
||||||
// Null -> ObjectInst|IFace|ptr
|
// Null -> ObjectInst|IFace|ptr
|
||||||
if ((typedVal.mType->IsNull()) &&
|
if ((typedVal.mType->IsNull()) &&
|
||||||
((toType->IsObjectOrInterface()) || (toType->IsPointer() || (toType->IsFunction()))))
|
((toType->IsObjectOrInterface()) || (toType->IsPointer() || (toType->IsFunction()) || (toType->IsAllocType()))))
|
||||||
{
|
{
|
||||||
return mBfIRBuilder->CreateBitCast(typedVal.mValue, mBfIRBuilder->MapType(toType));
|
return mBfIRBuilder->CreateBitCast(typedVal.mValue, mBfIRBuilder->MapType(toType));
|
||||||
}
|
}
|
||||||
|
@ -13274,7 +13274,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
||||||
}
|
}
|
||||||
|
|
||||||
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, ignoreWrites);
|
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, ignoreWrites);
|
||||||
auto value = BoxValue(srcNode, typedVal, toType, scopeData, (castFlags & BfCastFlags_NoBoxDtor) == 0);
|
auto value = BoxValue(srcNode, typedVal, toType, scopeData, castFlags);
|
||||||
if (value)
|
if (value)
|
||||||
return value.mValue;
|
return value.mValue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,6 +237,28 @@ namespace Tests
|
||||||
return val.GetIt().GetExVal();
|
return val.GetIt().GetExVal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct StructA
|
||||||
|
{
|
||||||
|
public int mVal;
|
||||||
|
public int mVal2 = 111;
|
||||||
|
|
||||||
|
public this(int val, int val2)
|
||||||
|
{
|
||||||
|
mVal = val;
|
||||||
|
mVal2 = val2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension StructA
|
||||||
|
{
|
||||||
|
public int mVal3 = 222;
|
||||||
|
|
||||||
|
public this(int val)
|
||||||
|
{
|
||||||
|
mVal = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public static void TestBasics()
|
public static void TestBasics()
|
||||||
{
|
{
|
||||||
|
@ -272,6 +294,11 @@ namespace Tests
|
||||||
obj = new ClassG();
|
obj = new ClassG();
|
||||||
delete obj;
|
delete obj;
|
||||||
Test.Assert(ClassF.sVal == 6543);
|
Test.Assert(ClassF.sVal == 6543);
|
||||||
|
|
||||||
|
StructA ms = .(1);
|
||||||
|
Test.Assert((ms.mVal == 1) && (ms.mVal2 == 111) && (ms.mVal3 == 222));
|
||||||
|
ms = .(1, 2);
|
||||||
|
Test.Assert((ms.mVal == 1) && (ms.mVal2 == 2) && (ms.mVal3 == 222));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue