Brian Fiete vor 4 Jahren
Ursprung
Commit
8e9d7ed4c4
56 geänderte Dateien mit 1561 neuen und 776 gelöschten Zeilen
  1. 7 0
      BeefLibs/Beefy2D/src/theme/dark/DarkListView.bf
  2. 18 0
      BeefLibs/Beefy2D/src/widgets/KeyCode.bf
  3. 5 4
      BeefLibs/Beefy2D/src/widgets/TabbedView.bf
  4. 1 1
      BeefLibs/SDL2/src/SDL2.bf
  5. 1 1
      BeefLibs/SDL2/src/SDL2_ttf.bf
  6. 2 1
      BeefLibs/corlib/src/IO/OpenFileDialog.bf
  7. 5 0
      BeefySysLib/platform/win/Platform.cpp
  8. 20 7
      BeefySysLib/util/MultiHashSet.h
  9. 2 1
      IDE/dist/lib/gen/src/Program.bf
  10. 47 42
      IDE/src/BuildContext.bf
  11. 2 1
      IDE/src/Debugger/DebugManager.bf
  12. 169 61
      IDE/src/IDEApp.bf
  13. 1 1
      IDE/src/ScriptManager.bf
  14. 10 4
      IDE/src/ui/ClassViewPanel.bf
  15. 1 1
      IDE/src/ui/DisassemblyPanel.bf
  16. 9 1
      IDE/src/ui/ErrorsPanel.bf
  17. 19 2
      IDE/src/ui/HoverWatch.bf
  18. 33 3
      IDE/src/ui/ImmediateWidget.bf
  19. 8 14
      IDE/src/ui/MemoryPanel.bf
  20. 3 2
      IDE/src/ui/ProjectPanel.bf
  21. 3 3
      IDE/src/ui/SourceEditWidgetContent.bf
  22. 7 2
      IDE/src/ui/SourceViewPanel.bf
  23. 3 1
      IDE/src/ui/WatchPanel.bf
  24. 5 1
      IDEHelper/Backend/BeIRCodeGen.cpp
  25. 3 3
      IDEHelper/Backend/BeMCContext.cpp
  26. 2 1
      IDEHelper/Compiler/BfCodeGen.cpp
  27. 43 44
      IDEHelper/Compiler/BfCompiler.cpp
  28. 3 2
      IDEHelper/Compiler/BfCompiler.h
  29. 20 11
      IDEHelper/Compiler/BfConstResolver.cpp
  30. 5 4
      IDEHelper/Compiler/BfConstResolver.h
  31. 15 10
      IDEHelper/Compiler/BfContext.cpp
  32. 3 1
      IDEHelper/Compiler/BfContext.h
  33. 23 31
      IDEHelper/Compiler/BfDefBuilder.cpp
  34. 138 75
      IDEHelper/Compiler/BfExprEvaluator.cpp
  35. 38 37
      IDEHelper/Compiler/BfIRBuilder.cpp
  36. 4 1
      IDEHelper/Compiler/BfIRBuilder.h
  37. 22 14
      IDEHelper/Compiler/BfIRCodeGen.cpp
  38. 266 139
      IDEHelper/Compiler/BfModule.cpp
  39. 13 11
      IDEHelper/Compiler/BfModule.h
  40. 157 56
      IDEHelper/Compiler/BfModuleTypeUtils.cpp
  41. 45 1
      IDEHelper/Compiler/BfPrinter.cpp
  42. 4 2
      IDEHelper/Compiler/BfReducer.cpp
  43. 81 51
      IDEHelper/Compiler/BfResolvedTypeUtils.cpp
  44. 10 4
      IDEHelper/Compiler/BfResolvedTypeUtils.h
  45. 34 10
      IDEHelper/Compiler/BfSourceClassifier.cpp
  46. 9 11
      IDEHelper/Compiler/BfStmtEvaluator.cpp
  47. 28 6
      IDEHelper/Compiler/BfSystem.cpp
  48. 3 1
      IDEHelper/Compiler/BfSystem.h
  49. 30 6
      IDEHelper/Compiler/CeMachine.cpp
  50. 1 0
      IDEHelper/Debugger.h
  51. 64 57
      IDEHelper/NetManager.cpp
  52. 22 0
      IDEHelper/Tests/src/Comptime.bf
  53. 46 0
      IDEHelper/Tests/src/Extensions.bf
  54. 10 0
      IDEHelper/Tests/src/Generics2.bf
  55. 33 33
      IDEHelper/Tests/src/Reflection.bf
  56. 5 0
      IDEHelper/WinDebugger.cpp

+ 7 - 0
BeefLibs/Beefy2D/src/theme/dark/DarkListView.bf

@@ -796,6 +796,13 @@ namespace Beefy.theme.dark
                         mDragKind = .None;
                         mDragKind = .None;
                 }
                 }
 
 
+				if (Math.Abs(dY) < mSelfHeight * 0.21f)
+				{
+					mDragKind = .None;
+					mDragTarget = null;
+					return;
+				}
+
 				delete mCurDragEvent;
 				delete mCurDragEvent;
                 mCurDragEvent = new DragEvent();
                 mCurDragEvent = new DragEvent();
                 mCurDragEvent.mX = x;
                 mCurDragEvent.mX = x;

+ 18 - 0
BeefLibs/Beefy2D/src/widgets/KeyCode.bf

@@ -106,6 +106,24 @@ namespace Beefy.widgets
 
 
 	extension KeyCode
 	extension KeyCode
 	{
 	{
+		public bool IsModifier
+		{
+			get
+			{
+				switch (this)
+				{
+				case .LWin,
+					 .RWin,
+					 .Alt,
+					 .Control,
+					 .Command:
+					return true;
+				default:
+					return false;
+				}
+			}
+		}
+
 		public static Result<KeyCode> Parse(StringView str)
 		public static Result<KeyCode> Parse(StringView str)
 		{
 		{
 			if (str.Length == 1)
 			if (str.Length == 1)

+ 5 - 4
BeefLibs/Beefy2D/src/widgets/TabbedView.bf

@@ -200,7 +200,8 @@ namespace Beefy.widgets
             {
             {
                 return (mTabbedView.mParentDockingFrame.mParentDockingFrame == null) &&
                 return (mTabbedView.mParentDockingFrame.mParentDockingFrame == null) &&
                     (mTabbedView.mParentDockingFrame.GetDockedWindowCount() == 1) &&
                     (mTabbedView.mParentDockingFrame.GetDockedWindowCount() == 1) &&
-                    (mTabbedView.GetTabCount() == 1);
+                    (mTabbedView.GetTabCount() == 1) &&
+					mTabbedView.mAutoClose;
             }
             }
 
 
             void WindowDragLostFocusHandler(BFWindow window, BFWindow newFocus)
             void WindowDragLostFocusHandler(BFWindow window, BFWindow newFocus)
@@ -237,7 +238,7 @@ namespace Beefy.widgets
                             300, 500,
                             300, 500,
                             BFWindowBase.Flags.Border | BFWindowBase.Flags.ThickFrame | BFWindowBase.Flags.Resizable | BFWindowBase.Flags.SysMenu |
                             BFWindowBase.Flags.Border | BFWindowBase.Flags.ThickFrame | BFWindowBase.Flags.Resizable | BFWindowBase.Flags.SysMenu |
                             BFWindowBase.Flags.Caption | BFWindowBase.Flags.Minimize | BFWindowBase.Flags.ToolWindow | BFWindowBase.Flags.TopMost |
                             BFWindowBase.Flags.Caption | BFWindowBase.Flags.Minimize | BFWindowBase.Flags.ToolWindow | BFWindowBase.Flags.TopMost |
-                            BFWindowBase.Flags.UseParentMenu,
+                            BFWindowBase.Flags.UseParentMenu | BFWindowBase.Flags.Maximize,
                             subFrame);
                             subFrame);
                         Dock(subFrame, null, DockingFrame.WidgetAlign.Top);
                         Dock(subFrame, null, DockingFrame.WidgetAlign.Top);
                         //subFrame.AddDockedWidget(fourthTabbedView, null, DockingFrame.WidgetAlign.Left, false);
                         //subFrame.AddDockedWidget(fourthTabbedView, null, DockingFrame.WidgetAlign.Left, false);
@@ -288,7 +289,7 @@ namespace Beefy.widgets
                 if ((refWidget != null) && (refWidget.mWidgetWindow != mWidgetWindow) && (mWidgetWindow != null))
                 if ((refWidget != null) && (refWidget.mWidgetWindow != mWidgetWindow) && (mWidgetWindow != null))
                     mWidgetWindow.SetForeground();
                     mWidgetWindow.SetForeground();
 
 
-                if (mTabbedView.GetTabCount() == 1)
+                if ((mTabbedView.GetTabCount() == 1) && mTabbedView.mAutoClose)
                 {                    
                 {                    
                     mTabbedView.Dock(frame, refWidget, align);
                     mTabbedView.Dock(frame, refWidget, align);
                     return;
                     return;
@@ -327,7 +328,7 @@ namespace Beefy.widgets
                     tabbedView.Dock(frame, refWidget, align);                    
                     tabbedView.Dock(frame, refWidget, align);                    
                 }
                 }
 
 
-                if (prevTabbedView.GetTabCount() == 0)
+                if ((prevTabbedView.GetTabCount() == 0) && prevTabbedView.mAutoClose)
                 {                    
                 {                    
                     prevTabbedView.mParentDockingFrame.RemoveDockedWidget(prevTabbedView);
                     prevTabbedView.mParentDockingFrame.RemoveDockedWidget(prevTabbedView);
                 }
                 }

+ 1 - 1
BeefLibs/SDL2/src/SDL2.bf

@@ -746,7 +746,7 @@ namespace SDL2
 		public static extern int32 GetDisplayMode(int32 displayIndex, int32 modeIndex, out SDL_DisplayMode mode);
 		public static extern int32 GetDisplayMode(int32 displayIndex, int32 modeIndex, out SDL_DisplayMode mode);
 
 
 		/* Available in 2.0.5 or higher */
 		/* Available in 2.0.5 or higher */
-		[LinkName("SDL_GetDisplayMode")]
+		[LinkName("SDL_GetDisplayUsableBounds")]
 		public static extern int SDL_GetDisplayUsableBounds(int displayIndex, out Rect rect);
 		public static extern int SDL_GetDisplayUsableBounds(int displayIndex, out Rect rect);
 
 
 		[LinkName("SDL_GetNumDisplayModes")]
 		[LinkName("SDL_GetNumDisplayModes")]

+ 1 - 1
BeefLibs/SDL2/src/SDL2_ttf.bf

@@ -315,4 +315,4 @@ namespace SDL2
 			int index
 			int index
 		);
 		);
 	}
 	}
-}
+}

+ 2 - 1
BeefLibs/corlib/src/IO/OpenFileDialog.bf

@@ -119,7 +119,8 @@ namespace System.IO
 			DeleteAndNullify!(mTitle);
 			DeleteAndNullify!(mTitle);
 			DeleteAndNullify!(mInitialDir);
 			DeleteAndNullify!(mInitialDir);
 			DeleteAndNullify!(mDefaultExt);
 			DeleteAndNullify!(mDefaultExt);
-			DeleteAndNullify!(mFileNames);
+			DeleteContainerAndItems!(mFileNames);
+			mFileNames = null;
 			DeleteAndNullify!(mFilter);
 			DeleteAndNullify!(mFilter);
 			mFilterIndex = 1;
 			mFilterIndex = 1;
 			mSupportMultiDottedExtensions = false;
 			mSupportMultiDottedExtensions = false;

+ 5 - 0
BeefySysLib/platform/win/Platform.cpp

@@ -1,3 +1,8 @@
+#define INITKNOWNFOLDERS
+#include <guiddef.h>
+#include <KnownFolders.h>
+#undef INITKNOWNFOLDERS
+
 #pragma warning(disable:4065)
 #pragma warning(disable:4065)
 #pragma warning(disable:4996)
 #pragma warning(disable:4996)
 
 

+ 20 - 7
BeefySysLib/util/MultiHashSet.h

@@ -164,17 +164,30 @@ public:
 	{
 	{
 		auto newHashHeads = (Entry**)TFuncs::AllocateZero(sizeof(Entry*) * newHashSize, alignof(Entry*));
 		auto newHashHeads = (Entry**)TFuncs::AllocateZero(sizeof(Entry*) * newHashSize, alignof(Entry*));
 
 
+		SizedArray<Entry*, 32> entryList;
+
 		for (int hashIdx = 0; hashIdx < mHashSize; hashIdx++)
 		for (int hashIdx = 0; hashIdx < mHashSize; hashIdx++)
 		{
 		{
 			Entry* checkEntry = mHashHeads[hashIdx];
 			Entry* checkEntry = mHashHeads[hashIdx];
-			while (checkEntry != NULL)
+			if (checkEntry != NULL)
 			{
 			{
-				auto nextEntry = checkEntry->mNext;
-				int newHashIdx = (checkEntry->mHash & 0x7FFFFFFF) % newHashSize;
-				checkEntry->mNext = newHashHeads[newHashIdx];
-				newHashHeads[newHashIdx] = checkEntry;
-
-				checkEntry = nextEntry;
+				// We want to keep elements with equal hashes in their insert order so we need to 
+				// iterate through the linked list in reverse
+				entryList.Clear();
+				
+				while (checkEntry != NULL)
+				{
+					entryList.Add(checkEntry);
+					checkEntry = checkEntry->mNext;
+				}
+				
+				for (int i = (int)entryList.mSize - 1; i >= 0; i--)
+				{
+					auto checkEntry = entryList[i];					
+					int newHashIdx = (checkEntry->mHash & 0x7FFFFFFF) % newHashSize;
+					checkEntry->mNext = newHashHeads[newHashIdx];
+					newHashHeads[newHashIdx] = checkEntry;
+				}
 			}
 			}
 		}
 		}
 
 

+ 2 - 1
IDE/dist/lib/gen/src/Program.bf

@@ -12,7 +12,8 @@ namespace gen
 {
 {
 	class Program
 	class Program
 	{
 	{
-		static String[] sNames = new .[]("comdlg32", "gdi32", "kernel32", "ole32", "netapi32", "ntdll", "rpcrt4", "user32", "version", "winmm") ~ delete _;
+		static String[] sNames = new .[]("advapi32", "comdlg32", "crypt32", "d3d11", "dinput8", "gdi32", "kernel32", "ole32", "netapi32",
+			"ntdll", "rpcrt4", "shell32", "shlwapi", "user32", "version", "winmm", "winhttp", "wininet", "WS2_32", "wsock32") ~ delete _;
 
 
 		public static int Main(String[] args)
 		public static int Main(String[] args)
 		{
 		{

+ 47 - 42
IDE/src/BuildContext.bf

@@ -29,12 +29,8 @@ namespace IDE
 		public int32 mUpdateCnt;
 		public int32 mUpdateCnt;
 		public Project mHotProject;
 		public Project mHotProject;
 		public Workspace.Options mWorkspaceOptions;
 		public Workspace.Options mWorkspaceOptions;
-		public Dictionary<Project, String> mImpLibMap = new .() ~
-		{
-			for (let val in _.Values)
-				delete val;
-			delete _;
-		};
+		public Dictionary<Project, String> mImpLibMap = new .() ~ DeleteDictionaryAndValues!(_);
+		public Dictionary<Project, String> mTargetPathMap = new .() ~ DeleteDictionaryAndValues!(_);
 		public ScriptManager.Context mScriptContext = new .() ~ _.ReleaseLastRef();
 		public ScriptManager.Context mScriptContext = new .() ~ _.ReleaseLastRef();
 		public ScriptManager mScriptManager ~ delete _;
 		public ScriptManager mScriptManager ~ delete _;
 
 
@@ -122,7 +118,7 @@ namespace IDE
 
 
 			bool didCommands = false;
 			bool didCommands = false;
 
 
-			let targetName = scope String("Project ", project.mProjectName);
+			//let targetName = scope String("Project ", project.mProjectName);
 
 
 			//Console.WriteLine("Executing custom command {0} {1} {2}", highestDateTime, targetDateTime, forceRebuild);
 			//Console.WriteLine("Executing custom command {0} {1} {2}", highestDateTime, targetDateTime, forceRebuild);
 			for (let origCustomCmd in cmdList)
 			for (let origCustomCmd in cmdList)
@@ -163,19 +159,13 @@ namespace IDE
 					didCommands = true;
 					didCommands = true;
 				}
 				}
 
 
-				mScriptManager.QueueCommands(customCmd, scope String()..AppendF("project {}", project.mProjectName), .NoLines);
+				let scriptCmd = new IDEApp.ScriptCmd();
+				scriptCmd.mCmd = new String(customCmd);
+				scriptCmd.mPath = new $"project {project.mProjectName}";
+				gApp.mExecutionQueue.Add(scriptCmd);
 				continue;
 				continue;
 			}
 			}
 
 
-			let targetCompleteCmd = new IDEApp.TargetCompletedCmd(project);
-			if (didCommands)
-			{
-				mScriptManager.QueueCommands(scope String()..AppendF("%targetComplete {}", project.mProjectName), targetName, .NoLines);
-				targetCompleteCmd.mIsReady = false;
-				project.mNeedsTargetRebuild = true;
-			}
-			gApp.mExecutionQueue.Add(targetCompleteCmd);
-
 			return didCommands ? .HadCommands : .NoCommands;
 			return didCommands ? .HadCommands : .NoCommands;
 		}
 		}
 
 
@@ -874,9 +864,9 @@ namespace IDE
 						minRTModName.Insert(0, "_");
 						minRTModName.Insert(0, "_");
 
 
 					if (!is64Bit)
 					if (!is64Bit)
-						linkLine.Append("-libpath:\"", gApp.mInstallDir, "lib\\x86\" ", gApp.mInstallDir, "lib\\x86\\msvcrt.lib Beef", IDEApp.sRTVersionStr,"MinRT32", minRTModName, ".lib ");
+						linkLine.Append("-libpath:\"", gApp.mInstallDir, "lib\\x86\" \"", gApp.mInstallDir, "lib\\x86\\msvcrt.lib\" Beef", IDEApp.sRTVersionStr,"MinRT32", minRTModName, ".lib ");
 					else
 					else
-						linkLine.Append("-libpath:\"", gApp.mInstallDir, "lib\\x64\" ", gApp.mInstallDir, "lib\\x64\\msvcrt.lib Beef", IDEApp.sRTVersionStr,"MinRT64", minRTModName, ".lib ");
+						linkLine.Append("-libpath:\"", gApp.mInstallDir, "lib\\x64\" \"", gApp.mInstallDir, "lib\\x64\\msvcrt.lib\" Beef", IDEApp.sRTVersionStr,"MinRT64", minRTModName, ".lib ");
 					linkLine.Append("ntdll.lib user32.lib kernel32.lib gdi32.lib winmm.lib shell32.lib ole32.lib rpcrt4.lib version.lib comdlg32.lib -ignore:4049 -ignore:4217 ");
 					linkLine.Append("ntdll.lib user32.lib kernel32.lib gdi32.lib winmm.lib shell32.lib ole32.lib rpcrt4.lib version.lib comdlg32.lib -ignore:4049 -ignore:4217 ");
 				}
 				}
 
 
@@ -1062,17 +1052,8 @@ namespace IDE
 
 
 						IDEUtils.AppendWithOptionalQuotes(linkLine, resOutPath);
 						IDEUtils.AppendWithOptionalQuotes(linkLine, resOutPath);
 					}
 					}
-					
-					let binPath = (!is64Bit) ? gApp.mSettings.mVSSettings.mBin32Path : gApp.mSettings.mVSSettings.mBin64Path;
-					if (binPath.IsWhiteSpace)
-					{
-						gApp.OutputErrorLine("Visual Studio tool path not configured. Check Visual Studio configuration in File\\Preferences\\Settings.");
-						return false;
-					}
 
 
 					String linkerPath = scope String();
 					String linkerPath = scope String();
-					linkerPath.Append(binPath);
-					linkerPath.Append("/link.exe");
 					if (workspaceOptions.mToolsetType == .LLVM)
 					if (workspaceOptions.mToolsetType == .LLVM)
 					{
 					{
 						linkerPath.Clear();
 						linkerPath.Clear();
@@ -1097,6 +1078,17 @@ namespace IDE
 						if ((mPlatformType == .Windows) && (!is64Bit))
 						if ((mPlatformType == .Windows) && (!is64Bit))
 							linkLine.Append(" /safeseh:no");
 							linkLine.Append(" /safeseh:no");
 					}
 					}
+					else
+					{
+						let binPath = (!is64Bit) ? gApp.mSettings.mVSSettings.mBin32Path : gApp.mSettings.mVSSettings.mBin64Path;
+						if (binPath.IsWhiteSpace)
+						{
+							gApp.OutputErrorLine("Visual Studio tool path not configured. Check Visual Studio configuration in File\\Preferences\\Settings.");
+							return false;
+						}
+						linkerPath.Append(binPath);
+						linkerPath.Append("/link.exe");
+					}
 
 
 					if (options.mBuildOptions.mBeefLibType != .DynamicDebug)
 					if (options.mBuildOptions.mBeefLibType != .DynamicDebug)
 					{
 					{
@@ -1216,6 +1208,8 @@ namespace IDE
 				}
 				}
 			}
 			}
 
 
+			mTargetPathMap[project] = new String(targetPath);
+
 			if (hotProject == null)
 			if (hotProject == null)
 			{
 			{
 				switch (QueueProjectCustomBuildCommands(project, targetPath, compileKind.WantsRunAfter ? options.mBuildOptions.mBuildCommandsOnRun : options.mBuildOptions.mBuildCommandsOnCompile, options.mBuildOptions.mPreBuildCmds))
 				switch (QueueProjectCustomBuildCommands(project, targetPath, compileKind.WantsRunAfter ? options.mBuildOptions.mBuildCommandsOnRun : options.mBuildOptions.mBuildCommandsOnCompile, options.mBuildOptions.mPreBuildCmds))
@@ -1226,22 +1220,9 @@ namespace IDE
 					completedCompileCmd.mFailed = true;
 					completedCompileCmd.mFailed = true;
 				}
 				}
 			}
 			}
-
-			void DoPostBuild()
-			{
-				switch (QueueProjectCustomBuildCommands(project, targetPath, compileKind.WantsRunAfter ? options.mBuildOptions.mBuildCommandsOnRun : options.mBuildOptions.mBuildCommandsOnCompile, options.mBuildOptions.mPostBuildCmds))
-				{
-				case .NoCommands:
-				case .HadCommands:
-				case .Failed:
-					completedCompileCmd.mFailed = true;
-				}
-			}
 				
 				
 			if (project.mGeneralOptions.mTargetType == .CustomBuild)
 			if (project.mGeneralOptions.mTargetType == .CustomBuild)
 			{
 			{
-				if (hotProject == null)
-					DoPostBuild();
 				return true; 
 				return true; 
 			}
 			}
 
 
@@ -1402,8 +1383,32 @@ namespace IDE
 					return false;
 					return false;
 			}
 			}
 
 
-			DoPostBuild();
 		    return true;
 		    return true;
 		}
 		}
+
+		public bool QueueProjectPostBuild(Project project, Project hotProject, IDEApp.BuildCompletedCmd completedCompileCmd, List<String> hotFileNames, CompileKind compileKind)
+		{
+			if (hotProject != null)
+				return true;
+
+			Project.Options options = gApp.GetCurProjectOptions(project);
+			if (options == null)
+			    return true;
+
+			String targetPath = null;
+			mTargetPathMap.TryGetValue(project, out targetPath);
+			if (targetPath == null)
+				return false;
+
+			switch (QueueProjectCustomBuildCommands(project, targetPath, compileKind.WantsRunAfter ? options.mBuildOptions.mBuildCommandsOnRun : options.mBuildOptions.mBuildCommandsOnCompile, options.mBuildOptions.mPostBuildCmds))
+			{
+			case .NoCommands:
+			case .HadCommands:
+			case .Failed:
+				completedCompileCmd.mFailed = true;
+			}
+
+			return true;
+		}
 	}
 	}
 }
 }

+ 2 - 1
IDE/src/Debugger/DebugManager.bf

@@ -96,7 +96,8 @@ namespace IDE.Debugger
 			MemoryAddress		= 0x40,
 			MemoryAddress		= 0x40,
 			MemoryWatch			= 0x80,
 			MemoryWatch			= 0x80,
 			Symbol				= 0x100,
 			Symbol				= 0x100,
-			StepIntoCall		= 0x200
+			StepIntoCall		= 0x200,
+			RawStr				= 0x400,
 		}
 		}
 
 
 		[Reflect]
 		[Reflect]

+ 169 - 61
IDE/src/IDEApp.bf

@@ -436,6 +436,12 @@ namespace IDE
 			}
 			}
         }
         }
 
 
+		public class ScriptCmd : ExecutionCmd
+		{
+			public String mCmd ~ delete _;
+			public String mPath ~ delete _;
+		}
+
 		public enum ArgsFileKind
 		public enum ArgsFileKind
 		{
 		{
 			None,
 			None,
@@ -7447,85 +7453,105 @@ namespace IDE
 						return;
 						return;
 				}
 				}
 			}
 			}
+			
+			if ((mKeyChordState != null) && (evt.mKeyCode.IsModifier))
+			{
+				// Ignore
+			}
+			else
+			{
+				var keyState = scope KeyState();
+				keyState.mKeyCode = evt.mKeyCode;
+				keyState.mKeyFlags = evt.mKeyFlags;
 
 
-			var keyState = scope KeyState();
-			keyState.mKeyCode = evt.mKeyCode;
-			keyState.mKeyFlags = evt.mKeyFlags;
+				var curKeyMap = mCommands.mKeyMap;
 
 
-			var curKeyMap = mCommands.mKeyMap;
-			bool hadChordState = mKeyChordState != null;
-			if (mKeyChordState != null)
-				curKeyMap = mKeyChordState.mCommandMap;
-			DeleteAndNullify!(mKeyChordState);
+				bool hadChordState = mKeyChordState != null;
+				if (mKeyChordState != null)
+					curKeyMap = mKeyChordState.mCommandMap;
+				var prevKeyChordState = mKeyChordState;
+				defer delete prevKeyChordState;
+				mKeyChordState = null;
 
 
-			KeyState matchedKey;
-			IDECommandBase commandBase;
-			if (curKeyMap.mMap.TryGet(keyState, out matchedKey, out commandBase))
-			{
-				if (var commandMap = commandBase as CommandMap)
+				KeyState matchedKey;
+				IDECommandBase commandBase;
+
+				bool hadMatch = curKeyMap.mMap.TryGet(keyState, out matchedKey, out commandBase);
+				if ((!hadMatch) && (prevKeyChordState != null))
 				{
 				{
-					mKeyChordState = new .();
-					mKeyChordState.mCommandMap = commandMap;
-					mKeyChordState.mKeyState = matchedKey;
-					evt.mHandled = true;
-					return;
+					// If we have a "Ctrl+A, Ctrl+B" style sequence then also try to match that against "Ctrl+A, B"
+					KeyState rawKeyState = keyState;
+					rawKeyState.mKeyFlags &= ~prevKeyChordState.mKeyState.mKeyFlags;
+					hadMatch = curKeyMap.mMap.TryGet(rawKeyState, out matchedKey, out commandBase);
 				}
 				}
-				else if (var command = commandBase as IDECommand)
+
+				if (hadMatch)
 				{
 				{
-					bool foundMatch = false;
-					if (useFlags != .None)
+					if (var commandMap = commandBase as CommandMap)
+					{
+						mKeyChordState = new .();
+						mKeyChordState.mCommandMap = commandMap;
+						mKeyChordState.mKeyState = matchedKey;
+						evt.mHandled = true;
+						return;
+					}
+					else if (var command = commandBase as IDECommand)
 					{
 					{
-						var checkCommand = command;
-						while (checkCommand != null)
+						bool foundMatch = false;
+						if (useFlags != .None)
 						{
 						{
-							bool matches = checkCommand.mContextFlags == .None;
-							if (checkCommand.mContextFlags.HasFlag(.Editor))
-								matches |= useFlags.HasFlag(.Editor);
-							if (checkCommand.mContextFlags.HasFlag(.MainWindow))
-								matches |= useFlags.HasFlag(.MainWindow);
-							if (checkCommand.mContextFlags.HasFlag(.WorkWindow))
-								matches |= useFlags.HasFlag(.WorkWindow);
-
-							if (matches)
+							var checkCommand = command;
+							while (checkCommand != null)
 							{
 							{
-								checkCommand.mAction();
-								foundMatch = true;
+								bool matches = checkCommand.mContextFlags == .None;
+								if (checkCommand.mContextFlags.HasFlag(.Editor))
+									matches |= useFlags.HasFlag(.Editor);
+								if (checkCommand.mContextFlags.HasFlag(.MainWindow))
+									matches |= useFlags.HasFlag(.MainWindow);
+								if (checkCommand.mContextFlags.HasFlag(.WorkWindow))
+									matches |= useFlags.HasFlag(.WorkWindow);
+	
+								if (matches)
+								{
+									checkCommand.mAction();
+									foundMatch = true;
+								}
+								checkCommand = checkCommand.mNext;
 							}
 							}
-							checkCommand = checkCommand.mNext;
 						}
 						}
-					}
-
-					if (!foundMatch)
-					{
-						var checkCommand = command;
-						while (checkCommand != null)
+	
+						if (!foundMatch)
 						{
 						{
-							if (checkCommand.mContextFlags == .None)
+							var checkCommand = command;
+							while (checkCommand != null)
 							{
 							{
-								checkCommand.mAction();
-								foundMatch = true;
+								if (checkCommand.mContextFlags == .None)
+								{
+									checkCommand.mAction();
+									foundMatch = true;
+								}
+								checkCommand = checkCommand.mNext;
 							}
 							}
-							checkCommand = checkCommand.mNext;
+						}
+	
+						if (foundMatch)
+						{
+							evt.mHandled = true;
+							return;
 						}
 						}
 					}
 					}
-
-					if (foundMatch)
+				}
+				else
+				{
+					// Not found
+					if (hadChordState)
 					{
 					{
+						Beep(.Error);
 						evt.mHandled = true;
 						evt.mHandled = true;
 						return;
 						return;
 					}
 					}
 				}
 				}
 			}
 			}
-			else
-			{
-				// Not found
-				if (hadChordState)
-				{
-					Beep(.Error);
-					evt.mHandled = true;
-					return;
-				}
-			}
 
 
             SourceViewPanel sourceViewPanel = null;
             SourceViewPanel sourceViewPanel = null;
             Widget focusWidget = window.mFocusWidget;
             Widget focusWidget = window.mFocusWidget;
@@ -8256,6 +8282,21 @@ namespace IDE
 					}
 					}
 				}
 				}
 
 
+				if (let scriptCmd = next as ScriptCmd)
+				{
+					if (mBuildContext?.mScriptManager != null)
+					{
+						if (scriptCmd.mCmd != null)
+						{
+							mBuildContext.mScriptManager.QueueCommands(scriptCmd.mCmd, scriptCmd.mPath, .NoLines);
+							DeleteAndNullify!(scriptCmd.mCmd);
+						}
+
+						if (mBuildContext.mScriptManager.HasQueuedCommands)
+							return;
+					}
+				}
+
 				defer delete next;
 				defer delete next;
                 mExecutionQueue.RemoveAt(0);
                 mExecutionQueue.RemoveAt(0);
 
 
@@ -8411,6 +8452,11 @@ namespace IDE
 					if (gApp.mDebugger.mIsRunning)
 					if (gApp.mDebugger.mIsRunning)
 						mProfilePanel.StartProfiling(profileCmd.mThreadId, profileCmd.mDesc, profileCmd.mSampleRate);
 						mProfilePanel.StartProfiling(profileCmd.mThreadId, profileCmd.mDesc, profileCmd.mSampleRate);
 				}
 				}
+				else if (var scriptCmd = next as ScriptCmd)
+				{
+					// Already handled
+					(void)scriptCmd;
+				}
                 else
                 else
                 {
                 {
                     Runtime.FatalError("Unknown command");
                     Runtime.FatalError("Unknown command");
@@ -9163,7 +9209,8 @@ namespace IDE
 
 
         public bool DoResolveConfigString(String platformName, Workspace.Options workspaceOptions, Project project, Project.Options options, StringView configString, String error, String result)
         public bool DoResolveConfigString(String platformName, Workspace.Options workspaceOptions, Project project, Project.Options options, StringView configString, String error, String result)
         {
         {
-			int i = result.Length;
+			int startIdx = result.Length;
+			int i = startIdx;
 			result.Append(configString);
 			result.Append(configString);
 
 
 			bool hadError = false;
 			bool hadError = false;
@@ -9258,6 +9305,28 @@ namespace IDE
 									cmdErr = "Invalid number of arguments";
 									cmdErr = "Invalid number of arguments";
 							case "Var":
 							case "Var":
 								break ReplaceBlock;
 								break ReplaceBlock;
+							case "Arguments",
+								 "BuildDir",
+								 "LinkFlags",
+								 "ProjectDir",
+								 "ProjectName",
+								 "TargetDir",
+								 "TargetPath",
+								 "WorkingDir":
+								var selProject = mWorkspace.FindProject(args[0]);
+								if (selProject != null)
+								{
+									Workspace.Options selWorkspaceOptions = gApp.GetCurWorkspaceOptions();
+									Project.Options selOptions = gApp.GetCurProjectOptions(selProject);
+									String selConfigString = scope $"$({cmd})";
+									replaceStr.Clear();
+									newString = scope:ReplaceBlock .();
+									DoResolveConfigString(platformName, selWorkspaceOptions, selProject, selOptions, selConfigString, error, newString);
+								}
+								else
+									cmdErr = "Unable to find project";
+							default:
+								cmdErr = "Invalid command";
 							}
 							}
 
 
 							if (newString == null)
 							if (newString == null)
@@ -10251,6 +10320,12 @@ namespace IDE
                     success = false;
                     success = false;
             }
             }
 
 
+			for (var project in orderedProjectList)
+			{
+			    if (!mBuildContext.QueueProjectPostBuild(project, hotProject, completedCompileCmd, hotFileNames, compileKind))
+			        success = false;
+			}
+
             if (hotFileNames.Count > 0)
             if (hotFileNames.Count > 0)
             {
             {
 				// Why were we rehupping BEFORE hotLoad?
 				// Why were we rehupping BEFORE hotLoad?
@@ -10430,6 +10505,36 @@ namespace IDE
 #endif
 #endif
 		}
 		}
 
 
+		public bool IsVisualStudioRequired
+		{
+			get
+			{
+				if (Workspace.PlatformType.GetFromName(mPlatformName) != .Windows)
+					return false;
+				var workspaceOptions = GetCurWorkspaceOptions();
+				if (workspaceOptions.mToolsetType != .LLVM)
+					return true;
+
+				for (var project in mWorkspace.mProjects)
+				{
+					if ((project.mGeneralOptions.mTargetType != .BeefConsoleApplication) &&
+						(project.mGeneralOptions.mTargetType != .BeefGUIApplication) &&
+						(project.mGeneralOptions.mTargetType != .BeefApplication_DynamicLib) &&
+						(project.mGeneralOptions.mTargetType != .BeefApplication_StaticLib))
+					{
+						continue;
+					}
+
+					var options = GetCurProjectOptions(project);
+					if (options == null)
+						continue;
+					if (options.mBuildOptions.mCLibType != .SystemMSVCRT)
+						return true;
+				}
+				return false;
+			}
+		}
+
         protected bool Compile(CompileKind compileKind = .Normal, Project hotProject = null)
         protected bool Compile(CompileKind compileKind = .Normal, Project hotProject = null)
         {
         {
 			Debug.Assert(mBuildContext == null);
 			Debug.Assert(mBuildContext == null);
@@ -10604,7 +10709,7 @@ namespace IDE
 				}
 				}
 			}
 			}
 
 
