Brian Fiete 4 lat temu
rodzic
commit
8e9d7ed4c4
56 zmienionych plików z 1561 dodań i 776 usunięć
  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;
                 }
 
+				if (Math.Abs(dY) < mSelfHeight * 0.21f)
+				{
+					mDragKind = .None;
+					mDragTarget = null;
+					return;
+				}
+
 				delete mCurDragEvent;
                 mCurDragEvent = new DragEvent();
                 mCurDragEvent.mX = x;

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

@@ -106,6 +106,24 @@ namespace Beefy.widgets
 
 	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)
 		{
 			if (str.Length == 1)

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

@@ -200,7 +200,8 @@ namespace Beefy.widgets
             {
                 return (mTabbedView.mParentDockingFrame.mParentDockingFrame == null) &&
                     (mTabbedView.mParentDockingFrame.GetDockedWindowCount() == 1) &&
-                    (mTabbedView.GetTabCount() == 1);
+                    (mTabbedView.GetTabCount() == 1) &&
+					mTabbedView.mAutoClose;
             }
 
             void WindowDragLostFocusHandler(BFWindow window, BFWindow newFocus)
@@ -237,7 +238,7 @@ namespace Beefy.widgets
                             300, 500,
                             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.UseParentMenu,
+                            BFWindowBase.Flags.UseParentMenu | BFWindowBase.Flags.Maximize,
                             subFrame);
                         Dock(subFrame, null, DockingFrame.WidgetAlign.Top);
                         //subFrame.AddDockedWidget(fourthTabbedView, null, DockingFrame.WidgetAlign.Left, false);
@@ -288,7 +289,7 @@ namespace Beefy.widgets
                 if ((refWidget != null) && (refWidget.mWidgetWindow != mWidgetWindow) && (mWidgetWindow != null))
                     mWidgetWindow.SetForeground();
 
-                if (mTabbedView.GetTabCount() == 1)
+                if ((mTabbedView.GetTabCount() == 1) && mTabbedView.mAutoClose)
                 {                    
                     mTabbedView.Dock(frame, refWidget, align);
                     return;
@@ -327,7 +328,7 @@ namespace Beefy.widgets
                     tabbedView.Dock(frame, refWidget, align);                    
                 }
 
-                if (prevTabbedView.GetTabCount() == 0)
+                if ((prevTabbedView.GetTabCount() == 0) && prevTabbedView.mAutoClose)
                 {                    
                     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);
 
 		/* Available in 2.0.5 or higher */
-		[LinkName("SDL_GetDisplayMode")]
+		[LinkName("SDL_GetDisplayUsableBounds")]
 		public static extern int SDL_GetDisplayUsableBounds(int displayIndex, out Rect rect);
 
 		[LinkName("SDL_GetNumDisplayModes")]

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

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

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

@@ -119,7 +119,8 @@ namespace System.IO
 			DeleteAndNullify!(mTitle);
 			DeleteAndNullify!(mInitialDir);
 			DeleteAndNullify!(mDefaultExt);
-			DeleteAndNullify!(mFileNames);
+			DeleteContainerAndItems!(mFileNames);
+			mFileNames = null;
 			DeleteAndNullify!(mFilter);
 			mFilterIndex = 1;
 			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:4996)
 

+ 20 - 7
BeefySysLib/util/MultiHashSet.h

@@ -164,17 +164,30 @@ public:
 	{
 		auto newHashHeads = (Entry**)TFuncs::AllocateZero(sizeof(Entry*) * newHashSize, alignof(Entry*));
 
+		SizedArray<Entry*, 32> entryList;
+
 		for (int hashIdx = 0; hashIdx < mHashSize; 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
 	{
-		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)
 		{

+ 47 - 42
IDE/src/BuildContext.bf

@@ -29,12 +29,8 @@ namespace IDE
 		public int32 mUpdateCnt;
 		public Project mHotProject;
 		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 mScriptManager ~ delete _;
 
@@ -122,7 +118,7 @@ namespace IDE
 
 			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);
 			for (let origCustomCmd in cmdList)
@@ -163,19 +159,13 @@ namespace IDE
 					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;
 			}
 
-			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;
 		}
 
@@ -874,9 +864,9 @@ namespace IDE
 						minRTModName.Insert(0, "_");
 
 					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
-						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 ");
 				}
 
@@ -1062,17 +1052,8 @@ namespace IDE
 
 						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();
-					linkerPath.Append(binPath);
-					linkerPath.Append("/link.exe");
 					if (workspaceOptions.mToolsetType == .LLVM)
 					{
 						linkerPath.Clear();
@@ -1097,6 +1078,17 @@ namespace IDE
 						if ((mPlatformType == .Windows) && (!is64Bit))
 							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)
 					{
@@ -1216,6 +1208,8 @@ namespace IDE
 				}
 			}
 
+			mTargetPathMap[project] = new String(targetPath);
+
 			if (hotProject == null)
 			{
 				switch (QueueProjectCustomBuildCommands(project, targetPath, compileKind.WantsRunAfter ? options.mBuildOptions.mBuildCommandsOnRun : options.mBuildOptions.mBuildCommandsOnCompile, options.mBuildOptions.mPreBuildCmds))
@@ -1226,22 +1220,9 @@ namespace IDE
 					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 (hotProject == null)
-					DoPostBuild();
 				return true; 
 			}
 
@@ -1402,8 +1383,32 @@ namespace IDE
 					return false;
 			}
 
-			DoPostBuild();
 		    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,
 			MemoryWatch			= 0x80,
 			Symbol				= 0x100,
-			StepIntoCall		= 0x200
+			StepIntoCall		= 0x200,
+			RawStr				= 0x400,
 		}
 
 		[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
 		{
 			None,
@@ -7447,85 +7453,105 @@ namespace IDE
 						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;
 						return;
 					}
 				}
 			}
-			else
-			{
-				// Not found
-				if (hadChordState)
-				{
-					Beep(.Error);
-					evt.mHandled = true;
-					return;
-				}
-			}
 
             SourceViewPanel sourceViewPanel = null;
             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;
                 mExecutionQueue.RemoveAt(0);
 
@@ -8411,6 +8452,11 @@ namespace IDE
 					if (gApp.mDebugger.mIsRunning)
 						mProfilePanel.StartProfiling(profileCmd.mThreadId, profileCmd.mDesc, profileCmd.mSampleRate);
 				}
+				else if (var scriptCmd = next as ScriptCmd)
+				{
+					// Already handled
+					(void)scriptCmd;
+				}
                 else
                 {
                     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)
         {
-			int i = result.Length;
+			int startIdx = result.Length;
+			int i = startIdx;
 			result.Append(configString);
 
 			bool hadError = false;
@@ -9258,6 +9305,28 @@ namespace IDE
 									cmdErr = "Invalid number of arguments";
 							case "Var":
 								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)
@@ -10251,6 +10320,12 @@ namespace IDE
                     success = false;
             }
 
+			for (var project in orderedProjectList)
+			{
+			    if (!mBuildContext.QueueProjectPostBuild(project, hotProject, completedCompileCmd, hotFileNames, compileKind))
+			        success = false;
+			}
+
             if (hotFileNames.Count > 0)
             {
 				// Why were we rehupping BEFORE hotLoad?
@@ -10430,6 +10505,36 @@ namespace IDE
 #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)
         {
 			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())
 					mSettings.mVSSettings.SetDefaults();
@@ -10788,8 +10893,8 @@ namespace IDE
 
 			//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();
             ResolveConfigString(mPlatformName, workspaceOptions, project, options, "$(Arguments)", "debug command arguments", arguments);
             String workingDirRel = scope String();
@@ -10797,6 +10902,9 @@ namespace IDE
 			var workingDir = scope String();
 			Path.GetAbsolutePath(workingDirRel, project.mProjectDir, workingDir);
 
+			String launchPath = scope String();
+			Path.GetAbsolutePath(launchPathRel, workingDir, launchPath);
+
 			String targetPath = scope .();
 			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)
 			{
 				var nextCmd = gApp.mExecutionQueue[0];
-				if (!(nextCmd is IDEApp.TargetCompletedCmd))
+				if (!(nextCmd is IDEApp.ScriptCmd))
 					return false;
 			}
 

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

@@ -876,16 +876,22 @@ namespace IDE.ui
 		{
 			base.Update();
 
+			if (gApp.mBfResolveCompiler == null)
+				return;
+
 			var focusedItem = (ClassViewListViewItem)mTypeLV.GetRoot().FindFocusedItem();
 			var focusedStr = scope String();
 			if (focusedItem != null)
 				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))

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

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

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

@@ -276,7 +276,15 @@ namespace IDE.ui
 						SetLabel(item, codeStr);
 
 						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', ' ');
 
 						SetLabel(descItem, errStr);

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

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

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

@@ -7,6 +7,7 @@ using Beefy.theme.dark;
 using Beefy.gfx;
 using System.Diagnostics;
 using System.IO;
+using IDE.Debugger;
 
 namespace IDE.ui
 {
@@ -379,7 +380,11 @@ namespace IDE.ui
 				var subItemLabel = result.GetSubItem(1).mLabel;
 				if (subItemLabel == null)
 					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)
 				{
@@ -415,7 +420,11 @@ namespace IDE.ui
 			        for (int32 i = startPos; i < mEditWidgetContent.mData.mTextLength; i++)
 			            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));
 			        mEditWidgetContent.AddWidget(mInfoButton);
@@ -547,7 +556,16 @@ namespace IDE.ui
 				}
 				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;
 				}
 			}
@@ -570,7 +588,19 @@ namespace IDE.ui
                     }
 					var info = scope String()..Append(val, idx + ":autocomplete\n".Length);
 					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);
+					}
                 }
                 else if (editWidgetContent.mAutoComplete != null)
                     editWidgetContent.mAutoComplete.Close();                

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

@@ -284,26 +284,20 @@ namespace IDE.ui
 							s.AppendF("0x{:A}", (uint64)lockRange.mBaseOffset);
                         case RepType.Int8:
 							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:
 							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:
 							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:
 							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:
 							(*(float*)lockRange.mData.CArray()).ToString(s);
                         case RepType.Double:

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

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

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

@@ -5073,7 +5073,11 @@ namespace IDE.ui
 	                    String showMouseoverString = 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)
 							{
@@ -5676,7 +5680,8 @@ namespace IDE.ui
 				}
 			}
 
-            UpdateMouseover();            
+			if (gApp.mIsUpdateBatchStart)
+            	UpdateMouseover();
             
             var compiler = ResolveCompiler;
             var bfSystem = BfResolveSystem;

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

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

+ 5 - 1
IDEHelper/Backend/BeIRCodeGen.cpp

@@ -690,6 +690,8 @@ void BeIRCodeGen::Read(BeValue*& beValue)
 				CMD_PARAM(BeConstant*, initializer);
 				CMD_PARAM(String, name);
 				CMD_PARAM(bool, isTLS);
+
+				BF_ASSERT(varType != NULL);
 				
 				auto globalVariable = mBeModule->mGlobalVariables.Alloc();
 				globalVariable->mModule = mBeModule;
@@ -1906,7 +1908,9 @@ void BeIRCodeGen::HandleNextCmd()
 			CMD_PARAM(StringT<256>, name);
 			CMD_PARAM(bool, isTLS);
 			CMD_PARAM(BeConstant*, initializer);
-						
+			
+			BF_ASSERT(varType != NULL);
+
 			auto globalVariable = mBeModule->mGlobalVariables.Alloc();
 			globalVariable->mModule = mBeModule;
 			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 (mcOperand.mVRegIdx == 6)
+		if (mcOperand.mVRegIdx == 227)
 		{
 			NOP;
 		}
@@ -10364,7 +10364,7 @@ bool BeMCContext::DoLegalization()
 									inst->mArg0.mKind = BeMCOperandKind_SymbolAddr;
 								}
 
-								ReplaceWithNewVReg(inst->mArg0, movInstIdx, true, false);
+								ReplaceWithNewVReg(inst->mArg0, movInstIdx, true, false, true);
 								auto vregInfo = GetVRegInfo(inst->mArg0);
 								vregInfo->mDisableR11 = true;
 								instIdx += 2;
@@ -15842,7 +15842,7 @@ void BeMCContext::Generate(BeFunction* function)
 	mDbgPreferredRegs[32] = X64Reg_R8;*/
 
 	//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 == "?Hey@Blurg@bf@@SAXXZ")
 	// 		;

+ 2 - 1
IDEHelper/Compiler/BfCodeGen.cpp

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

+ 43 - 44
IDEHelper/Compiler/BfCompiler.cpp

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

+ 3 - 2
IDEHelper/Compiler/BfCompiler.h

@@ -323,6 +323,7 @@ public:
 	BfCodeGen mCodeGen;
 	String mOutputDirectory;
 	bool mCanceling;
+	bool mHasRequiredTypes;
 	bool mNeedsFullRefresh;
 	bool mFastFinish;
 	bool mHasQueuedTypeRebuilds; // Infers we had a fast finish that requires a type rebuild
@@ -352,14 +353,14 @@ public:
 	BfTypeDef* mDbgRawAllocDataTypeDef;
 	BfTypeDef* mDeferredCallTypeDef;		
 	BfTypeDef* mDelegateTypeDef;
+	BfTypeDef* mFunctionTypeDef;
 	BfTypeDef* mActionTypeDef;
 	BfTypeDef* mEnumTypeDef;
 	BfTypeDef* mStringTypeDef;
 	BfTypeDef* mStringViewTypeDef;
 	BfTypeDef* mTypeTypeDef;
 	BfTypeDef* mValueTypeTypeDef;	
-	BfTypeDef* mResultTypeDef;
-	BfTypeDef* mFunctionTypeDef;
+	BfTypeDef* mResultTypeDef;	
 	BfTypeDef* mGCTypeDef;	
 	BfTypeDef* mGenericIEnumerableTypeDef;
 	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)
-{	
+{
 	mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_Comptime);
 
 	// 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);					
 					if (stringId != -1)
 					{
-						if ((flags & BfConstResolveFlag_RemapFromStringId) != 0)
+						if ((flags & BfConstResolveFlag_ActualizeValues) != 0)
 						{
 							prevIgnoreWrites.Restore();
 							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);
@@ -232,7 +232,9 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo
 	}*/
 
 	mModule->FixIntUnknown(mResult);	
-	mModule->FixValueActualization(mResult);
+
+	if ((flags & BfConstResolveFlag_NoActualizeValues) == 0)
+		mModule->FixValueActualization(mResult, !prevIgnoreWrites.mPrevVal || ((flags & BfConstResolveFlag_ActualizeValues) != 0));
 
 	return mResult;
 }
@@ -416,15 +418,22 @@ bool BfConstResolver::PrepareMethodArguments(BfAstNode* targetSrc, BfMethodMatch
 		}
 		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++;
 		}
 		argIdx++;

+ 5 - 4
IDEHelper/Compiler/BfConstResolver.h

@@ -15,9 +15,10 @@ enum BfConstResolveFlags
 	BfConstResolveFlag_ExplicitCast = 1,
 	BfConstResolveFlag_NoCast = 2,
 	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
@@ -33,7 +34,7 @@ public:
 	BfConstResolver(BfModule* bfModule);		
 
 	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

+ 15 - 10
IDEHelper/Compiler/BfContext.cpp

@@ -829,8 +829,7 @@ void BfContext::ValidateDependencies()
 void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuildModule, bool placeSpecializiedInPurgatory)
 {
 	BfTypeInstance* typeInst = type->ToTypeInstance();		
-	
-	
+		
 	if (type->IsDeleting())
 	{
 		return;
@@ -2517,11 +2516,6 @@ void BfContext::QueueMethodSpecializations(BfTypeInstance* typeInst, bool checkS
 	
 	BP_ZONE("BfContext::QueueMethodSpecializations");
 
-	if (typeInst->mTypeId == 578)
-	{
-		NOP;
-	}
-
 	auto module = typeInst->mModule;
 	if (module == NULL)
 		return;
@@ -2917,10 +2911,21 @@ void BfContext::Cleanup()
 
 	// Clean up deleted BfTypes
 	// 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();
 

+ 3 - 1
IDEHelper/Compiler/BfContext.h

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

+ 23 - 31
IDEHelper/Compiler/BfDefBuilder.cpp

@@ -443,17 +443,7 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
 		{
 			methodDef->mIsConcrete = true;
 			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)
 		{
@@ -1775,24 +1765,21 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 		bool doInsertNew = true;
 		if (prevRevisionTypeDef != NULL)
 		{
-			mCurTypeDef->mIsNextRevision = true;			
+			mCurTypeDef->mIsNextRevision = true;
 			bfParser->mTypeDefs.Add(prevRevisionTypeDef);
 
 			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;
 				BF_ASSERT(mCurTypeDef->mSystem != NULL);
 				mCurActualTypeDef = prevRevisionTypeDef;
 				doInsertNew = false;
-			}
-			else
-			{
-				if (prevRevisionTypeDef->mNextRevision != NULL)
-					prevRevisionTypeDef = prevRevisionTypeDef->mNextRevision;
-
-				prevRevisionTypeDef = NULL;
-			}
+			}			
 		}
 		else
 		{
@@ -1820,8 +1807,8 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 		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);
 	
@@ -1875,9 +1862,9 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 
 		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;
 				BF_ASSERT(prevRevisionTypeDef->mNextRevision == mCurTypeDef);
 				prevRevisionTypeDef->mNextRevision = NULL;
@@ -1918,9 +1905,10 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 	BfMethodDef* dynamicCastMethod = NULL;
 	BfMethodDef* toStringMethod = NULL;
 	bool needsEqualsMethod = ((mCurTypeDef->mTypeCode == BfTypeCode_Struct) || (mCurTypeDef->mTypeCode == BfTypeCode_Enum)) && (!mCurTypeDef->mIsStatic);	
+	BfMethodDef* equalsOpMethod = NULL;
 	BfMethodDef* equalsMethod = NULL;
-	BfMethodDef* strictEqualsMethod = NULL;
-	
+	BfMethodDef* strictEqualsMethod = NULL;	
+
 	bool needsStaticInit = false;
 	for (int methodIdx = 0; methodIdx < (int)mCurTypeDef->mMethods.size(); methodIdx++)
 	{
@@ -1962,7 +1950,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 
 				auto ctorDeclaration = (BfConstructorDeclaration*)method->mMethodDeclaration;
 				if (method->mHasAppend)
-				{										
+				{				 						
 					mCurTypeDef->mHasAppendCtor = true;
 
 					auto methodDef = new BfMethodDef();
@@ -2038,6 +2026,10 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 			{
 				if (method->mName == BF_METHODNAME_MARKMEMBERS_STATIC)
 					_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
 			{
@@ -2061,7 +2053,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 					if ((method->mParams[0]->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;
 	}
 	
-	if ((needsEqualsMethod) && (equalsMethod == NULL))
+	if ((needsEqualsMethod) && (equalsMethod == NULL) && (equalsOpMethod == NULL))
 	{		
 		auto methodDef = new BfMethodDef();
 		mCurTypeDef->mMethods.push_back(methodDef);
@@ -2314,7 +2306,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 		methodDef->mAddedAfterEmit = mIsComptime;
 	}
 
-	if (needsEqualsMethod)
+	if ((needsEqualsMethod) && (strictEqualsMethod == NULL))
 	{
 		auto methodDef = new BfMethodDef();
 		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);
 	}
 
+	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;
 	int varSkipCount = 0;
 	if (fieldName.StartsWith('@'))
@@ -4627,6 +4635,8 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
 
 				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)))
 					doAccessCheck = false;
 
@@ -4853,7 +4863,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
 					}
 
 					// 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))
 						{
@@ -10104,19 +10114,22 @@ void BfExprEvaluator::Visit(BfTypeOfExpression* typeOfExpr)
 
 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);
 	
 	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)
@@ -10206,11 +10219,42 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie
 	else if ((memberName == "MinValue") || (memberName == "MaxValue"))
 	{
 		bool isMin = memberName == "MinValue";
-				
-		BfType* checkType = typeInstance;
+		
+		BfType* checkType = type;
 		if (checkType->IsTypedPrimitive())
 			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())
 		{
 			auto primType = (BfPrimitiveType*)checkType;
@@ -10257,15 +10301,15 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie
 				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 
 		{
-			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
@@ -11923,17 +11967,18 @@ void BfExprEvaluator::VisitLambdaBodies(BfAstNode* body, BfFieldDtorDeclaration*
 	if (auto blockBody = BfNodeDynCast<BfBlock>(body))
 		mModule->VisitChild(blockBody);
 	else if (auto bodyExpr = BfNodeDynCast<BfExpression>(body))
-	{
+	{		
 		auto result = mModule->CreateValueFromExpression(bodyExpr);
 		if ((result) && (mModule->mCurMethodState->mClosureState != NULL) &&
 			(mModule->mCurMethodState->mClosureState->mReturnTypeInferState == BfReturnTypeInferState_Inferring))
-			mModule->mCurMethodState->mClosureState->mReturnType = result.mType;
+			mModule->mCurMethodState->mClosureState->mReturnType = result.mType;		
 	}
 	
 	while (fieldDtor != NULL)
 	{
+		mModule->mCurMethodState->mLeftBlockUncond = false;
 		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);
 		}
 
+		if (arrayType == NULL)
+			return;
+
 		if (isAppendAlloc)
 			arrayValue = BfTypedValue(mModule->AppendAllocFromType(resultType, BfIRValue(), 0, arraySize, (int)dimLengthVals.size(), isRawArrayAlloc, zeroMemory), arrayType);
 		else
@@ -14790,7 +14838,15 @@ BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfAstNode* targetSrc,
 		if (unspecializedMethod == NULL)
 			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)
 			*overrideReturnType = specializedReturnType;
 	}
@@ -18711,10 +18767,10 @@ void BfExprEvaluator::Visit(BfTupleExpression* tupleExpr)
 	int valueIdx = -1;
 	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())
 			continue;
-		++valueIdx;
 		auto typedVal = typedValues[valueIdx];
 		if (!typedVal)
 		{
@@ -20399,11 +20455,70 @@ void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExp
 		}
 		return;
 	}
-	
+
 	BfType* wantType = leftValue.mType;
 	if ((binaryOp == BfBinaryOp_LeftShift) || (binaryOp == BfBinaryOp_RightShift))
 		wantType = NULL; // Don't presume
 	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));
 	if ((!leftValue) || (!rightValue))
 		return;
@@ -20611,58 +20726,6 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
 			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))
 	{
 		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)
 	{
 		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)
 	{
@@ -1875,6 +1865,7 @@ void BfIRBuilder::ClearConstData()
 	mTempAlloc.Clear();
 	mConstMemMap.Clear();
 	mFunctionMap.Clear();
+	mGlobalVarMap.Clear();
 	BF_ASSERT(mMethodTypeMap.GetCount() == 0);
 	BF_ASSERT(mTypeMap.GetCount() == 0);
 	BF_ASSERT(mDITemporaryTypes.size() == 0);
@@ -1889,6 +1880,7 @@ void BfIRBuilder::ClearNonConstData()
 {
 	mMethodTypeMap.Clear();
 	mFunctionMap.Clear();
+	mGlobalVarMap.Clear();
 	mTypeMap.Clear();
 	mConstMemMap.Clear();
 	mDITemporaryTypes.Clear();
@@ -2996,11 +2988,6 @@ void BfIRBuilder::CreateDbgTypeDefinition(BfType* type)
 
 						if (fieldInstance->mConstIdx != -1)
 						{
-							if (fieldInstance->GetFieldDef()->mName == "mMembers")
-							{
-								NOP;
-							}
-
 							constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx);
 							staticValue = mModule->ConstantToCurrent(constant, typeInstance->mConstHolder, resolvedFieldType);
 						}
@@ -4743,39 +4730,53 @@ BfIRValue BfIRBuilder::CreateStackRestore(BfIRValue stackVal)
 	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);
 
 	auto constGV = mTempAlloc.Alloc<BfGlobalVar>();
 	int chunkId = mTempAlloc.GetChunkedId(constGV);
 	constGV->mStreamId = -1;
- 	constGV->mConstType = BfConstType_GlobalVar;
-	constGV->mType = varType;	
+	constGV->mConstType = BfConstType_GlobalVar;
+	constGV->mType = varType;
 	constGV->mIsConst = isConstant;
 	constGV->mLinkageType = linkageType;
 	constGV->mInitializer = initializer;
 	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)

+ 4 - 1
IDEHelper/Compiler/BfIRBuilder.h

@@ -901,6 +901,7 @@ class BfIRConstHolder
 public:
 	BumpAllocatorT<256> mTempAlloc;
 	BfModule* mModule;
+	Dictionary<String, BfIRValue> mGlobalVarMap;
 	
 public:
 	void FixTypeCode(BfTypeCode& typeCode);
@@ -936,6 +937,7 @@ public:
 	BfIRValue CreateTypeOf(BfType* type);
 	BfIRValue CreateTypeOf(BfType* type, BfIRValue typeData);
 	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);
 	BfIRValue ReadConstant(void* ptr, BfType* type);
@@ -979,7 +981,7 @@ public:
 	bool mHasDebugInfo;
 	bool mHasDebugLineInfo;
 	Dictionary<BfMethodRef, BfIRFunctionType> mMethodTypeMap;
-	Dictionary<String, BfIRFunction> mFunctionMap;
+	Dictionary<String, BfIRFunction> mFunctionMap;	
 	Dictionary<BfType*, BfIRPopulateType> mTypeMap;
 	Dictionary<int, BfIRValue> mConstMemMap;
 	Array<BfTypeInstance*> mDITemporaryTypes;	
@@ -1227,6 +1229,7 @@ public:
 	BfIRValue CreateStackRestore(BfIRValue stackVal);
 	
 	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_SetInitializer(BfIRValue globalVar, BfIRValue initVal);
 	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);
 				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;
 
@@ -2389,13 +2393,17 @@ void BfIRCodeGen::HandleNextCmd()
 			CMD_PARAM(bool, isTLS);
 			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);
 		}
 		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
 	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();
 	mImportFileNames.Clear();
 	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)
-{			
+{
 	auto stringTypeInst = ResolveTypeDef(mCompiler->mStringTypeDef, define ? BfPopulateType_Data : BfPopulateType_Declaration)->ToTypeInstance();
 	mBfIRBuilder->PopulateType(stringTypeInst);
 
@@ -1654,8 +1657,14 @@ String* BfModule::GetStringPoolString(BfIRValue constantStr, BfIRConstHolder * c
 	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;
 	if (!mStringCharPtrPool.TryAdd(stringId, NULL, &irValue))
 		return *irValue;
@@ -1670,13 +1679,13 @@ BfIRValue BfModule::GetStringCharPtr(int stringId)
 	return strCharPtrConst;
 }
 
-BfIRValue BfModule::GetStringCharPtr(BfIRValue strValue)
+BfIRValue BfModule::GetStringCharPtr(BfIRValue strValue, bool force)
 {
 	if (strValue.IsConst())
 	{
 		int stringId = GetStringPoolIdx(strValue);
 		BF_ASSERT(stringId != -1);
-		return GetStringCharPtr(stringId);
+		return GetStringCharPtr(stringId, force);
 	}
 
 	BfIRValue charPtrPtr = mBfIRBuilder->CreateInBoundsGEP(strValue, 0, 1);	
@@ -1684,27 +1693,33 @@ BfIRValue BfModule::GetStringCharPtr(BfIRValue strValue)
 	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;
 	if (mStringObjectPool.TryGetValue(strId, &objValue))
 		return *objValue;
 
 	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);
 	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;
 	if (!mStringObjectPool.TryAdd(strId, NULL, &irValuePtr))
@@ -1916,13 +1931,7 @@ void BfModule::AddStackAlloc(BfTypedValue val, BfIRValue arraySize, BfAstNode* r
 		bool hadDtorCall = false;
 		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)
 			{				
 				auto dtorMethodInstance = GetMethodInstance(checkBaseType, dtorMethodDef, BfTypeVector());
@@ -3416,10 +3425,11 @@ void BfModule::AddDependency(BfType* usedType, BfType* userType, BfDependencyMap
 		BfModule* usedModule;
 		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
 			usedModule = usedType->GetModule();
@@ -5235,7 +5245,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 		typeFlags |= BfTypeFlags_Delegate;
 	if (type->IsFunction())
 		typeFlags |= BfTypeFlags_Function;
-	if (type->WantsGCMarking())
+	if ((type->mDefineState != BfTypeDefineState_CETypeInit) && (type->WantsGCMarking()))
 		typeFlags |= BfTypeFlags_WantsMarking;
 
 	int virtSlotIdx = -1;
@@ -5906,8 +5916,8 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 
 	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
 	{
@@ -5967,7 +5977,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 	// Fields
 	BfType* reflectFieldDataType = ResolveTypeDef(mCompiler->mReflectFieldDataDef);
 	BfIRValue emptyValueType = mBfIRBuilder->CreateConstAgg_Value(mBfIRBuilder->MapTypeInst(reflectFieldDataType->ToTypeInstance()->mBaseType), SizedArray<BfIRValue, 1>());
-	
+
 	auto _HandleCustomAttrs = [&](BfCustomAttributes* customAttributes)
 	{
 		if (customAttributes == NULL)
@@ -6023,7 +6033,28 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 			PUSH_INT16(0); // mSize
 
 			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);
 			int argIdx = 0;
@@ -6047,7 +6078,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 							*orderedIdPtr = (int)usedStringIdMap.size() - 1;							
 						}
 
-						GetStringObjectValue(stringId);
+						GetStringObjectValue(stringId, true, true);
 						PUSH_INT8(0xFF); // String
 						PUSH_INT32(*orderedIdPtr);
 						argIdx++;
@@ -6067,7 +6098,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 									*orderedIdPtr = (int)usedStringIdMap.size() - 1;
 								}
 
-								GetStringObjectValue(stringId);
+								GetStringObjectValue(stringId, true, true);
 								PUSH_INT8(0xFF); // String
 								PUSH_INT32(*orderedIdPtr);
 								argIdx++;
@@ -6231,7 +6262,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 		BfType* payloadType = typeInstance->GetUnionInnerType();		
 		if (!payloadType->IsValuelessType())
 		{
-			BfIRValue payloadNameConst = GetStringObjectValue("$payload", true);
+			BfIRValue payloadNameConst = GetStringObjectValue("$payload", !mIsComptimeModule);
 			SizedArray<BfIRValue, 8> payloadFieldVals =
 			{
 				emptyValueType,
@@ -6246,7 +6277,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 		}
 
 		BfType* dscrType = typeInstance->GetDiscriminatorType();
-		BfIRValue dscrNameConst = GetStringObjectValue("$discriminator", true);
+		BfIRValue dscrNameConst = GetStringObjectValue("$discriminator", !mIsComptimeModule);
 		SizedArray<BfIRValue, 8> dscrFieldVals =
 		{
 			emptyValueType,
@@ -6268,7 +6299,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 		BfFieldInstance* fieldInstance = &typeInstance->mFieldInstances[fieldIdx];
 		BfFieldDef* fieldDef = fieldInstance->GetFieldDef();
 
-		BfIRValue fieldNameConst = GetStringObjectValue(fieldDef->mName, true);
+		BfIRValue fieldNameConst = GetStringObjectValue(fieldDef->mName, !mIsComptimeModule);
 
 		int typeId = 0;
 		auto fieldType = fieldInstance->GetResolvedType();
@@ -6448,6 +6479,14 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 	BfType* reflectParamDataType = ResolveTypeDef(mCompiler->mReflectParamDataDef);
 	BfType* reflectParamDataPtrType = CreatePointerType(reflectParamDataType);
 
+	struct _SortedMethodInfo
+	{
+		BfMethodDef* mMethodDef;
+		BfCustomAttributes* mMethodCustomAttributes;
+	};
+
+	Array<_SortedMethodInfo> sortedMethodList;
+
 	SizedArray<BfIRValue, 16> methodTypes;	
 	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];
 		if (!methodInstanceGroup->IsImplemented())
-			continue;		
+			continue;
 		auto methodDef = typeDef->mMethods[methodIdx];
 		if (methodDef->mIsNoReflect)
 			continue;
@@ -6474,12 +6513,12 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 			continue;
 		if (!defaultMethod->mIsReified)
 			continue;
-		
+
 		if ((defaultMethod->mChainType == BfMethodChainType_ChainMember) || (defaultMethod->mChainType == BfMethodChainType_ChainSkip))
 			continue;
 		if (defaultMethod->mMethodDef->mMethodType == BfMethodType_CtorNoBody)
-			continue;		
-		
+			continue;
+
 		auto methodReflectKind = (BfReflectKind)(reflectKind & ~BfReflectKind_User);
 
 		bool includeMethod = reflectIncludeAllMethods;
@@ -6501,10 +6540,10 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 				}
 			}
 		}
-		
+
 		if ((!mIsComptimeModule) && (!typeInstance->IsTypeMemberAccessible(methodDef->mDeclaringType, mProject)))
 			continue;
-		
+
 		//
 		{
 			SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, typeInstance);
@@ -6522,13 +6561,42 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 			includeMethod = true;
 		if ((methodDef->mIsStatic) && ((methodReflectKind & BfReflectKind_StaticMethods) != 0))
 			includeMethod = true;
-		
+
 		if ((!includeMethod) && (typeOptions != NULL))
 			includeMethod = ApplyTypeOptionMethodFilters(includeMethod, methodDef, typeOptions);
-		
+
 		if (!includeMethod)
 			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;
 		BfIRValue funcVal = voidPtrNull;
 		
@@ -6544,11 +6612,11 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 				funcVal = mBfIRBuilder->CreateBitCast(moduleMethodInstance.mFunc, voidPtrIRType);
 		}
 				
