Ver Fonte

Fixed some comptime dependency rebuilding issues with aliases/extensions

Brian Fiete há 3 anos atrás
pai
commit
434a7406de

+ 67 - 12
BeefySysLib/util/BitSet.h

@@ -4,28 +4,43 @@
 
 
 NS_BF_BEGIN;
 NS_BF_BEGIN;
 
 
-#define BF_BITSET_ELEM_SIZE (sizeof(uintptr)*8)
+#define BF_BITSET_ELEM_BITCOUNT (sizeof(uintptr)*8)
 
 
 class BitSet
 class BitSet
 {
 {
 public:
 public:
 	uintptr* mBits;
 	uintptr* mBits;
-	int mNumInts;
+	int mNumBits;
 
 
 public:
 public:
 	BitSet()
 	BitSet()
 	{
 	{
-		mNumInts = 0;
+		mNumBits = 0;
 		mBits = NULL;
 		mBits = NULL;
 	}
 	}
 
 
 	BitSet(int numBits)
 	BitSet(int numBits)
 	{
 	{
-		mNumInts = 0;
+		mNumBits = 0;
 		mBits = NULL;
 		mBits = NULL;
 		this->Resize(numBits);
 		this->Resize(numBits);
 	}
 	}
 
 
+	BitSet(BitSet&& other)
+	{
+		mNumBits = other.mNumBits;
+		mBits = other.mBits;
+		other.mNumBits = 0;
+		other.mBits = NULL;
+	}
+
+	BitSet(const BitSet& other)
+	{
+		mNumBits = 0;
+		mBits = NULL;
+		*this = other;
+	}
+
 	~BitSet()
 	~BitSet()
 	{
 	{
 		delete this->mBits;
 		delete this->mBits;
@@ -33,28 +48,68 @@ public:
 
 
 	void Resize(int numBits)
 	void Resize(int numBits)
 	{
 	{
-		int numInts = (numBits + BF_BITSET_ELEM_SIZE - 1) / BF_BITSET_ELEM_SIZE;
-		if (numInts == mNumInts)
-			return;
-		this->mNumInts = numInts;
+		int numInts = (numBits + BF_BITSET_ELEM_BITCOUNT - 1) / BF_BITSET_ELEM_BITCOUNT;
+		int curNumInts = (mNumBits + BF_BITSET_ELEM_BITCOUNT - 1) / BF_BITSET_ELEM_BITCOUNT;
+		mNumBits = numBits;
+		if (numInts == curNumInts)		
+			return;		
+		this->mNumBits = numBits;
 		delete this->mBits;
 		delete this->mBits;
 		this->mBits = new uintptr[numInts];
 		this->mBits = new uintptr[numInts];
 		memset(this->mBits, 0, numInts * sizeof(uintptr));
 		memset(this->mBits, 0, numInts * sizeof(uintptr));
 	}
 	}
 
 
-	bool IsSet(int idx)
+	void Clear()
 	{
 	{
-		return (this->mBits[idx / BF_BITSET_ELEM_SIZE] & ((uintptr)1 << (idx % BF_BITSET_ELEM_SIZE))) != 0;
+		int curNumInts = (mNumBits + BF_BITSET_ELEM_BITCOUNT - 1) / BF_BITSET_ELEM_BITCOUNT;
+		memset(mBits, 0, curNumInts * sizeof(uintptr));
+	}
+
+	bool IsSet(int idx) const
+	{
+		BF_ASSERT((uintptr)idx < (uintptr)mNumBits);
+		return (this->mBits[idx / BF_BITSET_ELEM_BITCOUNT] & ((uintptr)1 << (idx % BF_BITSET_ELEM_BITCOUNT))) != 0;
 	}
 	}
 	
 	
 	void Set(int idx)
 	void Set(int idx)
 	{
 	{
-		this->mBits[idx / BF_BITSET_ELEM_SIZE] |= ((uintptr)1 << (idx % BF_BITSET_ELEM_SIZE));
+		BF_ASSERT((uintptr)idx < (uintptr)mNumBits);
+		this->mBits[idx / BF_BITSET_ELEM_BITCOUNT] |= ((uintptr)1 << (idx % BF_BITSET_ELEM_BITCOUNT));
 	}
 	}
 
 
 	void Clear(int idx)
 	void Clear(int idx)
 	{
 	{
-		this->mBits[idx / BF_BITSET_ELEM_SIZE] &= ~((uintptr)1 << (idx % BF_BITSET_ELEM_SIZE));
+		BF_ASSERT((uintptr)idx < (uintptr)mNumBits);
+		this->mBits[idx / BF_BITSET_ELEM_BITCOUNT] &= ~((uintptr)1 << (idx % BF_BITSET_ELEM_BITCOUNT));
+	}
+
+	bool IsEmpty()
+	{
+		return mNumBits == 0;
+	}
+
+	bool operator==(const BitSet& other) const
+	{
+		int curNumInts = (mNumBits + BF_BITSET_ELEM_BITCOUNT - 1) / BF_BITSET_ELEM_BITCOUNT;
+		if (mNumBits != other.mNumBits)
+			return false;
+		for (int i = 0; i < curNumInts; i++)
+			if (mBits[i] != other.mBits[i])
+				return false;
+		return true;
+	}
+
+	bool operator!=(const BitSet& other) const
+	{
+		return !(*this == other);
+	}
+
+	BitSet& operator=(const BitSet& other)
+	{
+		Resize(other.mNumBits);
+		int curNumInts = (mNumBits + BF_BITSET_ELEM_BITCOUNT - 1) / BF_BITSET_ELEM_BITCOUNT;
+		memcpy(mBits, other.mBits, curNumInts * sizeof(uintptr));
+		return *this;
 	}
 	}
 };
 };
 
 

+ 5 - 0
IDE/Tests/BugW008/BeefProj.toml

@@ -0,0 +1,5 @@
+FileVersion = 1
+
+[Project]
+Name = "Bug"
+StartupObject = "Bug.Program"

+ 6 - 0
IDE/Tests/BugW008/BeefSpace.toml

@@ -0,0 +1,6 @@
+FileVersion = 1
+Projects = {Bug = {Path = "."}}
+
+[Workspace]
+StartupProject = "Bug"
+

+ 15 - 0
IDE/Tests/BugW008/scripts/Test.txt

@@ -0,0 +1,15 @@
+# This tests that comptime changes to generic passed extension constraints rebuilds dependencies
+
+ShowFile("src/Program.bf")
+GotoText("//End")
+ToggleBreakpoint()
+RunWithCompiling()
+AssertEvalEquals("val", "1")
+StopRunning()
+
+ShowFile("src/Gen.bf")
+ToggleCommentAt("Void")
+ToggleCommentAt("String")
+RunWithCompiling()
+AssertEvalEquals("val", "2")
+StopRunning()

+ 18 - 0
IDE/Tests/BugW008/src/Gen.bf

@@ -0,0 +1,18 @@
+using System;
+
+namespace Bug
+{
+	class Gen
+	{
+		public static Type Get()
+		{
+			//*Void
+			return typeof(void);
+			/*@*/
+
+			/*String
+			return typeof(String);
+			*/
+		}
+	}
+}

+ 34 - 0
IDE/Tests/BugW008/src/Program.bf

@@ -0,0 +1,34 @@
+#pragma warning disable 168
+
+using System;
+using System.Collections;
+
+namespace Bug
+{
+	class Zonk<T>
+	{
+		public int Call(float val)
+		{
+			return 1;
+		}
+	}
+
+	extension Zonk<T> where comptype(Gen.Get()) : String
+	{
+		public int Call(int val)
+		{
+			return 2;
+		}
+	}
+	
+	class Program
+	{
+		public static int Main(String[] args)
+		{
+			Zonk<int> zk = scope .();
+			int val = zk.Call(1);
+			//End
+			return 0;
+		}
+	}
+}

+ 5 - 0
IDE/Tests/BugW009/BeefProj.toml

@@ -0,0 +1,5 @@
+FileVersion = 1
+
+[Project]
+Name = "Bug"
+StartupObject = "Bug.Program"

+ 6 - 0
IDE/Tests/BugW009/BeefSpace.toml

@@ -0,0 +1,6 @@
+FileVersion = 1
+Projects = {Bug = {Path = "."}}
+
+[Workspace]
+StartupProject = "Bug"
+

+ 15 - 0
IDE/Tests/BugW009/scripts/Test.txt

@@ -0,0 +1,15 @@
+# This tests that comptime alias changes rebuild dependent types
+
+ShowFile("src/Program.bf")
+GotoText("//End")
+ToggleBreakpoint()
+RunWithCompiling()
+AssertEvalEquals("val", "1")
+StopRunning()
+
+ShowFile("src/Gen.bf")
+ToggleCommentAt("ClassA")
+ToggleCommentAt("ClassB")
+RunWithCompiling()
+AssertEvalEquals("val", "2")
+StopRunning()

+ 18 - 0
IDE/Tests/BugW009/src/Gen.bf

@@ -0,0 +1,18 @@
+using System;
+
+namespace Bug
+{
+	class Gen
+	{
+		public static Type Get()
+		{
+			//*ClassA
+			return typeof(ClassA);
+			/*@*/
+
+			/*ClassB
+			return typeof(ClassB);
+			*/
+		}
+	}
+}

+ 42 - 0
IDE/Tests/BugW009/src/Program.bf

@@ -0,0 +1,42 @@
+#pragma warning disable 168
+
+using System;
+using System.Collections;
+
+namespace Bug
+{
+	class ClassA
+	{
+		public int Call()
+		{
+			return 1;
+		}
+	}
+
+	class ClassB
+	{
+		public int Call()
+		{
+			return 2;
+		}
+	}
+
+	typealias Alias1 = comptype(Gen.Get());
+	typealias Alias2 = Alias1;
+
+	class Zonk<T> : Alias2
+	{
+		
+	}
+
+	class Program
+	{
+		public static int Main(String[] args)
+		{
+			Zonk<int> zk = scope .();
+			int val = zk.Call();
+			//End
+			return 0;
+		}
+	}
+}

+ 45 - 34
IDEHelper/Compiler/BfCompiler.cpp

@@ -7012,47 +7012,58 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	mStats.mTypesQueued += (int)mContext->mPopulateTypeWorkList.size();
 	mStats.mTypesQueued += (int)mContext->mPopulateTypeWorkList.size();
 	mStats.mMethodsQueued += (int)mContext->mMethodWorkList.size();
 	mStats.mMethodsQueued += (int)mContext->mMethodWorkList.size();
 
 
-	//
-	{		
-		if (mBfObjectTypeDef != NULL)
-			mContext->mScratchModule->ResolveTypeDef(mBfObjectTypeDef, BfPopulateType_Full);
-		
-		mContext->RemapObject();
-				
-		mSystem->CheckLockYield();
-		
-		mWantsDeferMethodDecls = mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude;
-		
-		CompileReified();
-		mWantsDeferMethodDecls = false;	
-	}
-		
-	BpLeave();
-	BpEnter("Compile_End");
-		
+	while (true)
 	{
 	{
-		BP_ZONE("ProcessingLiveness");
+		//
+		{
+			if (mBfObjectTypeDef != NULL)
+				mContext->mScratchModule->ResolveTypeDef(mBfObjectTypeDef, BfPopulateType_Full);
 
 
-		for (auto type : mContext->mResolvedTypes)
-		{			
-			auto depType = type->ToDependedType();
-			if (depType != NULL)
-				depType->mRebuildFlags = (BfTypeRebuildFlags)(depType->mRebuildFlags | BfTypeRebuildFlag_AwaitingReference);
+			mContext->RemapObject();
+
+			mSystem->CheckLockYield();
+
+			mWantsDeferMethodDecls = mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude;
+
+			CompileReified();
+			mWantsDeferMethodDecls = false;
 		}
 		}
-			
-		bool didWork = false;
-		UpdateDependencyMap(mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_ResolveUnused, didWork);
 
 
-		if (mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude)
+		BpLeave();
+		BpEnter("Compile_End");
+
+		mContext->mHasReifiedQueuedRebuildTypes = false;
+
+		//
 		{
 		{
-			// If UpdateDependencyMap caused methods to be reified, then we need to run PopulateReified again-
-			//  because those methods may be virtual and we need to reify overrides (for example).
-			// We use the DoWorkLoop result to determine if there were actually any changes from UpdateDependencyMap
-			if (didWork)
+			BP_ZONE("ProcessingLiveness");
+
+			for (auto type : mContext->mResolvedTypes)
 			{
 			{
-				PopulateReified();
+				auto depType = type->ToDependedType();
+				if (depType != NULL)
+					depType->mRebuildFlags = (BfTypeRebuildFlags)(depType->mRebuildFlags | BfTypeRebuildFlag_AwaitingReference);
 			}
 			}
-		}						
+
+			bool didWork = false;
+			UpdateDependencyMap(mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_ResolveUnused, didWork);
+
+			if (mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude)
+			{
+				// If UpdateDependencyMap caused methods to be reified, then we need to run PopulateReified again-
+				//  because those methods may be virtual and we need to reify overrides (for example).
+				// We use the DoWorkLoop result to determine if there were actually any changes from UpdateDependencyMap
+				if (didWork)
+				{
+					PopulateReified();
+				}
+			}
+		}
+
+		if (!mContext->mHasReifiedQueuedRebuildTypes)
+			break;
+
+		BfLogSysM("DoCompile looping over CompileReified due to mHasReifiedQueuedRebuildTypes\n");
 	}
 	}
 		
 		
 	ProcessPurgatory(true);
 	ProcessPurgatory(true);

+ 31 - 5
IDEHelper/Compiler/BfContext.cpp

@@ -77,7 +77,8 @@ BfContext::BfContext(BfCompiler* compiler) :
 
 
 	mValueTypeDeinitSentinel = (BfMethodInstance*)1;
 	mValueTypeDeinitSentinel = (BfMethodInstance*)1;
 
 
-	mCurStringObjectPoolId = 0;		
+	mCurStringObjectPoolId = 0;
+	mHasReifiedQueuedRebuildTypes = false;
 }
 }
 
 
 void BfReportMemory();
 void BfReportMemory();
@@ -945,6 +946,9 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild
 			return;	
 			return;	
 	}	
 	}	
 	
 	
+	if (typeInst->mIsReified)
+		mHasReifiedQueuedRebuildTypes = true;
+
 	typeInst->mRebuildFlags = (BfTypeRebuildFlags)(typeInst->mRebuildFlags & ~BfTypeRebuildFlag_AddedToWorkList);
 	typeInst->mRebuildFlags = (BfTypeRebuildFlags)(typeInst->mRebuildFlags & ~BfTypeRebuildFlag_AddedToWorkList);
 
 
 	bool addToWorkList = true;
 	bool addToWorkList = true;
@@ -1131,8 +1135,8 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild
 		genericTypeInstance->mGenericTypeInfo->mGenericParams.Clear();
 		genericTypeInstance->mGenericTypeInfo->mGenericParams.Clear();
 		genericTypeInstance->mGenericTypeInfo->mValidatedGenericConstraints = false;
 		genericTypeInstance->mGenericTypeInfo->mValidatedGenericConstraints = false;
 		genericTypeInstance->mGenericTypeInfo->mHadValidateErrors = false;
 		genericTypeInstance->mGenericTypeInfo->mHadValidateErrors = false;
-		delete genericTypeInstance->mGenericTypeInfo->mGenericExtensionInfo;
-		genericTypeInstance->mGenericTypeInfo->mGenericExtensionInfo = NULL;
+		if (genericTypeInstance->mGenericTypeInfo->mGenericExtensionInfo != NULL)
+			genericTypeInstance->mGenericTypeInfo->mGenericExtensionInfo->Clear();
 		genericTypeInstance->mGenericTypeInfo->mProjectsReferenced.Clear();
 		genericTypeInstance->mGenericTypeInfo->mProjectsReferenced.Clear();
 	}	
 	}	
 
 
@@ -1182,6 +1186,22 @@ void BfContext::RebuildDependentTypes(BfDependedType* dType)
 		TypeMethodSignaturesChanged(typeInst);
 		TypeMethodSignaturesChanged(typeInst);
 }
 }
 
 
+void BfContext::RebuildDependentTypes_MidCompile(BfDependedType* dType, const String& reason)
+{
+	dType->mRebuildFlags = (BfTypeRebuildFlags)(dType->mRebuildFlags | BfTypeRebuildFlag_ChangedMidCompile);
+	int prevDeletedTypes = mCompiler->mStats.mTypesDeleted;
+	if (mCompiler->mIsResolveOnly)
+		mCompiler->mNeedsFullRefresh = true;
+	BfLogSysM("Rebuilding dependent types MidCompile Type:%p Reason:%s\n", dType, reason.c_str());
+	RebuildDependentTypes(dType);
+
+	if (mCompiler->mStats.mTypesDeleted != prevDeletedTypes)
+	{		
+		BfLogSysM("Rebuilding dependent types MidCompile Type:%p Reason:%s - updating after deleting types\n", dType, reason.c_str());
+		UpdateAfterDeletingTypes();
+	}
+}
+
 // Dependencies cascade as such:
 // Dependencies cascade as such:
 //  DerivedFrom / StructMemberData: these change the layout of memory for the dependent classes,
 //  DerivedFrom / StructMemberData: these change the layout of memory for the dependent classes,
 //   so not only do the dependent classes need to be rebuild, but any other classes relying on those derived classes
 //   so not only do the dependent classes need to be rebuild, but any other classes relying on those derived classes
@@ -1254,7 +1274,7 @@ void BfContext::TypeDataChanged(BfDependedType* dType, bool isNonStaticDataChang
 			}
 			}
 
 
 			if (dependentType->mRevision != mCompiler->mRevision)
 			if (dependentType->mRevision != mCompiler->mRevision)
-			{
+			{				
 				// We need to include DependencyFlag_ParamOrReturnValue because it could be a struct that changes its splatting ability
 				// We need to include DependencyFlag_ParamOrReturnValue because it could be a struct that changes its splatting ability
 							//  We can't ONLY check against structs, though, because a type could change from a class to a struct
 							//  We can't ONLY check against structs, though, because a type could change from a class to a struct
 				if (dependencyFlags &
 				if (dependencyFlags &
@@ -1264,6 +1284,12 @@ void BfContext::TypeDataChanged(BfDependedType* dType, bool isNonStaticDataChang
 				{
 				{
 					RebuildType(dependentType);
 					RebuildType(dependentType);
 				}
 				}
+				else if (((dependencyFlags & BfDependencyMap::DependencyFlag_NameReference) != 0) && 
+					((dType->mRebuildFlags & BfTypeRebuildFlag_ChangedMidCompile) != 0) &&
+					(dType->IsTypeAlias()))
+				{
+					RebuildType(dependentType);
+				}
 			}
 			}
 		}
 		}
 		else
 		else
@@ -1276,7 +1302,7 @@ void BfContext::TypeDataChanged(BfDependedType* dType, bool isNonStaticDataChang
 		}
 		}
 	}
 	}
 	
 	
-	if (dType->mRevision != mCompiler->mRevision)	
+	if (dType->mRevision != mCompiler->mRevision)
 		RebuildType(dType);	
 		RebuildType(dType);	
 }
 }
 
 

+ 3 - 1
IDEHelper/Compiler/BfContext.h

@@ -351,7 +351,7 @@ class BfContext
 {
 {
 public:
 public:
 	CritSect mCritSect;	
 	CritSect mCritSect;	
-	bool mDeleting;
+	bool mDeleting;	
 	
 	
 	BfTypeState* mCurTypeState;
 	BfTypeState* mCurTypeState;
 	BfSizedArray<BfNamespaceDeclaration*>* mCurNamespaceNodes;
 	BfSizedArray<BfNamespaceDeclaration*>* mCurNamespaceNodes;
@@ -397,6 +397,7 @@ public:
 	WorkQueue<BfTypeRefVerifyRequest> mTypeRefVerifyWorkList;
 	WorkQueue<BfTypeRefVerifyRequest> mTypeRefVerifyWorkList;
 	PtrWorkQueue<BfModule*> mFinishedSlotAwaitModuleWorkList;
 	PtrWorkQueue<BfModule*> mFinishedSlotAwaitModuleWorkList;
 	PtrWorkQueue<BfModule*> mFinishedModuleWorkList;
 	PtrWorkQueue<BfModule*> mFinishedModuleWorkList;
+	bool mHasReifiedQueuedRebuildTypes;
 
 
 	Array<BfGenericParamType*> mGenericParamTypes[3];
 	Array<BfGenericParamType*> mGenericParamTypes[3];
 	
 	
@@ -475,6 +476,7 @@ public:
 	void ValidateDependencies();
 	void ValidateDependencies();
 	void RebuildType(BfType* type, bool deleteOnDemandTypes = true, bool rebuildModule = true, bool placeSpecializiedInPurgatory = true);
 	void RebuildType(BfType* type, bool deleteOnDemandTypes = true, bool rebuildModule = true, bool placeSpecializiedInPurgatory = true);
 	void RebuildDependentTypes(BfDependedType* dType);	
 	void RebuildDependentTypes(BfDependedType* dType);	
+	void RebuildDependentTypes_MidCompile(BfDependedType* dType, const String& reason);
 	void TypeDataChanged(BfDependedType* dType, bool isNonStaticDataChange);
 	void TypeDataChanged(BfDependedType* dType, bool isNonStaticDataChange);
 	void TypeMethodSignaturesChanged(BfTypeInstance* typeInst);
 	void TypeMethodSignaturesChanged(BfTypeInstance* typeInst);
 	void TypeInlineMethodInternalsChanged(BfTypeInstance* typeInst);
 	void TypeInlineMethodInternalsChanged(BfTypeInstance* typeInst);

+ 5 - 1
IDEHelper/Compiler/BfIRBuilder.cpp

@@ -1746,7 +1746,11 @@ String BfIRBuilder::ToString(BfIRValue irValue)
 			auto typeofConst = (BfTypeOf_WithData_Const*)constant;
 			auto typeofConst = (BfTypeOf_WithData_Const*)constant;
 			return "typeof_withData " + mModule->TypeToString(typeofConst->mType);
 			return "typeof_withData " + mModule->TypeToString(typeofConst->mType);
 		}
 		}
-
+		else if (constant->mConstType == BfConstType_Undef)
+		{
+			auto constUndef = (BfConstantUndef*)constant;
+			return "undef " + ToString(constUndef->mType);
+		}
 		else
 		else
 		{
 		{
 			BF_FATAL("Unhandled");
 			BF_FATAL("Unhandled");

+ 1 - 1
IDEHelper/Compiler/BfModule.cpp

@@ -1258,7 +1258,7 @@ void BfModule::StartNewRevision(RebuildKind rebuildKind, bool force)
 	mHadBuildError = false;
 	mHadBuildError = false;
 	mHadBuildWarning = false;	
 	mHadBuildWarning = false;	
 	mExtensionCount = 0;
 	mExtensionCount = 0;
-	mRevision = mCompiler->mRevision;	
+	mRevision = mCompiler->mRevision;
 	mRebuildIdx++;
 	mRebuildIdx++;
 	ClearModuleData(!force);	
 	ClearModuleData(!force);	
 
 

+ 1 - 1
IDEHelper/Compiler/BfModule.h

@@ -1775,7 +1775,7 @@ public:
 	void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred);
 	void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred);
 	void DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers, bool underlyingTypeDeferred);
 	void DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers, bool underlyingTypeDeferred);
 	void DoCEEmit(BfMethodInstance* methodInstance);
 	void DoCEEmit(BfMethodInstance* methodInstance);
-	void DoPopulateType_TypeAlias(BfTypeInstance* typeAlias);
+	void DoPopulateType_TypeAlias(BfTypeAliasType* typeAlias);
 	void DoPopulateType_InitSearches(BfTypeInstance* typeInstance);
 	void DoPopulateType_InitSearches(BfTypeInstance* typeInstance);
 	void DoPopulateType_SetGenericDependencies(BfTypeInstance* genericTypeInstance);	
 	void DoPopulateType_SetGenericDependencies(BfTypeInstance* genericTypeInstance);	
 	void DoPopulateType_FinishEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred, HashContext* dataMemberHashCtx, BfType* unionInnerType);
 	void DoPopulateType_FinishEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred, HashContext* dataMemberHashCtx, BfType* unionInnerType);

+ 53 - 23
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -184,6 +184,21 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
 
 
 	if (!typeDef->mPartials.empty())
 	if (!typeDef->mPartials.empty())
 	{
 	{
+		BitSet prevConstraintsPassedSet;
+
+		if (!genericTypeInst->IsUnspecializedType())
+		{
+			if (genericTypeInst->mGenericTypeInfo->mGenericExtensionInfo != NULL)
+			{
+				auto genericExtensionInfo = genericTypeInst->mGenericTypeInfo->mGenericExtensionInfo;
+				prevConstraintsPassedSet = genericExtensionInfo->mConstraintsPassedSet;
+				genericExtensionInfo->mConstraintsPassedSet.Clear();
+			}
+		}
+
+		int extensionCount = 0;
+
+		BfLogSysM("BfModule::FinishGenericParams %p\n", resolvedTypeRef);
 		for (auto partialTypeDef : typeDef->mPartials)
 		for (auto partialTypeDef : typeDef->mPartials)
 		{
 		{
 			if (!partialTypeDef->IsExtension())
 			if (!partialTypeDef->IsExtension())
@@ -222,6 +237,13 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
 				auto genericExEntry = BuildGenericExtensionInfo(genericTypeInst, partialTypeDef);
 				auto genericExEntry = BuildGenericExtensionInfo(genericTypeInst, partialTypeDef);
 				if (genericExEntry == NULL)
 				if (genericExEntry == NULL)
 					continue;
 					continue;
+
+				auto genericExtensionInfo = genericTypeInst->mGenericTypeInfo->mGenericExtensionInfo;
+				if (extensionCount == 0)
+					genericExtensionInfo->mConstraintsPassedSet.Resize(typeDef->mPartials.mSize);
+
+				extensionCount++;
+				
 				if (!genericTypeInst->IsUnspecializedType())
 				if (!genericTypeInst->IsUnspecializedType())
 				{
 				{
 					SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, true);
 					SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, true);
@@ -249,7 +271,18 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
 						}
 						}
 					}
 					}
 				}
 				}