-			if (Workspace.PlatformType.GetFromName(mPlatformName) == .Windows)
+			if ((Workspace.PlatformType.GetFromName(mPlatformName) == .Windows) && (IsVisualStudioRequired))
 			{
 			{
 				if (!mSettings.mVSSettings.IsConfigured())
 				if (!mSettings.mVSSettings.IsConfigured())
 					mSettings.mVSSettings.SetDefaults();
 					mSettings.mVSSettings.SetDefaults();
@@ -10788,8 +10893,8 @@ namespace IDE
 
 
 			//options.mDebugOptions.mCommand
 			//options.mDebugOptions.mCommand
 
 
-            String launchPath = scope String();
-            ResolveConfigString(mPlatformName, workspaceOptions, project, options, options.mDebugOptions.mCommand, "debug command", launchPath);
+            String launchPathRel = scope String();
+            ResolveConfigString(mPlatformName, workspaceOptions, project, options, options.mDebugOptions.mCommand, "debug command", launchPathRel);
             String arguments = scope String();
             String arguments = scope String();
             ResolveConfigString(mPlatformName, workspaceOptions, project, options, "$(Arguments)", "debug command arguments", arguments);
             ResolveConfigString(mPlatformName, workspaceOptions, project, options, "$(Arguments)", "debug command arguments", arguments);
             String workingDirRel = scope String();
             String workingDirRel = scope String();
@@ -10797,6 +10902,9 @@ namespace IDE
 			var workingDir = scope String();
 			var workingDir = scope String();
 			Path.GetAbsolutePath(workingDirRel, project.mProjectDir, workingDir);
 			Path.GetAbsolutePath(workingDirRel, project.mProjectDir, workingDir);
 
 
+			String launchPath = scope String();
+			Path.GetAbsolutePath(launchPathRel, workingDir, launchPath);
+
 			String targetPath = scope .();
 			String targetPath = scope .();
 			ResolveConfigString(mPlatformName, workspaceOptions, project, options, "$(TargetPath)", "Target path", targetPath);
 			ResolveConfigString(mPlatformName, workspaceOptions, project, options, "$(TargetPath)", "Target path", targetPath);
 
 

+ 1 - 1
IDE/src/ScriptManager.bf

@@ -1007,7 +1007,7 @@ namespace IDE
 			if (!gApp.[Friend]mExecutionQueue.IsEmpty)
 			if (!gApp.[Friend]mExecutionQueue.IsEmpty)
 			{
 			{
 				var nextCmd = gApp.mExecutionQueue[0];
 				var nextCmd = gApp.mExecutionQueue[0];
-				if (!(nextCmd is IDEApp.TargetCompletedCmd))
+				if (!(nextCmd is IDEApp.ScriptCmd))
 					return false;
 					return false;
 			}
 			}
 
 

+ 10 - 4
IDE/src/ui/ClassViewPanel.bf

@@ -876,16 +876,22 @@ namespace IDE.ui
 		{
 		{
 			base.Update();
 			base.Update();
 
 
+			if (gApp.mBfResolveCompiler == null)
+				return;
+
 			var focusedItem = (ClassViewListViewItem)mTypeLV.GetRoot().FindFocusedItem();
 			var focusedItem = (ClassViewListViewItem)mTypeLV.GetRoot().FindFocusedItem();
 			var focusedStr = scope String();
 			var focusedStr = scope String();
 			if (focusedItem != null)
 			if (focusedItem != null)
 				GetName(focusedItem, focusedStr);
 				GetName(focusedItem, focusedStr);
 
 
-			int32 compileRevision = gApp.mBfResolveCompiler.GetCompileRevision();
-			if (mLastCompileRevision != compileRevision)
+			if (gApp.mBfResolveCompiler != null)
 			{
 			{
-				mCompileRevisionDirtyDelay = 30;
-				mLastCompileRevision = compileRevision;
+				int32 compileRevision = gApp.mBfResolveCompiler.GetCompileRevision();
+				if (mLastCompileRevision != compileRevision)
+				{
+					mCompileRevisionDirtyDelay = 30;
+					mLastCompileRevision = compileRevision;
+				}
 			}
 			}
 
 
 			if ((mCompileRevisionDirtyDelay > 0) && (--mCompileRevisionDirtyDelay == 0))
 			if ((mCompileRevisionDirtyDelay > 0) && (--mCompileRevisionDirtyDelay == 0))

+ 1 - 1
IDE/src/ui/DisassemblyPanel.bf

@@ -266,7 +266,7 @@ namespace IDE.ui
                 IdSpan liveCharIdData;
                 IdSpan liveCharIdData;
                 String liveText = scope:: String();
                 String liveText = scope:: String();
                 app.FindProjectSourceContent(projectSource, out liveCharIdData, true, liveText, null);
                 app.FindProjectSourceContent(projectSource, out liveCharIdData, true, liveText, null);
-				defer(stack) liveCharIdData.Dispose();
+				defer:: liveCharIdData.Dispose();
                 
                 
                 var compileInstance = IDEApp.sApp.mWorkspace.GetProjectSourceCompileInstance(projectSource, mHotIdx);
                 var compileInstance = IDEApp.sApp.mWorkspace.GetProjectSourceCompileInstance(projectSource, mHotIdx);
                 if (compileInstance == null)
                 if (compileInstance == null)

+ 9 - 1
IDE/src/ui/ErrorsPanel.bf

@@ -276,7 +276,15 @@ namespace IDE.ui
 						SetLabel(item, codeStr);
 						SetLabel(item, codeStr);
 
 
 						let descItem = item.GetSubItem(1);
 						let descItem = item.GetSubItem(1);
-						String errStr = scope String(32)..Append(error.mError);
+						String errStr = scope String(32);
+						int maxLen = 4*1024;
+						if (error.mError.Length > maxLen)
+						{
+							errStr.Append(error.mError.Substring(0, maxLen));
+							errStr.Append("...");
+						}
+						else
+							errStr.Append(error.mError);
 						errStr.Replace('\n', ' ');
 						errStr.Replace('\n', ' ');
 
 
 						SetLabel(descItem, errStr);
 						SetLabel(descItem, errStr);

+ 19 - 2
IDE/src/ui/HoverWatch.bf

@@ -718,6 +718,14 @@ namespace IDE.ui
             var watch = useListViewItem.mWatchEntry;
             var watch = useListViewItem.mWatchEntry;
             String.NewOrSet!(watch.mName, displayString);
             String.NewOrSet!(watch.mName, displayString);
             String.NewOrSet!(watch.mEvalStr, evalString);
             String.NewOrSet!(watch.mEvalStr, evalString);
+
+			if (watch.mEvalStr.StartsWith("!raw"))
+			{
+				for (int i < 4)
+					watch.mEvalStr[i] =  ' ';
+				watch.mResultType = .RawText;
+			}
+
             useListViewItem.mWatchEntry = watch;
             useListViewItem.mWatchEntry = watch;
 			if (!isLiteral)
 			if (!isLiteral)
             	useListViewItem.Label = displayString;
             	useListViewItem.Label = displayString;
@@ -730,7 +738,7 @@ namespace IDE.ui
             String val = scope String();
             String val = scope String();
             if (evalString.StartsWith(":", StringComparison.Ordinal))
             if (evalString.StartsWith(":", StringComparison.Ordinal))
             {
             {
-				var showString = scope String(evalString, 1);
+				var showString = scope String(4096)..Append(evalString, 1);
 				bool isShowingDoc = showString.Contains('\x01');
 				bool isShowingDoc = showString.Contains('\x01');
 				if (!isShowingDoc)
 				if (!isShowingDoc)
 				{
 				{
@@ -759,11 +767,13 @@ namespace IDE.ui
 						flags |= .AllowSideEffects | .AllowCalls;
 						flags |= .AllowSideEffects | .AllowCalls;
 					if (gApp.mSettings.mDebuggerSettings.mAutoEvaluateProperties)
 					if (gApp.mSettings.mDebuggerSettings.mAutoEvaluateProperties)
 						flags |= .AllowProperties;
 						flags |= .AllowProperties;
+					if (watch.mResultType == .RawText)
+						flags |= .RawStr;
 
 
 					DebugManager.Language language = mLanguage;
 					DebugManager.Language language = mLanguage;
 					if (parentWatchEntry != null)
 					if (parentWatchEntry != null)
 						language = parentWatchEntry.mLanguage;
 						language = parentWatchEntry.mLanguage;
-					gApp.DebugEvaluate(null, evalString, val, -1, language, flags);
+					gApp.DebugEvaluate(null, watch.mEvalStr, val, -1, language, flags);
 				}
 				}
 				if (val == "!pending")
 				if (val == "!pending")
 				{
 				{
@@ -773,6 +783,13 @@ namespace IDE.ui
 				}
 				}
 				watch.mIsPending = false;
 				watch.mIsPending = false;
 			}
 			}
+
+			if (watch.mResultType == .RawText)
+			{
+				String.NewOrSet!(valueSubItem.mLabel, val);
+				return useListViewItem;
+			}
+
             var vals = scope List<StringView>(val.Split('\n'));
             var vals = scope List<StringView>(val.Split('\n'));
 
 
 			//if (!vals[0].IsEmpty)
 			//if (!vals[0].IsEmpty)

+ 33 - 3
IDE/src/ui/ImmediateWidget.bf

@@ -7,6 +7,7 @@ using Beefy.theme.dark;
 using Beefy.gfx;
 using Beefy.gfx;
 using System.Diagnostics;
 using System.Diagnostics;
 using System.IO;
 using System.IO;
+using IDE.Debugger;
 
 
 namespace IDE.ui
 namespace IDE.ui
 {
 {
@@ -379,7 +380,11 @@ namespace IDE.ui
 				var subItemLabel = result.GetSubItem(1).mLabel;
 				var subItemLabel = result.GetSubItem(1).mLabel;
 				if (subItemLabel == null)
 				if (subItemLabel == null)
 					subItemLabel = "";
 					subItemLabel = "";
-			    mEditWidgetContent.AppendText(scope String("   ", subItemLabel, "\n"));
+
+				if (result.mWatchEntry.mResultType == .RawText)
+					mEditWidgetContent.AppendText(scope String(subItemLabel, "\n"));
+				else
+			    	mEditWidgetContent.AppendText(scope String("   ", subItemLabel, "\n"));
 
 
 				if (result.mWatchEntry.mWarnings != null)
 				if (result.mWatchEntry.mWarnings != null)
 				{
 				{
@@ -415,7 +420,11 @@ namespace IDE.ui
 			        for (int32 i = startPos; i < mEditWidgetContent.mData.mTextLength; i++)
 			        for (int32 i = startPos; i < mEditWidgetContent.mData.mTextLength; i++)
 			            mEditWidgetContent.mData.mText[i].mDisplayTypeId = (uint8)SourceElementType.Error;
 			            mEditWidgetContent.mData.mText[i].mDisplayTypeId = (uint8)SourceElementType.Error;
 			    }
 			    }
-			    else
+			    else if (result.mWatchEntry.mResultType == .RawText)
+				{
+					// No info button
+				}
+				else
 			    {
 			    {
 			        mInfoButton.Resize(resultX - GS!(3), resultY - GS!(2), GS!(20), GS!(20));
 			        mInfoButton.Resize(resultX - GS!(3), resultY - GS!(2), GS!(20), GS!(20));
 			        mEditWidgetContent.AddWidget(mInfoButton);
 			        mEditWidgetContent.AddWidget(mInfoButton);
@@ -547,7 +556,16 @@ namespace IDE.ui
 				}
 				}
 				else
 				else
 				{
 				{
-	                gApp.DebugEvaluate(null, cmdText, val, mEditWidgetContent.CursorTextPos - mEntryStartPos.mIndex - 2);
+					DebugManager.EvalExpressionFlags flags = .None;
+
+					if (cmdText.StartsWith("!raw"))
+					{
+						for (int i < 4)
+							cmdText[i] = ' ';
+						flags |= .RawStr;
+					}
+
+	                gApp.DebugEvaluate(null, cmdText, val, mEditWidgetContent.CursorTextPos - mEntryStartPos.mIndex - 2, .NotSet, flags);
 					gApp.mIsImmediateDebugExprEval = true;
 					gApp.mIsImmediateDebugExprEval = true;
 				}
 				}
 			}
 			}
@@ -570,7 +588,19 @@ namespace IDE.ui
                     }
                     }
 					var info = scope String()..Append(val, idx + ":autocomplete\n".Length);
 					var info = scope String()..Append(val, idx + ":autocomplete\n".Length);
 					if (!editWidgetContent.mAutoComplete.mIsDocumentationPass)
 					if (!editWidgetContent.mAutoComplete.mIsDocumentationPass)
+					{
+						if ((cmdText.StartsWith("!")) && (!cmdText.Contains(' ')))
+						{
+							if ("!raw".Contains(cmdText))
+								info.Append("cmd\traw\n");
+							if ("!info".Contains(cmdText))
+								info.Append("cmd\tinfo\n");
+							if ("!step".Contains(cmdText))
+								info.Append("cmd\tstep\n");
+						}
+
                     	editWidgetContent.mAutoComplete.SetInfo(info, true, mEntryStartPos.mIndex + 1);
                     	editWidgetContent.mAutoComplete.SetInfo(info, true, mEntryStartPos.mIndex + 1);
+					}
                 }
                 }
                 else if (editWidgetContent.mAutoComplete != null)
                 else if (editWidgetContent.mAutoComplete != null)
                     editWidgetContent.mAutoComplete.Close();                
                     editWidgetContent.mAutoComplete.Close();                

+ 8 - 14
IDE/src/ui/MemoryPanel.bf

@@ -284,26 +284,20 @@ namespace IDE.ui
 							s.AppendF("0x{:A}", (uint64)lockRange.mBaseOffset);
 							s.AppendF("0x{:A}", (uint64)lockRange.mBaseOffset);
                         case RepType.Int8:
                         case RepType.Int8:
 							hasAltS = true;
 							hasAltS = true;
-							(*(int8*)lockRange.mData.CArray()).ToString(s, (altIntBase == 10) ? "" : "X2", null);
-							if (altIntBase == 10)
-								((UInt64)*(uint8*)lockRange.mData.CArray()).ToString(altS, "", null);
+							(*(int8*)lockRange.mData.CArray()).ToString(s, (intBase == 10) ? "" : "X2", null);
+							((UInt64)*(uint8*)lockRange.mData.CArray()).ToString(altS, (altIntBase == 10) ? "" : "X2", null);
                         case RepType.Int16:
                         case RepType.Int16:
 							hasAltS = true;
 							hasAltS = true;
-							(*(int16*)lockRange.mData.CArray()).ToString(s, (altIntBase == 10) ? "" : "X4", null);
-							if (altIntBase == 10)
-								((UInt64)*(uint16*)lockRange.mData.CArray()).ToString(altS, "", null);
+							(*(int16*)lockRange.mData.CArray()).ToString(s, (intBase == 10) ? "" : "X4", null);
+							((UInt64)*(uint16*)lockRange.mData.CArray()).ToString(altS, (altIntBase == 10) ? "" : "X4", null);
                         case RepType.Int32:
                         case RepType.Int32:
 							hasAltS = true;
 							hasAltS = true;
-							(*(int32*)lockRange.mData.CArray()).ToString(s, (altIntBase == 10) ? "" : "X8", null);
-							if (altIntBase == 10)
-								((UInt64)*(uint32*)lockRange.mData.CArray()).ToString(altS, "", null);
+							(*(int32*)lockRange.mData.CArray()).ToString(s, (intBase == 10) ? "" : "X8", null);
+							((UInt64)*(uint32*)lockRange.mData.CArray()).ToString(altS, (altIntBase == 10) ? "" : "X8", null);
                         case RepType.Int64:
                         case RepType.Int64:
 							hasAltS = true;
 							hasAltS = true;
-							(*(int64*)lockRange.mData.CArray()).ToString(s, (altIntBase == 10) ? "" : "X16", null);
-							if (altIntBase == 0x10)
-								s.Insert(8, '\'');
-							if (altIntBase == 10)
-								((UInt64)*(uint64*)lockRange.mData.CArray()).ToString(altS, "", null);
+							(*(int64*)lockRange.mData.CArray()).ToString(s, (intBase == 10) ? "" : "X16", null);
+							((UInt64)*(uint64*)lockRange.mData.CArray()).ToString(altS, (altIntBase == 10) ? "" : "X16", null);
                         case RepType.Float:
                         case RepType.Float:
 							(*(float*)lockRange.mData.CArray()).ToString(s);
 							(*(float*)lockRange.mData.CArray()).ToString(s);
                         case RepType.Double:
                         case RepType.Double:

+ 3 - 2
IDE/src/ui/ProjectPanel.bf

@@ -187,9 +187,10 @@ namespace IDE.ui
 		{
 		{
 			base.FocusForKeyboard();
 			base.FocusForKeyboard();
 			SetFocus();
 			SetFocus();
-			if (mListView.GetRoot().FindFocusedItem() == null)
+			let root = mListView.GetRoot();
+			if (root.IsOpen && root.FindFocusedItem() == null)
 			{
 			{
-				mListView.GetRoot().GetChildAtIndex(0).Focused = true;
+				root.GetChildAtIndex(0).Focused = true;
 			}
 			}
 		}
 		}
 
 

+ 3 - 3
IDE/src/ui/SourceEditWidgetContent.bf

@@ -1244,7 +1244,7 @@ namespace IDE.ui
 			{
 			{
 				var undoBatchStart = new UndoBatchStart("pasteText");
 				var undoBatchStart = new UndoBatchStart("pasteText");
 				mData.mUndoManager.Add(undoBatchStart);
 				mData.mUndoManager.Add(undoBatchStart);
-				defer(stack) mData.mUndoManager.Add(undoBatchStart.mBatchEnd);
+				defer:: mData.mUndoManager.Add(undoBatchStart.mBatchEnd);
 			}
 			}
 
 
 			if (HasSelection())
 			if (HasSelection())
@@ -3644,7 +3644,7 @@ namespace IDE.ui
 
 
             bool hadSuggestion = false;
             bool hadSuggestion = false;
             List<String> suggestions = scope List<String>();
             List<String> suggestions = scope List<String>();
-			defer (scope) ClearAndDeleteItems(suggestions);
+			defer ClearAndDeleteItems(suggestions);
             spellChecker.GetSuggestions(word, suggestions);
             spellChecker.GetSuggestions(word, suggestions);
             for (var suggestion in suggestions)
             for (var suggestion in suggestions)
             {
             {
@@ -3789,7 +3789,7 @@ namespace IDE.ui
 	                                else if (bfSystem != null)
 	                                else if (bfSystem != null)
 	                                {
 	                                {
 	                                    parser = bfSystem.CreateEmptyParser(null);
 	                                    parser = bfSystem.CreateEmptyParser(null);
-										defer(stack) delete parser;
+										defer:: delete parser;
 	                                    var text = scope String();
 	                                    var text = scope String();
 	                                    mEditWidget.GetText(text);
 	                                    mEditWidget.GetText(text);
 	                                    parser.SetSource(text, mSourceViewPanel.mFilePath);
 	                                    parser.SetSource(text, mSourceViewPanel.mFilePath);

+ 7 - 2
IDE/src/ui/SourceViewPanel.bf

@@ -5073,7 +5073,11 @@ namespace IDE.ui
 	                    String showMouseoverString = null;
 	                    String showMouseoverString = null;
 	                    if (bestError.mError != null)
 	                    if (bestError.mError != null)
 	                    {
 	                    {
-	                        showMouseoverString = scope:: String(":", bestError.mError);
+							int maxLen = 16*1024;
+							if (bestError.mError.Length > maxLen)
+	                        	showMouseoverString = scope:: String()..Concat(":", StringView(bestError.mError, 0, maxLen), "...");
+							else
+								showMouseoverString = scope:: String()..Concat(":", bestError.mError);
 
 
 							if (bestError.mMoreInfo != null)
 							if (bestError.mMoreInfo != null)
 							{
 							{
@@ -5676,7 +5680,8 @@ namespace IDE.ui
 				}
 				}
 			}
 			}
 
 
-            UpdateMouseover();            
+			if (gApp.mIsUpdateBatchStart)
+            	UpdateMouseover();
             
             
             var compiler = ResolveCompiler;
             var compiler = ResolveCompiler;
             var bfSystem = BfResolveSystem;
             var bfSystem = BfResolveSystem;

+ 3 - 1
IDE/src/ui/WatchPanel.bf

@@ -27,7 +27,8 @@ namespace IDE.ui
         TypeClass 	= 0x80,
         TypeClass 	= 0x80,
         TypeValueType = 0x100,
         TypeValueType = 0x100,
         Namespace 	= 0x200,
         Namespace 	= 0x200,
-        Text 		= 0x400
+        Text 		= 0x400,
+		RawText		= 0x800
     }
     }
 
 
     public class WatchEntry
     public class WatchEntry
@@ -1740,6 +1741,7 @@ namespace IDE.ui
                 evt.mDragKind = .After;
                 evt.mDragKind = .After;
                 dragTarget = (WatchListViewItem)dragTarget.mParentItem;
                 dragTarget = (WatchListViewItem)dragTarget.mParentItem;
                 evt.mDragTarget = dragTarget;
                 evt.mDragTarget = dragTarget;
+				return;
             }
             }
             if ((dragTarget.mLabel == "") && (dragKind == .After))
             if ((dragTarget.mLabel == "") && (dragKind == .After))
                 dragKind = .Before;            
                 dragKind = .Before;            

+ 5 - 1
IDEHelper/Backend/BeIRCodeGen.cpp

@@ -690,6 +690,8 @@ void BeIRCodeGen::Read(BeValue*& beValue)
 				CMD_PARAM(BeConstant*, initializer);
 				CMD_PARAM(BeConstant*, initializer);
 				CMD_PARAM(String, name);
 				CMD_PARAM(String, name);
 				CMD_PARAM(bool, isTLS);
 				CMD_PARAM(bool, isTLS);
+
+				BF_ASSERT(varType != NULL);
 				
 				
 				auto globalVariable = mBeModule->mGlobalVariables.Alloc();
 				auto globalVariable = mBeModule->mGlobalVariables.Alloc();
 				globalVariable->mModule = mBeModule;
 				globalVariable->mModule = mBeModule;
@@ -1906,7 +1908,9 @@ void BeIRCodeGen::HandleNextCmd()
 			CMD_PARAM(StringT<256>, name);
 			CMD_PARAM(StringT<256>, name);
 			CMD_PARAM(bool, isTLS);
 			CMD_PARAM(bool, isTLS);
 			CMD_PARAM(BeConstant*, initializer);
 			CMD_PARAM(BeConstant*, initializer);
-						
+			
+			BF_ASSERT(varType != NULL);
+
 			auto globalVariable = mBeModule->mGlobalVariables.Alloc();
 			auto globalVariable = mBeModule->mGlobalVariables.Alloc();
 			globalVariable->mModule = mBeModule;
 			globalVariable->mModule = mBeModule;
 			globalVariable->mType = varType;
 			globalVariable->mType = varType;

+ 3 - 3
IDEHelper/Backend/BeMCContext.cpp

@@ -3787,7 +3787,7 @@ BeMCOperand BeMCContext::AllocVirtualReg(BeType* type, int refCount, bool mustBe
 
 
 	if (mDebugging)
 	if (mDebugging)
 	{
 	{
-		if (mcOperand.mVRegIdx == 6)
+		if (mcOperand.mVRegIdx == 227)
 		{
 		{
 			NOP;
 			NOP;
 		}
 		}
@@ -10364,7 +10364,7 @@ bool BeMCContext::DoLegalization()
 									inst->mArg0.mKind = BeMCOperandKind_SymbolAddr;
 									inst->mArg0.mKind = BeMCOperandKind_SymbolAddr;
 								}
 								}
 
 
-								ReplaceWithNewVReg(inst->mArg0, movInstIdx, true, false);
+								ReplaceWithNewVReg(inst->mArg0, movInstIdx, true, false, true);
 								auto vregInfo = GetVRegInfo(inst->mArg0);
 								auto vregInfo = GetVRegInfo(inst->mArg0);
 								vregInfo->mDisableR11 = true;
 								vregInfo->mDisableR11 = true;
 								instIdx += 2;
 								instIdx += 2;
@@ -15842,7 +15842,7 @@ void BeMCContext::Generate(BeFunction* function)
 	mDbgPreferredRegs[32] = X64Reg_R8;*/
 	mDbgPreferredRegs[32] = X64Reg_R8;*/
 
 
 	//mDbgPreferredRegs[8] = X64Reg_RAX;
 	//mDbgPreferredRegs[8] = X64Reg_RAX;
-	//mDebugging = (function->mName == "?ParseRegex@Program@Regex@bf@@CAPEAV?$List@?AUStringView@System@bf@@@Collections@System@3@UStringView@63@0@Z");
+	//mDebugging = (function->mName == "?Zoips@TestProgram@BeefTest@bf@@SAXXZ");
 	//		|| (function->mName == "?MethodA@TestProgram@BeefTest@bf@@CAXXZ");
 	//		|| (function->mName == "?MethodA@TestProgram@BeefTest@bf@@CAXXZ");
 	// 		|| (function->mName == "?Hey@Blurg@bf@@SAXXZ")
 	// 		|| (function->mName == "?Hey@Blurg@bf@@SAXXZ")
 	// 		;
 	// 		;

+ 2 - 1
IDEHelper/Compiler/BfCodeGen.cpp

@@ -439,7 +439,8 @@ void BfCodeGenThread::RunLoop()
 							errorMsg += "\n";
 							errorMsg += "\n";
 						errorMsg += "Failed writing IR '" + fileName + "': " + ec.message();						
 						errorMsg += "Failed writing IR '" + fileName + "': " + ec.message();						
 					}
 					}
-					fs.WriteSNZ(str);
+					else
+						fs.WriteSNZ(str);
 				}
 				}
 
 
 				if (!hasCacheMatch)
 				if (!hasCacheMatch)

+ 43 - 44
IDEHelper/Compiler/BfCompiler.cpp

@@ -341,11 +341,10 @@ BfCompiler::HotResolveData::~HotResolveData()
 
 
 BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
 BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
 {
 {
-	//llvm::DebugFlag = true;
-
 	memset(&mStats, 0, sizeof(mStats));
 	memset(&mStats, 0, sizeof(mStats));
 	mCompletionPct = 0;	
 	mCompletionPct = 0;	
 	mCanceling = false;
 	mCanceling = false;
+	mHasRequiredTypes = false;
 	mNeedsFullRefresh = false;
 	mNeedsFullRefresh = false;
 	mFastFinish = false;
 	mFastFinish = false;
 	mHasQueuedTypeRebuilds = false;
 	mHasQueuedTypeRebuilds = false;
@@ -399,6 +398,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
 	mDbgRawAllocDataTypeDef = NULL;
 	mDbgRawAllocDataTypeDef = NULL;
 	mDeferredCallTypeDef = NULL;
 	mDeferredCallTypeDef = NULL;
 	mDelegateTypeDef = NULL;	
 	mDelegateTypeDef = NULL;	
+	mFunctionTypeDef = NULL;
 	mActionTypeDef = NULL;
 	mActionTypeDef = NULL;
 	mEnumTypeDef = NULL;
 	mEnumTypeDef = NULL;
 	mFriendAttributeTypeDef = NULL;
 	mFriendAttributeTypeDef = NULL;
@@ -406,8 +406,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
 	mConstEvalAttributeTypeDef = NULL;
 	mConstEvalAttributeTypeDef = NULL;
 	mNoExtensionAttributeTypeDef = NULL;
 	mNoExtensionAttributeTypeDef = NULL;
 	mCheckedAttributeTypeDef = NULL;
 	mCheckedAttributeTypeDef = NULL;
-	mUncheckedAttributeTypeDef = NULL;
-	mFunctionTypeDef = NULL;
+	mUncheckedAttributeTypeDef = NULL;	
 	mGCTypeDef = NULL;
 	mGCTypeDef = NULL;
 	mGenericIEnumerableTypeDef = NULL;
 	mGenericIEnumerableTypeDef = NULL;
 	mGenericIEnumeratorTypeDef = NULL;
 	mGenericIEnumeratorTypeDef = NULL;
@@ -2146,7 +2145,7 @@ void BfCompiler::UpdateDependencyMap(bool deleteUnusued, bool& didWork)
 		madeFullPass = false;
 		madeFullPass = false;
 	if ((mResolvePassData != NULL) && (mResolvePassData->mParser != NULL))
 	if ((mResolvePassData != NULL) && (mResolvePassData->mParser != NULL))
 		madeFullPass = false;
 		madeFullPass = false;
-
+	
 	SetAndRestoreValue<bool> prevAssertOnPopulateType(mContext->mAssertOnPopulateType, deleteUnusued && madeFullPass);
 	SetAndRestoreValue<bool> prevAssertOnPopulateType(mContext->mAssertOnPopulateType, deleteUnusued && madeFullPass);
 
 
 	if ((deleteUnusued) && (madeFullPass))
 	if ((deleteUnusued) && (madeFullPass))
@@ -5107,6 +5106,18 @@ void BfCompiler::MarkStringPool(BfModule* module)
 		stringPoolEntry.mLastUsedRevision = mRevision;
 		stringPoolEntry.mLastUsedRevision = mRevision;
 	}
 	}
 
 
+	for (int stringId : module->mUnreifiedStringPoolRefs)
+	{
+		BfStringPoolEntry& stringPoolEntry = module->mContext->mStringObjectIdMap[stringId];
+		stringPoolEntry.mLastUsedRevision = mRevision;
+	}
+
+	for (int stringId : module->mImportFileNames)
+	{
+		BfStringPoolEntry& stringPoolEntry = module->mContext->mStringObjectIdMap[stringId];
+		stringPoolEntry.mLastUsedRevision = mRevision;
+	}
+
 	/*if (module->mOptModule != NULL)
 	/*if (module->mOptModule != NULL)
 		MarkStringPool(module->mOptModule);*/
 		MarkStringPool(module->mOptModule);*/
 	auto altModule = module->mNextAltModule;
 	auto altModule = module->mNextAltModule;
@@ -5220,7 +5231,7 @@ int BfCompiler::GetVTableMethodOffset()
 bool BfCompiler::DoWorkLoop(bool onlyReifiedTypes, bool onlyReifiedMethods)
 bool BfCompiler::DoWorkLoop(bool onlyReifiedTypes, bool onlyReifiedMethods)
 {
 {
 	bool hadAnyWork = false;
 	bool hadAnyWork = false;
-
+	
 	while (true)
 	while (true)
 	{
 	{
 		bool didWork = false;		
 		bool didWork = false;		
@@ -6596,7 +6607,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	
 	
 	BpEnter("Compile_Start");
 	BpEnter("Compile_Start");
 
 
-	bool hasRequiredTypes = true;
+	mHasRequiredTypes = true;
 
 
 	//HashSet<BfTypeDef*> internalTypeDefs;
 	//HashSet<BfTypeDef*> internalTypeDefs;
 
 
@@ -6606,7 +6617,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 		if (typeDef == NULL)
 		if (typeDef == NULL)
 		{
 		{
 			mPassInstance->Fail(StrFormat("Unable to find system type: %s", typeName.c_str()));
 			mPassInstance->Fail(StrFormat("Unable to find system type: %s", typeName.c_str()));
-			hasRequiredTypes = false;
+			mHasRequiredTypes = false;
 		}		
 		}		
 		return typeDef;
 		return typeDef;
 	};
 	};
@@ -6654,6 +6665,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	mDbgRawAllocDataTypeDef = _GetRequiredType("System.DbgRawAllocData");
 	mDbgRawAllocDataTypeDef = _GetRequiredType("System.DbgRawAllocData");
 	mDeferredCallTypeDef = _GetRequiredType("System.DeferredCall");
 	mDeferredCallTypeDef = _GetRequiredType("System.DeferredCall");
 	mDelegateTypeDef = _GetRequiredType("System.Delegate");
 	mDelegateTypeDef = _GetRequiredType("System.Delegate");
+	mFunctionTypeDef = _GetRequiredType("System.Function");
 	mActionTypeDef = _GetRequiredType("System.Action");
 	mActionTypeDef = _GetRequiredType("System.Action");
 	mEnumTypeDef = _GetRequiredType("System.Enum");
 	mEnumTypeDef = _GetRequiredType("System.Enum");
 	mFriendAttributeTypeDef = _GetRequiredType("System.FriendAttribute");
 	mFriendAttributeTypeDef = _GetRequiredType("System.FriendAttribute");
@@ -6662,8 +6674,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	mNoExtensionAttributeTypeDef = _GetRequiredType("System.NoExtensionAttribute");
 	mNoExtensionAttributeTypeDef = _GetRequiredType("System.NoExtensionAttribute");
 	mCheckedAttributeTypeDef = _GetRequiredType("System.CheckedAttribute");
 	mCheckedAttributeTypeDef = _GetRequiredType("System.CheckedAttribute");
 	mUncheckedAttributeTypeDef = _GetRequiredType("System.UncheckedAttribute");
 	mUncheckedAttributeTypeDef = _GetRequiredType("System.UncheckedAttribute");
-	mResultTypeDef = _GetRequiredType("System.Result", 1);
-	mFunctionTypeDef = _GetRequiredType("System.Function");
+	mResultTypeDef = _GetRequiredType("System.Result", 1);	
 	mGCTypeDef = _GetRequiredType("System.GC");	
 	mGCTypeDef = _GetRequiredType("System.GC");	
 	mGenericIEnumerableTypeDef = _GetRequiredType("System.Collections.IEnumerable", 1);
 	mGenericIEnumerableTypeDef = _GetRequiredType("System.Collections.IEnumerable", 1);
 	mGenericIEnumeratorTypeDef = _GetRequiredType("System.Collections.IEnumerator", 1);
 	mGenericIEnumeratorTypeDef = _GetRequiredType("System.Collections.IEnumerator", 1);
@@ -6722,21 +6733,17 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	mContext->mBfTypeType = NULL;
 	mContext->mBfTypeType = NULL;
 	mContext->mBfClassVDataPtrType = NULL;
 	mContext->mBfClassVDataPtrType = NULL;
 
 
-	if (!hasRequiredTypes)
-	{
-		// Force rebuilding
-		BfLogSysM("Compile missing required types\n");
-		mInInvalidState = true;
-		mOptions.mForceRebuildIdx++;
-		return true;
-	}
+ 	if (!mHasRequiredTypes)
+ 	{
+ 		// Force rebuilding
+ 		BfLogSysM("Compile missing required types\n");
+ 		mOptions.mForceRebuildIdx++;
+ 	}	
 		
 		
 	mSystem->CheckLockYield();
 	mSystem->CheckLockYield();
 
 
 	mContext->mScratchModule->ResolveTypeDef(mBfObjectTypeDef);
 	mContext->mScratchModule->ResolveTypeDef(mBfObjectTypeDef);
-	VisitSourceExteriorNodes();
-
-	//BF_ASSERT(hasRequiredTypes);
+	VisitSourceExteriorNodes();	
 
 
 	if (!mIsResolveOnly)
 	if (!mIsResolveOnly)
 	{
 	{
@@ -6811,19 +6818,14 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 
 
 	if (mIsResolveOnly)
 	if (mIsResolveOnly)
 		VisitAutocompleteExteriorIdentifiers();	
 		VisitAutocompleteExteriorIdentifiers();	
-
-	if (!hasRequiredTypes)
-	{
-		BfLogSysM("Missing required types\n");		
-	}
-
+	
 	mStats.mTypesQueued = 0;
 	mStats.mTypesQueued = 0;
 	mStats.mMethodsQueued = 0;
 	mStats.mMethodsQueued = 0;
 	
 	
 	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 (hasRequiredTypes)
+	//
 	{		
 	{		
 		mContext->mScratchModule->ResolveTypeDef(mBfObjectTypeDef, BfPopulateType_Full);
 		mContext->mScratchModule->ResolveTypeDef(mBfObjectTypeDef, BfPopulateType_Full);
 		
 		
@@ -6864,9 +6866,8 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 			}
 			}
 		}						
 		}						
 	}
 	}
-	
-	if (hasRequiredTypes)
-		ProcessPurgatory(true);
+		
+	ProcessPurgatory(true);
 
 
 	// Mark used modules
 	// Mark used modules
 	if ((mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude) && (!mCanceling))
 	if ((mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude) && (!mCanceling))
@@ -6967,7 +6968,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	}
 	}
 
 
 	// Generate slot nums
 	// Generate slot nums
-	if ((!mIsResolveOnly) && (hasRequiredTypes) && (!mCanceling))
+	if ((!mIsResolveOnly) && (!mCanceling))
 	{
 	{
 		if ((!IsHotCompile()) || (mHotState->mHasNewInterfaceTypes))
 		if ((!IsHotCompile()) || (mHotState->mHasNewInterfaceTypes))
 		{	
 		{	
@@ -6996,7 +6997,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 				}
 				}
 			}
 			}
 		}		
 		}		
-
+		
 		DoWorkLoop();
 		DoWorkLoop();
 
 
 		BfLogSysM("Compile QueueUnused\n");
 		BfLogSysM("Compile QueueUnused\n");
@@ -7098,13 +7099,12 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	{
 	{
 		DoWorkLoop();
 		DoWorkLoop();
 	}
 	}
-	
-	if (hasRequiredTypes)
-		ProcessPurgatory(false);
+		
+	ProcessPurgatory(false);
 	
 	
 	// Old Mark used modules	
 	// Old Mark used modules	
 
 