-		BfIRValue methodNameConst = GetStringObjectValue(methodDef->mName, true);
+		BfIRValue methodNameConst = GetStringObjectValue(methodDef->mName, !mIsComptimeModule);
 						
 		BfMethodFlags methodFlags = defaultMethod->GetMethodFlags();
 		
-		int customAttrIdx = _HandleCustomAttrs(methodCustomAttributes);
+		int customAttrIdx = _HandleCustomAttrs(methodInfo.mMethodCustomAttributes);
 
 		enum ParamFlags
 		{
@@ -6567,7 +6635,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 			if (defaultMethod->GetParamIsSplat(paramIdx))
 				paramFlags = (ParamFlags)(paramFlags | ParamFlag_Splat);
 
-			BfIRValue paramNameConst = GetStringObjectValue(paramName, true);
+			BfIRValue paramNameConst = GetStringObjectValue(paramName, !mIsComptimeModule);
 
 			SizedArray<BfIRValue, 8> paramDataVals =
 				{
@@ -7150,7 +7218,7 @@ BfIRFunction BfModule::GetBuiltInFunc(BfBuiltInFuncType 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();	
 	BfExternalConstraintDef* externConstraintDef = genericParamInstance->GetExternConstraintDef();
@@ -7256,14 +7324,23 @@ void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericPar
 		if (bfAutocomplete != NULL)
 			bfAutocomplete->CheckTypeRef(constraintTypeRef, true);
 		//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;
 		if (isUnspecialized)
 			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 (deferredResolveTypes != NULL)
+			{
+				PopulateType(constraintType, BfPopulateType_Declaration);
+				if (constraintType->IsUnspecializedTypeVariation())
+					deferredResolveTypes->Add(constraintTypeRef);
+			}
+
 			if ((constraintDef->mGenericParamFlags & BfGenericParamFlag_Const) != 0)
 			{
 				bool isValidTypeCode = false;				
@@ -7444,11 +7521,11 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
 		origCheckArgType = origCheckArgType->GetUnderlyingType();
 
 	bool argMayBeReferenceType = false;
-
+	
 	int checkGenericParamFlags = 0;
 	if (checkArgType->IsGenericParam())
 	{
-		auto checkGenericParamInst = GetGenericParamInstance((BfGenericParamType*)checkArgType);
+		BfGenericParamInstance* checkGenericParamInst = GetGenericParamInstance((BfGenericParamType*)checkArgType);
 		checkGenericParamFlags = checkGenericParamInst->mGenericParamFlags;
 		if (checkGenericParamInst->mTypeConstraint != NULL)
 			checkArgType = checkGenericParamInst->mTypeConstraint;
@@ -7782,7 +7859,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
 			if (TypeIsSubTypeOf(wrappedStructType, typeConstraintInst))
 				implementsInterface = true;
 		}
-
+		
 		if (!implementsInterface)
 		{
 			if ((!ignoreErrors) && (PreFail()))
@@ -10601,6 +10678,7 @@ void BfModule::ClearConstData()
 	mStringObjectPool.Clear();
 	mStringCharPtrPool.Clear();
 	mStringPoolRefs.Clear();
+	mUnreifiedStringPoolRefs.Clear();
 }
 
 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);
 			BfTypedValue typedValue;
 
+			bool allowUnactualized = mBfIRBuilder->mIgnoreWrites;
 			if (constant->mTypeCode == BfTypeCode_StringId)
 			{
 				if ((wantType->IsInstanceOf(mCompiler->mStringTypeDef)) ||
 					((wantType->IsPointer()) && (wantType->GetUnderlyingType() == GetPrimitiveType(BfTypeCode_Char8))))
 				{
-					typedValue = BfTypedValue(ConstantToCurrent(constant, constHolder, wantType), wantType);
+					typedValue = BfTypedValue(ConstantToCurrent(constant, constHolder, wantType, allowUnactualized), wantType);
 					return typedValue;
 				}
 
 				auto stringType = ResolveTypeDef(mCompiler->mStringTypeDef);
-				typedValue = BfTypedValue(ConstantToCurrent(constant, constHolder, stringType), stringType);
+				typedValue = BfTypedValue(ConstantToCurrent(constant, constHolder, stringType, allowUnactualized), stringType);
 			}
 			
 			if (!typedValue)
@@ -10684,7 +10763,27 @@ BfTypedValue BfModule::GetTypedValueFromConstant(BfConstant* constant, BfIRConst
 	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)
 	{
@@ -10699,20 +10798,27 @@ BfIRValue BfModule::ConstantToCurrent(BfConstant* constant, BfIRConstHolder* con
 
 	if (constant->mTypeCode == BfTypeCode_StringId)
 	{
-		if (!allowStringId)
+		if (!allowUnactualized)
 		{
 			if ((wantType->IsInstanceOf(mCompiler->mStringTypeDef)) ||
 				((wantType->IsPointer()) && (wantType->GetUnderlyingType() == GetPrimitiveType(BfTypeCode_Char8))))
 			{
 				const StringImpl& str = mContext->mStringObjectIdMap[constant->mInt32].mString;
-				BfIRValue stringObjConst = GetStringObjectValue(str);
+				BfIRValue stringObjConst = GetStringObjectValue(str, false, true);
 				if (wantType->IsPointer())
-					return GetStringCharPtr(stringObjConst);
+					return GetStringCharPtr(stringObjConst, true);
 				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)
 	{		
 		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)
 {
+	if (!mCompiler->mHasRequiredTypes)
+		return;
+
 	if ((attributesDirective != NULL) && (mCompiler->mResolvePassData != NULL) && 
 		(attributesDirective->IsFromParser(mCompiler->mResolvePassData->mParser)) && (mCompiler->mResolvePassData->mSourceClassifier != NULL))
 	{
@@ -10908,6 +11017,12 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 			continue;
 		}
 
+		if ((mIsReified) && (attrTypeInst->mAttributeData != NULL) && ((attrTypeInst->mAttributeData->mFlags & BfAttributeFlag_ReflectAttribute) != 0))
+		{
+			// Reify attribute
+			PopulateType(attrTypeInst);
+		}
+
 		if (mCurTypeInstance != NULL)
 			AddDependency(attrTypeInst, mCurTypeInstance, BfDependencyMap::DependencyFlag_CustomAttribute);
 
@@ -11018,8 +11133,8 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 
 					auto& fieldTypeInst = checkTypeInst->mFieldInstances[bestField->mIdx];
 					if (assignExpr->mRight != NULL)
-					{
-						BfTypedValue result = constResolver.Resolve(assignExpr->mRight, fieldTypeInst.mResolvedType);
+					{						
+						BfTypedValue result = constResolver.Resolve(assignExpr->mRight, fieldTypeInst.mResolvedType, BfConstResolveFlag_NoActualizeValues);
 						if (result)
 						{
 							CurrentAddToConstHolder(result.mValue);
@@ -11078,9 +11193,11 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 							auto propType = methodInstance.mMethodInstance->GetParamType(0);
 							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);
 									CurrentAddToConstHolder(result.mValue);
 									setProperty.mParam = result;
@@ -11092,7 +11209,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 				}
 
 				if ((!handledExpr) && (assignExpr->mRight != NULL))
-					constResolver.Resolve(assignExpr->mRight);
+					constResolver.Resolve(assignExpr->mRight, NULL, BfConstResolveFlag_NoActualizeValues);
 			}
 			else
 			{
@@ -11112,7 +11229,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 					resolvedArg.mArgFlags = BfArgFlag_DeferredEval;
 				}
 				else
-					resolvedArg.mTypedValue = constResolver.Resolve(arg);
+					resolvedArg.mTypedValue = constResolver.Resolve(arg, NULL, BfConstResolveFlag_NoActualizeValues);
 
 				if (!inPropSet)
 				{										
@@ -11193,7 +11310,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 			if ((arg.mArgFlags & BfArgFlag_DeferredEval) != 0)
 			{
 				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_IntUnknown:
 			case BfTypeCode_UIntUnknown:
-			case BfTypeCode_Float:
 			case BfTypeCode_Double:
 			case BfTypeCode_Char8:
 			case BfTypeCode_Char16:
 			case BfTypeCode_Char32:
 				variant.mTypeCode = constant->mTypeCode;
 				variant.mInt64 = constant->mInt64;
-				break;				
+				break;
+			case BfTypeCode_Float:
+				variant.mTypeCode = constant->mTypeCode;
+				variant.mSingle = (float)constant->mDouble;
+				break;
 			default:
 				if (refNode != NULL)
 					Fail("Invalid const expression type", refNode);
@@ -13624,6 +13744,13 @@ BfTypedValue BfModule::ReferenceStaticField(BfFieldInstance* fieldInstance)
 	{
 		globalValue = *globalValuePtr;
 		BF_ASSERT(globalValue);
+
+		auto globalVar = (BfGlobalVar*)mBfIRBuilder->GetConstant(globalValue);
+		if ((globalVar->mStreamId == -1) && (!mBfIRBuilder->mIgnoreWrites))
+		{
+			mBfIRBuilder->MapType(fieldInstance->mResolvedType);
+			mBfIRBuilder->CreateGlobalVariable(globalValue);
+		}
 	}
 	else
 	{				
@@ -13655,16 +13782,11 @@ BfTypedValue BfModule::ReferenceStaticField(BfFieldInstance* fieldInstance)
 				BfIRValue(),
 				staticVarName,
 				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);
-
 		}
 	}	
 
@@ -13676,7 +13798,7 @@ BfTypedValue BfModule::ReferenceStaticField(BfFieldInstance* fieldInstance)
 }
 
 BfTypedValue BfModule::GetThis()
-{
+{	
 	auto useMethodState = mCurMethodState;
 	while ((useMethodState != NULL) && (useMethodState->mClosureState != NULL) && (useMethodState->mClosureState->mCapturing))		
 	{
@@ -13705,33 +13827,6 @@ BfTypedValue BfModule::GetThis()
 		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'
 	{
 		auto checkMethodState = mCurMethodState;
@@ -14059,8 +14154,10 @@ void BfModule::DoLocalVariableDebugInfo(BfLocalVariable* localVarDef, bool doAli
 				if (mBfIRBuilder->HasDebugLocation())
 				{
 					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
 					{
@@ -15668,7 +15765,11 @@ void BfModule::EmitDtorBody()
 				}
 				else
 				{
-					if (!mCurTypeInstance->IsValueType())
+					if (fieldInst->mResolvedType->IsValuelessType())
+					{
+						value = mBfIRBuilder->GetFakeVal();
+					}
+					else if (!mCurTypeInstance->IsValueType())
 					{
 						auto thisValue = GetThis();
 						value = mBfIRBuilder->CreateInBoundsGEP(thisValue.mValue, 0, fieldInst->mDataIdx);						
@@ -15744,13 +15845,7 @@ void BfModule::EmitDtorBody()
 					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)
 				{
 					auto dtorMethodInstance = GetMethodInstance(checkBaseType, dtorMethodDef, BfTypeVector());
@@ -18160,7 +18255,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 	auto methodDeclaration = methodDef->GetMethodDeclaration();
 
 	if ((methodDef->mHasComptime) && (!mIsComptimeModule))
-		mBfIRBuilder->mIgnoreWrites = true;
+		mBfIRBuilder->mIgnoreWrites = true;	
 
 	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);
-	
+
+	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 (mBfIRBuilder->mIgnoreWrites)
@@ -19451,7 +19575,11 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 	}
 
 	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)
 		{
@@ -19463,34 +19591,19 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 		}
 
 		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)
 		{
@@ -21534,6 +21647,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 	{
 		BfTypeInstance* unspecializedTypeInstance = NULL;
 
+		Array<BfTypeReference*> deferredResolveTypes;
 		for (int genericParamIdx = 0; genericParamIdx < (int)methodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++)
 		{
 			auto genericParam = methodInstance->mMethodInfoEx->mGenericParams[genericParamIdx];
@@ -21557,8 +21671,8 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 				else
 					genericParam->mExternType = GetPrimitiveType(BfTypeCode_Var);
 			}
-
-			ResolveGenericParamConstraints(genericParam, methodInstance->mIsUnspecialized);
+			
+			ResolveGenericParamConstraints(genericParam, methodInstance->mIsUnspecialized, &deferredResolveTypes);						
 
 			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)
 		{
@@ -21920,6 +22036,12 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 			}
 			else
 			{
+				BfTypeState typeState;
+				typeState.mTypeInstance = mCurTypeInstance;
+				typeState.mCurTypeDef = methodDef->mDeclaringType;
+				//typeState.mCurMethodDef = methodDef;
+				SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
+
 				BfConstResolver constResolver(this);
 				defaultValue = constResolver.Resolve(paramDef->mParamDeclaration->mInitializer, resolvedParamType, (BfConstResolveFlags)(BfConstResolveFlag_NoCast | BfConstResolveFlag_AllowGlobalVariable));
 				if ((defaultValue) && (defaultValue.mType != resolvedParamType))
@@ -22051,7 +22173,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 				resolvedParamType = CreateArrayType(mContext->mBfObjectType, 1);
 			}
 
-			if (addParams)
+			if ((addParams) && (resolvedParamType != NULL))
 			{
 				BfMethodParam methodParam;				
 				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 ((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> mStringCharPtrPool;
 	Array<int> mStringPoolRefs;	
+	HashSet<int> mUnreifiedStringPoolRefs;
 	
 	Array<BfIRBuilder*> mPrevIRBuilders; // Before extensions	
 	BfIRBuilder* mBfIRBuilder;	
@@ -1538,12 +1539,12 @@ public:
 	BfIRValue CreateStringCharPtr(const StringImpl& str, int stringId, bool define);
 	int GetStringPoolIdx(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);
 	StringT<128> TypeToString(BfType* resolvedType, 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 CurrentAddToConstHolder(BfIRValue& irVal);
 	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 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);
@@ -1771,12 +1773,12 @@ public:
 	BfMethodRefType* CreateMethodRefType(BfMethodInstance* methodInstance, bool mustAlreadyExist = false);
 	BfType* FixIntUnknown(BfType* type);
 	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);
 	BfTypeDef* ResolveGenericInstanceDef(BfGenericInstanceTypeRef* genericTypeRef, BfType** outType = NULL, 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);
 	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);

+ 157 - 56
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -164,7 +164,8 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
 	typeState.mResolveKind = BfTypeState::ResolveKind_BuildingGenericParams;
 	typeState.mTypeInstance = resolvedTypeRef->ToTypeInstance();
 	SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
-	
+	Array<BfTypeReference*> deferredResolveTypes;
+
 	BF_ASSERT(mCurMethodInstance == NULL);
 
 	auto genericTypeInst = resolvedTypeRef->ToGenericTypeInstance();
@@ -210,7 +211,7 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
 							genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var);
 					}
 
-					ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType());
+					ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType(), &deferredResolveTypes);
 
 					if (genericParamDef != NULL)
 					{
@@ -283,7 +284,7 @@ bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
 					genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var);
 			}
 
-			ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType());
+			ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType(), &deferredResolveTypes);
 			auto genericParamDef = genericParamInstance->GetGenericParamDef();
 			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 constraintTypeInst : genericParam->mInterfaceConstraints)
@@ -339,6 +343,13 @@ bool BfModule::ValidateGenericConstraints(BfTypeReference* typeRef, BfTypeInstan
 		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;		
 	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->mWantsIRIgnoreWrites = false;						
 						for (auto ownedTypes : typeModule->mOwnedTypeInstances)
+						{
 							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++;
 						if (typeModule->mBfIRBuilder != NULL)
 						{
@@ -1038,7 +1063,7 @@ void BfModule::PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType
 							typeModule->SetupIRBuilder(false);
 						}
 						else
-							typeModule->PrepareForIRWriting(resolvedTypeRef->ToTypeInstance());
+							typeModule->PrepareForIRWriting(resolvedTypeRef->ToTypeInstance());						
 					}
 					else
 					{
@@ -2002,7 +2027,7 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance*
 	for (auto& customAttribute : customAttributes->mAttributes)
 	{			
 		auto attrType = customAttribute.mType;
-		PopulateType(attrType, BfPopulateType_DataAndMethods);
+		mContext->mUnreifiedModule->PopulateType(attrType, BfPopulateType_DataAndMethods);
 		if (attrType->mDefineState < BfTypeDefineState_DefinedAndMethodsSlotted)
 			continue;
 
@@ -2331,7 +2356,7 @@ void BfModule::DoCEEmit(BfMethodInstance* methodInstance)
 	for (auto& customAttribute : customAttributes->mAttributes)
 	{
 		auto attrType = customAttribute.mType;
-		PopulateType(attrType, BfPopulateType_DataAndMethods);
+		mContext->mUnreifiedModule->PopulateType(attrType, BfPopulateType_DataAndMethods);
 		if (attrType->mDefineState < BfTypeDefineState_DefinedAndMethodsSlotted)
 			continue;
 
@@ -2599,8 +2624,10 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 	SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, typeInstance);
 	SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, 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);
 	typeState.mPopulateType = populateType;
@@ -2640,8 +2667,8 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 	
 	if (typeInstance->mIsFinishingType)
 	{
-		// This type already failed
-		return;
+		if (typeInstance->mTypeFailed)
+			return;
 	}
 
 	if (!typeInstance->mTypeFailed)
@@ -3006,7 +3033,10 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 			bool populateBase = !typeInstance->mTypeFailed;			
 			auto checkType = ResolveTypeRef(checkTypeRef, BfPopulateType_Declaration);
 			if ((checkType != NULL) && (!checkType->IsInterface()) && (populateBase))
+			{
+				SetAndRestoreValue<BfTypeInstance*> prevBaseType(mContext->mCurTypeState->mCurBaseType, checkType->ToTypeInstance());
 				PopulateType(checkType, BfPopulateType_Data);
+			}
 
 			if (typeInstance->mDefineState >= BfTypeDefineState_Defined)
 			{
@@ -3387,6 +3417,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 	
 	for (auto& validateEntry : deferredTypeValidateList)
 	{
+		SetAndRestoreValue<BfTypeReference*> prevAttributeTypeRef(typeState.mCurAttributeTypeRef, validateEntry.mTypeRef);
 		SetAndRestoreValue<bool> ignoreErrors(mIgnoreErrors, mIgnoreErrors | validateEntry.mIgnoreErrors);
 		ValidateGenericConstraints(validateEntry.mTypeRef, validateEntry.mGenericType, false);
 	}
@@ -3742,7 +3773,12 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 
 				if (populateChildType)
 				{
-					BF_ASSERT(!resolvedFieldType->IsDataIncomplete());
+					if (resolvedFieldType->IsFinishingType())
+					{
+						AssertErrorState();
+					}
+					else
+						BF_ASSERT(!resolvedFieldType->IsDataIncomplete());
 				}
 				else
 				{
@@ -4319,34 +4355,41 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 	
 	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)
@@ -4962,7 +5005,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
 
 	//
 	{
-		if (typeInstance->IsSpecializedType())
+		if ((typeInstance->IsSpecializedType()) || (typeInstance->IsUnspecializedTypeVariation()))
 			wantsOnDemandMethods = true;
 		else if ((mCompiler->mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude) &&
 			(!typeInstance->IsUnspecializedTypeVariation()))
@@ -6000,11 +6043,14 @@ BfArrayType* BfModule::CreateArrayType(BfType* resolvedType, int dimensions)
 	BF_ASSERT(!resolvedType->IsVar());
 	BF_ASSERT(!resolvedType->IsIntUnknown());
 
+	auto arrayTypeDef = mCompiler->GetArrayTypeDef(dimensions);
+	if (arrayTypeDef == NULL)
+		return NULL;
 	auto arrayType = mContext->mArrayTypePool.Get();
 	delete arrayType->mGenericTypeInfo;
 	arrayType->mGenericTypeInfo = new BfGenericTypeInfo();
 	arrayType->mContext = mContext;
-	arrayType->mTypeDef = mCompiler->GetArrayTypeDef(dimensions);
+	arrayType->mTypeDef = arrayTypeDef;
 	arrayType->mDimensions = dimensions;
 	arrayType->mGenericTypeInfo->mTypeGenericArguments.clear();
 	arrayType->mGenericTypeInfo->mTypeGenericArguments.push_back(resolvedType);
@@ -6450,19 +6496,16 @@ void BfModule::FixIntUnknown(BfTypedValue& lhs, BfTypedValue& rhs)
 	FixIntUnknown(rhs);
 }
 
-void BfModule::FixValueActualization(BfTypedValue& typedVal)
+void BfModule::FixValueActualization(BfTypedValue& typedVal, bool force)
 {
 	if (!typedVal.mValue.IsConst())
 		return;	
-	if (mBfIRBuilder->mIgnoreWrites)
+	if ((mBfIRBuilder->mIgnoreWrites) && (!force))
 		return;
 	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)
@@ -7928,7 +7971,7 @@ bool BfModule::ResolveTypeResult_Validate(BfTypeReference* typeRef, BfType* reso
 				if ((curGenericTypeInstance->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;
 				}
 
@@ -9714,7 +9757,14 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 				CheckUnspecializedGenericType(genericTypeInst, populateType);
 				resolvedEntry->mValue = genericTypeInst;
 				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);
 			}
 		}
@@ -9731,6 +9781,11 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		}
 		typeInst->mTypeDef = typeDef;
 
+		if (((resolveFlags & BfResolveTypeRefFlag_NoReify) != 0) && (mCompiler->mOptions.mCompileOnDemandKind != BfCompileOnDemandKind_AlwaysInclude))
+		{
+			typeInst->mIsReified = false;
+		}
+
 		if (typeInst->mTypeDef->mGenericParamDefs.size() != 0)
 		{
 			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);
-		if (elementType == NULL)
+		auto arrayTypeDef = mCompiler->GetArrayTypeDef(arrayTypeRef->mDimensions);
+		if ((elementType == NULL) || (arrayTypeDef == NULL))
 		{
 			mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
 			return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags);
 		}
-
+		
 		if ((arrayTypeRef->mDimensions == 1) && (arrayTypeRef->mParams.size() == 1))
 		{
 			intptr elementCount = -1;
@@ -9840,7 +9896,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		arrayType->mGenericTypeInfo = new BfGenericTypeInfo();
 		arrayType->mContext = mContext;
 		arrayType->mDimensions = arrayTypeRef->mDimensions;
-		arrayType->mTypeDef = mCompiler->GetArrayTypeDef(arrayType->mDimensions);
+		arrayType->mTypeDef = arrayTypeDef;
 		arrayType->mGenericTypeInfo->mTypeGenericArguments.push_back(elementType);
 		resolvedEntry->mValue = arrayType;
 
@@ -9962,15 +10018,16 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 			auto parentTypeInstance = outerTypeInstance;
 			if (parentTypeInstance->IsTypeAlias())
 				parentTypeInstance = (BfTypeInstance*)GetOuterType(parentTypeInstance)->ToTypeInstance();
+			genericTypeInst->mGenericTypeInfo->mMaxGenericDepth = BF_MAX(genericTypeInst->mGenericTypeInfo->mMaxGenericDepth, parentTypeInstance->mGenericTypeInfo->mMaxGenericDepth);
 			for (int i = 0; i < startDefGenericParamIdx; i++)
 			{
 				genericTypeInst->mGenericTypeInfo->mGenericParams.push_back(parentTypeInstance->mGenericTypeInfo->mGenericParams[i]->AddRef());
 				genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.push_back(parentTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i]);
 				auto typeGenericArg = genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[i];
 				genericTypeInst->mGenericTypeInfo->mIsUnspecialized |= typeGenericArg->IsGenericParam() || typeGenericArg->IsUnspecializedType();
+				
 			}			
-		}
-		
+		}		
 
 		int wantedGenericParams = genericParamCount - startDefGenericParamIdx;
 		int genericArgDiffCount = (int)genericArguments.size() - wantedGenericParams;
@@ -9989,14 +10046,28 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		for (auto genericArgRef : genericArguments)
 		{
 			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->mTypeGenericArgumentRefs.push_back(genericArgRef);
 
 			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);
 		populateModule->InitType(genericTypeInst, populateType);
 
@@ -10011,6 +10082,8 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		{
 			BF_ASSERT(BfResolvedTypeSet::Equals(genericTypeInst, typeRef, &lookupCtx));
 		}
+
+		BfLogSysM("Generic type %p typeHash: %8X\n", genericTypeInst, resolvedEntry->mHash);
 #endif
 
 		BF_ASSERT(BfResolvedTypeSet::Hash(genericTypeInst, &lookupCtx) == resolvedEntry->mHash);		
@@ -10145,7 +10218,14 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		CheckUnspecializedGenericType(genericTypeInst, populateType);
 
 		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);
 		return ResolveTypeResult(typeRef, genericTypeInst, populateType, resolveFlags);
 	}
@@ -10281,7 +10361,11 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		if ((mCurTypeInstance == NULL) || (!mCurTypeInstance->IsGenericTypeInstance()))
 			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;
 		BfTypeInstance* delegateType = NULL;
@@ -10328,7 +10412,8 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		Val128 hashContext;
 
 		BfTypeDef* typeDef = new BfTypeDef();
-		typeDef->mProject = baseDelegateType->mTypeDef->mProject;
+		if (baseDelegateType != NULL)
+			typeDef->mProject = baseDelegateType->mTypeDef->mProject;
 		typeDef->mSystem = mCompiler->mSystem;
 		typeDef->mName = mSystem->mEmptyAtom;
 		if (delegateTypeRef->mTypeToken->GetToken() == BfToken_Delegate)
@@ -10360,9 +10445,12 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		delegateInfo->mDirectAllocNodes.push_back(directTypeRef);		
 		if (typeDef->mIsDelegate)
 			directTypeRef->Init(delegateType);
+		else if (mCompiler->mFunctionTypeDef == NULL)
+			failed = true;
 		else
 			directTypeRef->Init(ResolveTypeDef(mCompiler->mFunctionTypeDef));
-		typeDef->mBaseTypes.push_back(directTypeRef);		
+		if (!failed)
+			typeDef->mBaseTypes.push_back(directTypeRef);		
 
 		directTypeRef = BfAstNode::ZeroedAlloc<BfDirectTypeReference>();
 		delegateInfo->mDirectAllocNodes.push_back(directTypeRef);
@@ -11013,7 +11101,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 				{
 					SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true);
 					auto constraintTypeInst = genericParamInst->mTypeConstraint->ToTypeInstance();
-					if ((constraintTypeInst != NULL) && (constraintTypeInst->mTypeDef == mCompiler->mEnumTypeDef))
+					if ((constraintTypeInst != NULL) && (constraintTypeInst->mTypeDef == mCompiler->mEnumTypeDef) && (explicitCast))
 					{
 						// Enum->int
 						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)
 					{
@@ -12780,6 +12868,19 @@ bool BfModule::TypeIsSubTypeOf(BfTypeInstance* srcType, BfTypeInstance* wantType
 
 	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
 		//  While handling 'var' resolution, we don't want to force a PopulateType reentry 
 		//  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);
 		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;
@@ -1803,7 +1847,7 @@ void BfPrinter::Visit(BfDeferStatement* deferStmt)
 
 	VisitChild(deferStmt->mDeferToken);
 	VisitChild(deferStmt->mColonToken);
-	VisitChild(deferStmt->mScopeToken);
+	VisitChild(deferStmt->mScopeName);
 
 	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)
 				{
+					mPassInstance->Warn(0, "Syntax deprecated", nextTokenNode);
+
 					MEMBER_SET(deferStmt, mOpenParen, nextTokenNode);
 					mVisitorPos.MoveNext();
 
@@ -9264,9 +9266,9 @@ bool BfReducer::ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayIm
 
 	bool isFunction = 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;
-	else if ((mCurTypeDecl->mTypeNode != NULL) && (mCurTypeDecl->mTypeNode->GetToken() == BfToken_Delegate))
+	else if ((mCurTypeDecl != NULL) && (mCurTypeDecl->mTypeNode != NULL) && (mCurTypeDecl->mTypeNode->GetToken() == BfToken_Delegate))
 		isDelegate = true;
 
 	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);
 
-			mModule->PopulateType(checkInnerType);
+			mModule->PopulateType(checkInnerType, checkInnerType->IsValueType() ? BfPopulateType_Data : BfPopulateType_Declaration);
 			if (checkInnerType->mSize > unionSize)
 				unionSize = checkInnerType->mSize;	
 
@@ -2194,7 +2194,7 @@ bool BfTypeInstance::WantsGCMarking()
 		return true; 
 	if ((IsEnum()) && (!IsPayloadEnum()))
 		return false;	
-	BF_ASSERT(mDefineState >= BfTypeDefineState_Defined);
+	BF_ASSERT((mDefineState >= BfTypeDefineState_Defined) || (mTypeFailed));
 	return mWantsGCMarking;
 }
 
@@ -2674,7 +2674,7 @@ size_t BfTypeVectorHash::operator()(const BfTypeVector& typeVec) const
 	size_t hash = typeVec.size();
 	BfResolvedTypeSet::LookupContext ctx;
 	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;
 }
 
