mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-10 12:32:20 +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)
|
||||
{
|
||||
if (fieldInstance.mMergedDataIdx != -1)
|
||||
{
|
||||
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 (fieldInstance.mMergedDataIdx == -1)
|
||||
continue;
|
||||
|
||||
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
|
||||
{
|
||||
Fail(StrFormat("Auto-implemented property '%s.%s' must be fully assigned before control is returned to the caller",
|
||||
TypeToString(checkTypeInstance).c_str(),
|
||||
propName.c_str()), localNameNode, deferFullAnalysis); // 0171
|
||||
}
|
||||
int checkMask = 1 << fieldInstance.mMergedDataIdx;
|
||||
if ((localVar->mUnassignedFieldFlags & checkMask) != 0)
|
||||
{
|
||||
auto fieldDef = fieldInstance.GetFieldDef();
|
||||
|
||||
if (mCurMethodInstance->mMethodDef->mDeclaringType->mIsPartial)
|
||||
{
|
||||
if (mCurMethodInstance->mMethodDef->mDeclaringType != fieldInstance.GetFieldDef()->mDeclaringType)
|
||||
{
|
||||
// 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
|
||||
{
|
||||
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
|
||||
}
|
||||
Fail(StrFormat("Auto-implemented property '%s.%s' must be fully assigned before control is returned to the caller",
|
||||
TypeToString(checkTypeInstance).c_str(),
|
||||
propName.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;
|
||||
|
@ -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 (toType == mContext->mBfObjectType)
|
||||
|
@ -10160,7 +10180,7 @@ BfTypedValue BfModule::BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
|||
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();
|
||||
if (!boxedVal)
|
||||
return BfTypedValue();
|
||||
|
@ -17067,7 +17087,7 @@ void BfModule::EmitCtorBody(bool& skipBody)
|
|||
}
|
||||
|
||||
// Zero out memory for default ctor
|
||||
if ((methodDeclaration == NULL) && (mCurTypeInstance->IsStruct()))
|
||||
if ((methodDeclaration == NULL) && (mCurTypeInstance->IsStruct()) && (methodInstance->mChainType != BfMethodChainType_ChainMember))
|
||||
{
|
||||
if (mCurTypeInstance->IsTypedPrimitive())
|
||||
{
|
||||
|
@ -17075,7 +17095,7 @@ void BfModule::EmitCtorBody(bool& skipBody)
|
|||
mBfIRBuilder->CreateStore(GetDefaultValue(mCurTypeInstance), thisRef);
|
||||
}
|
||||
else if (mCurTypeInstance->mInstSize > 0)
|
||||
{
|
||||
{
|
||||
BfIRValue fillValue = GetConstValue8(0);
|
||||
BfIRValue sizeValue = GetConstValue(mCurTypeInstance->mInstSize);
|
||||
auto thisRef = mCurMethodState->mLocals[0]->mValue;
|
||||
|
|
|
@ -1626,7 +1626,7 @@ public:
|
|||
void EmitDeferredCallProcessor(SLIList<BfDeferredCallEntry*>& callEntries, BfIRValue callTail);
|
||||
bool CanCast(BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags = BfCastFlags_None);
|
||||
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 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);
|
||||
|
|
|
@ -11906,7 +11906,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
|||
|
||||
// Null -> ObjectInst|IFace|ptr
|
||||
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));
|
||||
}
|
||||
|
@ -13274,7 +13274,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
|||
}
|
||||
|
||||
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)
|
||||
return value.mValue;
|
||||
}
|
||||
|
|
|
@ -237,6 +237,28 @@ namespace Tests
|
|||
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]
|
||||
public static void TestBasics()
|
||||
{
|
||||
|
@ -272,6 +294,11 @@ namespace Tests
|
|||
obj = new ClassG();
|
||||
delete obj;
|
||||
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]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue