Ver código fonte

Fixed erroneous 'this' ctor assignment detection in struct extensions

Brian Fiete 3 anos atrás
pai
commit
fd4ec25e7b

+ 58 - 38
IDEHelper/Compiler/BfModule.cpp

@@ -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)
-							{								
-								int checkMask = 1 << fieldInstance.mMergedDataIdx;
-								if ((localVar->mUnassignedFieldFlags & checkMask) != 0)
+							if (fieldInstance.mMergedDataIdx == -1)
+								continue;
+
+							int checkMask = 1 << fieldInstance.mMergedDataIdx;
+							if ((localVar->mUnassignedFieldFlags & checkMask) != 0)
+							{
+								auto fieldDef = fieldInstance.GetFieldDef();
+
+								if (mCurMethodInstance->mMethodDef->mDeclaringType->mIsPartial)
 								{
 								{
-									auto fieldDef = fieldInstance.GetFieldDef();
-									if (auto propertyDeclaration = BfNodeDynCast<BfPropertyDeclaration>(fieldDef->mFieldDeclaration))
+									if (mCurMethodInstance->mMethodDef->mDeclaringType != fieldInstance.GetFieldDef()->mDeclaringType)
 									{
 									{
-										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
-										{
-											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
-										}
+										// 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("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;
 						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;

+ 1 - 1
IDEHelper/Compiler/BfModule.h

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

+ 2 - 2
IDEHelper/Compiler/BfModuleTypeUtils.cpp

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

+ 27 - 0
IDEHelper/Tests/src/Extensions.bf

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