@@ -2721,6 +2721,8 @@ BfResolvedTypeSet::~BfResolvedTypeSet()
 
 }
 
+#define HASH_MIX(origHashVal, newHashVal) ((((origHashVal) << 5) - (origHashVal)) ^ (newHashVal))
+
 #define HASH_VAL_PTR 1
 #define HASH_VAL_BOXED 2
 #define HASH_VAL_REF 3
@@ -2767,7 +2769,7 @@ BfVariant BfResolvedTypeSet::EvaluateToVariant(LookupContext* ctx, BfExpression*
 	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");
 
@@ -2787,13 +2789,13 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 	if (type->IsBoxed())
 	{
 		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;
 	}
 	else if (type->IsArray())
 	{
 		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;
 	}	
 	else if (type->IsDelegateFromTypeRef() || type->IsFunctionFromTypeRef())
@@ -2803,7 +2805,7 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 		
 		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];
 		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++)
 		{			
 			// 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;
 			int nameHash = (int)Hash64(paramName.c_str(), (int)paramName.length());
 			hashVal = ((hashVal ^ (nameHash)) << 5) - hashVal;
@@ -2852,7 +2854,7 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 				BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx];
 				
 				auto fieldType = fieldInstance->mResolvedType;
-				hashVal = ((hashVal ^ (Hash(fieldType, ctx))) << 5) - hashVal;
+				hashVal = ((hashVal ^ (Hash(fieldType, ctx, BfHashFlag_None, hashSeed))) << 5) - hashVal;
 				BfFieldDef* fieldDef = NULL;
                 if (tupleType->mTypeDef != NULL)
                     fieldDef = fieldInstance->GetFieldDef();