-			}
+
+				if (genericExEntry->mConstraintsPassed)
+					genericExtensionInfo->mConstraintsPassedSet.Set(partialTypeDef->mPartialIdx);
+
+				BfLogSysM("BfModule::FinishGenericParams %p partialTypeDef:%p passed:%d\n", resolvedTypeRef, partialTypeDef, genericExEntry->mConstraintsPassed);
+			}			
+		}
+
+		auto genericExtensionInfo = genericTypeInst->mGenericTypeInfo->mGenericExtensionInfo;
+		if ((extensionCount > 0) && (!prevConstraintsPassedSet.IsEmpty()) && (genericExtensionInfo->mConstraintsPassedSet != prevConstraintsPassedSet))
+		{
+			mContext->RebuildDependentTypes_MidCompile(genericTypeInst, "mConstraintsPassedSet changed");		
 		}
 		}
 	}
 	}
 	else
 	else
@@ -1224,7 +1257,8 @@ void BfModule::PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType
 	if (resolvedTypeRef->IsTypeAlias())	
 	if (resolvedTypeRef->IsTypeAlias())	
 	{
 	{
 		// Always populate these all the way
 		// Always populate these all the way
-		populateType = BfPopulateType_Data;
+		if (populateType != BfPopulateType_IdentityNoRemapAlias)
+			populateType = BfPopulateType_Data;
  	}
  	}
 
 
 	if (resolvedTypeRef->IsSizedArray())
 	if (resolvedTypeRef->IsSizedArray())
@@ -2730,7 +2764,7 @@ void BfModule::DoPopulateType_SetGenericDependencies(BfTypeInstance* genericType
 	}
 	}
 }
 }
 
 
-void BfModule::DoPopulateType_TypeAlias(BfTypeInstance* typeAlias)
+void BfModule::DoPopulateType_TypeAlias(BfTypeAliasType* typeAlias)
 {
 {
 	SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, typeAlias);
 	SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, typeAlias);
 	SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, NULL);
 	SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, NULL);
@@ -2766,6 +2800,8 @@ void BfModule::DoPopulateType_TypeAlias(BfTypeInstance* typeAlias)
 			aliasToType = ResolveTypeRef(typeAliasDecl->mAliasToType, BfPopulateType_IdentityNoRemapAlias);
 			aliasToType = ResolveTypeRef(typeAliasDecl->mAliasToType, BfPopulateType_IdentityNoRemapAlias);
 	}
 	}
 
 
+	BfLogSysM("DoPopulateType_TypeAlias %p %s = %p %s\n", typeAlias, TypeToString(typeAlias).c_str(), aliasToType, (aliasToType != NULL) ? TypeToString(aliasToType).c_str() : NULL);
+
 	if (aliasToType != NULL)
 	if (aliasToType != NULL)
 	{
 	{
 		if (aliasToType->IsConstExprValue())
 		if (aliasToType->IsConstExprValue())
@@ -2776,16 +2812,19 @@ void BfModule::DoPopulateType_TypeAlias(BfTypeInstance* typeAlias)
 	}
 	}
 
 
 	if (aliasToType != NULL)
 	if (aliasToType != NULL)
-	{
+	{		
 		AddDependency(aliasToType, typeAlias, BfDependencyMap::DependencyFlag_DerivedFrom);
 		AddDependency(aliasToType, typeAlias, BfDependencyMap::DependencyFlag_DerivedFrom);
 	}
 	}
 	else
 	else
 		mContext->mFailTypes.Add(typeAlias);
 		mContext->mFailTypes.Add(typeAlias);
 
 
 	if (typeAlias->mTypeFailed)
 	if (typeAlias->mTypeFailed)