-	if ((!mIsResolveOnly) && (hasRequiredTypes))
+	if (!mIsResolveOnly)
 	{	
 	{	
 // 		if ((!mPassInstance->HasFailed()) && (!mCanceling))
 // 		if ((!mPassInstance->HasFailed()) && (!mCanceling))
 // 		{
 // 		{
@@ -7161,7 +7161,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 
 
 	String moduleListStr;
 	String moduleListStr;
 	int numModulesWritten = 0;
 	int numModulesWritten = 0;
-	if ((hasRequiredTypes) && (!mCanceling))
+	if (!mCanceling)
 	{
 	{
 		if (!mIsResolveOnly)
 		if (!mIsResolveOnly)
 		{
 		{
@@ -7250,9 +7250,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	//printf("Compile done, waiting for finish\n");
 	//printf("Compile done, waiting for finish\n");
 
 
 	while (true)
 	while (true)
-	{
-		if (!hasRequiredTypes)
-			break;
+	{		
 		if (mCanceling)
 		if (mCanceling)
 			mCodeGen.Cancel();
 			mCodeGen.Cancel();
 		bool isDone = mCodeGen.Finish();
 		bool isDone = mCodeGen.Finish();
@@ -7391,8 +7389,8 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 // 	gBEMemReporter.Report();
 // 	gBEMemReporter.Report();
 // 	int memReporterSize = gBEMemReporterSize;
 // 	int memReporterSize = gBEMemReporterSize;
 
 
-	mLastRevisionAborted = mCanceling || !hasRequiredTypes;
-	bool didCancel = mCanceling && hasRequiredTypes;
+	mLastRevisionAborted = mCanceling;
+	bool didCancel = mCanceling;
 	mCanceling = false;
 	mCanceling = false;
 
 
 	mContext->ValidateDependencies();
 	mContext->ValidateDependencies();
@@ -8961,9 +8959,10 @@ BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetTypeInfo(BfCompiler* bfCompiler,
 	SetAndRestoreValue<bool> prevIgnoreWarnings(bfCompiler->mContext->mScratchModule->mIgnoreWarnings, true);
 	SetAndRestoreValue<bool> prevIgnoreWarnings(bfCompiler->mContext->mScratchModule->mIgnoreWarnings, true);
 	SetAndRestoreValue<BfResolvePassData*> prevResolvePass(bfCompiler->mResolvePassData, &resolvePass);	
 	SetAndRestoreValue<BfResolvePassData*> prevResolvePass(bfCompiler->mResolvePassData, &resolvePass);	
 
 
-	auto type = bfCompiler->mContext->mScratchModule->ResolveTypeRef(typeRef, BfPopulateType_Data, BfResolveTypeRefFlag_NoCreate);
+	auto type = bfCompiler->mContext->mScratchModule->ResolveTypeRef(typeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_NoCreate);
 	if (type != NULL)
 	if (type != NULL)
 	{
 	{
+		bfCompiler->mContext->mScratchModule->PopulateType(type);
 		outString += "Found";
 		outString += "Found";
 		if (auto typeInst = type->ToTypeInstance())
 		if (auto typeInst = type->ToTypeInstance())
 		{
 		{

+ 3 - 2
IDEHelper/Compiler/BfCompiler.h

@@ -323,6 +323,7 @@ public:
 	BfCodeGen mCodeGen;
 	BfCodeGen mCodeGen;
 	String mOutputDirectory;
 	String mOutputDirectory;
 	bool mCanceling;
 	bool mCanceling;
+	bool mHasRequiredTypes;
 	bool mNeedsFullRefresh;
 	bool mNeedsFullRefresh;
 	bool mFastFinish;
 	bool mFastFinish;
 	bool mHasQueuedTypeRebuilds; // Infers we had a fast finish that requires a type rebuild
 	bool mHasQueuedTypeRebuilds; // Infers we had a fast finish that requires a type rebuild
@@ -352,14 +353,14 @@ public:
 	BfTypeDef* mDbgRawAllocDataTypeDef;
 	BfTypeDef* mDbgRawAllocDataTypeDef;
 	BfTypeDef* mDeferredCallTypeDef;		
 	BfTypeDef* mDeferredCallTypeDef;		
 	BfTypeDef* mDelegateTypeDef;
 	BfTypeDef* mDelegateTypeDef;
+	BfTypeDef* mFunctionTypeDef;
 	BfTypeDef* mActionTypeDef;
 	BfTypeDef* mActionTypeDef;
 	BfTypeDef* mEnumTypeDef;
 	BfTypeDef* mEnumTypeDef;
 	BfTypeDef* mStringTypeDef;
 	BfTypeDef* mStringTypeDef;
 	BfTypeDef* mStringViewTypeDef;
 	BfTypeDef* mStringViewTypeDef;
 	BfTypeDef* mTypeTypeDef;
 	BfTypeDef* mTypeTypeDef;
 	BfTypeDef* mValueTypeTypeDef;	
 	BfTypeDef* mValueTypeTypeDef;	
-	BfTypeDef* mResultTypeDef;
-	BfTypeDef* mFunctionTypeDef;
+	BfTypeDef* mResultTypeDef;	
 	BfTypeDef* mGCTypeDef;	
 	BfTypeDef* mGCTypeDef;	
 	BfTypeDef* mGenericIEnumerableTypeDef;
 	BfTypeDef* mGenericIEnumerableTypeDef;
 	BfTypeDef* mGenericIEnumeratorTypeDef;
 	BfTypeDef* mGenericIEnumeratorTypeDef;

+ 20 - 11
IDEHelper/Compiler/BfConstResolver.cpp

@@ -35,7 +35,7 @@ BfConstResolver::BfConstResolver(BfModule* bfModule) : BfExprEvaluator(bfModule)
 }
 }
 
 
 BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfConstResolveFlags flags)
 BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfConstResolveFlags flags)
-{	
+{
 	mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_Comptime);
 	mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_Comptime);
 
 
 	// Handle the 'int[?] val = .(1, 2, 3)' case
 	// Handle the 'int[?] val = .(1, 2, 3)' case
@@ -137,11 +137,11 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo
 					int stringId = mModule->GetStringPoolIdx(mResult.mValue);					
 					int stringId = mModule->GetStringPoolIdx(mResult.mValue);					
 					if (stringId != -1)
 					if (stringId != -1)
 					{
 					{
-						if ((flags & BfConstResolveFlag_RemapFromStringId) != 0)
+						if ((flags & BfConstResolveFlag_ActualizeValues) != 0)
 						{
 						{
 							prevIgnoreWrites.Restore();
 							prevIgnoreWrites.Restore();
 							mModule->mBfIRBuilder->PopulateType(mResult.mType);
 							mModule->mBfIRBuilder->PopulateType(mResult.mType);
-							return BfTypedValue(mModule->GetStringObjectValue(stringId), mResult.mType);
+							return BfTypedValue(mModule->GetStringObjectValue(stringId, false, true), mResult.mType);
 						}
 						}
 
 
 						return BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_StringId, stringId), toType);
 						return BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_StringId, stringId), toType);
@@ -232,7 +232,9 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo
 	}*/
 	}*/
 
 
 	mModule->FixIntUnknown(mResult);	
 	mModule->FixIntUnknown(mResult);	
-	mModule->FixValueActualization(mResult);
+
+	if ((flags & BfConstResolveFlag_NoActualizeValues) == 0)
+		mModule->FixValueActualization(mResult, !prevIgnoreWrites.mPrevVal || ((flags & BfConstResolveFlag_ActualizeValues) != 0));
 
 
 	return mResult;
 	return mResult;
 }
 }
@@ -416,15 +418,22 @@ bool BfConstResolver::PrepareMethodArguments(BfAstNode* targetSrc, BfMethodMatch
 		}
 		}
 		else
 		else
 		{	
 		{	
-			if ((argValue.mValue.IsFake()) && (!argValue.mType->IsValuelessType()))
-			{
-				if ((mModule->mCurMethodInstance == NULL) || (mModule->mCurMethodInstance->mMethodDef->mMethodType != BfMethodType_Mixin))
-				{
-					mModule->Fail("Expression does not evaluate to a constant value", argExpr);
-				}
+			bool requiresConst = false;
+			if ((mModule->mCurMethodInstance == NULL) || (mModule->mCurMethodInstance->mMethodDef->mMethodType != BfMethodType_Mixin))
+				requiresConst = true;
+
+			if ((requiresConst) && (argValue.mValue.IsFake()) && (!argValue.mType->IsValuelessType()))
+			{				
+				mModule->Fail("Expression does not evaluate to a constant value", argExpr);				
 			}
 			}
 
 
-			llvmArgs.push_back(argValue.mValue);
+			if (!argValue.mType->IsVar())
+			{
+				if ((!requiresConst) || (argValue.mValue.IsConst()) || (argValue.mType->IsValuelessType()))
+					llvmArgs.push_back(argValue.mValue);
+				else
+					llvmArgs.push_back(mModule->GetDefaultValue(argValue.mType));
+			}
 			paramIdx++;
 			paramIdx++;
 		}
 		}
 		argIdx++;
 		argIdx++;

+ 5 - 4
IDEHelper/Compiler/BfConstResolver.h

@@ -15,9 +15,10 @@ enum BfConstResolveFlags
 	BfConstResolveFlag_ExplicitCast = 1,
 	BfConstResolveFlag_ExplicitCast = 1,
 	BfConstResolveFlag_NoCast = 2,
 	BfConstResolveFlag_NoCast = 2,
 	BfConstResolveFlag_AllowSoftFail = 4,
 	BfConstResolveFlag_AllowSoftFail = 4,
-	BfConstResolveFlag_RemapFromStringId = 8,
-	BfConstResolveFlag_ArrayInitSize = 0x10,
-	BfConstResolveFlag_AllowGlobalVariable = 0x20,
+	BfConstResolveFlag_ActualizeValues = 8,
+	BfConstResolveFlag_NoActualizeValues = 0x10,
+	BfConstResolveFlag_ArrayInitSize = 0x20,
+	BfConstResolveFlag_AllowGlobalVariable = 0x40,
 };
 };
 
 
 class BfConstResolver : public BfExprEvaluator
 class BfConstResolver : public BfExprEvaluator
@@ -33,7 +34,7 @@ public:
 	BfConstResolver(BfModule* bfModule);		
 	BfConstResolver(BfModule* bfModule);		
 
 
 	BfTypedValue Resolve(BfExpression* expr, BfType* wantType = NULL, BfConstResolveFlags flags = BfConstResolveFlag_None);
 	BfTypedValue Resolve(BfExpression* expr, BfType* wantType = NULL, BfConstResolveFlags flags = BfConstResolveFlag_None);
-	bool PrepareMethodArguments(BfAstNode* targetSrc, BfMethodMatcher* methodMatcher, Array<BfIRValue>& llvmArgs);			
+	bool PrepareMethodArguments(BfAstNode* targetSrc, BfMethodMatcher* methodMatcher, Array<BfIRValue>& llvmArgs);
 };
 };
 
 
 NS_BF_END
 NS_BF_END

+ 15 - 10
IDEHelper/Compiler/BfContext.cpp

@@ -829,8 +829,7 @@ void BfContext::ValidateDependencies()
 void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuildModule, bool placeSpecializiedInPurgatory)
 void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuildModule, bool placeSpecializiedInPurgatory)
 {
 {
 	BfTypeInstance* typeInst = type->ToTypeInstance();		
 	BfTypeInstance* typeInst = type->ToTypeInstance();		
-	
-	
+		
 	if (type->IsDeleting())
 	if (type->IsDeleting())
 	{
 	{
 		return;
 		return;
@@ -2517,11 +2516,6 @@ void BfContext::QueueMethodSpecializations(BfTypeInstance* typeInst, bool checkS
 	
 	
 	BP_ZONE("BfContext::QueueMethodSpecializations");
 	BP_ZONE("BfContext::QueueMethodSpecializations");
 
 
-	if (typeInst->mTypeId == 578)
-	{
-		NOP;
-	}
-
 	auto module = typeInst->mModule;
 	auto module = typeInst->mModule;
 	if (module == NULL)
 	if (module == NULL)
 		return;
 		return;
@@ -2917,10 +2911,21 @@ void BfContext::Cleanup()
 
 
 	// Clean up deleted BfTypes
 	// Clean up deleted BfTypes
 	// These need to get deleted before the modules because we access mModule in the MethodInstance dtors
 	// These need to get deleted before the modules because we access mModule in the MethodInstance dtors
-	for (auto type : mTypeGraveyard)
+	for (int pass = 0; pass < 2; pass++)
 	{
 	{
-		BF_ASSERT(type->mRebuildFlags & BfTypeRebuildFlag_Deleted);
-		delete type;
+		for (int i = 0; i < (int)mTypeGraveyard.size(); i++)		
+		{
+			auto type = mTypeGraveyard[i];
+			if (type == NULL)
+				continue;
+			bool deleteNow = (type->IsBoxed() == (pass == 0));
+			if (!deleteNow)
+				continue;
+
+			BF_ASSERT(type->mRebuildFlags & BfTypeRebuildFlag_Deleted);
+			delete type;
+			mTypeGraveyard[i] = NULL;
+		}
 	}
 	}
 	mTypeGraveyard.Clear();
 	mTypeGraveyard.Clear();
 
 

+ 3 - 1
IDEHelper/Compiler/BfContext.h

@@ -143,10 +143,11 @@ public:
 
 
 	BfPopulateType mPopulateType;
 	BfPopulateType mPopulateType;
 	BfTypeReference* mCurBaseTypeRef;
 	BfTypeReference* mCurBaseTypeRef;
+	BfTypeInstance* mCurBaseType;
 	BfTypeReference* mCurAttributeTypeRef;
 	BfTypeReference* mCurAttributeTypeRef;
 	BfFieldDef* mCurFieldDef;	
 	BfFieldDef* mCurFieldDef;	
 	BfTypeDef* mCurTypeDef;
 	BfTypeDef* mCurTypeDef;
-	BfTypeDef* mForceActiveTypeDef;
+	BfTypeDef* mForceActiveTypeDef;	
 	ResolveKind mResolveKind;
 	ResolveKind mResolveKind;
 	BfAstNode* mCurVarInitializer;
 	BfAstNode* mCurVarInitializer;
 	int mArrayInitializerSize;
 	int mArrayInitializerSize;
@@ -160,6 +161,7 @@ public:
 
 
 		mPopulateType = BfPopulateType_Identity;
 		mPopulateType = BfPopulateType_Identity;
 		mCurBaseTypeRef = NULL;
 		mCurBaseTypeRef = NULL;
+		mCurBaseType = NULL;
 		mCurFieldDef = NULL;
 		mCurFieldDef = NULL;
 		mCurAttributeTypeRef = NULL;
 		mCurAttributeTypeRef = NULL;
 		mCurTypeDef = NULL;
 		mCurTypeDef = NULL;

+ 23 - 31
IDEHelper/Compiler/BfDefBuilder.cpp

@@ -443,17 +443,7 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
 		{
 		{
 			methodDef->mIsConcrete = true;
 			methodDef->mIsConcrete = true;
 			methodDef->mIsVirtual = false;
 			methodDef->mIsVirtual = false;
-		}
-
-		if (mCurTypeDef->mTypeCode == BfTypeCode_Interface)
-		{
-			//
-		}
-		else
-		{
-			if (methodDef->mIsConcrete)
-				Fail("Only interfaces methods can be declared as 'concrete'", methodDeclaration->mVirtualSpecifier);
-		}
+		}		
 
 
 		if (methodDef->mIsAbstract)
 		if (methodDef->mIsAbstract)
 		{
 		{
@@ -1775,24 +1765,21 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 		bool doInsertNew = true;
 		bool doInsertNew = true;
 		if (prevRevisionTypeDef != NULL)
 		if (prevRevisionTypeDef != NULL)
 		{
 		{
-			mCurTypeDef->mIsNextRevision = true;			
+			mCurTypeDef->mIsNextRevision = true;
 			bfParser->mTypeDefs.Add(prevRevisionTypeDef);
 			bfParser->mTypeDefs.Add(prevRevisionTypeDef);
 
 
 			if (prevRevisionTypeDef->mDefState == BfTypeDef::DefState_AwaitingNewVersion)
 			if (prevRevisionTypeDef->mDefState == BfTypeDef::DefState_AwaitingNewVersion)
 			{
 			{
-				delete prevRevisionTypeDef->mNextRevision;
+				if (prevRevisionTypeDef->mNextRevision != NULL)
+				{
+					BfLogSysM("Deleting unused nextRevision %p from prevRevision %p\n", prevRevisionTypeDef->mNextRevision, prevRevisionTypeDef);
+					delete prevRevisionTypeDef->mNextRevision;
+				}
 				prevRevisionTypeDef->mNextRevision = mCurTypeDef;
 				prevRevisionTypeDef->mNextRevision = mCurTypeDef;
 				BF_ASSERT(mCurTypeDef->mSystem != NULL);
 				BF_ASSERT(mCurTypeDef->mSystem != NULL);
 				mCurActualTypeDef = prevRevisionTypeDef;
 				mCurActualTypeDef = prevRevisionTypeDef;
 				doInsertNew = false;
 				doInsertNew = false;
-			}
-			else
-			{
-				if (prevRevisionTypeDef->mNextRevision != NULL)
-					prevRevisionTypeDef = prevRevisionTypeDef->mNextRevision;
-
-				prevRevisionTypeDef = NULL;
-			}
+			}			
 		}
 		}
 		else
 		else
 		{
 		{
@@ -1820,8 +1807,8 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 		outerTypeDef->mNestedTypes.push_back(mCurActualTypeDef);
 		outerTypeDef->mNestedTypes.push_back(mCurActualTypeDef);
 	}
 	}
 
 
-	BfLogSysM("Creating TypeDef %p Hash:%d from TypeDecl: %p Source: %p ResolvePass: %d AutoComplete:%d\n", mCurTypeDef, mSystem->mTypeDefs.GetHash(mCurTypeDef), typeDeclaration, 
-		typeDeclaration->GetSourceData(), mResolvePassData != NULL, isAutoCompleteTempType);				
+	BfLogSysM("Creating TypeDef %p Hash:%d from TypeDecl: %p Source: %p ResolvePass: %d AutoComplete:%d PrevRevision:%d\n", mCurTypeDef, mSystem->mTypeDefs.GetHash(mCurTypeDef), typeDeclaration, 
+		typeDeclaration->GetSourceData(), mResolvePassData != NULL, isAutoCompleteTempType, prevRevisionTypeDef);				
 	
 	
 	BF_ASSERT(mCurTypeDef->mNameEx == NULL);
 	BF_ASSERT(mCurTypeDef->mNameEx == NULL);
 	
 	
@@ -1875,9 +1862,9 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 
 
 		if (mCurTypeDef->mFullHash == prevRevisionTypeDef->mFullHash)
 		if (mCurTypeDef->mFullHash == prevRevisionTypeDef->mFullHash)
 		{
 		{
-			if (!mFullRefresh)
+			if ((!mFullRefresh) && (!prevRevisionTypeDef->mForceUseNextRevision))
 			{
 			{
-				BfLogSys(bfParser->mSystem, "DefBuilder deleting typeDef with no changes %p\n", prevRevisionTypeDef);
+				BfLogSys(bfParser->mSystem, "DefBuilder deleting typeDef with no changes %p prevRevision: %p\n", mCurTypeDef, prevRevisionTypeDef);
 				prevRevisionTypeDef->mDefState = BfTypeDef::DefState_Defined;
 				prevRevisionTypeDef->mDefState = BfTypeDef::DefState_Defined;
 				BF_ASSERT(prevRevisionTypeDef->mNextRevision == mCurTypeDef);
 				BF_ASSERT(prevRevisionTypeDef->mNextRevision == mCurTypeDef);
 				prevRevisionTypeDef->mNextRevision = NULL;
 				prevRevisionTypeDef->mNextRevision = NULL;
@@ -1918,9 +1905,10 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 	BfMethodDef* dynamicCastMethod = NULL;
 	BfMethodDef* dynamicCastMethod = NULL;
 	BfMethodDef* toStringMethod = NULL;
 	BfMethodDef* toStringMethod = NULL;
 	bool needsEqualsMethod = ((mCurTypeDef->mTypeCode == BfTypeCode_Struct) || (mCurTypeDef->mTypeCode == BfTypeCode_Enum)) && (!mCurTypeDef->mIsStatic);	
 	bool needsEqualsMethod = ((mCurTypeDef->mTypeCode == BfTypeCode_Struct) || (mCurTypeDef->mTypeCode == BfTypeCode_Enum)) && (!mCurTypeDef->mIsStatic);	
+	BfMethodDef* equalsOpMethod = NULL;
 	BfMethodDef* equalsMethod = NULL;
 	BfMethodDef* equalsMethod = NULL;
-	BfMethodDef* strictEqualsMethod = NULL;
-	
+	BfMethodDef* strictEqualsMethod = NULL;	
+
 	bool needsStaticInit = false;
 	bool needsStaticInit = false;
 	for (int methodIdx = 0; methodIdx < (int)mCurTypeDef->mMethods.size(); methodIdx++)
 	for (int methodIdx = 0; methodIdx < (int)mCurTypeDef->mMethods.size(); methodIdx++)
 	{
 	{
@@ -1962,7 +1950,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 
 
 				auto ctorDeclaration = (BfConstructorDeclaration*)method->mMethodDeclaration;
 				auto ctorDeclaration = (BfConstructorDeclaration*)method->mMethodDeclaration;
 				if (method->mHasAppend)
 				if (method->mHasAppend)
-				{										
+				{				 						
 					mCurTypeDef->mHasAppendCtor = true;
 					mCurTypeDef->mHasAppendCtor = true;
 
 
 					auto methodDef = new BfMethodDef();
 					auto methodDef = new BfMethodDef();
@@ -2038,6 +2026,10 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 			{
 			{
 				if (method->mName == BF_METHODNAME_MARKMEMBERS_STATIC)
 				if (method->mName == BF_METHODNAME_MARKMEMBERS_STATIC)
 					_SetMethod(staticMarkMethod, method);
 					_SetMethod(staticMarkMethod, method);
+				if (method->mName == BF_METHODNAME_DEFAULT_EQUALS)
+					_SetMethod(equalsMethod, method);
+				if (method->mName == BF_METHODNAME_DEFAULT_STRICT_EQUALS)
+					_SetMethod(strictEqualsMethod, method);
 			}
 			}
 			else
 			else
 			{
 			{
@@ -2061,7 +2053,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 					if ((method->mParams[0]->mTypeRef->ToString() == mCurTypeDef->mName->ToString()) &&
 					if ((method->mParams[0]->mTypeRef->ToString() == mCurTypeDef->mName->ToString()) &&
 						(method->mParams[1]->mTypeRef->ToString() == mCurTypeDef->mName->ToString()))
 						(method->mParams[1]->mTypeRef->ToString() == mCurTypeDef->mName->ToString()))
 					{
 					{
-						_SetMethod(equalsMethod, method);
+						_SetMethod(equalsOpMethod, method);
 					}
 					}
 				}
 				}
 			}			
 			}			
@@ -2300,7 +2292,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 		methodDef->mAddedAfterEmit = mIsComptime;
 		methodDef->mAddedAfterEmit = mIsComptime;
 	}
 	}
 	
 	
-	if ((needsEqualsMethod) && (equalsMethod == NULL))
+	if ((needsEqualsMethod) && (equalsMethod == NULL) && (equalsOpMethod == NULL))
 	{		
 	{		
 		auto methodDef = new BfMethodDef();
 		auto methodDef = new BfMethodDef();
 		mCurTypeDef->mMethods.push_back(methodDef);
 		mCurTypeDef->mMethods.push_back(methodDef);
@@ -2314,7 +2306,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 		methodDef->mAddedAfterEmit = mIsComptime;
 		methodDef->mAddedAfterEmit = mIsComptime;
 	}
 	}
 
 
-	if (needsEqualsMethod)
+	if ((needsEqualsMethod) && (strictEqualsMethod == NULL))
 	{
 	{
 		auto methodDef = new BfMethodDef();
 		auto methodDef = new BfMethodDef();
 		mCurTypeDef->mMethods.push_back(methodDef);
 		mCurTypeDef->mMethods.push_back(methodDef);

+ 138 - 75
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -4248,6 +4248,14 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
 		mModule->PopulateType(startCheckType, BfPopulateType_BaseType);
 		mModule->PopulateType(startCheckType, BfPopulateType_BaseType);
 	}
 	}
 
 
+	if ((startCheckType != NULL) && (mModule->mContext->mCurTypeState != NULL))
+	{
+		// Don't allow lookups yet
+		if ((mModule->mContext->mCurTypeState->mResolveKind == BfTypeState::ResolveKind_Attributes) &&
+			(startCheckType == mModule->mContext->mCurTypeState->mTypeInstance))
+			return BfTypedValue();
+	}
+
 	String findName;
 	String findName;
 	int varSkipCount = 0;
 	int varSkipCount = 0;
 	if (fieldName.StartsWith('@'))
 	if (fieldName.StartsWith('@'))
@@ -4627,6 +4635,8 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
 
 
 				bool doAccessCheck = true;
 				bool doAccessCheck = true;
 
 
+				if ((flags & BfLookupFieldFlag_BindOnly) != 0)
+					doAccessCheck = false;
 				if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL) && (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mDisableObjectAccessChecksAttributeTypeDef)))
 				if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL) && (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mDisableObjectAccessChecksAttributeTypeDef)))
 					doAccessCheck = false;
 					doAccessCheck = false;
 
 
@@ -4853,7 +4863,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
 					}
 					}
 
 
 					// Check for direct auto-property access
 					// Check for direct auto-property access
-					if (startCheckType == mModule->mCurTypeInstance)
+					if ((startCheckType == mModule->mCurTypeInstance) && ((flags & BfLookupFieldFlag_BindOnly) == 0))
 					{
 					{
 						if (auto propertyDeclaration = BfNodeDynCast<BfPropertyDeclaration>(mPropDef->mFieldDeclaration))
 						if (auto propertyDeclaration = BfNodeDynCast<BfPropertyDeclaration>(mPropDef->mFieldDeclaration))
 						{
 						{
@@ -10104,19 +10114,22 @@ void BfExprEvaluator::Visit(BfTypeOfExpression* typeOfExpr)
 
 
 bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifierNode* propName)
 bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifierNode* propName)
 {
 {
-	// We ignore errors because we go through the normal Visit(BfTypeOfExpression) if this fails, which will throw the error again
-	SetAndRestoreValue<bool> prevIgnoreErrors(mModule->mIgnoreErrors, true);
-
 	auto typeType = mModule->ResolveTypeDef(mModule->mCompiler->mTypeTypeDef);
 	auto typeType = mModule->ResolveTypeDef(mModule->mCompiler->mTypeTypeDef);
 	
 	
 	BfType* type;
 	BfType* type;
-	if (auto genericTypeRef = BfNodeDynCast<BfGenericInstanceTypeRef>(typeOfExpr->mTypeRef))
-	{
-		type = mModule->ResolveTypeRefAllowUnboundGenerics(typeOfExpr->mTypeRef, BfPopulateType_Identity);
-	}
-	else
+	//
 	{
 	{
-		type = ResolveTypeRef(typeOfExpr->mTypeRef, BfPopulateType_Identity);
+		// We ignore errors because we go through the normal Visit(BfTypeOfExpression) if this fails, which will throw the error again
+		SetAndRestoreValue<bool> prevIgnoreErrors(mModule->mIgnoreErrors, true);
+		if (auto genericTypeRef = BfNodeDynCast<BfGenericInstanceTypeRef>(typeOfExpr->mTypeRef))
+		{
+			SetAndRestoreValue<bool> prevIgnoreErrors(mModule->mIgnoreErrors, true);
+			type = mModule->ResolveTypeRefAllowUnboundGenerics(typeOfExpr->mTypeRef, BfPopulateType_Identity);
+		}
+		else
+		{
+			type = ResolveTypeRef(typeOfExpr->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_IgnoreLookupError);
+		}
 	}
 	}
 
 
 	if (type == NULL)
 	if (type == NULL)
@@ -10206,11 +10219,42 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie
 	else if ((memberName == "MinValue") || (memberName == "MaxValue"))
 	else if ((memberName == "MinValue") || (memberName == "MaxValue"))
 	{
 	{
 		bool isMin = memberName == "MinValue";
 		bool isMin = memberName == "MinValue";
-				
-		BfType* checkType = typeInstance;
+		
+		BfType* checkType = type;
 		if (checkType->IsTypedPrimitive())
 		if (checkType->IsTypedPrimitive())
 			checkType = checkType->GetUnderlyingType();
 			checkType = checkType->GetUnderlyingType();
 
 
+		if (checkType->IsGenericParam())
+		{
+			bool foundMatch = false;
+
+			auto genericParamInstance = mModule->GetGenericParamInstance((BfGenericParamType*)checkType);
+			if (((genericParamInstance->mGenericParamFlags & BfGenericParamFlag_Enum) != 0) ||
+				((genericParamInstance->mTypeConstraint != NULL) && (genericParamInstance->mTypeConstraint->IsInstanceOf(mModule->mCompiler->mEnumTypeDef))))
+				foundMatch = true;			
+
+			if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized) && (mModule->mCurMethodInstance->mMethodInfoEx != NULL))
+			{
+				for (int genericParamIdx = (int)mModule->mCurMethodInstance->mMethodInfoEx->mMethodGenericArguments.size();
+					genericParamIdx < mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++)
+				{
+					genericParamInstance = mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx];
+					if (genericParamInstance->mExternType == type)
+					{
+						if (((genericParamInstance->mGenericParamFlags & BfGenericParamFlag_Enum) != 0) ||
+							((genericParamInstance->mTypeConstraint != NULL) && (genericParamInstance->mTypeConstraint->IsInstanceOf(mModule->mCompiler->mEnumTypeDef))))
+							foundMatch = true;
+					}
+				}
+			}
+
+			if (foundMatch)
+			{
+				mResult = mModule->GetDefaultTypedValue(type, false, Beefy::BfDefaultValueKind_Undef);
+				return true;
+			}
+		}
+
 		if (checkType->IsPrimitiveType())
 		if (checkType->IsPrimitiveType())
 		{
 		{
 			auto primType = (BfPrimitiveType*)checkType;
 			auto primType = (BfPrimitiveType*)checkType;
@@ -10257,15 +10301,15 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie
 				default: break;
 				default: break;
 				}
 				}
 			}
 			}
-		}
+		}		
 		
 		
-		if (typeInstance->IsEnum())
+		if (type->IsEnum())
 		{
 		{
-			mModule->Fail("'MinValue' cannot be used on enums with payloads", propName);			
+			mModule->Fail(StrFormat("'MinValue' cannot be used on enum with payload '%s'", mModule->TypeToString(type).c_str()), propName);
 		}
 		}
 		else 
 		else 
 		{
 		{
-			mModule->Fail(StrFormat("'%s' cannot be used on type '%s'", memberName.c_str(), mModule->TypeToString(typeInstance).c_str()), propName);
+			mModule->Fail(StrFormat("'%s' cannot be used on type '%s'", memberName.c_str(), mModule->TypeToString(type).c_str()), propName);
 		}
 		}
 	}	
 	}	
 	else
 	else
@@ -11923,17 +11967,18 @@ void BfExprEvaluator::VisitLambdaBodies(BfAstNode* body, BfFieldDtorDeclaration*
 	if (auto blockBody = BfNodeDynCast<BfBlock>(body))
 	if (auto blockBody = BfNodeDynCast<BfBlock>(body))
 		mModule->VisitChild(blockBody);
 		mModule->VisitChild(blockBody);
 	else if (auto bodyExpr = BfNodeDynCast<BfExpression>(body))
 	else if (auto bodyExpr = BfNodeDynCast<BfExpression>(body))
-	{
+	{		
 		auto result = mModule->CreateValueFromExpression(bodyExpr);
 		auto result = mModule->CreateValueFromExpression(bodyExpr);
 		if ((result) && (mModule->mCurMethodState->mClosureState != NULL) &&
 		if ((result) && (mModule->mCurMethodState->mClosureState != NULL) &&
 			(mModule->mCurMethodState->mClosureState->mReturnTypeInferState == BfReturnTypeInferState_Inferring))
 			(mModule->mCurMethodState->mClosureState->mReturnTypeInferState == BfReturnTypeInferState_Inferring))
-			mModule->mCurMethodState->mClosureState->mReturnType = result.mType;
+			mModule->mCurMethodState->mClosureState->mReturnType = result.mType;		
 	}
 	}
 	
 	
 	while (fieldDtor != NULL)
 	while (fieldDtor != NULL)
 	{
 	{
+		mModule->mCurMethodState->mLeftBlockUncond = false;
 		mModule->VisitChild(fieldDtor->mBody);
 		mModule->VisitChild(fieldDtor->mBody);
-		fieldDtor = fieldDtor->mNextFieldDtor;
+		fieldDtor = fieldDtor->mNextFieldDtor;		
 	}
 	}
 }
 }
 
 
@@ -13829,6 +13874,9 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs
 			mModule->Fail("Too many array dimensions, consider using a jagged array.", objCreateExpr);
 			mModule->Fail("Too many array dimensions, consider using a jagged array.", objCreateExpr);
 		}
 		}
 
 
+		if (arrayType == NULL)
+			return;
+
 		if (isAppendAlloc)
 		if (isAppendAlloc)
 			arrayValue = BfTypedValue(mModule->AppendAllocFromType(resultType, BfIRValue(), 0, arraySize, (int)dimLengthVals.size(), isRawArrayAlloc, zeroMemory), arrayType);
 			arrayValue = BfTypedValue(mModule->AppendAllocFromType(resultType, BfIRValue(), 0, arraySize, (int)dimLengthVals.size(), isRawArrayAlloc, zeroMemory), arrayType);
 		else
 		else
@@ -14790,7 +14838,15 @@ BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfAstNode* targetSrc,
 		if (unspecializedMethod == NULL)
 		if (unspecializedMethod == NULL)
 			unspecializedMethod = mModule->GetRawMethodInstance(curTypeInst, methodDef);
 			unspecializedMethod = mModule->GetRawMethodInstance(curTypeInst, methodDef);
 
 
-		BfType* specializedReturnType = mModule->ResolveGenericType(unspecializedMethod->mReturnType, NULL, &methodMatcher.mBestMethodGenericArguments);
+		BfTypeVector* typeGenericArgs = NULL;
+		auto typeUnspecMethodInstance = unspecializedMethod;
+		if (curTypeInst->IsUnspecializedTypeVariation())
+		{
+			typeUnspecMethodInstance = mModule->GetUnspecializedMethodInstance(typeUnspecMethodInstance, true);
+			typeGenericArgs = &curTypeInst->mGenericTypeInfo->mTypeGenericArguments;
+		}	
+		
+		BfType* specializedReturnType = mModule->ResolveGenericType(typeUnspecMethodInstance->mReturnType, typeGenericArgs, &methodMatcher.mBestMethodGenericArguments);
 		if (specializedReturnType != NULL)
 		if (specializedReturnType != NULL)
 			*overrideReturnType = specializedReturnType;
 			*overrideReturnType = specializedReturnType;
 	}
 	}
@@ -18711,10 +18767,10 @@ void BfExprEvaluator::Visit(BfTupleExpression* tupleExpr)
 	int valueIdx = -1;
 	int valueIdx = -1;
 	for (int fieldIdx = 0; fieldIdx < (int)tupleType->mFieldInstances.size(); fieldIdx++)
 	for (int fieldIdx = 0; fieldIdx < (int)tupleType->mFieldInstances.size(); fieldIdx++)
 	{
 	{
-		BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx];
+		BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx];		
+		++valueIdx;		
 		if (fieldInstance->mResolvedType->IsValuelessType())
 		if (fieldInstance->mResolvedType->IsValuelessType())
 			continue;
 			continue;
-		++valueIdx;
 		auto typedVal = typedValues[valueIdx];
 		auto typedVal = typedValues[valueIdx];
 		if (!typedVal)
 		if (!typedVal)
 		{
 		{
@@ -20399,11 +20455,70 @@ void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExp
 		}
 		}
 		return;
 		return;
 	}
 	}
-	
+
 	BfType* wantType = leftValue.mType;
 	BfType* wantType = leftValue.mType;
 	if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift))
 	if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift))
 		wantType = NULL; // Don't presume
 		wantType = NULL; // Don't presume
 	wantType = mModule->FixIntUnknown(wantType);
 	wantType = mModule->FixIntUnknown(wantType);
+
+	if ((binaryOp == BfBinaryOp_NullCoalesce) && (leftValue) && ((leftValue.mType->IsPointer()) || (leftValue.mType->IsFunction()) || (leftValue.mType->IsObject())))
+	{
+		auto prevBB = mModule->mBfIRBuilder->GetInsertBlock();
+
+		auto rhsBB = mModule->mBfIRBuilder->CreateBlock("nullc.rhs");
+		auto endBB = mModule->mBfIRBuilder->CreateBlock("nullc.end");
+
+		BfIRValue isNull;
+		if (leftValue.mType->IsFunction())
+			isNull = mModule->mBfIRBuilder->CreateIsNull(
+				mModule->mBfIRBuilder->CreateIntToPtr(leftValue.mValue, mModule->mBfIRBuilder->MapType(mModule->GetPrimitiveType(BfTypeCode_NullPtr))));
+		else
+			isNull = mModule->mBfIRBuilder->CreateIsNull(leftValue.mValue);
+		mModule->mBfIRBuilder->CreateCondBr(isNull, rhsBB, endBB);
+
+		mModule->AddBasicBlock(rhsBB);
+		rightValue = mModule->CreateValueFromExpression(rightExpression, wantType, (BfEvalExprFlags)((mBfEvalExprFlags & BfEvalExprFlags_InheritFlags) | BfEvalExprFlags_NoCast));
+		if (!rightValue)
+		{
+			mModule->AssertErrorState();
+			return;
+		}
+		else
+		{
+			auto rightToLeftValue = mModule->CastToValue(rightExpression, rightValue, leftValue.mType, BfCastFlags_SilentFail);
+			if (rightToLeftValue)
+			{
+				rightValue = BfTypedValue(rightToLeftValue, leftValue.mType);
+			}
+			else
+			{
+				auto leftToRightValue = mModule->CastToValue(leftExpression, leftValue, rightValue.mType, BfCastFlags_SilentFail);
+				if (leftToRightValue)
+				{
+					leftValue = BfTypedValue(leftToRightValue, rightValue.mType);
+				}
+				else
+				{
+					// Note: Annoying trigraph split for '??'
+					mModule->Fail(StrFormat("Operator '?" "?' cannot be applied to operands of type '%s' and '%s'",
+						mModule->TypeToString(leftValue.mType).c_str(), mModule->TypeToString(rightValue.mType).c_str()), opToken);
+					leftValue = mModule->GetDefaultTypedValue(rightValue.mType);
+				}
+			}
+		}
+
+		mModule->mBfIRBuilder->CreateBr(endBB);
+
+		auto endRhsBB = mModule->mBfIRBuilder->GetInsertBlock();
+		mModule->AddBasicBlock(endBB);
+		auto phi = mModule->mBfIRBuilder->CreatePhi(mModule->mBfIRBuilder->MapType(leftValue.mType), 2);
+		mModule->mBfIRBuilder->AddPhiIncoming(phi, leftValue.mValue, prevBB);
+		mModule->mBfIRBuilder->AddPhiIncoming(phi, rightValue.mValue, endRhsBB);
+		mResult = BfTypedValue(phi, leftValue.mType);
+
+		return;
+	}
+	
 	rightValue = mModule->CreateValueFromExpression(rightExpression, wantType, (BfEvalExprFlags)((mBfEvalExprFlags & BfEvalExprFlags_InheritFlags) | BfEvalExprFlags_NoCast));
 	rightValue = mModule->CreateValueFromExpression(rightExpression, wantType, (BfEvalExprFlags)((mBfEvalExprFlags & BfEvalExprFlags_InheritFlags) | BfEvalExprFlags_NoCast));
 	if ((!leftValue) || (!rightValue))
 	if ((!leftValue) || (!rightValue))
 		return;
 		return;
@@ -20611,58 +20726,6 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
 			return;
 			return;
 	}
 	}
 
 