@@ -2873,8 +2875,8 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 		else if (type->IsGenericTypeInstance())
 		{
 			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;
 	}
@@ -2886,7 +2888,7 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 	else if (type->IsPointer())
 	{
 		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;
 	}
 	else if (type->IsGenericParam())
@@ -2897,30 +2899,30 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 	else if (type->IsRef())
 	{
 		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;
 	}	
 	else if (type->IsModifiedTypeType())
 	{
 		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;
 	}
 	else if (type->IsConcreteInterfaceType())
 	{
 		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;
 	}
 	else if (type->IsSizedArray())
 	{
 		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;
 		if (type->IsUnknownSizedArrayType())
 		{
 			auto unknownSizedArray = (BfUnknownSizedArrayType*)type;
-			int elemHash = Hash(unknownSizedArray->mElementCountSource, ctx);
+			int elemHash = Hash(unknownSizedArray->mElementCountSource, ctx, BfHashFlag_None, hashSeed);
 			hashVal = ((hashVal ^ elemHash) << 5) - hashVal;
 		}
 		else
@@ -2940,7 +2942,7 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 	{
 		BfConstExprValueType* constExprValueType = (BfConstExprValueType*)type;
 		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;
 	}
 	else
@@ -2950,21 +2952,29 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 	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))
 	{
-		HashGenericArguments(elementedTypeRef->mElementType, ctx, hashVal);
+		HashGenericArguments(elementedTypeRef->mElementType, ctx, hashVal, hashSeed);
 	}
 	else if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(typeRef))
 	{
-		HashGenericArguments(qualifiedTypeRef->mLeft, ctx, hashVal);
+		HashGenericArguments(qualifiedTypeRef->mLeft, ctx, hashVal, hashSeed);
 	}
 
 	if (auto genericTypeRef = BfNodeDynCast<BfGenericInstanceTypeRef>(typeRef))
 	{
 		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());
 }
 