-		aliasToType = NULL;
+		aliasToType = NULL;	
 
 
-	((BfTypeAliasType*)typeAlias)->mAliasToType = aliasToType;
+ 	if ((typeAlias->mAliasToType != NULL) && (typeAlias->mAliasToType != aliasToType) && (!typeAlias->mDependencyMap.IsEmpty()))
+ 		mContext->RebuildDependentTypes_MidCompile(typeAlias, "type alias remapped");
+
+	typeAlias->mAliasToType = aliasToType;
 
 
 	if (aliasToType != NULL)
 	if (aliasToType != NULL)
 	{
 	{
@@ -3188,9 +3227,10 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 	if (resolvedTypeRef->IsTypeAlias())
 	if (resolvedTypeRef->IsTypeAlias())
 	{
 	{
 		prevTypeState.Restore();
 		prevTypeState.Restore();
-		DoPopulateType_TypeAlias(typeInstance);
+		DoPopulateType_TypeAlias((BfTypeAliasType*)typeInstance);
 
 
 		typeInstance->mTypeIncomplete = false;
 		typeInstance->mTypeIncomplete = false;
+		resolvedTypeRef->mRebuildFlags = BfTypeRebuildFlag_None;
 		resolvedTypeRef->mDefineState = BfTypeDefineState_DefinedAndMethodsSlotted;
 		resolvedTypeRef->mDefineState = BfTypeDefineState_DefinedAndMethodsSlotted;
 		return;
 		return;
 	}
 	}
@@ -4453,19 +4493,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 					if (!typeInstance->mCeTypeInfo->mNext->mFailed)
 					if (!typeInstance->mCeTypeInfo->mNext->mFailed)
 					{
 					{
 						if ((typeInstance->mCeTypeInfo->mHash != typeInstance->mCeTypeInfo->mNext->mHash) && (!typeInstance->mCeTypeInfo->mHash.IsZero()))
 						if ((typeInstance->mCeTypeInfo->mHash != typeInstance->mCeTypeInfo->mNext->mHash) && (!typeInstance->mCeTypeInfo->mHash.IsZero()))
-						{
-							int prevDeletedTypes = mCompiler->mStats.mTypesDeleted;
-							if (mCompiler->mIsResolveOnly)
-								mCompiler->mNeedsFullRefresh = true;
-							BfLogSysM("Type %p hash changed, rebuilding dependent types\n", typeInstance);
-							mContext->RebuildDependentTypes(typeInstance);
-							
-							if (mCompiler->mStats.mTypesDeleted != prevDeletedTypes)
-							{
-								BfLogSysM("Type %p hash changed, rebuilding dependent types - updating after deleting types\n", typeInstance);
-								mContext->UpdateAfterDeletingTypes();
-							}
-						}						
+							mContext->RebuildDependentTypes_MidCompile(typeInstance, "comptime hash changed");												
 						typeInstance->mCeTypeInfo->mOnCompileMap = typeInstance->mCeTypeInfo->mNext->mOnCompileMap;
 						typeInstance->mCeTypeInfo->mOnCompileMap = typeInstance->mCeTypeInfo->mNext->mOnCompileMap;
 						typeInstance->mCeTypeInfo->mTypeIFaceMap = typeInstance->mCeTypeInfo->mNext->mTypeIFaceMap;
 						typeInstance->mCeTypeInfo->mTypeIFaceMap = typeInstance->mCeTypeInfo->mNext->mTypeIFaceMap;
 						typeInstance->mCeTypeInfo->mHash = typeInstance->mCeTypeInfo->mNext->mHash;
 						typeInstance->mCeTypeInfo->mHash = typeInstance->mCeTypeInfo->mNext->mHash;
@@ -8922,9 +8950,11 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy
 		{
 		{
 			if (mCurTypeInstance != NULL)
 			if (mCurTypeInstance != NULL)
 				AddDependency(resolvedTypeRef, mCurTypeInstance, BfDependencyMap::DependencyFlag_NameReference);
 				AddDependency(resolvedTypeRef, mCurTypeInstance, BfDependencyMap::DependencyFlag_NameReference);
+			if (resolvedTypeRef->mDefineState == BfTypeDefineState_Undefined)
+				PopulateType(resolvedTypeRef);
 			if ((typeInstance->mCustomAttributes != NULL) && (!typeRef->IsTemporary()))
 			if ((typeInstance->mCustomAttributes != NULL) && (!typeRef->IsTemporary()))
-				CheckErrorAttributes(typeInstance, NULL, typeInstance->mCustomAttributes, typeRef);
-			resolvedTypeRef = resolvedTypeRef->GetUnderlyingType();
+				CheckErrorAttributes(typeInstance, NULL, typeInstance->mCustomAttributes, typeRef);			
+			resolvedTypeRef = resolvedTypeRef->GetUnderlyingType();			
 			if (resolvedTypeRef != NULL)
 			if (resolvedTypeRef != NULL)
 				typeInstance = resolvedTypeRef->ToTypeInstance();
 				typeInstance = resolvedTypeRef->ToTypeInstance();
 			else
 			else
@@ -11088,7 +11118,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 #ifdef _DEBUG
 #ifdef _DEBUG
 		if (BfResolvedTypeSet::Hash(refType, &lookupCtx) != resolvedEntry->mHash)
 		if (BfResolvedTypeSet::Hash(refType, &lookupCtx) != resolvedEntry->mHash)
 		{
 		{
-			int refHash = BfResolvedTypeSet::Hash(typeRef, &lookupCtx);
+			int refHash = BfResolvedTypeSet::Hash(typeRef, &lookupCtx, BfResolvedTypeSet::BfHashFlag_AllowRef);
 			int typeHash = BfResolvedTypeSet::Hash(refType, &lookupCtx);
 			int typeHash = BfResolvedTypeSet::Hash(refType, &lookupCtx);
 			BF_ASSERT(refHash == typeHash);
 			BF_ASSERT(refHash == typeHash);
 		}
 		}

+ 10 - 2
IDEHelper/Compiler/BfResolvedTypeUtils.h

@@ -7,6 +7,7 @@
 #include "BfSource.h"
 #include "BfSource.h"
 #include "BfIRBuilder.h"
 #include "BfIRBuilder.h"
 #include "BeefySysLib/util/MultiHashSet.h"
 #include "BeefySysLib/util/MultiHashSet.h"
+#include "BeefySysLib/util/BitSet.h"
 
 
 NS_BF_BEGIN
 NS_BF_BEGIN
 
 
@@ -428,7 +429,8 @@ enum BfTypeRebuildFlags
 	BfTypeRebuildFlag_ResolvingBase = 0x8000,
 	BfTypeRebuildFlag_ResolvingBase = 0x8000,
 	BfTypeRebuildFlag_InFailTypes = 0x10000,
 	BfTypeRebuildFlag_InFailTypes = 0x10000,
 	BfTypeRebuildFlag_RebuildQueued = 0x20000,
 	BfTypeRebuildFlag_RebuildQueued = 0x20000,
-	BfTypeRebuildFlag_ConstEvalCancelled = 0x40000
+	BfTypeRebuildFlag_ConstEvalCancelled = 0x40000,
+	BfTypeRebuildFlag_ChangedMidCompile = 0x80000,
 };
 };
 
 
 class BfTypeDIReplaceCallback;
 class BfTypeDIReplaceCallback;
@@ -489,7 +491,7 @@ public:
 	
 	
 	BfContext* mContext;
 	BfContext* mContext;
 	int mTypeId;
 	int mTypeId;
-	int mRevision;	
+	int mRevision;
 	
 	
 	// For Objects, align and size is ref-sized (object*).  	
 	// For Objects, align and size is ref-sized (object*).  	
 	//  Use mInstSize/mInstAlign for actual data size/align
 	//  Use mInstSize/mInstAlign for actual data size/align
@@ -1842,6 +1844,12 @@ class BfGenericExtensionInfo
 {
 {
 public:
 public:
 	Dictionary<BfTypeDef*, BfGenericExtensionEntry> mExtensionMap;
 	Dictionary<BfTypeDef*, BfGenericExtensionEntry> mExtensionMap;
+	BitSet mConstraintsPassedSet;
+
+	void Clear()
+	{
+		mExtensionMap.Clear();		
+	}
 };
 };
 
 
 // Note on nested generic types- mGenericParams is the accumulation of all generic params from outer to inner, so
 // Note on nested generic types- mGenericParams is the accumulation of all generic params from outer to inner, so

+ 2 - 2
IDEHelper/Compiler/BfStmtEvaluator.cpp

@@ -6122,7 +6122,7 @@ void BfModule::Visit(BfForEachStatement* forEachStmt)
 	}
 	}
 	
 	
 	if (varType == NULL)
 	if (varType == NULL)
-		varType = mContext->mBfObjectType;
+		varType = GetPrimitiveType(BfTypeCode_Var);
 	bool isArray = target.mType->IsArray();
 	bool isArray = target.mType->IsArray();
 	bool isSizedArray = target.mType->IsSizedArray();
 	bool isSizedArray = target.mType->IsSizedArray();
 	bool isVarEnumerator = target.mType->IsVar();
 	bool isVarEnumerator = target.mType->IsVar();
@@ -6437,7 +6437,7 @@ void BfModule::Visit(BfForEachStatement* forEachStmt)
 		}
 		}
 	}
 	}
 	if (nextEmbeddedType == NULL)
 	if (nextEmbeddedType == NULL)