-	if ((binaryOp == BfBinaryOp_NullCoalesce) && ((leftValue.mType->IsPointer()) || (leftValue.mType->IsObject())))
-	{
-		auto prevBB = mModule->mBfIRBuilder->GetInsertBlock();
-
-		auto rhsBB = mModule->mBfIRBuilder->CreateBlock("nullc.rhs");
-		auto endBB = mModule->mBfIRBuilder->CreateBlock("nullc.end");
-
-		auto isNull = mModule->mBfIRBuilder->CreateIsNull(leftValue.mValue);
-		mModule->mBfIRBuilder->CreateCondBr(isNull, rhsBB, endBB);
-
-		mModule->AddBasicBlock(rhsBB);		
-		if (!rightValue)			
-		{
-			mModule->AssertErrorState();
-			return;
-		}
-		else
-		{
-			auto rightToLeftValue = mModule->CastToValue(rightExpression, rightValue, leftValue.mType, BfCastFlags_SilentFail);
-			if (rightToLeftValue)
-			{
-				rightValue = BfTypedValue(rightToLeftValue, leftValue.mType);
-			}
-			else
-			{
-				auto leftToRightValue = mModule->CastToValue(leftExpression, leftValue, rightValue.mType, BfCastFlags_SilentFail);
-				if (leftToRightValue)
-				{
-					leftValue = BfTypedValue(leftToRightValue, rightValue.mType);
-				}
-				else
-				{
-					// Note: Annoying trigraph split for '??'
-					mModule->Fail(StrFormat("Operator '?" "?' cannot be applied to operands of type '%s' and '%s'",
-						mModule->TypeToString(leftValue.mType).c_str(), mModule->TypeToString(rightValue.mType).c_str()), opToken);					
-					leftValue = mModule->GetDefaultTypedValue(rightValue.mType);
-				}
-			}
-		}
-
-		mModule->mBfIRBuilder->CreateBr(endBB);
-
-		auto endRhsBB = mModule->mBfIRBuilder->GetInsertBlock();
-		mModule->AddBasicBlock(endBB);		
-		auto phi = mModule->mBfIRBuilder->CreatePhi(mModule->mBfIRBuilder->MapType(leftValue.mType), 2);
-		mModule->mBfIRBuilder->AddPhiIncoming(phi, leftValue.mValue, prevBB);
-		mModule->mBfIRBuilder->AddPhiIncoming(phi, rightValue.mValue, endRhsBB);
-		mResult = BfTypedValue(phi, leftValue.mType);
-		
-		return;
-	}
-
 	if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift))
 	if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift))
 	{
 	{
 		forceLeftType = true;		
 		forceLeftType = true;		

+ 38 - 37
IDEHelper/Compiler/BfIRBuilder.cpp

@@ -615,17 +615,7 @@ BfIRValue BfIRConstHolder::CreateConst(BfConstant* fromConst, BfIRConstHolder* f
 	else if (fromConst->mConstType == BfConstType_GlobalVar)
 	else if (fromConst->mConstType == BfConstType_GlobalVar)
 	{
 	{
 		auto fromGlobalVar = (BfGlobalVar*)fromConst;
 		auto fromGlobalVar = (BfGlobalVar*)fromConst;
-		auto constGV = mTempAlloc.Alloc<BfGlobalVar>();
-		chunkId = mTempAlloc.GetChunkedId(constGV);
-		constGV->mStreamId = -1;
-		constGV->mConstType = BfConstType_GlobalVar;
-		constGV->mType = fromGlobalVar->mType;
-		constGV->mIsConst = fromGlobalVar->mIsConst;
-		constGV->mLinkageType = fromGlobalVar->mLinkageType;
-		constGV->mInitializer = fromGlobalVar->mInitializer;
-		constGV->mName = AllocStr(fromGlobalVar->mName);
-		constGV->mIsTLS = fromGlobalVar->mIsTLS;
-		copiedConst = (BfConstant*)constGV;
+		return CreateGlobalVariableConstant(fromGlobalVar->mType, fromGlobalVar->mIsConst, fromGlobalVar->mLinkageType, fromGlobalVar->mInitializer, fromGlobalVar->mName, fromGlobalVar->mIsTLS);
 	}
 	}
 	else if (fromConst->mConstType == BfConstType_GEP32_2)
 	else if (fromConst->mConstType == BfConstType_GEP32_2)
 	{
 	{
@@ -1875,6 +1865,7 @@ void BfIRBuilder::ClearConstData()
 	mTempAlloc.Clear();
 	mTempAlloc.Clear();
 	mConstMemMap.Clear();
 	mConstMemMap.Clear();
 	mFunctionMap.Clear();
 	mFunctionMap.Clear();
+	mGlobalVarMap.Clear();
 	BF_ASSERT(mMethodTypeMap.GetCount() == 0);
 	BF_ASSERT(mMethodTypeMap.GetCount() == 0);
 	BF_ASSERT(mTypeMap.GetCount() == 0);
 	BF_ASSERT(mTypeMap.GetCount() == 0);
 	BF_ASSERT(mDITemporaryTypes.size() == 0);
 	BF_ASSERT(mDITemporaryTypes.size() == 0);
@@ -1889,6 +1880,7 @@ void BfIRBuilder::ClearNonConstData()
 {
 {
 	mMethodTypeMap.Clear();
 	mMethodTypeMap.Clear();
 	mFunctionMap.Clear();
 	mFunctionMap.Clear();
+	mGlobalVarMap.Clear();
 	mTypeMap.Clear();
 	mTypeMap.Clear();
 	mConstMemMap.Clear();
 	mConstMemMap.Clear();
 	mDITemporaryTypes.Clear();
 	mDITemporaryTypes.Clear();
@@ -2996,11 +2988,6 @@ void BfIRBuilder::CreateDbgTypeDefinition(BfType* type)
 
 
 						if (fieldInstance->mConstIdx != -1)
 						if (fieldInstance->mConstIdx != -1)
 						{
 						{
-							if (fieldInstance->GetFieldDef()->mName == "mMembers")
-							{
-								NOP;
-							}
-
 							constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx);
 							constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx);
 							staticValue = mModule->ConstantToCurrent(constant, typeInstance->mConstHolder, resolvedFieldType);
 							staticValue = mModule->ConstantToCurrent(constant, typeInstance->mConstHolder, resolvedFieldType);
 						}
 						}
@@ -4743,39 +4730,53 @@ BfIRValue BfIRBuilder::CreateStackRestore(BfIRValue stackVal)
 	return retVal;
 	return retVal;
 }
 }
 
 
-BfIRValue BfIRBuilder::CreateGlobalVariable(BfIRType varType, bool isConstant, BfIRLinkageType linkageType, BfIRValue initializer, const StringImpl& name, bool isTLS)
+void BfIRBuilder::CreateGlobalVariable(BfIRValue irValue)
+{
+	auto globalVar = (BfGlobalVar*)GetConstant(irValue);
+	
+	if ((!mIgnoreWrites) && (globalVar->mStreamId == -1))
+	{
+		if (globalVar->mInitializer)
+			mHasGlobalDefs = true;
+
+		BfIRValue retVal = WriteCmd(BfIRCmd_GlobalVariable, globalVar->mType, globalVar->mIsConst, (uint8)globalVar->mLinkageType, String(globalVar->mName), globalVar->mIsTLS, globalVar->mInitializer);
+		globalVar->mStreamId = retVal.mId;
+
+		NEW_CMD_INSERTED_IRVALUE;		
+	}
+}
+
+BfIRValue BfIRConstHolder::CreateGlobalVariableConstant(BfIRType varType, bool isConstant, BfIRLinkageType linkageType, BfIRValue initializer, const StringImpl& name, bool isTLS)
 {
 {
+	BfIRValue* valuePtr = NULL;
+	if ((!mGlobalVarMap.TryAdd(name, NULL, &valuePtr)) && (!initializer))
+	{
+		return *valuePtr;
+	}
+
 	BF_ASSERT(varType);
 	BF_ASSERT(varType);
 
 
 	auto constGV = mTempAlloc.Alloc<BfGlobalVar>();
 	auto constGV = mTempAlloc.Alloc<BfGlobalVar>();
 	int chunkId = mTempAlloc.GetChunkedId(constGV);
 	int chunkId = mTempAlloc.GetChunkedId(constGV);
 	constGV->mStreamId = -1;
 	constGV->mStreamId = -1;
- 	constGV->mConstType = BfConstType_GlobalVar;
-	constGV->mType = varType;	
+	constGV->mConstType = BfConstType_GlobalVar;
+	constGV->mType = varType;
 	constGV->mIsConst = isConstant;
 	constGV->mIsConst = isConstant;
 	constGV->mLinkageType = linkageType;
 	constGV->mLinkageType = linkageType;
 	constGV->mInitializer = initializer;
 	constGV->mInitializer = initializer;
 	constGV->mName = AllocStr(name);
 	constGV->mName = AllocStr(name);
-	constGV->mIsTLS = isTLS;	
+	constGV->mIsTLS = isTLS;
 
 
-	if (!mIgnoreWrites)
-	{
-		if (initializer)
-			mHasGlobalDefs = true;
-
-		BfIRValue retVal = WriteCmd(BfIRCmd_GlobalVariable, varType, isConstant, (uint8)linkageType, name, isTLS, initializer);
-		constGV->mStreamId = retVal.mId;
-		retVal.mFlags = BfIRValueFlags_Const;
-#ifdef CHECK_CONSTHOLDER
-		retVal.mHolder = this;
-#endif
-		retVal.mId = chunkId;
-		NEW_CMD_INSERTED_IRVALUE;
-		return retVal;
-	}	
+	auto irValue = BfIRValue(BfIRValueFlags_Const, chunkId);;
+	*valuePtr = irValue;
+	return irValue;
+}
 
 
-	auto irValue = BfIRValue(BfIRValueFlags_Const, chunkId);
-	return irValue;	
+BfIRValue BfIRBuilder::CreateGlobalVariable(BfIRType varType, bool isConstant, BfIRLinkageType linkageType, BfIRValue initializer, const StringImpl& name, bool isTLS)
+{
+	auto irValue = CreateGlobalVariableConstant(varType, isConstant, linkageType, initializer, name, isTLS);	
+	CreateGlobalVariable(irValue);
+	return irValue;
 }
 }
 
 
 void BfIRBuilder::GlobalVar_SetUnnamedAddr(BfIRValue val, bool unnamedAddr)
 void BfIRBuilder::GlobalVar_SetUnnamedAddr(BfIRValue val, bool unnamedAddr)

+ 4 - 1
IDEHelper/Compiler/BfIRBuilder.h

@@ -901,6 +901,7 @@ class BfIRConstHolder
 public:
 public:
 	BumpAllocatorT<256> mTempAlloc;
 	BumpAllocatorT<256> mTempAlloc;
 	BfModule* mModule;
 	BfModule* mModule;
+	Dictionary<String, BfIRValue> mGlobalVarMap;
 	
 	
 public:
 public:
 	void FixTypeCode(BfTypeCode& typeCode);
 	void FixTypeCode(BfTypeCode& typeCode);
@@ -936,6 +937,7 @@ public:
 	BfIRValue CreateTypeOf(BfType* type);
 	BfIRValue CreateTypeOf(BfType* type);
 	BfIRValue CreateTypeOf(BfType* type, BfIRValue typeData);
 	BfIRValue CreateTypeOf(BfType* type, BfIRValue typeData);
 	BfIRValue GetUndefConstValue(BfIRType type);	
 	BfIRValue GetUndefConstValue(BfIRType type);	
+	BfIRValue CreateGlobalVariableConstant(BfIRType varType, bool isConstant, BfIRLinkageType linkageType, BfIRValue initializer, const StringImpl& name, bool isTLS = false);
 
 
 	bool WriteConstant(BfIRValue val, void* ptr, BfType* type);
 	bool WriteConstant(BfIRValue val, void* ptr, BfType* type);
 	BfIRValue ReadConstant(void* ptr, BfType* type);
 	BfIRValue ReadConstant(void* ptr, BfType* type);
@@ -979,7 +981,7 @@ public:
 	bool mHasDebugInfo;
 	bool mHasDebugInfo;
 	bool mHasDebugLineInfo;
 	bool mHasDebugLineInfo;
 	Dictionary<BfMethodRef, BfIRFunctionType> mMethodTypeMap;
 	Dictionary<BfMethodRef, BfIRFunctionType> mMethodTypeMap;
-	Dictionary<String, BfIRFunction> mFunctionMap;
+	Dictionary<String, BfIRFunction> mFunctionMap;	
 	Dictionary<BfType*, BfIRPopulateType> mTypeMap;
 	Dictionary<BfType*, BfIRPopulateType> mTypeMap;
 	Dictionary<int, BfIRValue> mConstMemMap;
 	Dictionary<int, BfIRValue> mConstMemMap;
 	Array<BfTypeInstance*> mDITemporaryTypes;	
 	Array<BfTypeInstance*> mDITemporaryTypes;	
@@ -1227,6 +1229,7 @@ public:
 	BfIRValue CreateStackRestore(BfIRValue stackVal);
 	BfIRValue CreateStackRestore(BfIRValue stackVal);
 	
 	
 	BfIRValue CreateGlobalVariable(BfIRType varType, bool isConstant, BfIRLinkageType linkageType, BfIRValue initializer, const StringImpl& name, bool isTLS = false);	
 	BfIRValue CreateGlobalVariable(BfIRType varType, bool isConstant, BfIRLinkageType linkageType, BfIRValue initializer, const StringImpl& name, bool isTLS = false);	
+	void CreateGlobalVariable(BfIRValue irValue);
 	void GlobalVar_SetUnnamedAddr(BfIRValue val, bool unnamedAddr);
 	void GlobalVar_SetUnnamedAddr(BfIRValue val, bool unnamedAddr);
 	void GlobalVar_SetInitializer(BfIRValue globalVar, BfIRValue initVal);
 	void GlobalVar_SetInitializer(BfIRValue globalVar, BfIRValue initVal);
 	void GlobalVar_SetAlignment(BfIRValue globalVar, int alignment);
 	void GlobalVar_SetAlignment(BfIRValue globalVar, int alignment);

+ 22 - 14
IDEHelper/Compiler/BfIRCodeGen.cpp

@@ -810,13 +810,17 @@ void BfIRCodeGen::Read(llvm::Value*& llvmValue, BfIRCodeGenEntry** codeGenEntry,
 				llvm::GlobalVariable* globalVariable = mLLVMModule->getGlobalVariable(name.c_str(), true);
 				llvm::GlobalVariable* globalVariable = mLLVMModule->getGlobalVariable(name.c_str(), true);
 				if (globalVariable == NULL)
 				if (globalVariable == NULL)
 				{
 				{
-					globalVariable = new llvm::GlobalVariable(
-						*mLLVMModule,
-						varType,
-						isConstant,
-						LLVMMapLinkageType(linkageType),
-						initializer,
-						name.c_str(), NULL, isTLS ? llvm::GlobalValue::GeneralDynamicTLSModel : llvm::GlobalValue::NotThreadLocal);
+					globalVariable = mLLVMModule->getGlobalVariable(name.c_str());
+					if (globalVariable == NULL)
+					{
+						globalVariable = new llvm::GlobalVariable(
+							*mLLVMModule,
+							varType,
+							isConstant,
+							LLVMMapLinkageType(linkageType),
+							initializer,
+							name.c_str(), NULL, isTLS ? llvm::GlobalValue::GeneralDynamicTLSModel : llvm::GlobalValue::NotThreadLocal);
+					}
 				}
 				}
 				llvmValue = globalVariable;
 				llvmValue = globalVariable;
 
 
@@ -2389,13 +2393,17 @@ void BfIRCodeGen::HandleNextCmd()
 			CMD_PARAM(bool, isTLS);
 			CMD_PARAM(bool, isTLS);
 			CMD_PARAM(llvm::Constant*, initializer);
 			CMD_PARAM(llvm::Constant*, initializer);
 
 
-			auto globalVariable = new llvm::GlobalVariable(
-				*mLLVMModule,
-				varType,
-				isConstant,
-				LLVMMapLinkageType(linkageType),
-				initializer,
-				name.c_str(), NULL, isTLS ? llvm::GlobalValue::GeneralDynamicTLSModel : llvm::GlobalValue::NotThreadLocal);
+			auto globalVariable = mLLVMModule->getGlobalVariable(name.c_str());
+			if (globalVariable == NULL)
+			{
+				globalVariable = new llvm::GlobalVariable(
+					*mLLVMModule,
+					varType,
+					isConstant,
+					LLVMMapLinkageType(linkageType),
+					initializer,
+					name.c_str(), NULL, isTLS ? llvm::GlobalValue::GeneralDynamicTLSModel : llvm::GlobalValue::NotThreadLocal);
+			}
 			SetResult(curId, globalVariable);
 			SetResult(curId, globalVariable);
 		}
 		}
 		break;
 		break;

+ 266 - 139
IDEHelper/Compiler/BfModule.cpp

@@ -1222,7 +1222,10 @@ void BfModule::StartNewRevision(RebuildKind rebuildKind, bool force)
 
 
 	// Clear this here, not in ClearModuleData, so we preserve those references even after writing out module
 	// Clear this here, not in ClearModuleData, so we preserve those references even after writing out module
 	if (rebuildKind != BfModule::RebuildKind_None) // Leave string pool refs for when we need to use things like [LinkName("")] methods bofore re-reification
 	if (rebuildKind != BfModule::RebuildKind_None) // Leave string pool refs for when we need to use things like [LinkName("")] methods bofore re-reification
-		mStringPoolRefs.Clear();	
+	{
+		mStringPoolRefs.Clear();
+		mUnreifiedStringPoolRefs.Clear();
+	}
 	mDllImportEntries.Clear();
 	mDllImportEntries.Clear();
 	mImportFileNames.Clear();
 	mImportFileNames.Clear();
 	for (auto& pairVal : mDeferredMethodCallData)
 	for (auto& pairVal : mDeferredMethodCallData)
@@ -1543,7 +1546,7 @@ BfIRValue BfModule::CreateStringCharPtr(const StringImpl& str, int stringId, boo
 }
 }
 
 
 BfIRValue BfModule::CreateStringObjectValue(const StringImpl& str, int stringId, bool define)
 BfIRValue BfModule::CreateStringObjectValue(const StringImpl& str, int stringId, bool define)
-{			
+{
 	auto stringTypeInst = ResolveTypeDef(mCompiler->mStringTypeDef, define ? BfPopulateType_Data : BfPopulateType_Declaration)->ToTypeInstance();
 	auto stringTypeInst = ResolveTypeDef(mCompiler->mStringTypeDef, define ? BfPopulateType_Data : BfPopulateType_Declaration)->ToTypeInstance();
 	mBfIRBuilder->PopulateType(stringTypeInst);
 	mBfIRBuilder->PopulateType(stringTypeInst);
 
 
@@ -1654,8 +1657,14 @@ String* BfModule::GetStringPoolString(BfIRValue constantStr, BfIRConstHolder * c
 	return NULL;
 	return NULL;
 }
 }
 
 
-BfIRValue BfModule::GetStringCharPtr(int stringId)
+BfIRValue BfModule::GetStringCharPtr(int stringId, bool force)
 {
 {
+	if ((mBfIRBuilder->mIgnoreWrites) && (!force))
+	{
+		mUnreifiedStringPoolRefs.Add(stringId);			
+		return mBfIRBuilder->CreateConst(BfTypeCode_StringId, stringId);
+	}
+
 	BfIRValue* irValue = NULL;
 	BfIRValue* irValue = NULL;
 	if (!mStringCharPtrPool.TryAdd(stringId, NULL, &irValue))
 	if (!mStringCharPtrPool.TryAdd(stringId, NULL, &irValue))
 		return *irValue;
 		return *irValue;
@@ -1670,13 +1679,13 @@ BfIRValue BfModule::GetStringCharPtr(int stringId)
 	return strCharPtrConst;
 	return strCharPtrConst;
 }
 }
 
 
-BfIRValue BfModule::GetStringCharPtr(BfIRValue strValue)
+BfIRValue BfModule::GetStringCharPtr(BfIRValue strValue, bool force)
 {
 {
 	if (strValue.IsConst())
 	if (strValue.IsConst())
 	{
 	{
 		int stringId = GetStringPoolIdx(strValue);
 		int stringId = GetStringPoolIdx(strValue);
 		BF_ASSERT(stringId != -1);
 		BF_ASSERT(stringId != -1);
-		return GetStringCharPtr(stringId);
+		return GetStringCharPtr(stringId, force);
 	}
 	}
 
 
 	BfIRValue charPtrPtr = mBfIRBuilder->CreateInBoundsGEP(strValue, 0, 1);	
 	BfIRValue charPtrPtr = mBfIRBuilder->CreateInBoundsGEP(strValue, 0, 1);	
@@ -1684,27 +1693,33 @@ BfIRValue BfModule::GetStringCharPtr(BfIRValue strValue)
 	return charPtr;
 	return charPtr;
 }
 }
 
 
-BfIRValue BfModule::GetStringCharPtr(const StringImpl& str)
+BfIRValue BfModule::GetStringCharPtr(const StringImpl& str, bool force)
 {
 {
-	return GetStringCharPtr(GetStringObjectValue(str));	
+	return GetStringCharPtr(GetStringObjectValue(str, force), force);
 }
 }
 
 
-BfIRValue BfModule::GetStringObjectValue(int strId)
+BfIRValue BfModule::GetStringObjectValue(int strId, bool define, bool force)
 {	
 {	
 	BfIRValue* objValue;
 	BfIRValue* objValue;
 	if (mStringObjectPool.TryGetValue(strId, &objValue))
 	if (mStringObjectPool.TryGetValue(strId, &objValue))
 		return *objValue;
 		return *objValue;
 
 
 	auto stringPoolEntry = mContext->mStringObjectIdMap[strId];
 	auto stringPoolEntry = mContext->mStringObjectIdMap[strId];
-	return GetStringObjectValue(stringPoolEntry.mString, true);
+	return GetStringObjectValue(stringPoolEntry.mString, define, force);
 }
 }
 
 
-BfIRValue BfModule::GetStringObjectValue(const StringImpl& str, bool define)
+BfIRValue BfModule::GetStringObjectValue(const StringImpl& str, bool define, bool force)
 {	
 {	
 	auto stringType = ResolveTypeDef(mCompiler->mStringTypeDef, define ? BfPopulateType_Data : BfPopulateType_Declaration);
 	auto stringType = ResolveTypeDef(mCompiler->mStringTypeDef, define ? BfPopulateType_Data : BfPopulateType_Declaration);
 	mBfIRBuilder->PopulateType(stringType);
 	mBfIRBuilder->PopulateType(stringType);
 
 
-	int strId = mContext->GetStringLiteralId(str);
+	int strId = mContext->GetStringLiteralId(str);	
+
+	if ((mBfIRBuilder->mIgnoreWrites) && (!force))
+	{
+		mUnreifiedStringPoolRefs.Add(strId);			
+		return mBfIRBuilder->CreateConst(BfTypeCode_StringId, strId);
+	}
 
 
 	BfIRValue* irValuePtr = NULL;
 	BfIRValue* irValuePtr = NULL;
 	if (!mStringObjectPool.TryAdd(strId, NULL, &irValuePtr))
 	if (!mStringObjectPool.TryAdd(strId, NULL, &irValuePtr))
@@ -1916,13 +1931,7 @@ void BfModule::AddStackAlloc(BfTypedValue val, BfIRValue arraySize, BfAstNode* r
 		bool hadDtorCall = false;
 		bool hadDtorCall = false;
 		while (checkBaseType != NULL)
 		while (checkBaseType != NULL)
 		{	
 		{	
-			checkBaseType->mTypeDef->PopulateMemberSets();
-			BfMemberSetEntry* entry = NULL;
-			BfMethodDef* dtorMethodDef = NULL;
-			checkBaseType->mTypeDef->mMethodSet.TryGetWith(String("~this"), &entry);
-			if (entry != NULL)
-				dtorMethodDef = (BfMethodDef*)entry->mMemberDef;
-
+			BfMethodDef* dtorMethodDef = checkBaseType->mTypeDef->GetMethodByName("~this");
 			if (dtorMethodDef != NULL)
 			if (dtorMethodDef != NULL)
 			{				
 			{				
 				auto dtorMethodInstance = GetMethodInstance(checkBaseType, dtorMethodDef, BfTypeVector());
 				auto dtorMethodInstance = GetMethodInstance(checkBaseType, dtorMethodDef, BfTypeVector());
@@ -3416,10 +3425,11 @@ void BfModule::AddDependency(BfType* usedType, BfType* userType, BfDependencyMap
 		BfModule* usedModule;
 		BfModule* usedModule;
 		if (usedType->IsFunction())
 		if (usedType->IsFunction())
 		{
 		{
-			auto typeInst = usedType->ToTypeInstance();
-			if (typeInst->mBaseType == NULL)
-				PopulateType(typeInst);
-			usedModule = typeInst->mBaseType->GetModule();
+			if (mCompiler->mFunctionTypeDef != NULL)
+			{
+				auto functionType = ResolveTypeDef(mCompiler->mFunctionTypeDef)->ToTypeInstance();
+				usedModule = functionType->GetModule();
+			}
 		}
 		}
 		else
 		else
 			usedModule = usedType->GetModule();
 			usedModule = usedType->GetModule();
@@ -5235,7 +5245,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 		typeFlags |= BfTypeFlags_Delegate;
 		typeFlags |= BfTypeFlags_Delegate;
 	if (type->IsFunction())
 	if (type->IsFunction())
 		typeFlags |= BfTypeFlags_Function;
 		typeFlags |= BfTypeFlags_Function;
-	if (type->WantsGCMarking())
+	if ((type->mDefineState != BfTypeDefineState_CETypeInit) && (type->WantsGCMarking()))
 		typeFlags |= BfTypeFlags_WantsMarking;
 		typeFlags |= BfTypeFlags_WantsMarking;
 
 
 	int virtSlotIdx = -1;
 	int virtSlotIdx = -1;
@@ -5906,8 +5916,8 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 
 
 	if (needsTypeNames)
 	if (needsTypeNames)
 	{
 	{
-		typeNameConst = GetStringObjectValue(typeDef->mName->mString, true);
-		namespaceConst = GetStringObjectValue(typeDef->mNamespace.ToString(), true);
+		typeNameConst = GetStringObjectValue(typeDef->mName->mString, !mIsComptimeModule);
+		namespaceConst = GetStringObjectValue(typeDef->mNamespace.ToString(), !mIsComptimeModule);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -5967,7 +5977,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 	// Fields
 	// Fields
 	BfType* reflectFieldDataType = ResolveTypeDef(mCompiler->mReflectFieldDataDef);
 	BfType* reflectFieldDataType = ResolveTypeDef(mCompiler->mReflectFieldDataDef);
 	BfIRValue emptyValueType = mBfIRBuilder->CreateConstAgg_Value(mBfIRBuilder->MapTypeInst(reflectFieldDataType->ToTypeInstance()->mBaseType), SizedArray<BfIRValue, 1>());
 	BfIRValue emptyValueType = mBfIRBuilder->CreateConstAgg_Value(mBfIRBuilder->MapTypeInst(reflectFieldDataType->ToTypeInstance()->mBaseType), SizedArray<BfIRValue, 1>());
-	
+
 	auto _HandleCustomAttrs = [&](BfCustomAttributes* customAttributes)
 	auto _HandleCustomAttrs = [&](BfCustomAttributes* customAttributes)
 	{
 	{
 		if (customAttributes == NULL)
 		if (customAttributes == NULL)
@@ -6023,7 +6033,28 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 			PUSH_INT16(0); // mSize
 			PUSH_INT16(0); // mSize
 
 
 			PUSH_INT32(attr->mType->mTypeId); // mType
 			PUSH_INT32(attr->mType->mTypeId); // mType
-			PUSH_INT16(attr->mCtor->mIdx);
+
+			int ctorIdx = -1;
+			int ctorCount = 0;
+
+			attr->mType->mTypeDef->PopulateMemberSets();			
+			BfMemberSetEntry* entry;
+			if (attr->mType->mTypeDef->mMethodSet.TryGetWith(String("__BfCtor"), &entry))
+			{
+				BfMethodDef* nextMethodDef = (BfMethodDef*)entry->mMemberDef;
+				while (nextMethodDef != NULL)
+				{
+					if (nextMethodDef == attr->mCtor)
+						ctorIdx = ctorCount;
+					nextMethodDef = nextMethodDef->mNextWithSameName;
+					ctorCount++;
+				}
+			}
+
+			BF_ASSERT(ctorIdx != -1);
+			if (ctorIdx != -1)
+				ctorIdx = (ctorCount - 1) - ctorIdx;
+			PUSH_INT16(ctorIdx);
 
 
 			auto ctorMethodInstance = GetRawMethodInstanceAtIdx(attr->mType, attr->mCtor->mIdx);
 			auto ctorMethodInstance = GetRawMethodInstanceAtIdx(attr->mType, attr->mCtor->mIdx);
 			int argIdx = 0;
 			int argIdx = 0;
@@ -6047,7 +6078,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 							*orderedIdPtr = (int)usedStringIdMap.size() - 1;							
 							*orderedIdPtr = (int)usedStringIdMap.size() - 1;							
 						}
 						}
 
 
-						GetStringObjectValue(stringId);
+						GetStringObjectValue(stringId, true, true);
 						PUSH_INT8(0xFF); // String
 						PUSH_INT8(0xFF); // String
 						PUSH_INT32(*orderedIdPtr);
 						PUSH_INT32(*orderedIdPtr);
 						argIdx++;
 						argIdx++;
@@ -6067,7 +6098,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 									*orderedIdPtr = (int)usedStringIdMap.size() - 1;
 									*orderedIdPtr = (int)usedStringIdMap.size() - 1;
 								}
 								}
 
 
-								GetStringObjectValue(stringId);
+								GetStringObjectValue(stringId, true, true);
 								PUSH_INT8(0xFF); // String
 								PUSH_INT8(0xFF); // String
 								PUSH_INT32(*orderedIdPtr);
 								PUSH_INT32(*orderedIdPtr);
 								argIdx++;
 								argIdx++;
@@ -6231,7 +6262,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 		BfType* payloadType = typeInstance->GetUnionInnerType();		
 		BfType* payloadType = typeInstance->GetUnionInnerType();		
 		if (!payloadType->IsValuelessType())
 		if (!payloadType->IsValuelessType())
 		{
 		{
-			BfIRValue payloadNameConst = GetStringObjectValue("$payload", true);
+			BfIRValue payloadNameConst = GetStringObjectValue("$payload", !mIsComptimeModule);
 			SizedArray<BfIRValue, 8> payloadFieldVals =
 			SizedArray<BfIRValue, 8> payloadFieldVals =
 			{
 			{
 				emptyValueType,
 				emptyValueType,
@@ -6246,7 +6277,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 		}
 		}
 
 
 		BfType* dscrType = typeInstance->GetDiscriminatorType();
 		BfType* dscrType = typeInstance->GetDiscriminatorType();
-		BfIRValue dscrNameConst = GetStringObjectValue("$discriminator", true);
+		BfIRValue dscrNameConst = GetStringObjectValue("$discriminator", !mIsComptimeModule);
 		SizedArray<BfIRValue, 8> dscrFieldVals =
 		SizedArray<BfIRValue, 8> dscrFieldVals =
 		{
 		{
 			emptyValueType,
 			emptyValueType,
@@ -6268,7 +6299,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 		BfFieldInstance* fieldInstance = &typeInstance->mFieldInstances[fieldIdx];
 		BfFieldInstance* fieldInstance = &typeInstance->mFieldInstances[fieldIdx];
 		BfFieldDef* fieldDef = fieldInstance->GetFieldDef();
 		BfFieldDef* fieldDef = fieldInstance->GetFieldDef();
 
 
-		BfIRValue fieldNameConst = GetStringObjectValue(fieldDef->mName, true);
+		BfIRValue fieldNameConst = GetStringObjectValue(fieldDef->mName, !mIsComptimeModule);
 
 
 		int typeId = 0;
 		int typeId = 0;
 		auto fieldType = fieldInstance->GetResolvedType();
 		auto fieldType = fieldInstance->GetResolvedType();
@@ -6448,6 +6479,14 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 	BfType* reflectParamDataType = ResolveTypeDef(mCompiler->mReflectParamDataDef);
 	BfType* reflectParamDataType = ResolveTypeDef(mCompiler->mReflectParamDataDef);
 	BfType* reflectParamDataPtrType = CreatePointerType(reflectParamDataType);
 	BfType* reflectParamDataPtrType = CreatePointerType(reflectParamDataType);
 
 
+	struct _SortedMethodInfo
+	{
+		BfMethodDef* mMethodDef;
+		BfCustomAttributes* mMethodCustomAttributes;
+	};
+
+	Array<_SortedMethodInfo> sortedMethodList;
+
 	SizedArray<BfIRValue, 16> methodTypes;	
 	SizedArray<BfIRValue, 16> methodTypes;	
 	for (int methodIdx = 0; methodIdx < (int)typeDef->mMethods.size(); methodIdx++)
 	for (int methodIdx = 0; methodIdx < (int)typeDef->mMethods.size(); methodIdx++)
 	{
 	{
@@ -6460,7 +6499,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 
 
 		auto methodInstanceGroup = &typeInstance->mMethodInstanceGroups[methodIdx];
 		auto methodInstanceGroup = &typeInstance->mMethodInstanceGroups[methodIdx];
 		if (!methodInstanceGroup->IsImplemented())
 		if (!methodInstanceGroup->IsImplemented())
-			continue;		
+			continue;
 		auto methodDef = typeDef->mMethods[methodIdx];
 		auto methodDef = typeDef->mMethods[methodIdx];
 		if (methodDef->mIsNoReflect)
 		if (methodDef->mIsNoReflect)
 			continue;
 			continue;
@@ -6474,12 +6513,12 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 			continue;
 			continue;
 		if (!defaultMethod->mIsReified)
 		if (!defaultMethod->mIsReified)
 			continue;
 			continue;
-		
+
 		if ((defaultMethod->mChainType == BfMethodChainType_ChainMember) || (defaultMethod->mChainType == BfMethodChainType_ChainSkip))
 		if ((defaultMethod->mChainType == BfMethodChainType_ChainMember) || (defaultMethod->mChainType == BfMethodChainType_ChainSkip))
 			continue;
 			continue;
 		if (defaultMethod->mMethodDef->mMethodType == BfMethodType_CtorNoBody)
 		if (defaultMethod->mMethodDef->mMethodType == BfMethodType_CtorNoBody)
-			continue;		
-		
+			continue;
+
 		auto methodReflectKind = (BfReflectKind)(reflectKind & ~BfReflectKind_User);
 		auto methodReflectKind = (BfReflectKind)(reflectKind & ~BfReflectKind_User);
 
 
 		bool includeMethod = reflectIncludeAllMethods;
 		bool includeMethod = reflectIncludeAllMethods;
@@ -6501,10 +6540,10 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 				}
 				}
 			}
 			}
 		}
 		}
-		
+
 		if ((!mIsComptimeModule) && (!typeInstance->IsTypeMemberAccessible(methodDef->mDeclaringType, mProject)))
 		if ((!mIsComptimeModule) && (!typeInstance->IsTypeMemberAccessible(methodDef->mDeclaringType, mProject)))
 			continue;
 			continue;
-		
+
 		//
 		//
 		{
 		{
 			SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, typeInstance);
 			SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, typeInstance);
@@ -6522,13 +6561,42 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 			includeMethod = true;
 			includeMethod = true;
 		if ((methodDef->mIsStatic) && ((methodReflectKind & BfReflectKind_StaticMethods) != 0))
 		if ((methodDef->mIsStatic) && ((methodReflectKind & BfReflectKind_StaticMethods) != 0))
 			includeMethod = true;
 			includeMethod = true;
-		
+
 		if ((!includeMethod) && (typeOptions != NULL))
 		if ((!includeMethod) && (typeOptions != NULL))
 			includeMethod = ApplyTypeOptionMethodFilters(includeMethod, methodDef, typeOptions);
 			includeMethod = ApplyTypeOptionMethodFilters(includeMethod, methodDef, typeOptions);
-		
+
 		if (!includeMethod)
 		if (!includeMethod)
 			continue;
 			continue;
 
 
+		sortedMethodList.Add({ methodDef, methodCustomAttributes });
+	}
+
+	auto _GetMethodKind = [](BfMethodDef* methodDef)
+	{
+		if (methodDef->mMethodType == BfMethodType_Ctor)
+			return 0;
+		return 1;
+	};
+
+	std::sort(sortedMethodList.begin(), sortedMethodList.end(), [_GetMethodKind](const _SortedMethodInfo& lhs, const _SortedMethodInfo& rhs)
+		{
+			int lhsKind = _GetMethodKind(lhs.mMethodDef);
+			int rhsKind = _GetMethodKind(rhs.mMethodDef);
+			
+			if (lhsKind != rhsKind)
+				return lhsKind < rhsKind;
+			if (lhs.mMethodDef->mName != rhs.mMethodDef->mName)
+				return lhs.mMethodDef->mName < rhs.mMethodDef->mName;
+			return lhs.mMethodDef->mIdx < rhs.mMethodDef->mIdx;
+		});
+
+	for (auto& methodInfo : sortedMethodList)
+	{
+		auto methodDef = methodInfo.mMethodDef;
+		int methodIdx = methodDef->mIdx;
+		auto methodInstanceGroup = &typeInstance->mMethodInstanceGroups[methodIdx];
+		auto defaultMethod = methodInstanceGroup->mDefault;
+
 		BfModuleMethodInstance moduleMethodInstance;
 		BfModuleMethodInstance moduleMethodInstance;
 		BfIRValue funcVal = voidPtrNull;
 		BfIRValue funcVal = voidPtrNull;
 		
 		
@@ -6544,11 +6612,11 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 				funcVal = mBfIRBuilder->CreateBitCast(moduleMethodInstance.mFunc, voidPtrIRType);
 				funcVal = mBfIRBuilder->CreateBitCast(moduleMethodInstance.mFunc, voidPtrIRType);
 		}
 		}
 				
 				
-		BfIRValue methodNameConst = GetStringObjectValue(methodDef->mName, true);
+		BfIRValue methodNameConst = GetStringObjectValue(methodDef->mName, !mIsComptimeModule);
 						
 						
 		BfMethodFlags methodFlags = defaultMethod->GetMethodFlags();
 		BfMethodFlags methodFlags = defaultMethod->GetMethodFlags();
 		
 		
-		int customAttrIdx = _HandleCustomAttrs(methodCustomAttributes);
+		int customAttrIdx = _HandleCustomAttrs(methodInfo.mMethodCustomAttributes);
 
 
 		enum ParamFlags
 		enum ParamFlags
 		{
 		{
@@ -6567,7 +6635,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 			if (defaultMethod->GetParamIsSplat(paramIdx))
 			if (defaultMethod->GetParamIsSplat(paramIdx))
 				paramFlags = (ParamFlags)(paramFlags | ParamFlag_Splat);
 				paramFlags = (ParamFlags)(paramFlags | ParamFlag_Splat);
 
 
-			BfIRValue paramNameConst = GetStringObjectValue(paramName, true);
+			BfIRValue paramNameConst = GetStringObjectValue(paramName, !mIsComptimeModule);
 
 
 			SizedArray<BfIRValue, 8> paramDataVals =
 			SizedArray<BfIRValue, 8> paramDataVals =
 				{
 				{
@@ -7150,7 +7218,7 @@ BfIRFunction BfModule::GetBuiltInFunc(BfBuiltInFuncType funcTypeId)
 	return mBuiltInFuncs[(int)funcTypeId];
 	return mBuiltInFuncs[(int)funcTypeId];
 }
 }
 
 
-void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized)
+void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized, Array<BfTypeReference*>* deferredResolveTypes)
 {	
 {	
 	BfGenericParamDef* genericParamDef = genericParamInstance->GetGenericParamDef();	
 	BfGenericParamDef* genericParamDef = genericParamInstance->GetGenericParamDef();	
 	BfExternalConstraintDef* externConstraintDef = genericParamInstance->GetExternConstraintDef();
 	BfExternalConstraintDef* externConstraintDef = genericParamInstance->GetExternConstraintDef();
@@ -7256,14 +7324,23 @@ void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericPar
 		if (bfAutocomplete != NULL)
 		if (bfAutocomplete != NULL)
 			bfAutocomplete->CheckTypeRef(constraintTypeRef, true);
 			bfAutocomplete->CheckTypeRef(constraintTypeRef, true);
 		//TODO: Constraints may refer to other generic params (of either type or method)
 		//TODO: Constraints may refer to other generic params (of either type or method)
-		//  TO allow resolution, perhaps move this generic param initalization into GetMethodInstance (passing a genericPass bool)
+		//  TO allow resolution, perhaps move this generic param initialization into GetMethodInstance (passing a genericPass bool)
 
 
 		BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_AllowGenericMethodParamConstValue;
 		BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_AllowGenericMethodParamConstValue;
 		if (isUnspecialized)
 		if (isUnspecialized)
 			resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_DisallowComptime);
 			resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_DisallowComptime);
-		auto constraintType = ResolveTypeRef(constraintTypeRef, BfPopulateType_Declaration, resolveFlags);
+		// We we have a deferredResolveTypes then we defer the generic validation, because we may have a case like
+		//  `where T : Dictionay<TElem, int> and TElem : IHashable` and we don't want to throw the error on `T` before we build `TElem`
+		auto constraintType = ResolveTypeRef(constraintTypeRef, (deferredResolveTypes != NULL) ? BfPopulateType_Identity : BfPopulateType_Declaration, resolveFlags);
 		if (constraintType != NULL)
 		if (constraintType != NULL)
-		{
+		{			
+			if (deferredResolveTypes != NULL)
+			{
+				PopulateType(constraintType, BfPopulateType_Declaration);
+				if (constraintType->IsUnspecializedTypeVariation())
+					deferredResolveTypes->Add(constraintTypeRef);
+			}
+
 			if ((constraintDef->mGenericParamFlags & BfGenericParamFlag_Const) != 0)
 			if ((constraintDef->mGenericParamFlags & BfGenericParamFlag_Const) != 0)
 			{
 			{
 				bool isValidTypeCode = false;				
 				bool isValidTypeCode = false;				
@@ -7444,11 +7521,11 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
 		origCheckArgType = origCheckArgType->GetUnderlyingType();
 		origCheckArgType = origCheckArgType->GetUnderlyingType();
 
 
 	bool argMayBeReferenceType = false;
 	bool argMayBeReferenceType = false;
-
+	
 	int checkGenericParamFlags = 0;
 	int checkGenericParamFlags = 0;
 	if (checkArgType->IsGenericParam())
 	if (checkArgType->IsGenericParam())
 	{
 	{
-		auto checkGenericParamInst = GetGenericParamInstance((BfGenericParamType*)checkArgType);
+		BfGenericParamInstance* checkGenericParamInst = GetGenericParamInstance((BfGenericParamType*)checkArgType);
 		checkGenericParamFlags = checkGenericParamInst->mGenericParamFlags;
 		checkGenericParamFlags = checkGenericParamInst->mGenericParamFlags;
 		if (checkGenericParamInst->mTypeConstraint != NULL)
 		if (checkGenericParamInst->mTypeConstraint != NULL)
 			checkArgType = checkGenericParamInst->mTypeConstraint;
 			checkArgType = checkGenericParamInst->mTypeConstraint;
@@ -7782,7 +7859,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
 			if (TypeIsSubTypeOf(wrappedStructType, typeConstraintInst))
 			if (TypeIsSubTypeOf(wrappedStructType, typeConstraintInst))
 				implementsInterface = true;
 				implementsInterface = true;
 		}
 		}
-
+		
 		if (!implementsInterface)
 		if (!implementsInterface)
 		{
 		{
 			if ((!ignoreErrors) && (PreFail()))
 			if ((!ignoreErrors) && (PreFail()))
@@ -10601,6 +10678,7 @@ void BfModule::ClearConstData()
 	mStringObjectPool.Clear();
 	mStringObjectPool.Clear();
 	mStringCharPtrPool.Clear();
 	mStringCharPtrPool.Clear();
 	mStringPoolRefs.Clear();
 	mStringPoolRefs.Clear();
+	mUnreifiedStringPoolRefs.Clear();
 }
 }
 
 
 BfTypedValue BfModule::GetTypedValueFromConstant(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType)
 BfTypedValue BfModule::GetTypedValueFromConstant(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType)
@@ -10630,17 +10708,18 @@ BfTypedValue BfModule::GetTypedValueFromConstant(BfConstant* constant, BfIRConst
 			auto constVal = mBfIRBuilder->CreateConst(constant, constHolder);
 			auto constVal = mBfIRBuilder->CreateConst(constant, constHolder);
 			BfTypedValue typedValue;
 			BfTypedValue typedValue;
 
 
+			bool allowUnactualized = mBfIRBuilder->mIgnoreWrites;
 			if (constant->mTypeCode == BfTypeCode_StringId)
 			if (constant->mTypeCode == BfTypeCode_StringId)
 			{
 			{
 				if ((wantType->IsInstanceOf(mCompiler->mStringTypeDef)) ||
 				if ((wantType->IsInstanceOf(mCompiler->mStringTypeDef)) ||
 					((wantType->IsPointer()) && (wantType->GetUnderlyingType() == GetPrimitiveType(BfTypeCode_Char8))))
 					((wantType->IsPointer()) && (wantType->GetUnderlyingType() == GetPrimitiveType(BfTypeCode_Char8))))
 				{
 				{
-					typedValue = BfTypedValue(ConstantToCurrent(constant, constHolder, wantType), wantType);
+					typedValue = BfTypedValue(ConstantToCurrent(constant, constHolder, wantType, allowUnactualized), wantType);
 					return typedValue;
 					return typedValue;
 				}
 				}
 
 
 				auto stringType = ResolveTypeDef(mCompiler->mStringTypeDef);
 				auto stringType = ResolveTypeDef(mCompiler->mStringTypeDef);
-				typedValue = BfTypedValue(ConstantToCurrent(constant, constHolder, stringType), stringType);
+				typedValue = BfTypedValue(ConstantToCurrent(constant, constHolder, stringType, allowUnactualized), stringType);
 			}
 			}
 			
 			
 			if (!typedValue)
 			if (!typedValue)
@@ -10684,7 +10763,27 @@ BfTypedValue BfModule::GetTypedValueFromConstant(BfConstant* constant, BfIRConst
 	return BfTypedValue(irValue, wantType, false);
 	return BfTypedValue(irValue, wantType, false);
 }
 }
 
 
-BfIRValue BfModule::ConstantToCurrent(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType, bool allowStringId)
+bool BfModule::HasUnactializedConstant(BfConstant* constant, BfIRConstHolder* constHolder)
+{
+	if ((constant->mConstType == BfConstType_TypeOf) || (constant->mConstType == BfConstType_TypeOf_WithData))
+		return true;
+	if (constant->mTypeCode == BfTypeCode_StringId)
+		return true;
+
+	if (constant->mConstType == BfConstType_Agg)
+	{
+		auto constArray = (BfConstantAgg*)constant;		
+		for (auto val : constArray->mValues)
+		{
+			if (HasUnactializedConstant(constHolder->GetConstant(val), constHolder))
+				return true;			
+		}		
+	}
+
+	return false;
+}
+
+BfIRValue BfModule::ConstantToCurrent(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType, bool allowUnactualized)
 {
 {
 	if (constant->mTypeCode == BfTypeCode_NullPtr)
 	if (constant->mTypeCode == BfTypeCode_NullPtr)
 	{
 	{
@@ -10699,20 +10798,27 @@ BfIRValue BfModule::ConstantToCurrent(BfConstant* constant, BfIRConstHolder* con
 
 
 	if (constant->mTypeCode == BfTypeCode_StringId)
 	if (constant->mTypeCode == BfTypeCode_StringId)
 	{
 	{
-		if (!allowStringId)
+		if (!allowUnactualized)
 		{
 		{
 			if ((wantType->IsInstanceOf(mCompiler->mStringTypeDef)) ||
 			if ((wantType->IsInstanceOf(mCompiler->mStringTypeDef)) ||
 				((wantType->IsPointer()) && (wantType->GetUnderlyingType() == GetPrimitiveType(BfTypeCode_Char8))))
 				((wantType->IsPointer()) && (wantType->GetUnderlyingType() == GetPrimitiveType(BfTypeCode_Char8))))
 			{
 			{
 				const StringImpl& str = mContext->mStringObjectIdMap[constant->mInt32].mString;
 				const StringImpl& str = mContext->mStringObjectIdMap[constant->mInt32].mString;
-				BfIRValue stringObjConst = GetStringObjectValue(str);
+				BfIRValue stringObjConst = GetStringObjectValue(str, false, true);
 				if (wantType->IsPointer())
 				if (wantType->IsPointer())
-					return GetStringCharPtr(stringObjConst);
+					return GetStringCharPtr(stringObjConst, true);
 				return stringObjConst;
 				return stringObjConst;
 			}
 			}
 		}
 		}
 	}
 	}
 
 
+	if (constant->mConstType == Beefy::BfConstType_TypeOf)
+	{
+		auto constTypeOf = (BfTypeOf_Const*)constant;
+		AddDependency(constTypeOf->mType, mCurTypeInstance, BfDependencyMap::DependencyFlag_ExprTypeReference);
+		return CreateTypeDataRef(constTypeOf->mType);
+	}
+
 	if (constant->mConstType == BfConstType_Agg)
 	if (constant->mConstType == BfConstType_Agg)
 	{		
 	{		
 		auto constArray = (BfConstantAgg*)constant;
 		auto constArray = (BfConstantAgg*)constant;
@@ -10789,6 +10895,9 @@ void BfModule::ValidateCustomAttributes(BfCustomAttributes* customAttributes, Bf
 
 
 void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrTarget, bool allowNonConstArgs, BfCaptureInfo* captureInfo)
 void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrTarget, bool allowNonConstArgs, BfCaptureInfo* captureInfo)
 {
 {
+	if (!mCompiler->mHasRequiredTypes)
+		return;
+
 	if ((attributesDirective != NULL) && (mCompiler->mResolvePassData != NULL) && 
 	if ((attributesDirective != NULL) && (mCompiler->mResolvePassData != NULL) && 
 		(attributesDirective->IsFromParser(mCompiler->mResolvePassData->mParser)) && (mCompiler->mResolvePassData->mSourceClassifier != NULL))
 		(attributesDirective->IsFromParser(mCompiler->mResolvePassData->mParser)) && (mCompiler->mResolvePassData->mSourceClassifier != NULL))
 	{
 	{
@@ -10908,6 +11017,12 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 			continue;
 			continue;
 		}
 		}
 
 
+		if ((mIsReified) && (attrTypeInst->mAttributeData != NULL) && ((attrTypeInst->mAttributeData->mFlags & BfAttributeFlag_ReflectAttribute) != 0))
+		{
+			// Reify attribute
+			PopulateType(attrTypeInst);
+		}
+
 		if (mCurTypeInstance != NULL)
 		if (mCurTypeInstance != NULL)
 			AddDependency(attrTypeInst, mCurTypeInstance, BfDependencyMap::DependencyFlag_CustomAttribute);
 			AddDependency(attrTypeInst, mCurTypeInstance, BfDependencyMap::DependencyFlag_CustomAttribute);
 
 
@@ -11018,8 +11133,8 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 
 
 					auto& fieldTypeInst = checkTypeInst->mFieldInstances[bestField->mIdx];
 					auto& fieldTypeInst = checkTypeInst->mFieldInstances[bestField->mIdx];
 					if (assignExpr->mRight != NULL)
 					if (assignExpr->mRight != NULL)
-					{
-						BfTypedValue result = constResolver.Resolve(assignExpr->mRight, fieldTypeInst.mResolvedType);
+					{						
+						BfTypedValue result = constResolver.Resolve(assignExpr->mRight, fieldTypeInst.mResolvedType, BfConstResolveFlag_NoActualizeValues);
 						if (result)
 						if (result)
 						{
 						{
 							CurrentAddToConstHolder(result.mValue);
 							CurrentAddToConstHolder(result.mValue);
@@ -11078,9 +11193,11 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 							auto propType = methodInstance.mMethodInstance->GetParamType(0);
 							auto propType = methodInstance.mMethodInstance->GetParamType(0);
 							if (assignExpr->mRight != NULL)
 							if (assignExpr->mRight != NULL)
 							{
 							{
-								BfTypedValue result = constResolver.Resolve(assignExpr->mRight, propType);
-								if (result)
+								BfTypedValue result = constResolver.Resolve(assignExpr->mRight, propType, BfConstResolveFlag_NoActualizeValues);
+								if ((result) && (!result.mType->IsVar()))
 								{
 								{
+									if (!result.mValue.IsConst())
+										result = GetDefaultTypedValue(result.mType);
 									BF_ASSERT(result.mType == propType);
 									BF_ASSERT(result.mType == propType);
 									CurrentAddToConstHolder(result.mValue);
 									CurrentAddToConstHolder(result.mValue);
 									setProperty.mParam = result;
 									setProperty.mParam = result;
@@ -11092,7 +11209,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 				}
 				}
 
 
 				if ((!handledExpr) && (assignExpr->mRight != NULL))
 				if ((!handledExpr) && (assignExpr->mRight != NULL))
-					constResolver.Resolve(assignExpr->mRight);
+					constResolver.Resolve(assignExpr->mRight, NULL, BfConstResolveFlag_NoActualizeValues);
 			}
 			}
 			else
 			else
 			{
 			{
@@ -11112,7 +11229,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 					resolvedArg.mArgFlags = BfArgFlag_DeferredEval;
 					resolvedArg.mArgFlags = BfArgFlag_DeferredEval;
 				}
 				}
 				else
 				else
-					resolvedArg.mTypedValue = constResolver.Resolve(arg);
+					resolvedArg.mTypedValue = constResolver.Resolve(arg, NULL, BfConstResolveFlag_NoActualizeValues);
 
 
 				if (!inPropSet)
 				if (!inPropSet)
 				{										
 				{										
@@ -11193,7 +11310,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 			if ((arg.mArgFlags & BfArgFlag_DeferredEval) != 0)
 			if ((arg.mArgFlags & BfArgFlag_DeferredEval) != 0)
 			{
 			{
 				if (auto expr = BfNodeDynCast<BfExpression>(arg.mExpression))
 				if (auto expr = BfNodeDynCast<BfExpression>(arg.mExpression))
-					constResolver.Resolve(expr);
+					constResolver.Resolve(expr, NULL, BfConstResolveFlag_NoActualizeValues);
 			}
 			}
 		}
 		}
 
 
@@ -11512,14 +11629,17 @@ BfVariant BfModule::TypedValueToVariant(BfAstNode* refNode, const BfTypedValue&
 			case BfTypeCode_UIntPtr:
 			case BfTypeCode_UIntPtr:
 			case BfTypeCode_IntUnknown:
 			case BfTypeCode_IntUnknown:
 			case BfTypeCode_UIntUnknown:
 			case BfTypeCode_UIntUnknown:
-			case BfTypeCode_Float:
 			case BfTypeCode_Double:
 			case BfTypeCode_Double:
 			case BfTypeCode_Char8:
 			case BfTypeCode_Char8:
 			case BfTypeCode_Char16:
 			case BfTypeCode_Char16:
 			case BfTypeCode_Char32:
 			case BfTypeCode_Char32:
 				variant.mTypeCode = constant->mTypeCode;
 				variant.mTypeCode = constant->mTypeCode;
 				variant.mInt64 = constant->mInt64;
 				variant.mInt64 = constant->mInt64;
-				break;				
+				break;
+			case BfTypeCode_Float:
+				variant.mTypeCode = constant->mTypeCode;
+				variant.mSingle = (float)constant->mDouble;
+				break;
 			default:
 			default:
 				if (refNode != NULL)
 				if (refNode != NULL)
 					Fail("Invalid const expression type", refNode);
 					Fail("Invalid const expression type", refNode);
@@ -13624,6 +13744,13 @@ BfTypedValue BfModule::ReferenceStaticField(BfFieldInstance* fieldInstance)
 	{
 	{
 		globalValue = *globalValuePtr;
 		globalValue = *globalValuePtr;
 		BF_ASSERT(globalValue);
 		BF_ASSERT(globalValue);
+
+		auto globalVar = (BfGlobalVar*)mBfIRBuilder->GetConstant(globalValue);
+		if ((globalVar->mStreamId == -1) && (!mBfIRBuilder->mIgnoreWrites))
+		{
+			mBfIRBuilder->MapType(fieldInstance->mResolvedType);
+			mBfIRBuilder->CreateGlobalVariable(globalValue);
+		}
 	}
 	}
 	else
 	else
 	{				
 	{				
@@ -13655,16 +13782,11 @@ BfTypedValue BfModule::ReferenceStaticField(BfFieldInstance* fieldInstance)
 				BfIRValue(),
 				BfIRValue(),
 				staticVarName,
 				staticVarName,
 				IsThreadLocal(fieldInstance));
 				IsThreadLocal(fieldInstance));
-
-			if (!mBfIRBuilder->mIgnoreWrites)
-			{
-				// Only store this if we actually did the creation
-				BF_ASSERT(globalValue);
-				mStaticFieldRefs[fieldInstance] = globalValue;
-			}
+			
+			BF_ASSERT(globalValue);
+			mStaticFieldRefs[fieldInstance] = globalValue;
 				
 				
 			BfLogSysM("Mod:%p Type:%p ReferenceStaticField %p -> %p\n", this, fieldInstance->mOwner, fieldInstance, globalValue);
 			BfLogSysM("Mod:%p Type:%p ReferenceStaticField %p -> %p\n", this, fieldInstance->mOwner, fieldInstance, globalValue);
-
 		}
 		}
 	}	
 	}	
 
 
@@ -13676,7 +13798,7 @@ BfTypedValue BfModule::ReferenceStaticField(BfFieldInstance* fieldInstance)
 }
 }
 
 
 BfTypedValue BfModule::GetThis()
 BfTypedValue BfModule::GetThis()
-{
+{	
 	auto useMethodState = mCurMethodState;
 	auto useMethodState = mCurMethodState;
 	while ((useMethodState != NULL) && (useMethodState->mClosureState != NULL) && (useMethodState->mClosureState->mCapturing))		
 	while ((useMethodState != NULL) && (useMethodState->mClosureState != NULL) && (useMethodState->mClosureState->mCapturing))		
 	{
 	{
@@ -13705,33 +13827,6 @@ BfTypedValue BfModule::GetThis()
 		return BfTypedValue();
 		return BfTypedValue();
 	}
 	}
 
 
-// 	if (useMethodState->HasNonStaticMixin())
-// 	{
-// 		auto checkMethodState = useMethodState;
-// 		while (checkMethodState != NULL)
-// 		{
-// 			for (int localIdx = (int)checkMethodState->mLocals.size() - 1; localIdx >= 0; localIdx--)
-// 			{
-// 				auto varDecl = checkMethodState->mLocals[localIdx];
-// 				if (varDecl->mName == "this")
-// 				{
-// 					varDecl->mReadFromId = useMethodState->GetRootMethodState()->mCurAccessId++;
-// 					if (varDecl->mIsSplat)
-// 					{
-// 						return BfTypedValue(varDecl->mValue, varDecl->mResolvedType, BfTypedValueKind_ThisSplatHead);
-// 					}
-// 					else if ((varDecl->mResolvedType->IsValueType()) && (varDecl->mAddr))
-// 					{
-// 						return BfTypedValue(varDecl->mAddr, varDecl->mResolvedType, BfTypedValueKind_ThisAddr);
-// 					}
-// 					return BfTypedValue(varDecl->mValue, varDecl->mResolvedType, varDecl->mResolvedType->IsValueType() ? BfTypedValueKind_ThisAddr : BfTypedValueKind_ThisValue);
-// 				}
-// 			}
-// 		
-// 			checkMethodState = checkMethodState->mPrevMethodState;
-// 		}
-// 	}
-
 	// Check mixin state for 'this'
 	// Check mixin state for 'this'
 	{
 	{
 		auto checkMethodState = mCurMethodState;
 		auto checkMethodState = mCurMethodState;
@@ -14059,8 +14154,10 @@ void BfModule::DoLocalVariableDebugInfo(BfLocalVariable* localVarDef, bool doAli
 				if (mBfIRBuilder->HasDebugLocation())
 				if (mBfIRBuilder->HasDebugLocation())
 				{
 				{
 					if ((isConstant) && (!didConstToMem))
 					if ((isConstant) && (!didConstToMem))
-					{
-						localVarDef->mDbgDeclareInst = mBfIRBuilder->DbgInsertValueIntrinsic(localVarDef->mConstValue, diVariable);
+					{	
+						BfTypedValue result(localVarDef->mConstValue, localVarDef->mResolvedType);
+						FixValueActualization(result);
+						localVarDef->mDbgDeclareInst = mBfIRBuilder->DbgInsertValueIntrinsic(result.mValue, diVariable);
 					}
 					}
 					else
 					else
 					{
 					{
@@ -15668,7 +15765,11 @@ void BfModule::EmitDtorBody()
 				}
 				}
 				else
 				else
 				{
 				{
-					if (!mCurTypeInstance->IsValueType())
+					if (fieldInst->mResolvedType->IsValuelessType())
+					{
+						value = mBfIRBuilder->GetFakeVal();
+					}
+					else if (!mCurTypeInstance->IsValueType())
 					{
 					{
 						auto thisValue = GetThis();
 						auto thisValue = GetThis();
 						value = mBfIRBuilder->CreateInBoundsGEP(thisValue.mValue, 0, fieldInst->mDataIdx);						
 						value = mBfIRBuilder->CreateInBoundsGEP(thisValue.mValue, 0, fieldInst->mDataIdx);						
@@ -15744,13 +15845,7 @@ void BfModule::EmitDtorBody()
 					UpdateSrcPos(typeDef->mTypeDeclaration->mNameNode);
 					UpdateSrcPos(typeDef->mTypeDeclaration->mNameNode);
 				}
 				}
 
 
-				checkBaseType->mTypeDef->PopulateMemberSets();
-				BfMemberSetEntry* entry = NULL;
-				BfMethodDef* dtorMethodDef = NULL;
-				checkBaseType->mTypeDef->mMethodSet.TryGetWith(String("~this"), &entry);
-				if (entry != NULL)
-					dtorMethodDef = (BfMethodDef*)entry->mMemberDef;
-
+				BfMethodDef* dtorMethodDef = checkBaseType->mTypeDef->GetMethodByName("~this"); 
 				if (dtorMethodDef != NULL)
 				if (dtorMethodDef != NULL)
 				{
 				{
 					auto dtorMethodInstance = GetMethodInstance(checkBaseType, dtorMethodDef, BfTypeVector());
 					auto dtorMethodInstance = GetMethodInstance(checkBaseType, dtorMethodDef, BfTypeVector());
@@ -18160,7 +18255,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 	auto methodDeclaration = methodDef->GetMethodDeclaration();
 	auto methodDeclaration = methodDef->GetMethodDeclaration();
 
 
 	if ((methodDef->mHasComptime) && (!mIsComptimeModule))
 	if ((methodDef->mHasComptime) && (!mIsComptimeModule))
-		mBfIRBuilder->mIgnoreWrites = true;
+		mBfIRBuilder->mIgnoreWrites = true;	
 
 
 	if ((methodInstance->mIsReified) && (methodInstance->mVirtualTableIdx != -1))
 	if ((methodInstance->mIsReified) && (methodInstance->mVirtualTableIdx != -1))
 	{
 	{
@@ -18285,7 +18380,36 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 	}
 	}
 
 
 	BfLogSysM("ProcessMethod %p Unspecialized: %d Module: %p IRFunction: %d Reified: %d Incomplete:%d\n", methodInstance, mCurTypeInstance->IsUnspecializedType(), this, methodInstance->mIRFunction.mId, methodInstance->mIsReified, mIncompleteMethodCount);
 	BfLogSysM("ProcessMethod %p Unspecialized: %d Module: %p IRFunction: %d Reified: %d Incomplete:%d\n", methodInstance, mCurTypeInstance->IsUnspecializedType(), this, methodInstance->mIRFunction.mId, methodInstance->mIsReified, mIncompleteMethodCount);
-	
+
+	int importStrNum = -1;
+	auto importKind = methodInstance->GetImportKind();
+	if ((!mCompiler->mIsResolveOnly) &&
+		((importKind == BfImportKind_Import_Static) || (importKind == BfImportKind_Import_Dynamic)))
+	{
+		if (auto customAttr = methodInstance->GetCustomAttributes()->Get(mCompiler->mImportAttributeTypeDef))
+		{
+			if (customAttr->mCtorArgs.size() == 1)
+			{
+				auto fileNameArg = customAttr->mCtorArgs[0];				
+				auto constant = mCurTypeInstance->mConstHolder->GetConstant(fileNameArg);
+				if (constant != NULL)
+				{
+					if (!constant->IsNull())						
+						importStrNum = constant->mInt32;
+				}
+				else
+				{
+					importStrNum = GetStringPoolIdx(fileNameArg, mCurTypeInstance->mConstHolder);
+				}
+				if (importStrNum != -1)
+				{
+					if (!mStringPoolRefs.Contains(importStrNum))
+						mStringPoolRefs.Add(importStrNum);					
+				}
+			}
+		}
+	}
+
 	if (methodInstance->GetImportCallKind() != BfImportCallKind_None)
 	if (methodInstance->GetImportCallKind() != BfImportCallKind_None)
 	{
 	{
 		if (mBfIRBuilder->mIgnoreWrites)
 		if (mBfIRBuilder->mIgnoreWrites)
@@ -19451,7 +19575,11 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 	}
 	}
 
 
 	auto bodyBlock = BfNodeDynCast<BfBlock>(methodDef->mBody);
 	auto bodyBlock = BfNodeDynCast<BfBlock>(methodDef->mBody);
-	if (methodDef->mBody == NULL)
+	if (!mCompiler->mHasRequiredTypes)
+	{
+		// Skip processing to avoid errors
+	}
+	else if (methodDef->mBody == NULL)
 	{
 	{
 		if (methodDeclaration != NULL)
 		if (methodDeclaration != NULL)
 		{
 		{
@@ -19463,34 +19591,19 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 		}
 		}
 
 
 		bool isDllImport = false;		
 		bool isDllImport = false;		
-		if (methodInstance->GetImportKind() == BfImportKind_Import_Static)
+		if ((importKind == BfImportKind_Import_Static) || (importKind == BfImportKind_Import_Dynamic))
 		{
 		{
-			for (auto customAttr : methodInstance->GetCustomAttributes()->mAttributes)
-			{
-				if (customAttr.mType->mTypeDef->mFullName.ToString() == "System.ImportAttribute")
+			if (importStrNum != -1)
+			{				
+				if (importKind == BfImportKind_Import_Static)
 				{
 				{
-					if (customAttr.mCtorArgs.size() == 1)
+					if (!mImportFileNames.Contains(importStrNum))
 					{
 					{
-						auto fileNameArg = customAttr.mCtorArgs[0];
-						int strNum = 0;
-						auto constant = mCurTypeInstance->mConstHolder->GetConstant(fileNameArg);
-						if (constant != NULL)
-						{
-							if (constant->IsNull())
-								continue; // Invalid					
-							strNum = constant->mInt32;
-						}
-						else
-						{
-							strNum = GetStringPoolIdx(fileNameArg, mCurTypeInstance->mConstHolder);
-						}
-						if (!mImportFileNames.Contains(strNum))
-							mImportFileNames.Add(strNum);
+						mImportFileNames.Add(importStrNum);
 					}
 					}
 				}
 				}
+						
 			}
 			}
-
-			//mImportFileNames
 		}
 		}
 		else if (methodInstance->GetImportKind() == BfImportKind_Import_Dynamic)
 		else if (methodInstance->GetImportKind() == BfImportKind_Import_Dynamic)
 		{
 		{
@@ -21534,6 +21647,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 	{
 	{
 		BfTypeInstance* unspecializedTypeInstance = NULL;
 		BfTypeInstance* unspecializedTypeInstance = NULL;
 
 
+		Array<BfTypeReference*> deferredResolveTypes;
 		for (int genericParamIdx = 0; genericParamIdx < (int)methodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++)
 		for (int genericParamIdx = 0; genericParamIdx < (int)methodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++)
 		{
 		{
 			auto genericParam = methodInstance->mMethodInfoEx->mGenericParams[genericParamIdx];
 			auto genericParam = methodInstance->mMethodInfoEx->mGenericParams[genericParamIdx];
@@ -21557,8 +21671,8 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 				else
 				else
 					genericParam->mExternType = GetPrimitiveType(BfTypeCode_Var);
 					genericParam->mExternType = GetPrimitiveType(BfTypeCode_Var);
 			}
 			}
-
-			ResolveGenericParamConstraints(genericParam, methodInstance->mIsUnspecialized);
+			
+			ResolveGenericParamConstraints(genericParam, methodInstance->mIsUnspecialized, &deferredResolveTypes);						
 
 
 			if (genericParamIdx < (int)methodDef->mGenericParams.size())
 			if (genericParamIdx < (int)methodDef->mGenericParams.size())
 			{
 			{
@@ -21572,6 +21686,8 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 				}
 				}
 			}
 			}
 		}
 		}
+		for (auto typeRef : deferredResolveTypes)
+			auto constraintType = ResolveTypeRef(typeRef, BfPopulateType_Declaration, BfResolveTypeRefFlag_None);
 
 
 		for (auto genericParam : methodInstance->mMethodInfoEx->mGenericParams)
 		for (auto genericParam : methodInstance->mMethodInfoEx->mGenericParams)
 		{
 		{
@@ -21920,6 +22036,12 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 			}
 			}
 			else
 			else
 			{
 			{
+				BfTypeState typeState;
+				typeState.mTypeInstance = mCurTypeInstance;
+				typeState.mCurTypeDef = methodDef->mDeclaringType;
+				//typeState.mCurMethodDef = methodDef;
+				SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
+
 				BfConstResolver constResolver(this);
 				BfConstResolver constResolver(this);
 				defaultValue = constResolver.Resolve(paramDef->mParamDeclaration->mInitializer, resolvedParamType, (BfConstResolveFlags)(BfConstResolveFlag_NoCast | BfConstResolveFlag_AllowGlobalVariable));
 				defaultValue = constResolver.Resolve(paramDef->mParamDeclaration->mInitializer, resolvedParamType, (BfConstResolveFlags)(BfConstResolveFlag_NoCast | BfConstResolveFlag_AllowGlobalVariable));
 				if ((defaultValue) && (defaultValue.mType != resolvedParamType))
 				if ((defaultValue) && (defaultValue.mType != resolvedParamType))
@@ -22051,7 +22173,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 				resolvedParamType = CreateArrayType(mContext->mBfObjectType, 1);
 				resolvedParamType = CreateArrayType(mContext->mBfObjectType, 1);
 			}
 			}
 
 
-			if (addParams)
+			if ((addParams) && (resolvedParamType != NULL))
 			{
 			{
 				BfMethodParam methodParam;				
 				BfMethodParam methodParam;				
 				methodParam.mResolvedType = resolvedParamType;
 				methodParam.mResolvedType = resolvedParamType;
@@ -22692,6 +22814,11 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 		}
 		}
 	}
 	}
 
 
+	if ((methodDef->mIsConcrete) && (!methodInstance->mIsForeignMethodDef) && (!mCurTypeInstance->IsInterface()))
+	{
+		Fail("Only interfaces methods can be declared as 'concrete'", methodDeclaration->mVirtualSpecifier);
+	}
+
 	if ((methodDef->mIsVirtual) && (methodDef->mIsStatic) && (!methodInstance->mIsInnerOverride))
 	if ((methodDef->mIsVirtual) && (methodDef->mIsStatic) && (!methodInstance->mIsInnerOverride))
 	{
 	{
 		if ((virtualToken != NULL) && (virtualToken->mToken == BfToken_Override) && (methodDef->mDeclaringType->mTypeCode == BfTypeCode_Extension))
 		if ((virtualToken != NULL) && (virtualToken->mToken == BfToken_Override) && (methodDef->mDeclaringType->mTypeCode == BfTypeCode_Extension))

+ 13 - 11
IDEHelper/Compiler/BfModule.h

@@ -1435,6 +1435,7 @@ public:
 	Dictionary<int, BfIRValue> mStringObjectPool;
 	Dictionary<int, BfIRValue> mStringObjectPool;
 	Dictionary<int, BfIRValue> mStringCharPtrPool;
 	Dictionary<int, BfIRValue> mStringCharPtrPool;
 	Array<int> mStringPoolRefs;	
 	Array<int> mStringPoolRefs;	
+	HashSet<int> mUnreifiedStringPoolRefs;
 	
 	
 	Array<BfIRBuilder*> mPrevIRBuilders; // Before extensions	
 	Array<BfIRBuilder*> mPrevIRBuilders; // Before extensions	
 	BfIRBuilder* mBfIRBuilder;	
 	BfIRBuilder* mBfIRBuilder;	
@@ -1538,12 +1539,12 @@ public:
 	BfIRValue CreateStringCharPtr(const StringImpl& str, int stringId, bool define);
 	BfIRValue CreateStringCharPtr(const StringImpl& str, int stringId, bool define);
 	int GetStringPoolIdx(BfIRValue constantStr, BfIRConstHolder* constHolder = NULL);
 	int GetStringPoolIdx(BfIRValue constantStr, BfIRConstHolder* constHolder = NULL);
 	String* GetStringPoolString(BfIRValue constantStr, BfIRConstHolder* constHolder = NULL);
 	String* GetStringPoolString(BfIRValue constantStr, BfIRConstHolder* constHolder = NULL);
-	BfIRValue GetStringCharPtr(int stringId);
-	BfIRValue GetStringCharPtr(BfIRValue strValue);	
-	BfIRValue GetStringCharPtr(const StringImpl& str);
-	BfIRValue GetStringObjectValue(int idx);
-	BfIRValue GetStringObjectValue(const StringImpl& str, bool define = false);
-	BfIRValue CreateGlobalConstValue(const StringImpl& name, BfIRValue constant, BfIRType type, bool external);
+	BfIRValue GetStringCharPtr(int stringId, bool force = false);
+	BfIRValue GetStringCharPtr(BfIRValue strValue, bool force = false);
+	BfIRValue GetStringCharPtr(const StringImpl& str, bool force = false);
+	BfIRValue GetStringObjectValue(int idx, bool define, bool force);
+	BfIRValue GetStringObjectValue(const StringImpl& str, bool define = false, bool force = false);
+	BfIRValue CreateGlobalConstValue(const StringImpl& name, BfIRValue constant, BfIRType type, bool external);	
 	void VariantToString(StringImpl& str, const BfVariant& variant);
 	void VariantToString(StringImpl& str, const BfVariant& variant);
 	StringT<128> TypeToString(BfType* resolvedType, Array<String>* genericMethodParamNameOverrides = NULL);
 	StringT<128> TypeToString(BfType* resolvedType, Array<String>* genericMethodParamNameOverrides = NULL);
 	StringT<128> TypeToString(BfType* resolvedType, BfTypeNameFlags typeNameFlags, Array<String>* genericMethodParamNameOverrides = NULL);	
 	StringT<128> TypeToString(BfType* resolvedType, BfTypeNameFlags typeNameFlags, Array<String>* genericMethodParamNameOverrides = NULL);	
@@ -1553,8 +1554,9 @@ public:
 	void pm(BfMethodInstance* type);
 	void pm(BfMethodInstance* type);
 	void CurrentAddToConstHolder(BfIRValue& irVal);
 	void CurrentAddToConstHolder(BfIRValue& irVal);
 	void ClearConstData();
 	void ClearConstData();
-	BfTypedValue GetTypedValueFromConstant(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType);
-	BfIRValue ConstantToCurrent(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType, bool allowStringId = false);
+	bool HasUnactializedConstant(BfConstant* constant, BfIRConstHolder* constHolder);
+	BfTypedValue GetTypedValueFromConstant(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType);		
+	BfIRValue ConstantToCurrent(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType, bool allowUnactualized = false);
 	void ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget);
 	void ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget);
 	void GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs = false, BfCaptureInfo* captureInfo = NULL);	
 	void GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs = false, BfCaptureInfo* captureInfo = NULL);	
 	BfCustomAttributes* GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs = false, BfCaptureInfo* captureInfo = NULL);
 	BfCustomAttributes* GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs = false, BfCaptureInfo* captureInfo = NULL);
@@ -1771,12 +1773,12 @@ public:
 	BfMethodRefType* CreateMethodRefType(BfMethodInstance* methodInstance, bool mustAlreadyExist = false);
 	BfMethodRefType* CreateMethodRefType(BfMethodInstance* methodInstance, bool mustAlreadyExist = false);
 	BfType* FixIntUnknown(BfType* type);
 	BfType* FixIntUnknown(BfType* type);
 	void FixIntUnknown(BfTypedValue& typedVal, BfType* matchType = NULL);	
 	void FixIntUnknown(BfTypedValue& typedVal, BfType* matchType = NULL);	
-	void FixIntUnknown(BfTypedValue& lhs, BfTypedValue& rhs);	
-	void FixValueActualization(BfTypedValue& typedVal);
+	void FixIntUnknown(BfTypedValue& lhs, BfTypedValue& rhs);		
+	void FixValueActualization(BfTypedValue& typedVal, bool force = false);
 	bool TypeEquals(BfTypedValue& val, BfType* type);
 	bool TypeEquals(BfTypedValue& val, BfType* type);
 	BfTypeDef* ResolveGenericInstanceDef(BfGenericInstanceTypeRef* genericTypeRef, BfType** outType = NULL, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
 	BfTypeDef* ResolveGenericInstanceDef(BfGenericInstanceTypeRef* genericTypeRef, BfType** outType = NULL, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
 	BfType* ResolveType(BfType* lookupType, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
 	BfType* ResolveType(BfType* lookupType, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
-	void ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized);
+	void ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized, Array<BfTypeReference*>* deferredResolveTypes = NULL);
 	String GenericParamSourceToString(const BfGenericParamSource& genericParamSource);
 	String GenericParamSourceToString(const BfGenericParamSource& genericParamSource);
 	bool CheckGenericConstraints(const BfGenericParamSource& genericParamSource, BfType* checkArgType, BfAstNode* checkArgTypeRef, BfGenericParamInstance* genericParamInst, BfTypeVector* methodGenericArgs = NULL, BfError** errorOut = NULL);
 	bool CheckGenericConstraints(const BfGenericParamSource& genericParamSource, BfType* checkArgType, BfAstNode* checkArgTypeRef, BfGenericParamInstance* genericParamInst, BfTypeVector* methodGenericArgs = NULL, BfError** errorOut = NULL);
 	BfIRValue AllocLocalVariable(BfType* type, const StringImpl& name, bool doLifetimeEnd = true);
 	BfIRValue AllocLocalVariable(BfType* type, const StringImpl& name, bool doLifetimeEnd = true);

+ 157 - 56
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -164,7 +164,8 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
 	typeState.mResolveKind = BfTypeState::ResolveKind_BuildingGenericParams;
 	typeState.mResolveKind = BfTypeState::ResolveKind_BuildingGenericParams;
 	typeState.mTypeInstance = resolvedTypeRef->ToTypeInstance();
 	typeState.mTypeInstance = resolvedTypeRef->ToTypeInstance();
 	SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
 	SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
-	
+	Array<BfTypeReference*> deferredResolveTypes;
+
 	BF_ASSERT(mCurMethodInstance == NULL);
 	BF_ASSERT(mCurMethodInstance == NULL);
 
 
 	auto genericTypeInst = resolvedTypeRef->ToGenericTypeInstance();
 	auto genericTypeInst = resolvedTypeRef->ToGenericTypeInstance();
@@ -210,7 +211,7 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
 							genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var);
 							genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var);
 					}
 					}
 
 
-					ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType());
+					ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType(), &deferredResolveTypes);
 
 
 					if (genericParamDef != NULL)
 					if (genericParamDef != NULL)
 					{
 					{
@@ -283,7 +284,7 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
 					genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var);
 					genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var);
 			}
 			}
 
 
-			ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType());
+			ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType(), &deferredResolveTypes);
 			auto genericParamDef = genericParamInstance->GetGenericParamDef();
 			auto genericParamDef = genericParamInstance->GetGenericParamDef();
 			if (genericParamDef != NULL)
 			if (genericParamDef != NULL)
 			{
 			{
@@ -295,6 +296,9 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
 		}
 		}
 	}
 	}
 
 
+	for (auto typeRef : deferredResolveTypes)
+		auto constraintType = ResolveTypeRef(typeRef, BfPopulateType_Declaration, BfResolveTypeRefFlag_None);
+
 	for (auto genericParam : genericTypeInst->mGenericTypeInfo->mGenericParams)
 	for (auto genericParam : genericTypeInst->mGenericTypeInfo->mGenericParams)
 	{
 	{
 		for (auto constraintTypeInst : genericParam->mInterfaceConstraints)
 		for (auto constraintTypeInst : genericParam->mInterfaceConstraints)
@@ -339,6 +343,13 @@ bool BfModule::ValidateGenericConstraints(BfTypeReference* typeRef, BfTypeInstan
 		return true;
 		return true;
 	}
 	}
 
 
+	for (auto typeArg : genericTypeInst->mGenericTypeInfo->mTypeGenericArguments)
+	{
+		auto genericArg = typeArg->ToGenericTypeInstance();
+		if (genericArg != NULL)
+			genericTypeInst->mGenericTypeInfo->mMaxGenericDepth = BF_MAX(genericTypeInst->mGenericTypeInfo->mMaxGenericDepth, genericArg->mGenericTypeInfo->mMaxGenericDepth + 1);
+	}
+
 	auto typeDef = genericTypeInst->mTypeDef;		
 	auto typeDef = genericTypeInst->mTypeDef;		
 	for (int paramIdx = 0; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mGenericParams.size(); paramIdx++)
 	for (int paramIdx = 0; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mGenericParams.size(); paramIdx++)
 	{
 	{
@@ -1029,7 +1040,21 @@ void BfModule::PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType
 						typeModule->mIsReified = true;
 						typeModule->mIsReified = true;
 						typeModule->mWantsIRIgnoreWrites = false;						
 						typeModule->mWantsIRIgnoreWrites = false;						
 						for (auto ownedTypes : typeModule->mOwnedTypeInstances)
 						for (auto ownedTypes : typeModule->mOwnedTypeInstances)
+						{
 							ownedTypes->mIsReified = true;
 							ownedTypes->mIsReified = true;
+
+							if (ownedTypes->mCustomAttributes != NULL)
+							{
+								for (auto& attr : ownedTypes->mCustomAttributes->mAttributes)
+								{
+									if ((attr.mType->mAttributeData != NULL) && ((attr.mType->mAttributeData->mFlags & BfCustomAttributeFlags_ReflectAttribute) != 0))
+									{
+										// Reify this attribute
+										typeModule->PopulateType(attr.mType);
+									}
+								}
+							}
+						}
 						mCompiler->mStats.mReifiedModuleCount++;
 						mCompiler->mStats.mReifiedModuleCount++;
 						if (typeModule->mBfIRBuilder != NULL)
 						if (typeModule->mBfIRBuilder != NULL)
 						{
 						{
@@ -1038,7 +1063,7 @@ void BfModule::PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType
 							typeModule->SetupIRBuilder(false);
 							typeModule->SetupIRBuilder(false);
 						}
 						}
 						else
 						else
-							typeModule->PrepareForIRWriting(resolvedTypeRef->ToTypeInstance());
+							typeModule->PrepareForIRWriting(resolvedTypeRef->ToTypeInstance());						
 					}
 					}
 					else
 					else
 					{
 					{
@@ -2002,7 +2027,7 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance*
 	for (auto& customAttribute : customAttributes->mAttributes)
 	for (auto& customAttribute : customAttributes->mAttributes)
 	{			
 	{			
 		auto attrType = customAttribute.mType;
 		auto attrType = customAttribute.mType;
-		PopulateType(attrType, BfPopulateType_DataAndMethods);
+		mContext->mUnreifiedModule->PopulateType(attrType, BfPopulateType_DataAndMethods);
 		if (attrType->mDefineState < BfTypeDefineState_DefinedAndMethodsSlotted)
 		if (attrType->mDefineState < BfTypeDefineState_DefinedAndMethodsSlotted)
 			continue;
 			continue;
 
 
@@ -2331,7 +2356,7 @@ void BfModule::DoCEEmit(BfMethodInstance* methodInstance)
 	for (auto& customAttribute : customAttributes->mAttributes)
 	for (auto& customAttribute : customAttributes->mAttributes)
 	{
 	{
 		auto attrType = customAttribute.mType;
 		auto attrType = customAttribute.mType;
-		PopulateType(attrType, BfPopulateType_DataAndMethods);
+		mContext->mUnreifiedModule->PopulateType(attrType, BfPopulateType_DataAndMethods);
 		if (attrType->mDefineState < BfTypeDefineState_DefinedAndMethodsSlotted)
 		if (attrType->mDefineState < BfTypeDefineState_DefinedAndMethodsSlotted)
 			continue;
 			continue;
 
 
@@ -2599,8 +2624,10 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 	SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, typeInstance);
 	SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, typeInstance);
 	SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, NULL);
 	SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, NULL);
 	SetAndRestoreValue<BfMethodState*> prevMethodState(mCurMethodState, NULL);
 	SetAndRestoreValue<BfMethodState*> prevMethodState(mCurMethodState, NULL);
-	SetAndRestoreValue<bool> prevHadError(mHadBuildError, false);
-	SetAndRestoreValue<bool> prevHadWarning(mHadBuildWarning, false);
+
+	// WHY were we clearing these values? 
+	//SetAndRestoreValue<bool> prevHadError(mHadBuildError, false);
+	//SetAndRestoreValue<bool> prevHadWarning(mHadBuildWarning, false);
 
 
 	BfTypeState typeState(mCurTypeInstance, mContext->mCurTypeState);
 	BfTypeState typeState(mCurTypeInstance, mContext->mCurTypeState);
 	typeState.mPopulateType = populateType;
 	typeState.mPopulateType = populateType;
@@ -2640,8 +2667,8 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 	
 	
 	if (typeInstance->mIsFinishingType)
 	if (typeInstance->mIsFinishingType)
 	{
 	{
-		// This type already failed
-		return;
+		if (typeInstance->mTypeFailed)
+			return;
 	}
 	}
 
 
 	if (!typeInstance->mTypeFailed)
 	if (!typeInstance->mTypeFailed)
@@ -3006,7 +3033,10 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 			bool populateBase = !typeInstance->mTypeFailed;			
 			bool populateBase = !typeInstance->mTypeFailed;			
 			auto checkType = ResolveTypeRef(checkTypeRef, BfPopulateType_Declaration);
 			auto checkType = ResolveTypeRef(checkTypeRef, BfPopulateType_Declaration);
 			if ((checkType != NULL) && (!checkType->IsInterface()) && (populateBase))
 			if ((checkType != NULL) && (!checkType->IsInterface()) && (populateBase))
+			{
+				SetAndRestoreValue<BfTypeInstance*> prevBaseType(mContext->mCurTypeState->mCurBaseType, checkType->ToTypeInstance());
 				PopulateType(checkType, BfPopulateType_Data);
 				PopulateType(checkType, BfPopulateType_Data);
+			}
 
 
 			if (typeInstance->mDefineState >= BfTypeDefineState_Defined)
 			if (typeInstance->mDefineState >= BfTypeDefineState_Defined)
 			{
 			{
@@ -3387,6 +3417,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 	
 	
 	for (auto& validateEntry : deferredTypeValidateList)
 	for (auto& validateEntry : deferredTypeValidateList)
 	{
 	{
+		SetAndRestoreValue<BfTypeReference*> prevAttributeTypeRef(typeState.mCurAttributeTypeRef, validateEntry.mTypeRef);
 		SetAndRestoreValue<bool> ignoreErrors(mIgnoreErrors, mIgnoreErrors | validateEntry.mIgnoreErrors);
 		SetAndRestoreValue<bool> ignoreErrors(mIgnoreErrors, mIgnoreErrors | validateEntry.mIgnoreErrors);
 		ValidateGenericConstraints(validateEntry.mTypeRef, validateEntry.mGenericType, false);
 		ValidateGenericConstraints(validateEntry.mTypeRef, validateEntry.mGenericType, false);
 	}
 	}
@@ -3742,7 +3773,12 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 
 
 				if (populateChildType)
 				if (populateChildType)
 				{
 				{
-					BF_ASSERT(!resolvedFieldType->IsDataIncomplete());
+					if (resolvedFieldType->IsFinishingType())
+					{
+						AssertErrorState();
+					}
+					else
+						BF_ASSERT(!resolvedFieldType->IsDataIncomplete());
 				}
 				}
 				else
 				else
 				{
 				{
@@ -4319,34 +4355,41 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 	
 	
 	if ((mCompiler->mOptions.mAllowHotSwapping) && (typeInstance->mDefineState < BfTypeDefineState_Defined))
 	if ((mCompiler->mOptions.mAllowHotSwapping) && (typeInstance->mDefineState < BfTypeDefineState_Defined))
 	{	
 	{	
-		auto hotTypeVersion = typeInstance->mHotTypeData->mTypeVersions.back();
-
-		if ((typeInstance->mBaseType != NULL) && (typeInstance->mBaseType->mHotTypeData != NULL))
+		if (typeInstance->mHotTypeData == NULL)
 		{
 		{
-			hotTypeVersion->mMembers.Add(typeInstance->mBaseType->mHotTypeData->GetLatestVersion());
+			BF_ASSERT(typeInstance->mTypeFailed);
 		}
 		}
-
-		for (auto& fieldInst : typeInstance->mFieldInstances)
+		else
 		{
 		{
-			auto fieldDef = fieldInst.GetFieldDef();
-			if ((fieldDef == NULL) || (fieldDef->mIsStatic))
-				continue;
-			auto depType = fieldInst.mResolvedType;
+			auto hotTypeVersion = typeInstance->mHotTypeData->mTypeVersions.back();
 
 
-			while (depType->IsSizedArray())
-				depType = ((BfSizedArrayType*)depType)->mElementType;
-			if (depType->IsStruct())
+			if ((typeInstance->mBaseType != NULL) && (typeInstance->mBaseType->mHotTypeData != NULL))
 			{
 			{
-				PopulateType(depType);
-				auto depTypeInst = depType->ToTypeInstance();
-				BF_ASSERT(depTypeInst->mHotTypeData != NULL);
-				if (depTypeInst->mHotTypeData != NULL)
-					hotTypeVersion->mMembers.Add(depTypeInst->mHotTypeData->GetLatestVersion());
+				hotTypeVersion->mMembers.Add(typeInstance->mBaseType->mHotTypeData->GetLatestVersion());
 			}
 			}
-		}
 
 
-		for (auto member : hotTypeVersion->mMembers)
-			member->mRefCount++;
+			for (auto& fieldInst : typeInstance->mFieldInstances)
+			{
+				auto fieldDef = fieldInst.GetFieldDef();
+				if ((fieldDef == NULL) || (fieldDef->mIsStatic))
+					continue;
+				auto depType = fieldInst.mResolvedType;
+
+				while (depType->IsSizedArray())
+					depType = ((BfSizedArrayType*)depType)->mElementType;
+				if (depType->IsStruct())
+				{
+					PopulateType(depType);
+					auto depTypeInst = depType->ToTypeInstance();
+					BF_ASSERT(depTypeInst->mHotTypeData != NULL);
+					if (depTypeInst->mHotTypeData != NULL)
+						hotTypeVersion->mMembers.Add(depTypeInst->mHotTypeData->GetLatestVersion());
+				}
+			}
+
+			for (auto member : hotTypeVersion->mMembers)
+				member->mRefCount++;
+		}
 	}
 	}
 
 
 	if (typeInstance->mDefineState < BfTypeDefineState_Defined)
 	if (typeInstance->mDefineState < BfTypeDefineState_Defined)
@@ -4962,7 +5005,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
 
 
 	//
 	//
 	{
 	{
-		if (typeInstance->IsSpecializedType())
+		if ((typeInstance->IsSpecializedType()) || (typeInstance->IsUnspecializedTypeVariation()))
 			wantsOnDemandMethods = true;
 			wantsOnDemandMethods = true;
 		else if ((mCompiler->mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude) &&
 		else if ((mCompiler->mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude) &&
 			(!typeInstance->IsUnspecializedTypeVariation()))
 			(!typeInstance->IsUnspecializedTypeVariation()))
@@ -6000,11 +6043,14 @@ BfArrayType* BfModule::CreateArrayType(BfType* resolvedType, int dimensions)
 	BF_ASSERT(!resolvedType->IsVar());
 	BF_ASSERT(!resolvedType->IsVar());
 	BF_ASSERT(!resolvedType->IsIntUnknown());
 	BF_ASSERT(!resolvedType->IsIntUnknown());
 
 
+	auto arrayTypeDef = mCompiler->GetArrayTypeDef(dimensions);
+	if (arrayTypeDef == NULL)
+		return NULL;
 	auto arrayType = mContext->mArrayTypePool.Get();
 	auto arrayType = mContext->mArrayTypePool.Get();
 	delete arrayType->mGenericTypeInfo;
 	delete arrayType->mGenericTypeInfo;
 	arrayType->mGenericTypeInfo = new BfGenericTypeInfo();
 	arrayType->mGenericTypeInfo = new BfGenericTypeInfo();
 	arrayType->mContext = mContext;
 	arrayType->mContext = mContext;
-	arrayType->mTypeDef = mCompiler->GetArrayTypeDef(dimensions);
+	arrayType->mTypeDef = arrayTypeDef;
 	arrayType->mDimensions = dimensions;
 	arrayType->mDimensions = dimensions;
 	arrayType->mGenericTypeInfo->mTypeGenericArguments.clear();
 	arrayType->mGenericTypeInfo->mTypeGenericArguments.clear();
 	arrayType->mGenericTypeInfo->mTypeGenericArguments.push_back(resolvedType);
 	arrayType->mGenericTypeInfo->mTypeGenericArguments.push_back(resolvedType);
@@ -6450,19 +6496,16 @@ void BfModule::FixIntUnknown(BfTypedValue& lhs, BfTypedValue& rhs)
 	FixIntUnknown(rhs);
 	FixIntUnknown(rhs);
 }
 }
 
 
-void BfModule::FixValueActualization(BfTypedValue& typedVal)
+void BfModule::FixValueActualization(BfTypedValue& typedVal, bool force)
 {
 {
 	if (!typedVal.mValue.IsConst())
 	if (!typedVal.mValue.IsConst())
 		return;	
 		return;	
-	if (mBfIRBuilder->mIgnoreWrites)
+	if ((mBfIRBuilder->mIgnoreWrites) && (!force))
 		return;
 		return;
 	auto constant = mBfIRBuilder->GetConstant(typedVal.mValue);
 	auto constant = mBfIRBuilder->GetConstant(typedVal.mValue);
-	if (constant->mConstType == BfConstType_TypeOf)
-	{				
-		auto constTypeOf = (BfTypeOf_Const*)constant;
-		AddDependency(constTypeOf->mType, mCurTypeInstance, BfDependencyMap::DependencyFlag_ExprTypeReference);
-		typedVal.mValue = CreateTypeDataRef(constTypeOf->mType);
-	}
+	if (!HasUnactializedConstant(constant, mBfIRBuilder))
+		return;	
+	typedVal.mValue = ConstantToCurrent(constant, mBfIRBuilder, typedVal.mType, false);
 }
 }
 
 
 BfTypeInstance* BfModule::GetPrimitiveStructType(BfTypeCode typeCode)
 BfTypeInstance* BfModule::GetPrimitiveStructType(BfTypeCode typeCode)
@@ -7928,7 +7971,7 @@ bool BfModule::ResolveTypeResult_Validate(BfTypeReference* typeRef, BfType* reso
 				if ((curGenericTypeInstance->mDependencyMap.mMinDependDepth > 32) &&
 				if ((curGenericTypeInstance->mDependencyMap.mMinDependDepth > 32) &&
 					(genericTypeInstance->mDependencyMap.mMinDependDepth > 32))
 					(genericTypeInstance->mDependencyMap.mMinDependDepth > 32))
 				{
 				{
-					Fail(StrFormat("Generic type dependency depth exceeded for type '{}'", TypeToString(genericTypeInstance).c_str()), typeRef);
+					Fail(StrFormat("Generic type dependency depth exceeded for type '%s'", TypeToString(genericTypeInstance).c_str()), typeRef);
 					return false;
 					return false;
 				}
 				}
 
 
@@ -9714,7 +9757,14 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 				CheckUnspecializedGenericType(genericTypeInst, populateType);
 				CheckUnspecializedGenericType(genericTypeInst, populateType);
 				resolvedEntry->mValue = genericTypeInst;
 				resolvedEntry->mValue = genericTypeInst;
 				populateModule->InitType(genericTypeInst, populateType);
 				populateModule->InitType(genericTypeInst, populateType);
-				BF_ASSERT(BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) == resolvedEntry->mHash);				
+#ifdef _DEBUG
+				if (BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) != resolvedEntry->mHash)
+				{
+					int refHash = BfResolvedTypeSet::Hash(typeRef, &lookupCtx);
+					int typeHash = BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx);
+					BF_ASSERT(refHash == typeHash);
+				}
+#endif
 				return ResolveTypeResult(typeRef, genericTypeInst, populateType, resolveFlags);
 				return ResolveTypeResult(typeRef, genericTypeInst, populateType, resolveFlags);
 			}
 			}
 		}
 		}
@@ -9731,6 +9781,11 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		}
 		}
 		typeInst->mTypeDef = typeDef;
 		typeInst->mTypeDef = typeDef;
 
 
+		if (((resolveFlags & BfResolveTypeRefFlag_NoReify) != 0) && (mCompiler->mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude))
+		{
+			typeInst->mIsReified = false;
+		}
+
 		if (typeInst->mTypeDef->mGenericParamDefs.size() != 0)
 		if (typeInst->mTypeDef->mGenericParamDefs.size() != 0)
 		{
 		{
 			Fail("Generic type arguments expected", typeRef);
 			Fail("Generic type arguments expected", typeRef);
@@ -9767,12 +9822,13 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		}
 		}
 
 
 		auto elementType = ResolveTypeRef(arrayTypeRef->mElementType, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue);
 		auto elementType = ResolveTypeRef(arrayTypeRef->mElementType, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue);
-		if (elementType == NULL)
+		auto arrayTypeDef = mCompiler->GetArrayTypeDef(arrayTypeRef->mDimensions);
+		if ((elementType == NULL) || (arrayTypeDef == NULL))
 		{
 		{
 			mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
 			mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
 			return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags);
 			return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags);
 		}
 		}
-
+		
 		if ((arrayTypeRef->mDimensions == 1) && (arrayTypeRef->mParams.size() == 1))
 		if ((arrayTypeRef->mDimensions == 1) && (arrayTypeRef->mParams.size() == 1))
 		{
 		{
 			intptr elementCount = -1;
 			intptr elementCount = -1;
@@ -9840,7 +9896,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		arrayType->mGenericTypeInfo = new BfGenericTypeInfo();
 		arrayType->mGenericTypeInfo = new BfGenericTypeInfo();
 		arrayType->mContext = mContext;
 		arrayType->mContext = mContext;
 		arrayType->mDimensions = arrayTypeRef->mDimensions;
 		arrayType->mDimensions = arrayTypeRef->mDimensions;
-		arrayType->mTypeDef = mCompiler->GetArrayTypeDef(arrayType->mDimensions);
+		arrayType->mTypeDef = arrayTypeDef;
 		arrayType->mGenericTypeInfo->mTypeGenericArguments.push_back(elementType);
 		arrayType->mGenericTypeInfo->mTypeGenericArguments.push_back(elementType);
 		resolvedEntry->mValue = arrayType;
 		resolvedEntry->mValue = arrayType;
 
 
@@ -9962,15 +10018,16 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 			auto parentTypeInstance = outerTypeInstance;
 			auto parentTypeInstance = outerTypeInstance;
 			if (parentTypeInstance->IsTypeAlias())
 			if (parentTypeInstance->IsTypeAlias())
 				parentTypeInstance = (BfTypeInstance*)GetOuterType(parentTypeInstance)->ToTypeInstance();
 				parentTypeInstance = (BfTypeInstance*)GetOuterType(parentTypeInstance)->ToTypeInstance();
+			genericTypeInst->mGenericTypeInfo->mMaxGenericDepth = BF_MAX(genericTypeInst->mGenericTypeInfo->mMaxGenericDepth, parentTypeInstance->mGenericTypeInfo->mMaxGenericDepth);
 			for (int i = 0; i < startDefGenericParamIdx; i++)
 			for (int i = 0; i < startDefGenericParamIdx; i++)
 			{
 			{
 				genericTypeInst->mGenericTypeInfo->mGenericParams.push_back(parentTypeInstance->mGenericTypeInfo->mGenericParams[i]->AddRef());
 				genericTypeInst->mGenericTypeInfo->mGenericParams.push_back(parentTypeInstance->mGenericTypeInfo->mGenericParams[i]->AddRef());
 				genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.push_back(parentTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i]);
 				genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.push_back(parentTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i]);
 				auto typeGenericArg = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[i];
 				auto typeGenericArg = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[i];
 				genericTypeInst->mGenericTypeInfo->mIsUnspecialized |= typeGenericArg->IsGenericParam() || typeGenericArg->IsUnspecializedType();
 				genericTypeInst->mGenericTypeInfo->mIsUnspecialized |= typeGenericArg->IsGenericParam() || typeGenericArg->IsUnspecializedType();
+				
 			}			
 			}			
-		}
-		
+		}		
 
 
 		int wantedGenericParams = genericParamCount - startDefGenericParamIdx;
 		int wantedGenericParams = genericParamCount - startDefGenericParamIdx;
 		int genericArgDiffCount = (int)genericArguments.size() - wantedGenericParams;
 		int genericArgDiffCount = (int)genericArguments.size() - wantedGenericParams;
@@ -9989,14 +10046,28 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		for (auto genericArgRef : genericArguments)
 		for (auto genericArgRef : genericArguments)
 		{
 		{
 			auto genericArg = genericArgs[genericParamIdx + startDefGenericParamIdx];
 			auto genericArg = genericArgs[genericParamIdx + startDefGenericParamIdx];
+
+			if (auto genericGenericArg = genericArg->ToGenericTypeInstance())
+			{
+				genericTypeInst->mGenericTypeInfo->mMaxGenericDepth = BF_MAX(genericTypeInst->mGenericTypeInfo->mMaxGenericDepth, genericGenericArg->mGenericTypeInfo->mMaxGenericDepth + 1);
+			}
+
 			genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.push_back(genericArg);
 			genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.push_back(genericArg);
 			genericTypeInst->mGenericTypeInfo->mTypeGenericArgumentRefs.push_back(genericArgRef);
 			genericTypeInst->mGenericTypeInfo->mTypeGenericArgumentRefs.push_back(genericArgRef);
 
 
 			genericParamIdx++;
 			genericParamIdx++;
 		}
 		}
 
 
-		resolvedEntry->mValue = genericTypeInst;		
+		if (genericTypeInst->mGenericTypeInfo->mMaxGenericDepth > 64)
+		{
+			Fail("Maximum generic depth exceeded", typeRef);
+			delete genericTypeInst;
+			mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
+			return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags);
+		}
 
 
+		resolvedEntry->mValue = genericTypeInst;		
+		
 		CheckUnspecializedGenericType(genericTypeInst, populateType);
 		CheckUnspecializedGenericType(genericTypeInst, populateType);
 		populateModule->InitType(genericTypeInst, populateType);
 		populateModule->InitType(genericTypeInst, populateType);
 
 
@@ -10011,6 +10082,8 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		{
 		{
 			BF_ASSERT(BfResolvedTypeSet::Equals(genericTypeInst, typeRef, &lookupCtx));
 			BF_ASSERT(BfResolvedTypeSet::Equals(genericTypeInst, typeRef, &lookupCtx));
 		}
 		}
+
+		BfLogSysM("Generic type %p typeHash: %8X\n", genericTypeInst, resolvedEntry->mHash);
 #endif
 #endif
 
 
 		BF_ASSERT(BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) == resolvedEntry->mHash);		
 		BF_ASSERT(BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) == resolvedEntry->mHash);		
@@ -10145,7 +10218,14 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		CheckUnspecializedGenericType(genericTypeInst, populateType);
 		CheckUnspecializedGenericType(genericTypeInst, populateType);
 
 
 		resolvedEntry->mValue = genericTypeInst;
 		resolvedEntry->mValue = genericTypeInst;
-		BF_ASSERT(BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) == resolvedEntry->mHash);
+#ifdef _DEBUG
+		if (BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) != resolvedEntry->mHash)
+		{
+			int refHash = BfResolvedTypeSet::Hash(typeRef, &lookupCtx);
+			int typeHash = BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx);
+			BF_ASSERT(refHash == typeHash);
+		}
+#endif
 		populateModule->InitType(genericTypeInst, populateType);
 		populateModule->InitType(genericTypeInst, populateType);
 		return ResolveTypeResult(typeRef, genericTypeInst, populateType, resolveFlags);
 		return ResolveTypeResult(typeRef, genericTypeInst, populateType, resolveFlags);
 	}
 	}
@@ -10281,7 +10361,11 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		if ((mCurTypeInstance == NULL) || (!mCurTypeInstance->IsGenericTypeInstance()))
 		if ((mCurTypeInstance == NULL) || (!mCurTypeInstance->IsGenericTypeInstance()))
 			wantGeneric = false;
 			wantGeneric = false;
 
 
-		auto baseDelegateType = ResolveTypeDef(mCompiler->mDelegateTypeDef)->ToTypeInstance();
+		BfTypeInstance* baseDelegateType = NULL;
+		if (mCompiler->mDelegateTypeDef != NULL)
+			baseDelegateType = ResolveTypeDef(mCompiler->mDelegateTypeDef)->ToTypeInstance();
+		else
+			failed = true;
 
 
 		BfDelegateInfo* delegateInfo = NULL;
 		BfDelegateInfo* delegateInfo = NULL;
 		BfTypeInstance* delegateType = NULL;
 		BfTypeInstance* delegateType = NULL;
@@ -10328,7 +10412,8 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		Val128 hashContext;
 		Val128 hashContext;
 
 
 		BfTypeDef* typeDef = new BfTypeDef();
 		BfTypeDef* typeDef = new BfTypeDef();
-		typeDef->mProject = baseDelegateType->mTypeDef->mProject;
+		if (baseDelegateType != NULL)
+			typeDef->mProject = baseDelegateType->mTypeDef->mProject;
 		typeDef->mSystem = mCompiler->mSystem;
 		typeDef->mSystem = mCompiler->mSystem;
 		typeDef->mName = mSystem->mEmptyAtom;
 		typeDef->mName = mSystem->mEmptyAtom;
 		if (delegateTypeRef->mTypeToken->GetToken() == BfToken_Delegate)
 		if (delegateTypeRef->mTypeToken->GetToken() == BfToken_Delegate)
@@ -10360,9 +10445,12 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		delegateInfo->mDirectAllocNodes.push_back(directTypeRef);		
 		delegateInfo->mDirectAllocNodes.push_back(directTypeRef);		
 		if (typeDef->mIsDelegate)
 		if (typeDef->mIsDelegate)
 			directTypeRef->Init(delegateType);
 			directTypeRef->Init(delegateType);
+		else if (mCompiler->mFunctionTypeDef == NULL)
+			failed = true;
 		else
 		else
 			directTypeRef->Init(ResolveTypeDef(mCompiler->mFunctionTypeDef));
 			directTypeRef->Init(ResolveTypeDef(mCompiler->mFunctionTypeDef));
-		typeDef->mBaseTypes.push_back(directTypeRef);		
+		if (!failed)
+			typeDef->mBaseTypes.push_back(directTypeRef);		
 
 
 		directTypeRef = BfAstNode::ZeroedAlloc<BfDirectTypeReference>();
 		directTypeRef = BfAstNode::ZeroedAlloc<BfDirectTypeReference>();
 		delegateInfo->mDirectAllocNodes.push_back(directTypeRef);
 		delegateInfo->mDirectAllocNodes.push_back(directTypeRef);
@@ -11013,7 +11101,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 				{
 				{
 					SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true);
 					SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true);
 					auto constraintTypeInst = genericParamInst->mTypeConstraint->ToTypeInstance();
 					auto constraintTypeInst = genericParamInst->mTypeConstraint->ToTypeInstance();
-					if ((constraintTypeInst != NULL) && (constraintTypeInst->mTypeDef == mCompiler->mEnumTypeDef))
+					if ((constraintTypeInst != NULL) && (constraintTypeInst->mTypeDef == mCompiler->mEnumTypeDef) && (explicitCast))
 					{
 					{
 						// Enum->int
 						// Enum->int
 						if ((explicitCast) && (toType->IsInteger()))
 						if ((explicitCast) && (toType->IsInteger()))
@@ -11052,7 +11140,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 					}
 					}
 				}
 				}
 
 
-				if (toType->IsInteger())
+				if ((toType->IsInteger()) && (explicitCast))
 				{
 				{
 					if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Enum) != 0)
 					if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Enum) != 0)
 					{
 					{
@@ -12780,6 +12868,19 @@ bool BfModule::TypeIsSubTypeOf(BfTypeInstance* srcType, BfTypeInstance* wantType
 
 
 	if (srcType->mDefineState < BfTypeDefineState_HasInterfaces)
 	if (srcType->mDefineState < BfTypeDefineState_HasInterfaces)
 	{
 	{
+		if (srcType->mDefineState == BfTypeDefineState_ResolvingBaseType)
+		{
+			auto typeState = mContext->mCurTypeState;
+			while (typeState != NULL)
+			{
+				if ((typeState->mTypeInstance == srcType) && (typeState->mCurBaseType != NULL))
+				{
+					return TypeIsSubTypeOf(typeState->mCurBaseType, wantType, checkAccessibility);
+				}
+				typeState = typeState->mPrevState;
+			}
+		}
+
 		// Type is incomplete.  We don't do the IsIncomplete check here because of re-entry
 		// Type is incomplete.  We don't do the IsIncomplete check here because of re-entry
 		//  While handling 'var' resolution, we don't want to force a PopulateType reentry 
 		//  While handling 'var' resolution, we don't want to force a PopulateType reentry 
 		//  but we do have enough information for TypeIsSubTypeOf
 		//  but we do have enough information for TypeIsSubTypeOf

+ 45 - 1
IDEHelper/Compiler/BfPrinter.cpp

@@ -374,6 +374,50 @@ void BfPrinter::WriteIgnoredNode(BfAstNode* node)
 	{
 	{
 		Visit((BfAstNode*)node);
 		Visit((BfAstNode*)node);
 		startIdx = node->mSrcStart;
 		startIdx = node->mSrcStart;
+
+		if (doWrap)
+		{			
+			bool wantWrap = false;
+
+			int spacedWordCount = 0;
+			bool inQuotes = false;
+			auto src = astNodeSrc->mSrc;
+			bool isDefinitelyCode = false;
+			bool hadNonSlash = false;
+
+			for (int i = node->mSrcStart + 1; i < node->mSrcEnd - 1; i++)
+			{
+				char c = src[i];
+				if (c != '/')
+					hadNonSlash = true;
+				if (inQuotes)
+				{
+					if (c == '\\')
+					{
+						i++;
+					}
+					else if (c == '\"')
+					{
+						inQuotes = false;
+					}
+				}
+				else if (c == '"')
+				{
+					inQuotes = true;
+				}
+				else if (c == ' ')
+				{
+					if ((isalpha((uint8)src[i - 1])) && (isalpha((uint8)src[i + 1])))
+						spacedWordCount++;
+				}
+				else if ((c == '/') && (src[i - 1] == '/') && (hadNonSlash))
+					isDefinitelyCode = true;
+			}
+
+			// If this doesn't look like a sentence then don't try to word wrap
+			if ((isDefinitelyCode) || (spacedWordCount < 4))
+				doWrap = false;
+		}
 	}
 	}
 
 
 	int lineEmittedChars = 0;
 	int lineEmittedChars = 0;
@@ -1803,7 +1847,7 @@ void BfPrinter::Visit(BfDeferStatement* deferStmt)
 
 
 	VisitChild(deferStmt->mDeferToken);
 	VisitChild(deferStmt->mDeferToken);
 	VisitChild(deferStmt->mColonToken);
 	VisitChild(deferStmt->mColonToken);
-	VisitChild(deferStmt->mScopeToken);
+	VisitChild(deferStmt->mScopeName);
 
 
 	if (deferStmt->mBind != NULL)
 	if (deferStmt->mBind != NULL)
 	{
 	{

+ 4 - 2
IDEHelper/Compiler/BfReducer.cpp

@@ -3797,6 +3797,8 @@ BfAstNode* BfReducer::DoCreateStatement(BfAstNode* node, CreateStmtFlags createS
 				}
 				}
 				else if (nextTokenNode->GetToken() == BfToken_LParen)
 				else if (nextTokenNode->GetToken() == BfToken_LParen)
 				{
 				{
+					mPassInstance->Warn(0, "Syntax deprecated", nextTokenNode);
+
 					MEMBER_SET(deferStmt, mOpenParen, nextTokenNode);
 					MEMBER_SET(deferStmt, mOpenParen, nextTokenNode);
 					mVisitorPos.MoveNext();
 					mVisitorPos.MoveNext();
 
 
@@ -9264,9 +9266,9 @@ bool BfReducer::ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayIm
 
 
 	bool isFunction = false;
 	bool isFunction = false;
 	bool isDelegate = false;
 	bool isDelegate = false;
-	if ((mCurTypeDecl->mTypeNode != NULL) && (mCurTypeDecl->mTypeNode->GetToken() == BfToken_Function))
+	if ((mCurTypeDecl != NULL) && (mCurTypeDecl->mTypeNode != NULL) && (mCurTypeDecl->mTypeNode->GetToken() == BfToken_Function))
 		isFunction = true;
 		isFunction = true;
-	else if ((mCurTypeDecl->mTypeNode != NULL) && (mCurTypeDecl->mTypeNode->GetToken() == BfToken_Delegate))
+	else if ((mCurTypeDecl != NULL) && (mCurTypeDecl->mTypeNode != NULL) && (mCurTypeDecl->mTypeNode->GetToken() == BfToken_Delegate))
 		isDelegate = true;
 		isDelegate = true;
 
 
 	if ((!isFunction) && (!isDelegate))
 	if ((!isFunction) && (!isDelegate))

+ 81 - 51
IDEHelper/Compiler/BfResolvedTypeUtils.cpp

@@ -1686,7 +1686,7 @@ BfType* BfTypeInstance::GetUnionInnerType(bool* wantSplat)
 		{
 		{
 			SetAndRestoreValue<BfFieldDef*> prevTypeRef(mContext->mCurTypeState->mCurFieldDef, fieldDef);
 			SetAndRestoreValue<BfFieldDef*> prevTypeRef(mContext->mCurTypeState->mCurFieldDef, fieldDef);
 
 
-			mModule->PopulateType(checkInnerType);
+			mModule->PopulateType(checkInnerType, checkInnerType->IsValueType() ? BfPopulateType_Data : BfPopulateType_Declaration);
 			if (checkInnerType->mSize > unionSize)
 			if (checkInnerType->mSize > unionSize)
 				unionSize = checkInnerType->mSize;	
 				unionSize = checkInnerType->mSize;	
 
 
@@ -2194,7 +2194,7 @@ bool BfTypeInstance::WantsGCMarking()
 		return true; 
 		return true; 
 	if ((IsEnum()) && (!IsPayloadEnum()))
 	if ((IsEnum()) && (!IsPayloadEnum()))
 		return false;	
 		return false;	
-	BF_ASSERT(mDefineState >= BfTypeDefineState_Defined);
+	BF_ASSERT((mDefineState >= BfTypeDefineState_Defined) || (mTypeFailed));
 	return mWantsGCMarking;
 	return mWantsGCMarking;
 }
 }
 
 
@@ -2674,7 +2674,7 @@ size_t BfTypeVectorHash::operator()(const BfTypeVector& typeVec) const
 	size_t hash = typeVec.size();
 	size_t hash = typeVec.size();
 	BfResolvedTypeSet::LookupContext ctx;
 	BfResolvedTypeSet::LookupContext ctx;
 	for (auto type : typeVec)
 	for (auto type : typeVec)
-		hash = ((hash ^ BfResolvedTypeSet::Hash(type, &ctx)) << 5) - hash;
+		hash = ((hash ^ BfResolvedTypeSet::Hash(type, &ctx, Beefy::BfResolvedTypeSet::BfHashFlag_None, 0)) << 5) - hash;
 	return hash;
 	return hash;
 }
 }
 
 
@@ -2721,6 +2721,8 @@ BfResolvedTypeSet::~BfResolvedTypeSet()
 
 
 }
 }
 
 
+#define HASH_MIX(origHashVal, newHashVal) ((((origHashVal) << 5) - (origHashVal)) ^ (newHashVal))
+
 #define HASH_VAL_PTR 1
 #define HASH_VAL_PTR 1
 #define HASH_VAL_BOXED 2
 #define HASH_VAL_BOXED 2
 #define HASH_VAL_REF 3
 #define HASH_VAL_REF 3
@@ -2767,7 +2769,7 @@ BfVariant BfResolvedTypeSet::EvaluateToVariant(LookupContext* ctx, BfExpression*
 	return variant;
 	return variant;
 }
 }
 
 
-int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
+int BfResolvedTypeSet::DoHash(BfType* type, LookupContext* ctx, bool allowRef, int hashSeed)
 {
 {
 	//BP_ZONE("BfResolvedTypeSet::Hash");
 	//BP_ZONE("BfResolvedTypeSet::Hash");
 
 
@@ -2787,13 +2789,13 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 	if (type->IsBoxed())
 	if (type->IsBoxed())
 	{
 	{
 		BfBoxedType* boxedType = (BfBoxedType*)type;
 		BfBoxedType* boxedType = (BfBoxedType*)type;
-		int elemHash = Hash(boxedType->mElementType, ctx) ^ HASH_VAL_BOXED;
+		int elemHash = Hash(boxedType->mElementType, ctx, BfHashFlag_None, hashSeed) ^ HASH_VAL_BOXED;
 		return (elemHash << 5) - elemHash;
 		return (elemHash << 5) - elemHash;
 	}
 	}
 	else if (type->IsArray())
 	else if (type->IsArray())
 	{
 	{
 		BfArrayType* arrayType = (BfArrayType*)type;
 		BfArrayType* arrayType = (BfArrayType*)type;
-		int elemHash = Hash(arrayType->mGenericTypeInfo->mTypeGenericArguments[0], ctx) ^ (arrayType->mDimensions << 8);
+		int elemHash = Hash(arrayType->mGenericTypeInfo->mTypeGenericArguments[0], ctx, BfHashFlag_None, hashSeed) ^ (arrayType->mDimensions << 8);
 		return (elemHash << 5) - elemHash;
 		return (elemHash << 5) - elemHash;
 	}	
 	}	
 	else if (type->IsDelegateFromTypeRef() || type->IsFunctionFromTypeRef())
 	else if (type->IsDelegateFromTypeRef() || type->IsFunctionFromTypeRef())
@@ -2803,7 +2805,7 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 		
 		
 		auto delegateInfo = type->GetDelegateInfo();
 		auto delegateInfo = type->GetDelegateInfo();
 
 
-		hashVal = ((hashVal ^ (Hash(delegateInfo->mReturnType, ctx))) << 5) - hashVal;
+		hashVal = ((hashVal ^ (Hash(delegateInfo->mReturnType, ctx, BfHashFlag_None, hashSeed))) << 5) - hashVal;
 
 
 		auto methodDef = typeInst->mTypeDef->mMethods[0];
 		auto methodDef = typeInst->mTypeDef->mMethods[0];
 		BF_ASSERT(methodDef->mName == "Invoke");
 		BF_ASSERT(methodDef->mName == "Invoke");
@@ -2817,7 +2819,7 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 		for (int paramIdx = 0; paramIdx < delegateInfo->mParams.size(); paramIdx++)
 		for (int paramIdx = 0; paramIdx < delegateInfo->mParams.size(); paramIdx++)
 		{			
 		{			
 			// Parse attributes?			
 			// Parse attributes?			
-			hashVal = ((hashVal ^ (Hash(delegateInfo->mParams[paramIdx], ctx))) << 5) - hashVal;
+			hashVal = ((hashVal ^ (Hash(delegateInfo->mParams[paramIdx], ctx, BfHashFlag_None, hashSeed))) << 5) - hashVal;
 			String paramName = methodDef->mParams[paramIdx]->mName;
 			String paramName = methodDef->mParams[paramIdx]->mName;
 			int nameHash = (int)Hash64(paramName.c_str(), (int)paramName.length());
 			int nameHash = (int)Hash64(paramName.c_str(), (int)paramName.length());
 			hashVal = ((hashVal ^ (nameHash)) << 5) - hashVal;
 			hashVal = ((hashVal ^ (nameHash)) << 5) - hashVal;
@@ -2852,7 +2854,7 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 				BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx];
 				BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx];
 				
 				
 				auto fieldType = fieldInstance->mResolvedType;
 				auto fieldType = fieldInstance->mResolvedType;
-				hashVal = ((hashVal ^ (Hash(fieldType, ctx))) << 5) - hashVal;
+				hashVal = ((hashVal ^ (Hash(fieldType, ctx, BfHashFlag_None, hashSeed))) << 5) - hashVal;
 				BfFieldDef* fieldDef = NULL;
 				BfFieldDef* fieldDef = NULL;
                 if (tupleType->mTypeDef != NULL)
                 if (tupleType->mTypeDef != NULL)
                     fieldDef = fieldInstance->GetFieldDef();
                     fieldDef = fieldInstance->GetFieldDef();
@@ -2873,8 +2875,8 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 		else if (type->IsGenericTypeInstance())
 		else if (type->IsGenericTypeInstance())
 		{
 		{
 			BfTypeInstance* genericType = (BfTypeInstance*)type;
 			BfTypeInstance* genericType = (BfTypeInstance*)type;
-			for (auto genericArg : genericType->mGenericTypeInfo->mTypeGenericArguments)
-				hashVal = ((hashVal ^ (Hash(genericArg, ctx))) << 5) - hashVal;
+			for (auto genericArg : genericType->mGenericTypeInfo->mTypeGenericArguments)				
+				hashVal = HASH_MIX(hashVal, Hash(genericArg, ctx, BfHashFlag_None, hashSeed + 1));
 		}
 		}
 		return hashVal;
 		return hashVal;
 	}
 	}
@@ -2886,7 +2888,7 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 	else if (type->IsPointer())
 	else if (type->IsPointer())
 	{
 	{
 		BfPointerType* pointerType = (BfPointerType*) type;
 		BfPointerType* pointerType = (BfPointerType*) type;
-		int elemHash = Hash(pointerType->mElementType, ctx) ^ HASH_VAL_PTR;
+		int elemHash = Hash(pointerType->mElementType, ctx, BfHashFlag_None, hashSeed) ^ HASH_VAL_PTR;
 		return (elemHash << 5) - elemHash;
 		return (elemHash << 5) - elemHash;
 	}
 	}
 	else if (type->IsGenericParam())
 	else if (type->IsGenericParam())
@@ -2897,30 +2899,30 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 	else if (type->IsRef())
 	else if (type->IsRef())
 	{
 	{
 		auto refType = (BfRefType*)type;
 		auto refType = (BfRefType*)type;
-		int elemHash = Hash(refType->mElementType, ctx) ^ (HASH_VAL_REF + (int)refType->mRefKind);
+		int elemHash = Hash(refType->mElementType, ctx, BfHashFlag_None, hashSeed) ^ (HASH_VAL_REF + (int)refType->mRefKind);
 		return (elemHash << 5) - elemHash;
 		return (elemHash << 5) - elemHash;
 	}	
 	}	
 	else if (type->IsModifiedTypeType())
 	else if (type->IsModifiedTypeType())
 	{
 	{
 		auto modifiedTypeType = (BfModifiedTypeType*)type;
 		auto modifiedTypeType = (BfModifiedTypeType*)type;
-		int elemHash = Hash(modifiedTypeType->mElementType, ctx) ^ HASH_MODTYPE + (int)modifiedTypeType->mModifiedKind;
+		int elemHash = Hash(modifiedTypeType->mElementType, ctx, BfHashFlag_None, hashSeed) ^ HASH_MODTYPE + (int)modifiedTypeType->mModifiedKind;
 		return (elemHash << 5) - elemHash;
 		return (elemHash << 5) - elemHash;
 	}
 	}
 	else if (type->IsConcreteInterfaceType())
 	else if (type->IsConcreteInterfaceType())
 	{
 	{
 		auto concreteInterfaceType = (BfConcreteInterfaceType*)type;
 		auto concreteInterfaceType = (BfConcreteInterfaceType*)type;
-		int elemHash = Hash(concreteInterfaceType->mInterface, ctx) ^ HASH_CONCRETE_INTERFACE;
+		int elemHash = Hash(concreteInterfaceType->mInterface, ctx, BfHashFlag_None, hashSeed) ^ HASH_CONCRETE_INTERFACE;
 		return (elemHash << 5) - elemHash;
 		return (elemHash << 5) - elemHash;
 	}
 	}
 	else if (type->IsSizedArray())
 	else if (type->IsSizedArray())
 	{
 	{
 		auto sizedArray = (BfSizedArrayType*)type;
 		auto sizedArray = (BfSizedArrayType*)type;
-		int elemHash = Hash(sizedArray->mElementType, ctx) ^ HASH_SIZED_ARRAY;
+		int elemHash = Hash(sizedArray->mElementType, ctx, BfHashFlag_None, hashSeed) ^ HASH_SIZED_ARRAY;
 		int hashVal = (elemHash << 5) - elemHash;
 		int hashVal = (elemHash << 5) - elemHash;
 		if (type->IsUnknownSizedArrayType())
 		if (type->IsUnknownSizedArrayType())
 		{
 		{
 			auto unknownSizedArray = (BfUnknownSizedArrayType*)type;
 			auto unknownSizedArray = (BfUnknownSizedArrayType*)type;
-			int elemHash = Hash(unknownSizedArray->mElementCountSource, ctx);
+			int elemHash = Hash(unknownSizedArray->mElementCountSource, ctx, BfHashFlag_None, hashSeed);
 			hashVal = ((hashVal ^ elemHash) << 5) - hashVal;
 			hashVal = ((hashVal ^ elemHash) << 5) - hashVal;
 		}
 		}
 		else
 		else
@@ -2940,7 +2942,7 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 	{
 	{
 		BfConstExprValueType* constExprValueType = (BfConstExprValueType*)type;
 		BfConstExprValueType* constExprValueType = (BfConstExprValueType*)type;
 		int hashVal = ((int)constExprValueType->mValue.mTypeCode << 17) ^ (constExprValueType->mValue.mInt32 << 3) ^ HASH_CONSTTYPE;
 		int hashVal = ((int)constExprValueType->mValue.mTypeCode << 17) ^ (constExprValueType->mValue.mInt32 << 3) ^ HASH_CONSTTYPE;
-		hashVal = ((hashVal ^ (Hash(constExprValueType->mType, ctx, BfHashFlag_AllowRef))) << 5) - hashVal;
+		hashVal = ((hashVal ^ (Hash(constExprValueType->mType, ctx, BfHashFlag_AllowRef, hashSeed))) << 5) - hashVal;
 		return hashVal;
 		return hashVal;
 	}
 	}
 	else
 	else
@@ -2950,21 +2952,29 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 	return 0;
 	return 0;
 }
 }
 
 
-void BfResolvedTypeSet::HashGenericArguments(BfTypeReference* typeRef, LookupContext* ctx, int& hashVal)
+int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef, int hashSeed)
+{
+	int hashVal = DoHash(type, ctx, allowRef, hashSeed);
+	if (hashSeed == 0)
+		return hashVal;
+	return HASH_MIX(hashVal, hashSeed);
+}
+
+void BfResolvedTypeSet::HashGenericArguments(BfTypeReference* typeRef, LookupContext* ctx, int& hashVal, int hashSeed)
 {
 {
 	if (auto elementedTypeRef = BfNodeDynCast<BfElementedTypeRef>(typeRef))
 	if (auto elementedTypeRef = BfNodeDynCast<BfElementedTypeRef>(typeRef))
 	{
 	{
-		HashGenericArguments(elementedTypeRef->mElementType, ctx, hashVal);
+		HashGenericArguments(elementedTypeRef->mElementType, ctx, hashVal, hashSeed);
 	}
 	}
 	else if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(typeRef))
 	else if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(typeRef))
 	{
 	{
-		HashGenericArguments(qualifiedTypeRef->mLeft, ctx, hashVal);
+		HashGenericArguments(qualifiedTypeRef->mLeft, ctx, hashVal, hashSeed);
 	}
 	}
 
 
 	if (auto genericTypeRef = BfNodeDynCast<BfGenericInstanceTypeRef>(typeRef))
 	if (auto genericTypeRef = BfNodeDynCast<BfGenericInstanceTypeRef>(typeRef))
 	{
 	{
 		for (auto genericArg : genericTypeRef->mGenericArguments)
 		for (auto genericArg : genericTypeRef->mGenericArguments)
-			hashVal = ((hashVal ^ (Hash(genericArg, ctx, BfHashFlag_AllowGenericParamConstValue))) << 5) - hashVal;
+			hashVal = HASH_MIX(hashVal, Hash(genericArg, ctx, BfHashFlag_AllowGenericParamConstValue, hashSeed + 1));			
 	}
 	}
 }
 }
 
 