-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;
 
@@ -2990,7 +3000,7 @@ int BfResolvedTypeSet::DirectHash(BfTypeReference* typeRef, LookupContext* ctx,
 		ctx->mFailed = true;
 		return 0;
 	}
-	return Hash(resolvedType, ctx);
+	return Hash(resolvedType, ctx, BfHashFlag_None, hashSeed);
 }
 
 BfTypeDef* BfResolvedTypeSet::FindRootCommonOuterType(BfTypeDef* outerType, LookupContext* ctx, BfTypeInstance*& outOuterTypeInstance)
@@ -3020,7 +3030,7 @@ BfTypeDef* BfResolvedTypeSet::FindRootCommonOuterType(BfTypeDef* outerType, Look
 	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) &&
 		((typeRef->IsNamedTypeReference()) || (BfNodeIsA<BfDirectTypeDefReference>(typeRef))))
@@ -3072,8 +3082,8 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 			auto curGenericTypeInst = (BfTypeInstance*)checkTypeInstance;
 			int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size();
 			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())
 	{
-		return DirectHash(typeRef, ctx, flags);
+		int hashVal = DirectHash(typeRef, ctx, flags, hashSeed);
+		hashSeed = 0;
+		return hashVal;
 	}
 	if (auto genericInstTypeRef = BfNodeDynCastExact<BfGenericInstanceTypeRef>(typeRef))
 	{
@@ -3124,7 +3136,9 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 						ctx->mFailed = true;
 						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;
 				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;
 	}
 	else if (auto tupleTypeRef = BfNodeDynCastExact<BfTupleTypeRef>(typeRef))
-	{	
+	{
 		int hashVal = HASH_VAL_TUPLE;
 
 		for (int fieldIdx = 0; fieldIdx < (int)tupleTypeRef->mFieldTypes.size(); 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;		
 			BfIdentifierNode* fieldName = NULL;
@@ -3197,7 +3211,7 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 	{
 		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 hashVal = (elemHash << 5) - elemHash;
 
@@ -3221,7 +3235,7 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 				BfTypedValue typedVal = constResolver.Resolve(sizeExpr, NULL, BfConstResolveFlag_ArrayInitSize);
 				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;
 					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;
 		}
 	}
 	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;
 	}
 	else if (auto nullableType = BfNodeDynCastExact<BfNullableTypeRef>(typeRef))
@@ -3294,8 +3308,8 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 		if (ctx->mRootTypeRef == typeRef)
 			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;
 	}	
 	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)
 				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;
 		}
 		else
@@ -3356,7 +3370,9 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 			ctx->mFailed = true;
 			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))
 	{
@@ -3379,26 +3395,26 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 		if (ctx->mRootTypeRef != retTypeTypeRef)
 		{
 			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;
 	}
 	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))
 	{
 		// 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))
 	{
 		int hashVal = HASH_DELEGATE;
 		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
 			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;
 			isFirstParam = true;
 		}
@@ -3508,7 +3524,9 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 			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))
 	{
@@ -3518,7 +3536,11 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 		{
 			result = EvaluateToVariant(ctx, constExprTypeRef->mConstExpr, resultType);			
 			if ((resultType != NULL) && (resultType->IsGenericParam()))
-				return Hash(resultType, ctx);
+			{
+				int hashVal = Hash(resultType, ctx, BfHashFlag_None, hashSeed);
+				hashSeed = 0;
+				return hashVal;
+			}
 		}
 
 		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;		
-		hashVal = ((hashVal ^ (Hash(resultType, ctx, BfHashFlag_AllowRef))) << 5) - hashVal;
+		hashVal = ((hashVal ^ (Hash(resultType, ctx, BfHashFlag_AllowRef, hashSeed))) << 5) - hashVal;		
 		return hashVal;
 	}
 	else if (auto dotTypeRef = BfNodeDynCastExact<BfDotTypeReference>(typeRef))	
@@ -3544,6 +3566,14 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
 	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
 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 HasTypeFailed() { return false; }
 	virtual bool IsDataIncomplete() { return mDefineState == BfTypeDefineState_Undefined; }
+	virtual bool IsFinishingType() { return false;  }
 	virtual bool IsIncomplete() { return mDefineState < BfTypeDefineState_Defined; }
 	virtual bool IsDeleting() { return ((mRebuildFlags & (BfTypeRebuildFlag_Deleted | BfTypeRebuildFlag_DeleteQueued)) != 0); }
 	virtual bool IsDeclared() { return mDefineState >= BfTypeDefineState_Declared; }
@@ -1774,6 +1775,7 @@ public:
 	bool mInitializedGenericParams;
 	bool mFinishedGenericParams;	
 	Array<BfProject*> mProjectsReferenced; // Generic methods that only refer to these projects don't need a specialized extension
+	int32 mMaxGenericDepth;
 
 public:
 	BfGenericTypeInfo()
@@ -1785,6 +1787,7 @@ public:
 		mValidatedGenericConstraints = false;
 		mInitializedGenericParams = false;
 		mFinishedGenericParams = false;
+		mMaxGenericDepth = -1;
 	}
 
 	~BfGenericTypeInfo();
@@ -1955,6 +1958,7 @@ public:
 	virtual bool IsReified() override { return mIsReified; }
 	virtual bool NeedsExplicitAlignment() override { return !IsSizeAligned() || mIsPacked; }	
 	virtual bool IsDataIncomplete() override { return ((mTypeIncomplete) || (mBaseTypeMayBeIncomplete)) && (!mNeedsMethodProcessing); }	
+	virtual bool IsFinishingType() override { return mIsFinishingType; }
 	virtual bool IsIncomplete() override { return (mTypeIncomplete) || (mBaseTypeMayBeIncomplete); }
 	virtual bool IsSplattable() override { BF_ASSERT((mInstSize >= 0) || (!IsComposite())); return mIsSplattable; }
 	virtual int GetSplatCount() override;
@@ -2525,10 +2529,12 @@ public:
 	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* 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, BfTypeReference* rhs, 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 "BfParser.h"
+#include "BeefySysLib/util/BeefPerf.h"
 
 USING_NS_BF;
 
@@ -421,14 +422,22 @@ void BfSourceClassifier::Visit(BfTokenNode* tokenNode)
 
 void BfSourceClassifier::Visit(BfInvocationExpression* invocationExpr)
 {
-	BfElementVisitor::Visit(invocationExpr);
+	//BfElementVisitor::Visit(invocationExpr);
+	Visit(invocationExpr->ToBase());
+
+	//BP_ZONE("BfSourceClassifier BfInvocationExpression");
 	
 	BfAstNode* target = invocationExpr->mTarget;
 	if (target == NULL)
 		return;
-
+	
+	VisitChild(invocationExpr->mOpenParen);
+	VisitChild(invocationExpr->mCloseParen);
+	VisitChild(invocationExpr->mGenericArgs);
+	
 	if (auto scopedTarget = BfNodeDynCast<BfScopedInvocationTarget>(target))
 	{
+		VisitChild(target);
 		target = scopedTarget->mTarget;
 		VisitChild(scopedTarget->mScopeName);
 	}
@@ -438,25 +447,33 @@ void BfSourceClassifier::Visit(BfInvocationExpression* invocationExpr)
 	{
 		VisitChild(qualifiedName->mLeft);
 		VisitChild(qualifiedName->mDot);
+		VisitChild(qualifiedName->mRight);
 		identifier = qualifiedName->mRight;		
 	}
 	else if ((identifier = BfNodeDynCast<BfIdentifierNode>(target)))
 	{
+		VisitChild(target);
 		// Leave as BfAttributedIdentifierNode if that's the case
-		identifier = target;
+		identifier = target;		
 	}
 	else if (auto qualifiedName = BfNodeDynCast<BfQualifiedNameNode>(target))
 	{
 		VisitChild(qualifiedName->mLeft);
 		VisitChild(qualifiedName->mDot);
+		VisitChild(qualifiedName->mRight);
 		identifier = qualifiedName->mRight;		
 	}
 	else if (auto memberRefExpr = BfNodeDynCast<BfMemberReferenceExpression>(target))
 	{
 		VisitChild(memberRefExpr->mTarget);
 		VisitChild(memberRefExpr->mDotToken);
+		VisitChild(memberRefExpr->mMemberName);
 		identifier = memberRefExpr->mMemberName;		
 	}
+	else
+	{
+		VisitChild(target);
+	}
 
 	if (identifier != NULL)
 	{
@@ -469,20 +486,25 @@ void BfSourceClassifier::Visit(BfInvocationExpression* invocationExpr)
 		if (identifier != NULL)
 			SetElementType(identifier, BfSourceElementType_Method);
 	}
+
+	for (auto& val : invocationExpr->mArguments)
+		VisitChild(val);
+	for (auto& val : invocationExpr->mCommas)
+		VisitChild(val);
 }
 
 void BfSourceClassifier::Visit(BfIndexerExpression* indexerExpr)
 {
-	BfElementVisitor::Visit(indexerExpr);
+	//BfElementVisitor::Visit(indexerExpr);
+	Visit(indexerExpr->ToBase());
 
 	VisitChild(indexerExpr->mTarget);
 	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);
 }
 
