1
0
Fork 0
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:
Brian Fiete 2022-02-13 07:41:31 -05:00
parent b341b6d3b4
commit fd4ec25e7b
4 changed files with 89 additions and 42 deletions

View file

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

View file

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

View file

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

View file

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