@@ -2976,7 +2986,7 @@ static int HashNode(BfAstNode* node)
 	return (int)Hash64(nameStr, node->GetSrcLength());
 	return (int)Hash64(nameStr, node->GetSrcLength());
 }
 }
 
 
-int BfResolvedTypeSet::DirectHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags)
+int BfResolvedTypeSet::DirectHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags, int hashSeed)
 {
 {
 	bool isHeadType = typeRef == ctx->mRootTypeRef;
 	bool isHeadType = typeRef == ctx->mRootTypeRef;
 
 
@@ -2990,7 +3000,7 @@ int BfResolvedTypeSet::DirectHash(BfTypeReference* typeRef, LookupContext* ctx,
 		ctx->mFailed = true;
 		ctx->mFailed = true;
 		return 0;
 		return 0;
 	}
 	}
-	return Hash(resolvedType, ctx);
+	return Hash(resolvedType, ctx, BfHashFlag_None, hashSeed);
 }
 }
 
 
 BfTypeDef* BfResolvedTypeSet::FindRootCommonOuterType(BfTypeDef* outerType, LookupContext* ctx, BfTypeInstance*& outOuterTypeInstance)
 BfTypeDef* BfResolvedTypeSet::FindRootCommonOuterType(BfTypeDef* outerType, LookupContext* ctx, BfTypeInstance*& outOuterTypeInstance)