@@ -523,6 +545,8 @@ void BfSourceClassifier::Visit(BfMethodDeclaration* methodDeclaration)
 	if (!IsInterestedInMember(methodDeclaration))
 		return;
 
+	//BP_ZONE("BfSourceClassifier BfMethodDeclaration");
+
 	SetAndRestoreValue<BfAstNode*> prevMember(mCurMember, methodDeclaration);
 
 	BfElementVisitor::Visit(methodDeclaration);	

+ 9 - 11
IDEHelper/Compiler/BfStmtEvaluator.cpp

@@ -1654,7 +1654,7 @@ BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varD
 			if (isConst)
 			{
 				BfConstResolver constResolver(this);
-				initValue = constResolver.Resolve(varDecl->mInitializer, resolvedType, BfConstResolveFlag_RemapFromStringId);
+				initValue = constResolver.Resolve(varDecl->mInitializer, resolvedType, BfConstResolveFlag_ActualizeValues);
 				if (!initValue)							
 					initValue = GetDefaultTypedValue(resolvedType);
 			}
@@ -3934,15 +3934,7 @@ void BfModule::Visit(BfDeleteStatement* deleteStmt)
 		bool allowProtected = allowPrivate || TypeIsSubTypeOf(mCurTypeInstance, checkTypeInst);
 		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 (!CheckProtection(dtorMethodDef->mProtection, checkTypeInst->mTypeDef, allowProtected, allowPrivate))
@@ -6734,7 +6726,13 @@ void BfModule::Visit(BfDeferStatement* deferStmt)
 
 	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))

+ 28 - 6
IDEHelper/Compiler/BfSystem.cpp

@@ -833,12 +833,26 @@ int BfTypeDef::GetSelfGenericParamCount()
 
 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)
@@ -1810,7 +1824,7 @@ BfSystem::BfSystem()
 	if (gPerfManager == NULL)
 		gPerfManager = new PerfManager();
 	//gPerfManager->StartRecording();
-
+	
 	mAtomUpdateIdx = 0;
 	mAtomCreateIdx = 0;
 	mTypeMapVersion = 1;
@@ -2586,6 +2600,13 @@ void BfSystem::RemoveTypeDef(BfTypeDef* typeDef)
 	mTypeDefs.Remove(typeDef);	
 	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
 	//  mAtomUpdateIdx increment will trigger lookup changes in BfContext::VerifyTypeLookups
 	if (typeDef->mName != mEmptyAtom)
@@ -2797,6 +2818,7 @@ void BfSystem::InjectNewRevision(BfTypeDef* typeDef)
 	typeDef->mNextRevision = NULL;
 
 	typeDef->mDefState = BfTypeDef::DefState_Defined;	
+	typeDef->mForceUseNextRevision = false;
 
 	VerifyTypeDef(typeDef);
 }

+ 3 - 1
IDEHelper/Compiler/BfSystem.h

@@ -1006,6 +1006,7 @@ public:
 	bool mIsNextRevision;
 	bool mInDeleteQueue;
 	bool mHasEmitMembers;
+	bool mForceUseNextRevision;
 
 public:
 	BfTypeDef()
@@ -1048,6 +1049,7 @@ public:
 		mIsNextRevision = false;
 		mInDeleteQueue = false;
 		mHasEmitMembers = false;
+		mForceUseNextRevision = false;
 		mDupDetectedRevision = -1;
 		mNestDepth = 0;
 		mOuterType = NULL;
@@ -1500,7 +1502,7 @@ public:
 	Array<BfTypeOptions> mMergedTypeOptions;
 	int mUpdateCnt;
 	bool mWorkspaceConfigChanged;
-	Val128 mWorkspaceConfigHash;	
+	Val128 mWorkspaceConfigHash;
 
 	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)
 {
-	module->PopulateType(customAttribute->mType);
+	module->mContext->mUnreifiedModule->PopulateType(customAttribute->mType);
 	auto ceAttrAddr = CeMalloc(customAttribute->mType->mSize) - mMemory.mVals;	
 	BfIRValue ceAttrVal = module->mBfIRBuilder->CreateConstAggCE(module->mBfIRBuilder->MapType(customAttribute->mType, BfIRPopulateType_Identity), ceAttrAddr);
 	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)
-{	
+{
 	auto ceModule = mCeMachine->mCeModule;
 	CeFunction* ceFunction = startFunction;
 	returnType = startFunction->mMethodInstance->mReturnType;
@@ -5408,6 +5408,15 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
 					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;
 			}
 
@@ -6255,6 +6264,9 @@ CeMachine::~CeMachine()
 
 	auto _RemoveFunctionInfo = [&](CeFunctionInfo* functionInfo)
 	{
+		if (functionInfo->mMethodInstance != NULL)
+			functionInfo->mMethodInstance->mInCEMachine = false;
+
 		if (functionInfo->mCeFunction != NULL)
 		{
 			// 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"))
 		{
 			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);
 			int64 addr64 = stringAddr;
 			memcpy(ptr, &addr64, ceModule->mSystem->mPtrSize);
@@ -6932,10 +6957,9 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f
 		ceFunction->mCeMachine = this;
 		ceFunction->mIsVarReturn = methodInstance->mReturnType->IsVar();
 		ceFunction->mCeFunctionInfo = ceFunctionInfo;
-		ceFunction->mMethodInstance = methodInstance;
-
+		ceFunction->mMethodInstance = methodInstance;		
 		ceFunctionInfo->mMethodInstance = methodInstance;
-		ceFunctionInfo->mCeFunction = ceFunction;
+		ceFunctionInfo->mCeFunction = ceFunction;		
 		MapFunctionId(ceFunction);
 	}
 	

+ 1 - 0
IDEHelper/Debugger.h

@@ -120,6 +120,7 @@ enum DwEvalExpressionFlags : int16
 	DwEvalExpressionFlag_MemoryWatch = 0x80,
 	DwEvalExpressionFlag_Symbol = 0x100,
 	DwEvalExpressionFlag_StepIntoCalls = 0x200,	
+	DwEvalExpressionFlag_RawStr = 0x400
 };
 
 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()
 {
 	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()
@@ -105,65 +102,75 @@ void NetRequest::DoTransfer()
 // 		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;
 			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)
 	{

+ 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
 		{
 			ErrorA,
@@ -168,6 +183,13 @@ namespace Tests
 			Test.Assert(ca.mC == 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;");
 			Test.Assert(val == 99);
 

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

@@ -160,6 +160,32 @@ namespace Tests
 				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
 		{
@@ -226,6 +252,26 @@ namespace Tests
 			ClassE ce = scope .();
 			Test.Assert(ce.mD == 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]

+ 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]
 		public static void TestBasics()
 		{

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

@@ -239,6 +239,32 @@ namespace Tests
 				switch (methodIdx)
 				{
 				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 };
 
 					Test.Assert(methodInfo.Name == "StaticMethodA");
@@ -291,7 +317,7 @@ namespace Tests
 					let attrC = methodInfo.GetCustomAttribute<AttrCAttribute>().Get();
 					Test.Assert(attrC.mA == 71);
 					Test.Assert(attrC.mB == 72);
-				case 1:
+				case 5:
 					Test.Assert(methodInfo.Name == "StaticMethodB");
 
 					var fieldA = typeInfo.GetField("mA").Value;
@@ -337,33 +363,6 @@ namespace Tests
 					res.Dispose();
 					fieldSAV.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:
 					Test.FatalError(); // Shouldn't have any more
 				}
@@ -445,6 +444,8 @@ namespace Tests
 				switch (methodIdx)
 				{
 				case 0:
+					Test.Assert(methodInfo.Name == "__BfCtor");
+				case 1:
 					Test.Assert(methodInfo.Name == "GetA");
 
 					var result = methodInfo.Invoke(sa, 34).Get();
@@ -464,7 +465,7 @@ namespace Tests
 					result = methodInfo.Invoke(.Create(&sa), .Create(34));
 					Test.Assert(result.Get<int32>() == 1234);
 					result.Dispose();
-				case 1:
+				case 2:
 					Test.Assert(methodInfo.Name == "GetB");
 
 					var result = methodInfo.Invoke(sa, 34).Get();
@@ -489,16 +490,15 @@ namespace Tests
 					Test.Assert(sa.mB == 91);
 					result.Dispose();
 
-				case 2:
-					Test.Assert(methodInfo.Name == "MethodA0");
 				case 3:
-					Test.Assert(methodInfo.Name == "MethodA1");
+					Test.Assert(methodInfo.Name == "MethodA0");
 				case 4:
-					Test.Assert(methodInfo.Name == "__BfCtor");
+					Test.Assert(methodInfo.Name == "MethodA1");
 				case 5:
 					Test.Assert(methodInfo.Name == "__Equals");
 				case 6:
 					Test.Assert(methodInfo.Name == "__StrictEquals");
+				
 				default:
 					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);
 	}
 
+	if ((expressionFlags & DwEvalExpressionFlag_RawStr) != 0)
+	{
+		formatInfo.mRawString = true;
+	}
+
 	auto dbgModule = GetCallStackDbgModule(callStackIdx);
 	auto dbgSubprogram = GetCallStackSubprogram(callStackIdx);
 	DbgCompileUnit* dbgCompileUnit = NULL;