-		nextEmbeddedType = mContext->mBfObjectType;
+		nextEmbeddedType = GetPrimitiveType(BfTypeCode_Var);
 
 
 	BfLocalVariable* itrLocalDef = NULL;
 	BfLocalVariable* itrLocalDef = NULL;
 
 

+ 1 - 1
IDEHelper/Tests/src/ConstEval.bf

@@ -14,7 +14,7 @@ namespace Tests
 
 
 			public struct Inner
 			public struct Inner
 			{
 			{
-				public const EnumA cVal = EnumA.C("InnerTest");
+				public const EnumA cVal = .C("InnerTest");
 			}
 			}
 		}
 		}
 
 

+ 8 - 0
bin/test_ide.bat

@@ -67,6 +67,14 @@ PUSHD %~dp0..\
 @CALL :TEST
 @CALL :TEST
 @IF !ERRORLEVEL! NEQ 0 GOTO HADERROR
 @IF !ERRORLEVEL! NEQ 0 GOTO HADERROR
 
 
+@SET TESTPATH=IDE\Tests\BugW008
+@CALL :TEST
+@IF !ERRORLEVEL! NEQ 0 GOTO HADERROR
+
+@SET TESTPATH=IDE\Tests\BugW009
+@CALL :TEST
+@IF !ERRORLEVEL! NEQ 0 GOTO HADERROR
+
 @SET TESTPATH=IDE\Tests\IndentTest
 @SET TESTPATH=IDE\Tests\IndentTest
 @CALL :TEST
 @CALL :TEST
 @IF !ERRORLEVEL! NEQ 0 GOTO HADERROR
 @IF !ERRORLEVEL! NEQ 0 GOTO HADERROR