@@ -3020,7 +3030,7 @@ BfTypeDef* BfResolvedTypeSet::FindRootCommonOuterType(BfTypeDef* outerType, Look
 	return commonOuterType;
 	return commonOuterType;
 }
 }
 
 
-int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags)
+int BfResolvedTypeSet::DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags, int& hashSeed)
 {
 {
 	if ((typeRef == ctx->mRootTypeRef) && (ctx->mRootTypeDef != NULL) &&
 	if ((typeRef == ctx->mRootTypeRef) && (ctx->mRootTypeDef != NULL) &&
 		((typeRef->IsNamedTypeReference()) || (BfNodeIsA<BfDirectTypeDefReference>(typeRef))))
 		((typeRef->IsNamedTypeReference()) || (BfNodeIsA<BfDirectTypeDefReference>(typeRef))))
@@ -3072,8 +3082,8 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 			auto curGenericTypeInst = (BfTypeInstance*)checkTypeInstance;
 			auto curGenericTypeInst = (BfTypeInstance*)checkTypeInstance;
 			int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size();
 			int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size();
 			for (int i = 0; i < numParentGenericParams; i++)
 			for (int i = 0; i < numParentGenericParams; i++)
-			{
-				hashVal = ((hashVal ^ (Hash(curGenericTypeInst->mGenericTypeInfo->mTypeGenericArguments[i], ctx))) << 5) - hashVal;
+			{				
+				hashVal = HASH_MIX(hashVal, Hash(curGenericTypeInst->mGenericTypeInfo->mTypeGenericArguments[i], ctx, BfHashFlag_None, hashSeed + 1));
 			}
 			}
 		}
 		}
 
 
@@ -3082,7 +3092,9 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 
 
 	if (typeRef->IsNamedTypeReference())
 	if (typeRef->IsNamedTypeReference())
 	{
 	{
-		return DirectHash(typeRef, ctx, flags);
+		int hashVal = DirectHash(typeRef, ctx, flags, hashSeed);
+		hashSeed = 0;
+		return hashVal;
 	}
 	}
 	if (auto genericInstTypeRef = BfNodeDynCastExact<BfGenericInstanceTypeRef>(typeRef))
 	if (auto genericInstTypeRef = BfNodeDynCastExact<BfGenericInstanceTypeRef>(typeRef))
 	{
 	{
@@ -3124,7 +3136,9 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 						ctx->mFailed = true;
 						ctx->mFailed = true;
 						return 0;
 						return 0;
 					}
 					}
-					return Hash(underlyingType, ctx, flags);
+					int hashVal = Hash(underlyingType, ctx, flags, hashSeed);
+					hashSeed = 0;
+					return hashVal;
 				}
 				}
 			}
 			}
 		}
 		}
@@ -3155,23 +3169,23 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 			{
 			{
 				auto parentTypeInstance = checkTypeInstance;
 				auto parentTypeInstance = checkTypeInstance;
 				int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size();
 				int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size();
-				for (int i = 0; i < numParentGenericParams; i++)			
-					hashVal = ((hashVal ^ (Hash(parentTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i], ctx))) << 5) - hashVal;
+				for (int i = 0; i < numParentGenericParams; i++)
+					hashVal = HASH_MIX(hashVal, Hash(parentTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i], ctx, Beefy::BfResolvedTypeSet::BfHashFlag_None, hashSeed + 1));					
 			}
 			}
 		}
 		}
 
 
-		HashGenericArguments(genericInstTypeRef, ctx, hashVal);
+		HashGenericArguments(genericInstTypeRef, ctx, hashVal, hashSeed);
 
 
 		return hashVal;
 		return hashVal;
 	}
 	}
 	else if (auto tupleTypeRef = BfNodeDynCastExact<BfTupleTypeRef>(typeRef))
 	else if (auto tupleTypeRef = BfNodeDynCastExact<BfTupleTypeRef>(typeRef))
-	{	
+	{
 		int hashVal = HASH_VAL_TUPLE;
 		int hashVal = HASH_VAL_TUPLE;
 
 
 		for (int fieldIdx = 0; fieldIdx < (int)tupleTypeRef->mFieldTypes.size(); fieldIdx++)
 		for (int fieldIdx = 0; fieldIdx < (int)tupleTypeRef->mFieldTypes.size(); fieldIdx++)
 		{
 		{
 			BfTypeReference* fieldType = tupleTypeRef->mFieldTypes[fieldIdx];
 			BfTypeReference* fieldType = tupleTypeRef->mFieldTypes[fieldIdx];
-			hashVal = ((hashVal ^ (Hash(fieldType, ctx))) << 5) - hashVal;
+			hashVal = ((hashVal ^ (Hash(fieldType, ctx, BfHashFlag_None, hashSeed))) << 5) - hashVal;
 
 
 			int nameHash = 0;		
 			int nameHash = 0;		
 			BfIdentifierNode* fieldName = NULL;
 			BfIdentifierNode* fieldName = NULL;
@@ -3197,7 +3211,7 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 	{
 	{
 		if ((arrayType->mDimensions == 1) && (arrayType->mParams.size() != 0))
 		if ((arrayType->mDimensions == 1) && (arrayType->mParams.size() != 0))
 		{
 		{
-			int rawElemHash = Hash(arrayType->mElementType, ctx);
+			int rawElemHash = Hash(arrayType->mElementType, ctx, BfHashFlag_None, hashSeed);
 			int elemHash = rawElemHash ^ HASH_SIZED_ARRAY;
 			int elemHash = rawElemHash ^ HASH_SIZED_ARRAY;
 			int hashVal = (elemHash << 5) - elemHash;
 			int hashVal = (elemHash << 5) - elemHash;
 
 
@@ -3221,7 +3235,7 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 				BfTypedValue typedVal = constResolver.Resolve(sizeExpr, NULL, BfConstResolveFlag_ArrayInitSize);
 				BfTypedValue typedVal = constResolver.Resolve(sizeExpr, NULL, BfConstResolveFlag_ArrayInitSize);
 				if (typedVal.mKind == BfTypedValueKind_GenericConstValue)
 				if (typedVal.mKind == BfTypedValueKind_GenericConstValue)
 				{
 				{
-					int elemHash = Hash(typedVal.mType, ctx);
+					int elemHash = Hash(typedVal.mType, ctx, BfHashFlag_None, hashSeed);
 					hashVal = ((hashVal ^ elemHash) << 5) - hashVal;
 					hashVal = ((hashVal ^ elemHash) << 5) - hashVal;
 					return hashVal;
 					return hashVal;
 				}
 				}
@@ -3280,13 +3294,13 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 				}
 				}
 			}
 			}
 
 
-			int elemHash = Hash(arrayType->mElementType, ctx) ^ (arrayType->mDimensions << 8);
+			int elemHash = Hash(arrayType->mElementType, ctx, BfHashFlag_None, hashSeed) ^ (arrayType->mDimensions << 8);
 			return (elemHash << 5) - elemHash;
 			return (elemHash << 5) - elemHash;
 		}
 		}
 	}
 	}
 	else if (auto pointerType = BfNodeDynCastExact<BfPointerTypeRef>(typeRef))
 	else if (auto pointerType = BfNodeDynCastExact<BfPointerTypeRef>(typeRef))
 	{		
 	{		
-		int elemHash = Hash(pointerType->mElementType, ctx) ^ HASH_VAL_PTR;
+		int elemHash = Hash(pointerType->mElementType, ctx, BfHashFlag_None, hashSeed) ^ HASH_VAL_PTR;
 		return (elemHash << 5) - elemHash;
 		return (elemHash << 5) - elemHash;
 	}
 	}
 	else if (auto nullableType = BfNodeDynCastExact<BfNullableTypeRef>(typeRef))
 	else if (auto nullableType = BfNodeDynCastExact<BfNullableTypeRef>(typeRef))
@@ -3294,8 +3308,8 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 		if (ctx->mRootTypeRef == typeRef)
 		if (ctx->mRootTypeRef == typeRef)
 			ctx->mRootTypeDef = ctx->mModule->mCompiler->mNullableTypeDef;
 			ctx->mRootTypeDef = ctx->mModule->mCompiler->mNullableTypeDef;
 
 
-		int hashVal = ctx->mModule->mCompiler->mNullableTypeDef->mHash;
-		hashVal = ((hashVal ^ (Hash(nullableType->mElementType, ctx))) << 5) - hashVal;
+		int hashVal = ctx->mModule->mCompiler->mNullableTypeDef->mHash;		
+		hashVal = HASH_MIX(hashVal, Hash(nullableType->mElementType, ctx, BfHashFlag_None, hashSeed + 1));
 		return hashVal;
 		return hashVal;
 	}	
 	}	
 	else if (auto refType = BfNodeDynCastExact<BfRefTypeRef>(typeRef))
 	else if (auto refType = BfNodeDynCastExact<BfRefTypeRef>(typeRef))
@@ -3312,7 +3326,7 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 			else if (refType->mRefToken->GetToken() == BfToken_Mut)
 			else if (refType->mRefToken->GetToken() == BfToken_Mut)
 				refKind = BfRefType::RefKind_Mut;
 				refKind = BfRefType::RefKind_Mut;
 
 
-			int elemHash = Hash(refType->mElementType, ctx) ^ (HASH_VAL_REF + (int)refKind);
+			int elemHash = Hash(refType->mElementType, ctx, BfHashFlag_None, hashSeed) ^ (HASH_VAL_REF + (int)refKind);
 			return (elemHash << 5) - elemHash;
 			return (elemHash << 5) - elemHash;
 		}
 		}
 		else
 		else
@@ -3356,7 +3370,9 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 			ctx->mFailed = true;
 			ctx->mFailed = true;
 			return 0;
 			return 0;
 		}
 		}
-		return Hash(resolvedType, ctx);
+		int hashVal = Hash(resolvedType, ctx, BfHashFlag_None, hashSeed);
+		hashSeed = 0;
+		return hashVal;
 	}
 	}
 	else if (auto varType = BfNodeDynCastExact<BfVarTypeReference>(typeRef))
 	else if (auto varType = BfNodeDynCastExact<BfVarTypeReference>(typeRef))
 	{
 	{
@@ -3379,26 +3395,26 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 		if (ctx->mRootTypeRef != retTypeTypeRef)
 		if (ctx->mRootTypeRef != retTypeTypeRef)
 		{
 		{
 			auto type = ctx->mModule->ResolveTypeRef(retTypeTypeRef, BfPopulateType_Identity, ctx->mResolveFlags);
 			auto type = ctx->mModule->ResolveTypeRef(retTypeTypeRef, BfPopulateType_Identity, ctx->mResolveFlags);
-			return Hash(type, ctx, flags);
+			return Hash(type, ctx, flags, hashSeed);
 		}
 		}
 
 
-		int elemHash = Hash(retTypeTypeRef->mElementType, ctx) ^ HASH_MODTYPE + retTypeTypeRef->mRetTypeToken->mToken;
+		int elemHash = Hash(retTypeTypeRef->mElementType, ctx, BfHashFlag_None, hashSeed) ^ HASH_MODTYPE + retTypeTypeRef->mRetTypeToken->mToken;
 		return (elemHash << 5) - elemHash;
 		return (elemHash << 5) - elemHash;
 	}
 	}
 	else if (auto resolvedTypeRef = BfNodeDynCastExact<BfResolvedTypeReference>(typeRef))
 	else if (auto resolvedTypeRef = BfNodeDynCastExact<BfResolvedTypeReference>(typeRef))
 	{
 	{
-		return Hash(resolvedTypeRef->mType, ctx);
+		return Hash(resolvedTypeRef->mType, ctx, BfHashFlag_None, hashSeed);
 	}
 	}
 	else if (auto constTypeRef = BfNodeDynCastExact<BfConstTypeRef>(typeRef))
 	else if (auto constTypeRef = BfNodeDynCastExact<BfConstTypeRef>(typeRef))
 	{
 	{
 		// We purposely don't mix in a HASH_CONSTTYPE because there's no such thing as a const type in Beef, so we just strip it
 		// We purposely don't mix in a HASH_CONSTTYPE because there's no such thing as a const type in Beef, so we just strip it
-		return Hash(constTypeRef->mElementType, ctx, flags);
+		return Hash(constTypeRef->mElementType, ctx, flags, hashSeed);
 	}	
 	}	
 	else if (auto delegateTypeRef = BfNodeDynCastExact<BfDelegateTypeRef>(typeRef))
 	else if (auto delegateTypeRef = BfNodeDynCastExact<BfDelegateTypeRef>(typeRef))
 	{
 	{
 		int hashVal = HASH_DELEGATE;
 		int hashVal = HASH_DELEGATE;
 		if (delegateTypeRef->mReturnType != NULL)
 		if (delegateTypeRef->mReturnType != NULL)
-			hashVal = ((hashVal ^ (Hash(delegateTypeRef->mReturnType, ctx, BfHashFlag_AllowRef))) << 5) - hashVal;
+			hashVal = ((hashVal ^ (Hash(delegateTypeRef->mReturnType, ctx, BfHashFlag_AllowRef, hashSeed))) << 5) - hashVal;
 		else
 		else
 			ctx->mFailed = true;
 			ctx->mFailed = true;
 		
 		
@@ -3431,7 +3447,7 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 				}
 				}
 			}
 			}
 			
 			
-			hashVal = ((hashVal ^ (Hash(fieldType, ctx, (BfHashFlags)(BfHashFlag_AllowRef)))) << 5) - hashVal;
+			hashVal = ((hashVal ^ (Hash(fieldType, ctx, (BfHashFlags)(BfHashFlag_AllowRef), hashSeed))) << 5) - hashVal;
 			hashVal = ((hashVal ^ (HashNode(param->mNameNode))) << 5) - hashVal;
 			hashVal = ((hashVal ^ (HashNode(param->mNameNode))) << 5) - hashVal;
 			isFirstParam = true;
 			isFirstParam = true;
 		}
 		}
@@ -3508,7 +3524,9 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 			return 0;
 			return 0;
 		}		
 		}		
 
 
-		return Hash(cachedResolvedType, ctx, flags);
+		int hashVal = Hash(cachedResolvedType, ctx, flags, hashSeed);
+		hashSeed = 0;
+		return hashVal;
 	}
 	}
 	else if (auto constExprTypeRef = BfNodeDynCastExact<BfConstExprTypeRef>(typeRef))
 	else if (auto constExprTypeRef = BfNodeDynCastExact<BfConstExprTypeRef>(typeRef))
 	{
 	{
@@ -3518,7 +3536,11 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 		{
 		{
 			result = EvaluateToVariant(ctx, constExprTypeRef->mConstExpr, resultType);			
 			result = EvaluateToVariant(ctx, constExprTypeRef->mConstExpr, resultType);			
 			if ((resultType != NULL) && (resultType->IsGenericParam()))
 			if ((resultType != NULL) && (resultType->IsGenericParam()))
-				return Hash(resultType, ctx);
+			{
+				int hashVal = Hash(resultType, ctx, BfHashFlag_None, hashSeed);
+				hashSeed = 0;
+				return hashVal;
+			}
 		}
 		}
 
 
 		if (resultType == NULL)
 		if (resultType == NULL)
@@ -3528,7 +3550,7 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 		}
 		}
 
 
 		auto hashVal = ((int)result.mTypeCode << 17) ^ (result.mInt32 << 3) ^ HASH_CONSTTYPE;		
 		auto hashVal = ((int)result.mTypeCode << 17) ^ (result.mInt32 << 3) ^ HASH_CONSTTYPE;		
-		hashVal = ((hashVal ^ (Hash(resultType, ctx, BfHashFlag_AllowRef))) << 5) - hashVal;
+		hashVal = ((hashVal ^ (Hash(resultType, ctx, BfHashFlag_AllowRef, hashSeed))) << 5) - hashVal;		
 		return hashVal;
 		return hashVal;
 	}
 	}
 	else if (auto dotTypeRef = BfNodeDynCastExact<BfDotTypeReference>(typeRef))	
 	else if (auto dotTypeRef = BfNodeDynCastExact<BfDotTypeReference>(typeRef))	
@@ -3544,6 +3566,14 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 	return 0;
 	return 0;
 }
 }
 
 
+int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags, int hashSeed)
+{
+	int hashVal = DoHash(typeRef, ctx, flags, hashSeed);
+	if (hashSeed == 0)
+		return hashVal;
+	return HASH_MIX(hashVal, hashSeed);
+}
+
 // These types can be from different contexts ("foreign" types) so we can't just compare ptrs
 // These types can be from different contexts ("foreign" types) so we can't just compare ptrs
 bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx)
 bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx)
 {
 {

+ 10 - 4
IDEHelper/Compiler/BfResolvedTypeUtils.h

@@ -501,6 +501,7 @@ public:
 	virtual bool HasBeenReferenced() { return mDefineState != BfTypeDefineState_Undefined; }
 	virtual bool HasBeenReferenced() { return mDefineState != BfTypeDefineState_Undefined; }
 	virtual bool HasTypeFailed() { return false; }
 	virtual bool HasTypeFailed() { return false; }
 	virtual bool IsDataIncomplete() { return mDefineState == BfTypeDefineState_Undefined; }
 	virtual bool IsDataIncomplete() { return mDefineState == BfTypeDefineState_Undefined; }
+	virtual bool IsFinishingType() { return false;  }
 	virtual bool IsIncomplete() { return mDefineState < BfTypeDefineState_Defined; }
 	virtual bool IsIncomplete() { return mDefineState < BfTypeDefineState_Defined; }
 	virtual bool IsDeleting() { return ((mRebuildFlags & (BfTypeRebuildFlag_Deleted | BfTypeRebuildFlag_DeleteQueued)) != 0); }
 	virtual bool IsDeleting() { return ((mRebuildFlags & (BfTypeRebuildFlag_Deleted | BfTypeRebuildFlag_DeleteQueued)) != 0); }
 	virtual bool IsDeclared() { return mDefineState >= BfTypeDefineState_Declared; }
 	virtual bool IsDeclared() { return mDefineState >= BfTypeDefineState_Declared; }
@@ -1774,6 +1775,7 @@ public:
 	bool mInitializedGenericParams;
 	bool mInitializedGenericParams;
 	bool mFinishedGenericParams;	
 	bool mFinishedGenericParams;	
 	Array<BfProject*> mProjectsReferenced; // Generic methods that only refer to these projects don't need a specialized extension
 	Array<BfProject*> mProjectsReferenced; // Generic methods that only refer to these projects don't need a specialized extension
+	int32 mMaxGenericDepth;
 
 
 public:
 public:
 	BfGenericTypeInfo()
 	BfGenericTypeInfo()
@@ -1785,6 +1787,7 @@ public:
 		mValidatedGenericConstraints = false;
 		mValidatedGenericConstraints = false;
 		mInitializedGenericParams = false;
 		mInitializedGenericParams = false;
 		mFinishedGenericParams = false;
 		mFinishedGenericParams = false;
+		mMaxGenericDepth = -1;
 	}
 	}
 
 
 	~BfGenericTypeInfo();
 	~BfGenericTypeInfo();
@@ -1955,6 +1958,7 @@ public:
 	virtual bool IsReified() override { return mIsReified; }
 	virtual bool IsReified() override { return mIsReified; }
 	virtual bool NeedsExplicitAlignment() override { return !IsSizeAligned() || mIsPacked; }	
 	virtual bool NeedsExplicitAlignment() override { return !IsSizeAligned() || mIsPacked; }	
 	virtual bool IsDataIncomplete() override { return ((mTypeIncomplete) || (mBaseTypeMayBeIncomplete)) && (!mNeedsMethodProcessing); }	
 	virtual bool IsDataIncomplete() override { return ((mTypeIncomplete) || (mBaseTypeMayBeIncomplete)) && (!mNeedsMethodProcessing); }	
+	virtual bool IsFinishingType() override { return mIsFinishingType; }
 	virtual bool IsIncomplete() override { return (mTypeIncomplete) || (mBaseTypeMayBeIncomplete); }
 	virtual bool IsIncomplete() override { return (mTypeIncomplete) || (mBaseTypeMayBeIncomplete); }
 	virtual bool IsSplattable() override { BF_ASSERT((mInstSize >= 0) || (!IsComposite())); return mIsSplattable; }
 	virtual bool IsSplattable() override { BF_ASSERT((mInstSize >= 0) || (!IsComposite())); return mIsSplattable; }
 	virtual int GetSplatCount() override;
 	virtual int GetSplatCount() override;
@@ -2525,10 +2529,12 @@ public:
 	static BfVariant EvaluateToVariant(LookupContext* ctx, BfExpression* expr, BfType*& outType);
 	static BfVariant EvaluateToVariant(LookupContext* ctx, BfExpression* expr, BfType*& outType);
 	static bool GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* lhsTypeGenericArguments, BfTypeReference* rhs, LookupContext* ctx, int& genericParamOffset);
 	static bool GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* lhsTypeGenericArguments, BfTypeReference* rhs, LookupContext* ctx, int& genericParamOffset);
 	static bool GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* typeGenericArguments, BfTypeReference* rhs, BfTypeDef* rhsTypeDef, LookupContext* ctx);
 	static bool GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* typeGenericArguments, BfTypeReference* rhs, BfTypeDef* rhsTypeDef, LookupContext* ctx);
-	static void HashGenericArguments(BfTypeReference* typeRef, LookupContext* ctx, int& hash);
-	static int Hash(BfType* type, LookupContext* ctx, bool allowRef = false);
-	static int DirectHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags = BfHashFlag_None);
-	static int Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags = BfHashFlag_None);
+	static void HashGenericArguments(BfTypeReference* typeRef, LookupContext* ctx, int& hash, int hashSeed);
+	static int DoHash(BfType* type, LookupContext* ctx, bool allowRef, int hashSeed);
+	static int Hash(BfType* type, LookupContext* ctx, bool allowRef = false, int hashSeed = 0);
+	static int DirectHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags = BfHashFlag_None, int hashSeed = 0);
+	static int DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags, int& hashSeed);
+	static int Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags = BfHashFlag_None, int hashSeed = 0);
 	static bool Equals(BfType* lhs, BfType* rhs, LookupContext* ctx);	
 	static bool Equals(BfType* lhs, BfType* rhs, LookupContext* ctx);	
 	static bool Equals(BfType* lhs, BfTypeReference* rhs, LookupContext* ctx);
 	static bool Equals(BfType* lhs, BfTypeReference* rhs, LookupContext* ctx);
 	static bool Equals(BfType* lhs, BfTypeReference* rhs, BfTypeDef* rhsTypeDef, LookupContext* ctx);
 	static bool Equals(BfType* lhs, BfTypeReference* rhs, BfTypeDef* rhsTypeDef, LookupContext* ctx);

+ 34 - 10
IDEHelper/Compiler/BfSourceClassifier.cpp

@@ -1,5 +1,6 @@
 #include "BfSourceClassifier.h"
 #include "BfSourceClassifier.h"
 #include "BfParser.h"
 #include "BfParser.h"
+#include "BeefySysLib/util/BeefPerf.h"
 
 
 USING_NS_BF;
 USING_NS_BF;
 
 
@@ -421,14 +422,22 @@ void BfSourceClassifier::Visit(BfTokenNode* tokenNode)
 
 
 void BfSourceClassifier::Visit(BfInvocationExpression* invocationExpr)
 void BfSourceClassifier::Visit(BfInvocationExpression* invocationExpr)
 {
 {
-	BfElementVisitor::Visit(invocationExpr);
+	//BfElementVisitor::Visit(invocationExpr);
+	Visit(invocationExpr->ToBase());
+
+	//BP_ZONE("BfSourceClassifier BfInvocationExpression");
 	
 	
 	BfAstNode* target = invocationExpr->mTarget;
 	BfAstNode* target = invocationExpr->mTarget;
 	if (target == NULL)
 	if (target == NULL)
 		return;
 		return;
-
+	
+	VisitChild(invocationExpr->mOpenParen);
+	VisitChild(invocationExpr->mCloseParen);
+	VisitChild(invocationExpr->mGenericArgs);
+	
 	if (auto scopedTarget = BfNodeDynCast<BfScopedInvocationTarget>(target))
 	if (auto scopedTarget = BfNodeDynCast<BfScopedInvocationTarget>(target))
 	{
 	{
+		VisitChild(target);
 		target = scopedTarget->mTarget;
 		target = scopedTarget->mTarget;
 		VisitChild(scopedTarget->mScopeName);
 		VisitChild(scopedTarget->mScopeName);
 	}
 	}
@@ -438,25 +447,33 @@ void BfSourceClassifier::Visit(BfInvocationExpression* invocationExpr)
 	{
 	{
 		VisitChild(qualifiedName->mLeft);
 		VisitChild(qualifiedName->mLeft);
 		VisitChild(qualifiedName->mDot);
 		VisitChild(qualifiedName->mDot);
+		VisitChild(qualifiedName->mRight);
 		identifier = qualifiedName->mRight;		
 		identifier = qualifiedName->mRight;		
 	}
 	}
 	else if ((identifier = BfNodeDynCast<BfIdentifierNode>(target)))
 	else if ((identifier = BfNodeDynCast<BfIdentifierNode>(target)))
 	{
 	{
+		VisitChild(target);
 		// Leave as BfAttributedIdentifierNode if that's the case
 		// Leave as BfAttributedIdentifierNode if that's the case
-		identifier = target;
+		identifier = target;		
 	}
 	}
 	else if (auto qualifiedName = BfNodeDynCast<BfQualifiedNameNode>(target))
 	else if (auto qualifiedName = BfNodeDynCast<BfQualifiedNameNode>(target))
 	{
 	{
 		VisitChild(qualifiedName->mLeft);
 		VisitChild(qualifiedName->mLeft);
 		VisitChild(qualifiedName->mDot);
 		VisitChild(qualifiedName->mDot);
+		VisitChild(qualifiedName->mRight);
 		identifier = qualifiedName->mRight;		
 		identifier = qualifiedName->mRight;		
 	}
 	}
 	else if (auto memberRefExpr = BfNodeDynCast<BfMemberReferenceExpression>(target))
 	else if (auto memberRefExpr = BfNodeDynCast<BfMemberReferenceExpression>(target))
 	{
 	{
 		VisitChild(memberRefExpr->mTarget);
 		VisitChild(memberRefExpr->mTarget);
 		VisitChild(memberRefExpr->mDotToken);
 		VisitChild(memberRefExpr->mDotToken);
+		VisitChild(memberRefExpr->mMemberName);
 		identifier = memberRefExpr->mMemberName;		
 		identifier = memberRefExpr->mMemberName;		
 	}
 	}
+	else
+	{
+		VisitChild(target);
+	}
 
 
 	if (identifier != NULL)
 	if (identifier != NULL)
 	{
 	{
@@ -469,20 +486,25 @@ void BfSourceClassifier::Visit(BfInvocationExpression* invocationExpr)
 		if (identifier != NULL)
 		if (identifier != NULL)
 			SetElementType(identifier, BfSourceElementType_Method);
 			SetElementType(identifier, BfSourceElementType_Method);
 	}
 	}
+
+	for (auto& val : invocationExpr->mArguments)
+		VisitChild(val);
+	for (auto& val : invocationExpr->mCommas)
+		VisitChild(val);
 }
 }
 
 
 void BfSourceClassifier::Visit(BfIndexerExpression* indexerExpr)
 void BfSourceClassifier::Visit(BfIndexerExpression* indexerExpr)
 {
 {
-	BfElementVisitor::Visit(indexerExpr);
+	//BfElementVisitor::Visit(indexerExpr);
+	Visit(indexerExpr->ToBase());
 
 
 	VisitChild(indexerExpr->mTarget);
 	VisitChild(indexerExpr->mTarget);
 	VisitChild(indexerExpr->mOpenBracket);
 	VisitChild(indexerExpr->mOpenBracket);
-	for (int i = 0; i < (int) indexerExpr->mArguments.size(); i++)
-	{
-		if (i > 0)
-			VisitChild(indexerExpr->mCommas[i - 1]);
-		VisitChild(indexerExpr->mArguments[i]);
-	}
+
+	for (auto& val : indexerExpr->mArguments)
+		VisitChild(val);
+	for (auto& val : indexerExpr->mCommas)
+		VisitChild(val);
 	VisitChild(indexerExpr->mCloseBracket);
 	VisitChild(indexerExpr->mCloseBracket);
 }
 }
 
 
@@ -523,6 +545,8 @@ void BfSourceClassifier::Visit(BfMethodDeclaration* methodDeclaration)
 	if (!IsInterestedInMember(methodDeclaration))
 	if (!IsInterestedInMember(methodDeclaration))
 		return;
 		return;
 
 
+	//BP_ZONE("BfSourceClassifier BfMethodDeclaration");
+
 	SetAndRestoreValue<BfAstNode*> prevMember(mCurMember, methodDeclaration);
 	SetAndRestoreValue<BfAstNode*> prevMember(mCurMember, methodDeclaration);
 
 
 	BfElementVisitor::Visit(methodDeclaration);	
 	BfElementVisitor::Visit(methodDeclaration);	

+ 9 - 11
IDEHelper/Compiler/BfStmtEvaluator.cpp

@@ -1654,7 +1654,7 @@ BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varD
 			if (isConst)
 			if (isConst)
 			{
 			{
 				BfConstResolver constResolver(this);
 				BfConstResolver constResolver(this);
-				initValue = constResolver.Resolve(varDecl->mInitializer, resolvedType, BfConstResolveFlag_RemapFromStringId);
+				initValue = constResolver.Resolve(varDecl->mInitializer, resolvedType, BfConstResolveFlag_ActualizeValues);
 				if (!initValue)							
 				if (!initValue)							
 					initValue = GetDefaultTypedValue(resolvedType);
 					initValue = GetDefaultTypedValue(resolvedType);
 			}
 			}
@@ -3934,15 +3934,7 @@ void BfModule::Visit(BfDeleteStatement* deleteStmt)
 		bool allowProtected = allowPrivate || TypeIsSubTypeOf(mCurTypeInstance, checkTypeInst);
 		bool allowProtected = allowPrivate || TypeIsSubTypeOf(mCurTypeInstance, checkTypeInst);
 		while (checkTypeInst != NULL)
 		while (checkTypeInst != NULL)
 		{
 		{
-			auto checkTypeDef = checkTypeInst->mTypeDef;
-
-			checkTypeDef->PopulateMemberSets();
-			BfMemberSetEntry* entry = NULL;
-			BfMethodDef* dtorMethodDef = NULL;
-			checkTypeDef->mMethodSet.TryGetWith(String("~this"), &entry);
-			if (entry != NULL)
-				dtorMethodDef = (BfMethodDef*)entry->mMemberDef;
-
+			auto dtorMethodDef = checkTypeInst->mTypeDef->GetMethodByName("~this");
 			if (dtorMethodDef)
 			if (dtorMethodDef)
 			{
 			{
 				if (!CheckProtection(dtorMethodDef->mProtection, checkTypeInst->mTypeDef, allowProtected, allowPrivate))
 				if (!CheckProtection(dtorMethodDef->mProtection, checkTypeInst->mTypeDef, allowProtected, allowPrivate))
@@ -6734,7 +6726,13 @@ void BfModule::Visit(BfDeferStatement* deferStmt)
 
 
 	if ((scope == mCurMethodState->mCurScope) && (scope->mCloseNode == NULL))
 	if ((scope == mCurMethodState->mCurScope) && (scope->mCloseNode == NULL))
 	{
 	{
-		Warn(0, "This defer will immediately execute. Consider specifying a wider scope target such as 'defer::'", deferStmt->mDeferToken);
+		auto parser = deferStmt->GetParser();
+		if ((parser != NULL) && (parser->mFileName.Contains('|')))
+		{
+			// Is emitted
+		}
+		else
+			Warn(0, "This defer will immediately execute. Consider specifying a wider scope target such as 'defer::'", deferStmt->mDeferToken);
 	}
 	}
 
 
 	if (auto block = BfNodeDynCast<BfBlock>(deferStmt->mTargetNode))
 	if (auto block = BfNodeDynCast<BfBlock>(deferStmt->mTargetNode))

+ 28 - 6
IDEHelper/Compiler/BfSystem.cpp

@@ -833,12 +833,26 @@ int BfTypeDef::GetSelfGenericParamCount()
 
 
 BfMethodDef* BfTypeDef::GetMethodByName(const StringImpl& name, int paramCount)
 BfMethodDef* BfTypeDef::GetMethodByName(const StringImpl& name, int paramCount)
 {
 {
-	for (auto method : mMethods)
-	{
-		if ((name == method->mName) && ((paramCount == -1) || (paramCount == (int)method->mParams.size())))
-			return method;
+	PopulateMemberSets();
+	BfMemberSetEntry* entry = NULL;	
+	if (!mMethodSet.TryGetWith(name, &entry))
+		return NULL;
+
+	BfMethodDef* bestMethodDef = NULL;
+	auto methodDef = (BfMethodDef*)entry->mMemberDef;
+	while (methodDef != NULL)
+	{		
+		if (((paramCount == -1) || (paramCount == (int)methodDef->mParams.size())))
+		{
+			if ((bestMethodDef == NULL) ||
+				((bestMethodDef->mDeclaringType->IsExtension()) && (!methodDef->mDeclaringType->IsExtension())))
+				bestMethodDef = methodDef;
+		}
+
+		methodDef = methodDef->mNextWithSameName;
 	}
 	}
-	return NULL;
+
+	return bestMethodDef;
 }
 }
 
 
 BfFieldDef* BfTypeDef::GetFieldByName(const StringImpl& name)
 BfFieldDef* BfTypeDef::GetFieldByName(const StringImpl& name)
@@ -1810,7 +1824,7 @@ BfSystem::BfSystem()
 	if (gPerfManager == NULL)
 	if (gPerfManager == NULL)
 		gPerfManager = new PerfManager();
 		gPerfManager = new PerfManager();
 	//gPerfManager->StartRecording();
 	//gPerfManager->StartRecording();
-
+	
 	mAtomUpdateIdx = 0;
 	mAtomUpdateIdx = 0;
 	mAtomCreateIdx = 0;
 	mAtomCreateIdx = 0;
 	mTypeMapVersion = 1;
 	mTypeMapVersion = 1;
@@ -2586,6 +2600,13 @@ void BfSystem::RemoveTypeDef(BfTypeDef* typeDef)
 	mTypeDefs.Remove(typeDef);	
 	mTypeDefs.Remove(typeDef);	
 	AutoCrit autoCrit(mDataLock);
 	AutoCrit autoCrit(mDataLock);
 	
 	
+	if (typeDef->mOuterType != NULL)
+	{		
+		// We are in the outer type's mNestedTypes list
+		BfLogSys(this, "Setting mForceUseNextRevision on outer type %p from %p\n", typeDef->mOuterType, typeDef);
+		typeDef->mOuterType->mForceUseNextRevision = true;
+	}
+
 	// This will get properly handled in UntrackName when we process the mTypeDefDeleteQueue, but this
 	// This will get properly handled in UntrackName when we process the mTypeDefDeleteQueue, but this
 	//  mAtomUpdateIdx increment will trigger lookup changes in BfContext::VerifyTypeLookups
 	//  mAtomUpdateIdx increment will trigger lookup changes in BfContext::VerifyTypeLookups
 	if (typeDef->mName != mEmptyAtom)
 	if (typeDef->mName != mEmptyAtom)
@@ -2797,6 +2818,7 @@ void BfSystem::InjectNewRevision(BfTypeDef* typeDef)
 	typeDef->mNextRevision = NULL;
 	typeDef->mNextRevision = NULL;
 
 
 	typeDef->mDefState = BfTypeDef::DefState_Defined;	
 	typeDef->mDefState = BfTypeDef::DefState_Defined;	
+	typeDef->mForceUseNextRevision = false;
 
 
 	VerifyTypeDef(typeDef);
 	VerifyTypeDef(typeDef);
 }
 }

+ 3 - 1
IDEHelper/Compiler/BfSystem.h

@@ -1006,6 +1006,7 @@ public:
 	bool mIsNextRevision;
 	bool mIsNextRevision;
 	bool mInDeleteQueue;
 	bool mInDeleteQueue;
 	bool mHasEmitMembers;
 	bool mHasEmitMembers;
+	bool mForceUseNextRevision;
 
 
 public:
 public:
 	BfTypeDef()
 	BfTypeDef()
@@ -1048,6 +1049,7 @@ public:
 		mIsNextRevision = false;
 		mIsNextRevision = false;
 		mInDeleteQueue = false;
 		mInDeleteQueue = false;
 		mHasEmitMembers = false;
 		mHasEmitMembers = false;
+		mForceUseNextRevision = false;
 		mDupDetectedRevision = -1;
 		mDupDetectedRevision = -1;
 		mNestDepth = 0;
 		mNestDepth = 0;
 		mOuterType = NULL;
 		mOuterType = NULL;
@@ -1500,7 +1502,7 @@ public:
 	Array<BfTypeOptions> mMergedTypeOptions;
 	Array<BfTypeOptions> mMergedTypeOptions;
 	int mUpdateCnt;
 	int mUpdateCnt;
 	bool mWorkspaceConfigChanged;
 	bool mWorkspaceConfigChanged;
-	Val128 mWorkspaceConfigHash;	
+	Val128 mWorkspaceConfigHash;
 
 
 	Array<BfCompiler*> mCompilers;
 	Array<BfCompiler*> mCompilers;
 
 

+ 30 - 6
IDEHelper/Compiler/CeMachine.cpp

@@ -3809,7 +3809,7 @@ BfIRValue CeContext::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType
 
 
 BfIRValue CeContext::CreateAttribute(BfAstNode* targetSrc, BfModule* module, BfIRConstHolder* constHolder, BfCustomAttribute* customAttribute)
 BfIRValue CeContext::CreateAttribute(BfAstNode* targetSrc, BfModule* module, BfIRConstHolder* constHolder, BfCustomAttribute* customAttribute)
 {
 {
-	module->PopulateType(customAttribute->mType);
+	module->mContext->mUnreifiedModule->PopulateType(customAttribute->mType);
 	auto ceAttrAddr = CeMalloc(customAttribute->mType->mSize) - mMemory.mVals;	
 	auto ceAttrAddr = CeMalloc(customAttribute->mType->mSize) - mMemory.mVals;	
 	BfIRValue ceAttrVal = module->mBfIRBuilder->CreateConstAggCE(module->mBfIRBuilder->MapType(customAttribute->mType, BfIRPopulateType_Identity), ceAttrAddr);
 	BfIRValue ceAttrVal = module->mBfIRBuilder->CreateConstAggCE(module->mBfIRBuilder->MapType(customAttribute->mType, BfIRPopulateType_Identity), ceAttrAddr);
 	BfTypedValue ceAttrTypedValue(ceAttrVal, customAttribute->mType);
 	BfTypedValue ceAttrTypedValue(ceAttrVal, customAttribute->mType);
@@ -4335,7 +4335,7 @@ static void CeSetAddrVal(void* ptr, addr_ce val, int32 ptrSize)
 }
 }
 
 
 bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr, BfType*& returnType)
 bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr, BfType*& returnType)
-{	
+{
 	auto ceModule = mCeMachine->mCeModule;
 	auto ceModule = mCeMachine->mCeModule;
 	CeFunction* ceFunction = startFunction;
 	CeFunction* ceFunction = startFunction;
 	returnType = startFunction->mMethodInstance->mReturnType;
 	returnType = startFunction->mMethodInstance->mReturnType;
@@ -5408,6 +5408,15 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
 					mCeMachine->PrepareFunction(callEntry.mFunction, NULL);
 					mCeMachine->PrepareFunction(callEntry.mFunction, NULL);
 				}
 				}
 
 
+				if (callEntry.mFunction->mMethodInstance != NULL)
+				{
+					if (callEntry.mFunction->mMethodInstance->GetOwner()->IsDeleting())
+					{
+						_Fail("Calling method on deleted type");
+						return false;
+					}
+				}
+
 				callEntry.mBindRevision = mCeMachine->mMethodBindRevision;
 				callEntry.mBindRevision = mCeMachine->mMethodBindRevision;
 			}
 			}
 
 
@@ -6255,6 +6264,9 @@ CeMachine::~CeMachine()
 
 
 	auto _RemoveFunctionInfo = [&](CeFunctionInfo* functionInfo)
 	auto _RemoveFunctionInfo = [&](CeFunctionInfo* functionInfo)
 	{
 	{
+		if (functionInfo->mMethodInstance != NULL)
+			functionInfo->mMethodInstance->mInCEMachine = false;
+
 		if (functionInfo->mCeFunction != NULL)
 		if (functionInfo->mCeFunction != NULL)
 		{
 		{
 			// We don't need to actually unmap it at this point
 			// We don't need to actually unmap it at this point
@@ -6411,8 +6423,21 @@ CeErrorKind CeMachine::WriteConstant(CeConstStructData& data, BeConstant* constV
 		if (globalVar->mName.StartsWith("__bfStrObj"))
 		if (globalVar->mName.StartsWith("__bfStrObj"))
 		{
 		{
 			int stringId = atoi(globalVar->mName.c_str() + 10);
 			int stringId = atoi(globalVar->mName.c_str() + 10);
-			addr_ce stringAddr = ceContext->GetString(stringId);
 
 
+			addr_ce stringAddr;
+			if (data.mQueueFixups)
+			{
+				stringAddr = 0;
+				CeConstStructFixup fixup;
+				fixup.mKind = CeConstStructFixup::Kind_StringPtr;
+				fixup.mValue = stringId;
+				fixup.mOffset = (int)data.mData.mSize;
+				data.mFixups.Add(fixup);
+			}
+			else
+			{
+				stringAddr = ceContext->GetString(stringId);
+			}
 			auto ptr = data.mData.GrowUninitialized(ceModule->mSystem->mPtrSize);
 			auto ptr = data.mData.GrowUninitialized(ceModule->mSystem->mPtrSize);
 			int64 addr64 = stringAddr;
 			int64 addr64 = stringAddr;
 			memcpy(ptr, &addr64, ceModule->mSystem->mPtrSize);
 			memcpy(ptr, &addr64, ceModule->mSystem->mPtrSize);
@@ -6932,10 +6957,9 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f
 		ceFunction->mCeMachine = this;
 		ceFunction->mCeMachine = this;
 		ceFunction->mIsVarReturn = methodInstance->mReturnType->IsVar();
 		ceFunction->mIsVarReturn = methodInstance->mReturnType->IsVar();
 		ceFunction->mCeFunctionInfo = ceFunctionInfo;
 		ceFunction->mCeFunctionInfo = ceFunctionInfo;
-		ceFunction->mMethodInstance = methodInstance;
-
+		ceFunction->mMethodInstance = methodInstance;		
 		ceFunctionInfo->mMethodInstance = methodInstance;
 		ceFunctionInfo->mMethodInstance = methodInstance;
-		ceFunctionInfo->mCeFunction = ceFunction;
+		ceFunctionInfo->mCeFunction = ceFunction;		
 		MapFunctionId(ceFunction);
 		MapFunctionId(ceFunction);
 	}
 	}
 	
 	

+ 1 - 0
IDEHelper/Debugger.h

@@ -120,6 +120,7 @@ enum DwEvalExpressionFlags : int16
 	DwEvalExpressionFlag_MemoryWatch = 0x80,
 	DwEvalExpressionFlag_MemoryWatch = 0x80,
 	DwEvalExpressionFlag_Symbol = 0x100,
 	DwEvalExpressionFlag_Symbol = 0x100,
 	DwEvalExpressionFlag_StepIntoCalls = 0x200,	
 	DwEvalExpressionFlag_StepIntoCalls = 0x200,	
+	DwEvalExpressionFlag_RawStr = 0x400
 };
 };
 
 
 struct DwDisplayInfo
 struct DwDisplayInfo

+ 64 - 57
IDEHelper/NetManager.cpp

@@ -82,17 +82,14 @@ static size_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb, voi
 void NetRequest::Cleanup()
 void NetRequest::Cleanup()
 {
 {
 	if (mCURLMulti != NULL)
 	if (mCURLMulti != NULL)
-	{
-		curl_multi_remove_handle(mCURLMulti, mCURL);		
-	}
-
-	if (mCURL != NULL)
-		curl_easy_cleanup(mCURL);
-
-	if (mCURLMulti != NULL)
-	{
-		curl_multi_cleanup(mCURLMulti);
-	}
+		curl_multi_remove_handle(mCURLMulti, mCURL);
+	if (mCURL != NULL)	
+		curl_easy_cleanup(mCURL);		
+	if (mCURLMulti != NULL)	
+		curl_multi_cleanup(mCURLMulti);	
+
+	mCURL = NULL;
+	mCURLMulti = NULL;
 }
 }
 
 
 void NetRequest::DoTransfer()
 void NetRequest::DoTransfer()
@@ -105,65 +102,75 @@ void NetRequest::DoTransfer()
 // 		return;
 // 		return;
 // 	}
 // 	}
 
 
-	BfLogDbg("NetManager starting get on %s\n", mURL.c_str());
-	mNetManager->mDebugManager->OutputRawMessage(StrFormat("msgLo Getting '%s'\n", mURL.c_str()));
+	long response_code = 0;
+	for (int pass = 0; pass < 3; pass++)
+	{
+		BfLogDbg("NetManager starting get on %s Pass:%d\n", mURL.c_str(), pass);
+		mNetManager->mDebugManager->OutputRawMessage(StrFormat("msgLo Getting '%s'\n", mURL.c_str()));
 
 
-	mOutTempPath = mOutPath + "__partial";	
-	
-	mCURLMulti = curl_multi_init();
+		mOutTempPath = mOutPath + "__partial";
 
 
-	mCURL = curl_easy_init();	
+		mCURLMulti = curl_multi_init();
 
 
-	if (mShowTracking)
-	{		
-		mNetManager->mDebugManager->OutputRawMessage(StrFormat("symsrv Getting '%s'", mURL.c_str()));		
-	}
+		mCURL = curl_easy_init();
 
 
-	//OutputDebugStrF("Getting '%s'\n", mURL.c_str());
+		if (mShowTracking)
+		{
+			mNetManager->mDebugManager->OutputRawMessage(StrFormat("symsrv Getting '%s'", mURL.c_str()));
+		}
 
 
-	curl_easy_setopt(mCURL, CURLOPT_URL, mURL.c_str());
-	curl_easy_setopt(mCURL, CURLOPT_WRITEDATA, (void*)this);
-	curl_easy_setopt(mCURL, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
-	curl_easy_setopt(mCURL, CURLOPT_XFERINFODATA, (void*)this);
-	curl_easy_setopt(mCURL, CURLOPT_XFERINFOFUNCTION, TransferInfoCallback);
-	curl_easy_setopt(mCURL, CURLOPT_FOLLOWLOCATION, 1L);
-	curl_easy_setopt(mCURL, CURLOPT_NOPROGRESS, 0L);
-	curl_easy_setopt(mCURL, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); // Connects go slow without this
-	//auto result = curl_easy_perform(mCURL);
+		//OutputDebugStrF("Getting '%s'\n", mURL.c_str());
 
 
-	CURLMcode mcode = curl_multi_add_handle(mCURLMulti, mCURL);
-	if (mcode != CURLM_OK)
-	{
-		mFailed = true;
-		return;
-	}
-	
-	while (true)
-	{ 
-		int activeCount = 0;
-		curl_multi_perform(mCURLMulti, &activeCount);
-		if (activeCount == 0)
-			break;
-
-		int waitRet = 0;
-		curl_multi_wait(mCURLMulti, NULL, 0, 20, &waitRet);		
+		curl_easy_setopt(mCURL, CURLOPT_URL, mURL.c_str());
+		curl_easy_setopt(mCURL, CURLOPT_WRITEDATA, (void*)this);
+		curl_easy_setopt(mCURL, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+		curl_easy_setopt(mCURL, CURLOPT_XFERINFODATA, (void*)this);
+		curl_easy_setopt(mCURL, CURLOPT_XFERINFOFUNCTION, TransferInfoCallback);
+		curl_easy_setopt(mCURL, CURLOPT_FOLLOWLOCATION, 1L);
+		curl_easy_setopt(mCURL, CURLOPT_NOPROGRESS, 0L);
+		curl_easy_setopt(mCURL, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); // Connects go slow without this
+		//auto result = curl_easy_perform(mCURL);
 
 
-		if (mCancelling)
+		CURLMcode mcode = curl_multi_add_handle(mCURLMulti, mCURL);
+		if (mcode != CURLM_OK)
 		{
 		{
 			mFailed = true;
 			mFailed = true;
 			return;
 			return;
 		}
 		}
-	}
 
 
-// 	if (result != CURLE_OK)
-// 	{
-// 		mFailed = true;
-// 		return;
-// 	}
+		while (true)
+		{
+			int activeCount = 0;
+			curl_multi_perform(mCURLMulti, &activeCount);
+			if (activeCount == 0)
+				break;
+
+			int waitRet = 0;
+			curl_multi_wait(mCURLMulti, NULL, 0, 20, &waitRet);
+
+			if (mCancelling)
+			{
+				mFailed = true;
+				return;
+			}
+		}
+
+		// 	if (result != CURLE_OK)
+		// 	{
+		// 		mFailed = true;
+		// 		return;
+		// 	}
 		
 		
-	long response_code = 0;
-	curl_easy_getinfo(mCURL, CURLINFO_RESPONSE_CODE, &response_code);
-	mNetManager->mDebugManager->OutputRawMessage(StrFormat("msgLo Result for '%s': %d\n", mURL.c_str(), response_code));
+		response_code = 0;
+		curl_easy_getinfo(mCURL, CURLINFO_RESPONSE_CODE, &response_code);
+		mNetManager->mDebugManager->OutputRawMessage(StrFormat("msgLo Result for '%s': %d\n", mURL.c_str(), response_code));
+
+		if ((response_code == 0) || (response_code == 200) || (response_code == 404))
+			break;
+
+		Cleanup();
+		// Try again!
+	}
 
 
 	if (response_code == 200)
 	if (response_code == 200)
 	{
 	{

+ 22 - 0
IDEHelper/Tests/src/Comptime.bf

@@ -80,6 +80,21 @@ namespace Tests
 			}
 			}
 		}
 		}
 
 
+		[IFaceA("C", InitVal=345)]
+		struct StructA
+		{
+			public int mA = 123;
+
+			[OnCompile(.TypeInit), Comptime]
+			public static void Generate()
+			{
+				Compiler.EmitTypeBody(typeof(Self), """
+					public int32 mB = 234;
+					public int32 GetValB() => mB;
+					""");
+			}
+		}
+
 		enum MethodAErr
 		enum MethodAErr
 		{
 		{
 			ErrorA,
 			ErrorA,
@@ -168,6 +183,13 @@ namespace Tests
 			Test.Assert(ca.mC == 345);
 			Test.Assert(ca.mC == 345);
 			Test.Assert(ca.GetValC() == 345);
 			Test.Assert(ca.GetValC() == 345);
 
 
+			StructA sa = .();
+			Test.Assert(sa.mA == 123);
+			Test.Assert(sa.mB == 234);
+			Test.Assert(sa.GetValB() == 234);
+			Test.Assert(sa.mC == 345);
+			Test.Assert(sa.GetValC() == 345);
+
 			Compiler.Mixin("int val = 99;");
 			Compiler.Mixin("int val = 99;");
 			Test.Assert(val == 99);
 			Test.Assert(val == 99);
 
 

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

@@ -160,6 +160,32 @@ namespace Tests
 				return 1;
 				return 1;
 			}
 			}
 		}
 		}
+		
+		class ClassF
+		{
+			public static int sVal = 3;
+
+			public int mF0 = 1 ~
+				{
+					sVal += 40;
+				};
+		}
+
+		extension ClassF
+		{
+			public int mF1 = 2 ~
+				{
+					sVal += 500;
+				};
+		}
+
+		class ClassG : ClassF
+		{
+			public int mG0 = 3 ~
+			{
+				sVal += 6000;
+			};
+		}
 
 
 		extension TClassA<T> where T : IGetExVal
 		extension TClassA<T> where T : IGetExVal
 		{
 		{
@@ -226,6 +252,26 @@ namespace Tests
 			ClassE ce = scope .();
 			ClassE ce = scope .();
 			Test.Assert(ce.mD == 1);
 			Test.Assert(ce.mD == 1);
 			Test.Assert(ce.mE == 1);
 			Test.Assert(ce.mE == 1);
+
+			///
+			{
+				ClassF cf = scope .();
+			}
+			Test.Assert(ClassF.sVal == 543);
+			///
+			{
+				ClassF.sVal = 3;
+				ClassG cg = scope .();
+			}
+			Test.Assert(ClassF.sVal == 6543);
+			ClassF.sVal = 3;
+			Object obj = new ClassF();
+			delete obj;
+			Test.Assert(ClassF.sVal == 543);
+			ClassF.sVal = 3;
+			obj = new ClassG();
+			delete obj;
+			Test.Assert(ClassF.sVal == 6543);
 		}
 		}
 
 
 		[Test]
 		[Test]

+ 10 - 0
IDEHelper/Tests/src/Generics2.bf

@@ -95,6 +95,16 @@ namespace Tests
 			}
 			}
 		}
 		}
 
 
+		class IFaceA<T0, T1> where T0 : Dictionary<T1, int> where T1 : IHashable
+		{
+			Dictionary<T1, int> mDict;
+		}
+
+		public static void MethodA<T0, T1>() where T0 : Dictionary<T1, int> where T1 : IHashable
+		{
+
+		}
+
 		[Test]
 		[Test]
 		public static void TestBasics()
 		public static void TestBasics()
 		{
 		{

+ 33 - 33
IDEHelper/Tests/src/Reflection.bf

@@ -239,6 +239,32 @@ namespace Tests
 				switch (methodIdx)
 				switch (methodIdx)
 				{
 				{
 				case 0:
 				case 0:
+					Test.Assert(methodInfo.Name == "__BfCtor");
+					Test.Assert(methodInfo.IsConstructor);
+				case 1:
+					Test.Assert(methodInfo.Name == "__BfStaticCtor");
+					Test.Assert(methodInfo.IsConstructor);
+				case 2:
+					Test.Assert(methodInfo.Name == "GetA");
+					var result = methodInfo.Invoke(ca, 123).Get();
+					Test.Assert(result.Get<int>() == 1123);
+					result.Dispose();
+					result = methodInfo.Invoke(ca2, 123).Get();
+					Test.Assert(result.Get<int>() == 2123);
+					result.Dispose();
+					result = methodInfo.Invoke(.Create(ca2), .Create(123)).Get();
+					Test.Assert(result.Get<int>() == 2123);
+					result.Dispose();
+				case 3:
+					Test.Assert(methodInfo.Name == "MemberMethodA");
+					var result = methodInfo.Invoke(ca, 100, (int32)20, 3.0f).Get();
+					Test.Assert(result.Get<float>() == 123);
+					result.Dispose();
+
+					result = methodInfo.Invoke(.Create(ca), .Create(100), .Create((int32)20), .Create(3.0f)).Get();
+					Test.Assert(result.Get<float>() == 123);
+					result.Dispose();
+				case 4:
 					StructA sa = .() { mA = 1, mB = 2 };
 					StructA sa = .() { mA = 1, mB = 2 };
 
 
 					Test.Assert(methodInfo.Name == "StaticMethodA");
 					Test.Assert(methodInfo.Name == "StaticMethodA");
@@ -291,7 +317,7 @@ namespace Tests
 					let attrC = methodInfo.GetCustomAttribute<AttrCAttribute>().Get();
 					let attrC = methodInfo.GetCustomAttribute<AttrCAttribute>().Get();
 					Test.Assert(attrC.mA == 71);
 					Test.Assert(attrC.mA == 71);
 					Test.Assert(attrC.mB == 72);
 					Test.Assert(attrC.mB == 72);
-				case 1:
+				case 5:
 					Test.Assert(methodInfo.Name == "StaticMethodB");
 					Test.Assert(methodInfo.Name == "StaticMethodB");
 
 
 					var fieldA = typeInfo.GetField("mA").Value;
 					var fieldA = typeInfo.GetField("mA").Value;
@@ -337,33 +363,6 @@ namespace Tests
 					res.Dispose();
 					res.Dispose();
 					fieldSAV.Dispose();
 					fieldSAV.Dispose();
 					fieldSStrV.Dispose();
 					fieldSStrV.Dispose();
-
-				case 2:
-					Test.Assert(methodInfo.Name == "MemberMethodA");
-					var result = methodInfo.Invoke(ca, 100, (int32)20, 3.0f).Get();
-					Test.Assert(result.Get<float>() == 123);
-					result.Dispose();
-
-					result = methodInfo.Invoke(.Create(ca), .Create(100), .Create((int32)20), .Create(3.0f)).Get();
-					Test.Assert(result.Get<float>() == 123);
-					result.Dispose();
-				case 3:
-					Test.Assert(methodInfo.Name == "GetA");
-					var result = methodInfo.Invoke(ca, 123).Get();
-					Test.Assert(result.Get<int>() == 1123);
-					result.Dispose();
-					result = methodInfo.Invoke(ca2, 123).Get();
-					Test.Assert(result.Get<int>() == 2123);
-					result.Dispose();
-					result = methodInfo.Invoke(.Create(ca2), .Create(123)).Get();
-					Test.Assert(result.Get<int>() == 2123);
-					result.Dispose();
-				case 4:
-					Test.Assert(methodInfo.Name == "__BfStaticCtor");
-					Test.Assert(methodInfo.IsConstructor);
-				case 5:
-					Test.Assert(methodInfo.Name == "__BfCtor");
-					Test.Assert(methodInfo.IsConstructor);
 				case 6:
 				case 6:
 					Test.FatalError(); // Shouldn't have any more
 					Test.FatalError(); // Shouldn't have any more
 				}
 				}
@@ -445,6 +444,8 @@ namespace Tests
 				switch (methodIdx)
 				switch (methodIdx)
 				{
 				{
 				case 0:
 				case 0:
+					Test.Assert(methodInfo.Name == "__BfCtor");
+				case 1:
 					Test.Assert(methodInfo.Name == "GetA");
 					Test.Assert(methodInfo.Name == "GetA");
 
 
 					var result = methodInfo.Invoke(sa, 34).Get();
 					var result = methodInfo.Invoke(sa, 34).Get();
@@ -464,7 +465,7 @@ namespace Tests
 					result = methodInfo.Invoke(.Create(&sa), .Create(34));
 					result = methodInfo.Invoke(.Create(&sa), .Create(34));
 					Test.Assert(result.Get<int32>() == 1234);
 					Test.Assert(result.Get<int32>() == 1234);
 					result.Dispose();
 					result.Dispose();
-				case 1:
+				case 2:
 					Test.Assert(methodInfo.Name == "GetB");
 					Test.Assert(methodInfo.Name == "GetB");
 
 
 					var result = methodInfo.Invoke(sa, 34).Get();
 					var result = methodInfo.Invoke(sa, 34).Get();
@@ -489,16 +490,15 @@ namespace Tests
 					Test.Assert(sa.mB == 91);
 					Test.Assert(sa.mB == 91);
 					result.Dispose();
 					result.Dispose();
 
 
-				case 2:
-					Test.Assert(methodInfo.Name == "MethodA0");
 				case 3:
 				case 3:
-					Test.Assert(methodInfo.Name == "MethodA1");
+					Test.Assert(methodInfo.Name == "MethodA0");
 				case 4:
 				case 4:
-					Test.Assert(methodInfo.Name == "__BfCtor");
+					Test.Assert(methodInfo.Name == "MethodA1");
 				case 5:
 				case 5:
 					Test.Assert(methodInfo.Name == "__Equals");
 					Test.Assert(methodInfo.Name == "__Equals");
 				case 6:
 				case 6:
 					Test.Assert(methodInfo.Name == "__StrictEquals");
 					Test.Assert(methodInfo.Name == "__StrictEquals");
+				
 				default:
 				default:
 					Test.FatalError(); // Shouldn't have any more
 					Test.FatalError(); // Shouldn't have any more
 				}
 				}

+ 5 - 0
IDEHelper/WinDebugger.cpp

@@ -9504,6 +9504,11 @@ String WinDebugger::Evaluate(const StringImpl& expr, DwFormatInfo formatInfo, in
 		expressionFlags = (DwEvalExpressionFlags)(expressionFlags & ~DwEvalExpressionFlag_AllowCalls);
 		expressionFlags = (DwEvalExpressionFlags)(expressionFlags & ~DwEvalExpressionFlag_AllowCalls);
 	}
 	}
 
 
+	if ((expressionFlags & DwEvalExpressionFlag_RawStr) != 0)
+	{
+		formatInfo.mRawString = true;
+	}
+
 	auto dbgModule = GetCallStackDbgModule(callStackIdx);
 	auto dbgModule = GetCallStackDbgModule(callStackIdx);
 	auto dbgSubprogram = GetCallStackSubprogram(callStackIdx);
 	auto dbgSubprogram = GetCallStackSubprogram(callStackIdx);
 	DbgCompileUnit* dbgCompileUnit = NULL;
 	DbgCompileUnit* dbgCompileUnit = NULL;