Преглед на файлове

Handle zero-sized enums (<= 1 member)

Brian Fiete преди 9 месеца
родител
ревизия
14a3dd8e7d

+ 183 - 103
IDE/src/ui/AutoComplete.bf

@@ -196,7 +196,6 @@ namespace IDE.ui
         {
             public AutoComplete mAutoComplete;
             public bool mIsInitted;
-            public int mIgnoreMove;
 			public bool mOwnsWindow;
 			public float mRightBoxAdjust;
 			public float mWantHeight;
@@ -237,7 +236,7 @@ namespace IDE.ui
 						return;
 				}
 
-                if ((mIgnoreMove == 0) && (mWidgetWindow != null) && (!mWidgetWindow.mHasClosed))
+                if ((mAutoComplete.mIgnoreMove == 0) && (mWidgetWindow != null) && (!mWidgetWindow.mHasClosed))
                     mAutoComplete.Close();
             }
 
@@ -345,7 +344,6 @@ namespace IDE.ui
 			public override void Update()
 			{
 				base.Update();
-				Debug.Assert((mIgnoreMove >= 0) && (mIgnoreMove <= 4));
 			}
         }
 
@@ -591,15 +589,11 @@ namespace IDE.ui
 
 					int windowHeight = (int)(mWantHeight + Math.Max(0, mDocHeight - GS!(32)));
 
-					mIgnoreMove++;
-					if (mAutoComplete.mInvokeWidget != null)
-						mAutoComplete.mInvokeWidget.mIgnoreMove++;
+					mAutoComplete.mIgnoreMove++;
 					mWidgetWindow.Resize(mWidgetWindow.mNormX, mWidgetWindow.mNormY, windowWidth, windowHeight);
 					mScrollContent.mWidth = mWidth;
 					//Resize(0, 0, mWidgetWindow.mClientWidth, mWidgetWindow.mClientHeight);
-					mIgnoreMove--;
-					if (mAutoComplete.mInvokeWidget != null)
-						mAutoComplete.mInvokeWidget.mIgnoreMove--;
+					mAutoComplete.mIgnoreMove--;
 					ResizeContent(-1, -1, mVertScrollbar != null);
 				}
 			}
@@ -653,7 +647,7 @@ namespace IDE.ui
 					entryWidget.mDocumentation = new:mAlloc String(documentation);
                 entryWidget.mIcon = icon;
 
-				entryWidget.SetMatches(matchIndices);
+				entryWidget.SetMatches(matchIndices ?? scope .());
 
                 UpdateEntry(entryWidget, mEntryList.Count);
                 mEntryList.Add(entryWidget);
@@ -860,6 +854,7 @@ namespace IDE.ui
             {
                 public String mText ~ delete _;
 				public String mDocumentation ~ delete _;
+				public int32 mArgMatchCount;
 
 				public int GetParamCount()
 				{
@@ -941,9 +936,9 @@ namespace IDE.ui
 				{
 					if (mOwnsWindow)
 					{
-						mIgnoreMove++;
+						mAutoComplete.mIgnoreMove++;
 						mAutoComplete.UpdateWindow(ref mWidgetWindow, this, mAutoComplete.mInvokeSrcPositions[0], (int32)extWidth, (int32)extHeight);
-						mIgnoreMove--;
+						mAutoComplete.mIgnoreMove--;
 					}
 					else
 					{
@@ -966,11 +961,15 @@ namespace IDE.ui
                     mSelectIdx = 0;
             }
 
-            public void SelectDirection(int32 dir)
+            public bool SelectDirection(int32 dir)
             {
                 int32 newSelection = mSelectIdx + dir;
                 if ((newSelection >= 0) && (newSelection < mEntryList.Count))
+				{
                     Select(newSelection);
+					return true;
+				}
+				return false;
             }
 
             public override void Update()
@@ -979,36 +978,15 @@ namespace IDE.ui
 
             }
 
-			void DrawInfo(Graphics g, out float extWidth, out float extHeight)
+			public void GetState(out int cursorSection)
 			{
-				var font = IDEApp.sApp.mCodeFont;
-
-				extWidth = 0;
-
-				float curX = GS!(8);
-				float curY = GS!(5);
-
-				if (mEntryList.Count > 1)
-				{
-					String numStr = scope String();
-					numStr.AppendF("{0}/{1}", mSelectIdx + 1, mEntryList.Count);
-					if (g != null)
-					{
-					    using (g.PushColor(gApp.mSettings.mUISettings.mColors.mAutoCompleteSubText))
-					        g.DrawString(numStr, curX, curY);
-					}
-					curX += font.GetWidth(numStr) + GS!(8);
-				}
+				cursorSection = -1;
 
 				var selectedEntry = mEntryList[mSelectIdx];
-				
-				float maxWidth = mWidth;
 
-				StringView paramName = .();
 				List<StringView> textSections = scope List<StringView>(selectedEntry.mText.Split('\x01'));
 
 				int cursorPos = mAutoComplete.mTargetEditWidget.Content.CursorTextPos;
-				int cursorSection = -1;
 				for (int sectionIdx = 0; sectionIdx < mAutoComplete.mInvokeSrcPositions.Count - 1; sectionIdx++)
 				{
 				    if (cursorPos > mAutoComplete.mInvokeSrcPositions[sectionIdx])
@@ -1085,6 +1063,37 @@ namespace IDE.ui
 						}
 					}
 				}
+			}
+
+			void DrawInfo(Graphics g, out float extWidth, out float extHeight)
+			{
+				var font = IDEApp.sApp.mCodeFont;
+
+				extWidth = 0;
+
+				float curX = GS!(8);
+				float curY = GS!(5);
+
+				if (mEntryList.Count > 1)
+				{
+					String numStr = scope String();
+					numStr.AppendF("{0}/{1}", mSelectIdx + 1, mEntryList.Count);
+					if (g != null)
+					{
+					    using (g.PushColor(gApp.mSettings.mUISettings.mColors.mAutoCompleteSubText))
+					        g.DrawString(numStr, curX, curY);
+					}
+					curX += font.GetWidth(numStr) + GS!(8);
+				}
+
+				var selectedEntry = mEntryList[mSelectIdx];
+				
+				float maxWidth = mWidth;
+
+				StringView paramName = .();
+				List<StringView> textSections = scope List<StringView>(selectedEntry.mText.Split('\x01'));
+
+				GetState(var cursorSection);
 
 				float paramX = 0;
 				for (int sectionIdx = 0; sectionIdx < textSections.Count; sectionIdx++)
@@ -1259,6 +1268,7 @@ namespace IDE.ui
 		public bool mIsDocumentationPass;
 		public bool mIsUserRequested;
 
+		public int mIgnoreMove;
 		bool mClosed;
 		bool mPopulating;
 		float mWantX;
@@ -1412,6 +1422,8 @@ namespace IDE.ui
 
         public void Update()
         {
+			Debug.Assert((mIgnoreMove >= 0) && (mIgnoreMove <= 4));
+
             if ((mInvokeWindow != null) && (!mInvokeWidget.mIsAboveText))
             {
                 int textIdx = mTargetEditWidget.Content.CursorTextPos;
@@ -1440,18 +1452,13 @@ namespace IDE.ui
 				int insertLine = line;
 				if ((insertLine != invokeLine) && ((insertLine - invokeLine) * gApp.mCodeFont.GetHeight() < GS!(40)))
                 {
-                    mInvokeWidget.mIgnoreMove++;
-                    if (mListWindow != null)
-                        mAutoCompleteListWidget.mIgnoreMove++;
+                    mIgnoreMove++;
                     mInvokeWidget.mIsAboveText = true;
 					mInvokeWidget.ResizeContent(false);
                     UpdateWindow(ref mInvokeWindow, mInvokeWidget, mInvokeSrcPositions[0], (int32)mInvokeWidget.mWidth, (int32)mInvokeWidget.mHeight);                    
                     if (mListWindow != null)
-                    {
                         UpdateWindow(ref mListWindow, mAutoCompleteListWidget, mInsertStartIdx, mListWindow.mWindowWidth, mListWindow.mWindowHeight);
-                        mAutoCompleteListWidget.mIgnoreMove--;
-                    }
-                    mInvokeWidget.mIgnoreMove--;
+                    mIgnoreMove--;
                 }
             }
 
@@ -1470,6 +1477,67 @@ namespace IDE.ui
 					Close();
 				}
 			}
+
+			/*if (mInvokeWidget != null)
+			{
+				var invokeEntry = mInvokeWidget.mEntryList[mInvokeWidget.mSelectIdx];
+
+				mInvokeWidget.GetState(var cursorSection);
+
+				if (mAutoCompleteListWidget != null)
+				{
+
+				}
+				else
+				{
+					if (cursorSection > 0)
+					{
+						int sectionStartIdx = -1;
+						int sectionEndIdx = -1;
+
+						int foundSectionIdx = 0;
+						for (var c in invokeEntry.mText.RawChars)
+						{
+							if (c == '\x01')
+							{
+								foundSectionIdx++;
+								if (foundSectionIdx == cursorSection)
+									sectionStartIdx = @c.Index;
+								else if (foundSectionIdx == cursorSection + 1)
+									sectionEndIdx = @c.Index;
+							}
+						}
+
+						if (sectionEndIdx != -1)
+						{
+							StringView argText = invokeEntry.mText.Substring(sectionStartIdx + 1, sectionEndIdx - sectionStartIdx - 1);
+							argText.Trim();
+							while (!argText.IsEmpty)
+							{
+								char8 c = argText[argText.Length - 1];
+								if ((c.IsLetterOrDigit) || (c == '_'))
+									break;
+								argText.RemoveFromEnd(1);
+							}
+
+							if (argText.StartsWith("tag "))
+							{
+								int spacePos = argText.IndexOf(' ', 4);
+								if (spacePos == -1)
+									spacePos = argText.Length;
+								StringView tagName = argText.Substring(4, spacePos - 4);
+
+								mInsertStartIdx = mInvokeSrcPositions[cursorSection - 1];
+								mInsertEndIdx = mInsertStartIdx;
+								mAutoCompleteListWidget = new AutoCompleteListWidget(this);
+								mAutoCompleteListWidget.AddEntry("value", scope $".{tagName}", DarkTheme.sDarkTheme.GetImage(.IconValue));
+								HandleAutoCompleteListWidget(1);
+								mAutoCompleteListWidget.mSelectIdx = 0;
+							}
+						}
+					}
+				}
+			}*/
         }
 
 		public void GetFilter(String outFilter)
@@ -1718,10 +1786,7 @@ namespace IDE.ui
 
 		public void SetIgnoreMove(bool ignoreMove)
 		{
-			if (mAutoCompleteListWidget != null)
-			    mAutoCompleteListWidget.mIgnoreMove += ignoreMove ? 1 : -1;
-			if (mInvokeWidget != null)
-			    mInvokeWidget.mIgnoreMove += ignoreMove ? 1 : -1;	
+			mIgnoreMove += ignoreMove ? 1 : -1;
 		}
 
 		// IDEHelper/third_party/FtsFuzzyMatch.h 
@@ -1996,61 +2061,7 @@ namespace IDE.ui
 
             if (mAutoCompleteListWidget != null)
             {
-                if (mAutoCompleteListWidget.mEntryList.Count > 0)
-                {
-					mAutoCompleteListWidget.mOwnsWindow = !IsInPanel();
-					mAutoCompleteListWidget.mAutoFocus = IsInPanel();
-					int32 windowWidth = (int32)mAutoCompleteListWidget.mMaxWidth;
-					if (mAutoCompleteListWidget.mRightBoxAdjust != 0)
-						windowWidth += (int32)mAutoCompleteListWidget.mRightBoxAdjust; // - GS!(16);
-					//windowWidth += (int32)mAutoCompleteListWidget.mDocWidth;
-					windowWidth += GS!(16);
-
-					int32 contentHeight = (int32)(visibleCount * mAutoCompleteListWidget.mItemSpacing);
-					int32 windowHeight = contentHeight + GS!(20);
-					int32 maxWindowHeight = GetMaxWindowHeight();
-					bool wantScrollbar = false;
-					if (windowHeight > maxWindowHeight)
-					{
-					    windowHeight = maxWindowHeight;
-					    wantScrollbar = true;
-					    windowWidth += GS!(12);
-					}
-					contentHeight += GS!(8);
-					mAutoCompleteListWidget.ResizeContent(windowWidth, contentHeight, wantScrollbar);
-					if ((mInsertStartIdx != -1) && (!IsInPanel()))
-					{
-						UpdateWindow(ref mListWindow, mAutoCompleteListWidget, mInsertStartIdx, windowWidth, windowHeight);
-						mAutoCompleteListWidget.mWantHeight = windowHeight;
-					}
-					mAutoCompleteListWidget.UpdateScrollbars();
-					mAutoCompleteListWidget.CenterSelection();
-					mAutoCompleteListWidget.UpdateWidth();
-                }
-                else
-                {
-					if ((mListWindow == null) || (mListWindow.mRootWidget != mAutoCompleteListWidget))
-                    {
-						if (IsInPanel())
-						{
-							gApp.mAutoCompletePanel.Unbind(this);
-							if (mInvokeWidget != null)
-							{
-								if (mInvokeWidget.mParent != null)
-									mInvokeWidget.RemoveSelf();
-								delete mInvokeWidget;
-								mInvokeWidget = null;
-							}
-						}
-						delete mAutoCompleteListWidget;
-					}
-                    if (mListWindow != null)
-                    {
-                        mListWindow.Close();
-                        mListWindow = null;
-                    }
-                    mAutoCompleteListWidget = null;
-                }
+				HandleAutoCompleteListWidget(visibleCount);
             }
 			gApp.mAutoCompletePanel.FinishBind();
             SetIgnoreMove(false);
@@ -2174,6 +2185,65 @@ namespace IDE.ui
 			//Debug.WriteLine("UpdateInfo {0} {1}", mInsertStartIdx, mInsertEndIdx);
 		}
 
+		public void HandleAutoCompleteListWidget(int visibleCount)
+		{
+			if (mAutoCompleteListWidget.mEntryList.Count > 0)
+			{
+				mAutoCompleteListWidget.mOwnsWindow = !IsInPanel();
+				mAutoCompleteListWidget.mAutoFocus = IsInPanel();
+				int32 windowWidth = (int32)mAutoCompleteListWidget.mMaxWidth;
+				if (mAutoCompleteListWidget.mRightBoxAdjust != 0)
+					windowWidth += (int32)mAutoCompleteListWidget.mRightBoxAdjust; // - GS!(16);
+				//windowWidth += (int32)mAutoCompleteListWidget.mDocWidth;
+				windowWidth += GS!(16);
+
+				int32 contentHeight = (int32)(visibleCount * mAutoCompleteListWidget.mItemSpacing);
+				int32 windowHeight = contentHeight + GS!(20);
+				int32 maxWindowHeight = GetMaxWindowHeight();
+				bool wantScrollbar = false;
+				if (windowHeight > maxWindowHeight)
+				{
+				    windowHeight = maxWindowHeight;
+				    wantScrollbar = true;
+				    windowWidth += GS!(12);
+				}
+				contentHeight += GS!(8);
+				mAutoCompleteListWidget.ResizeContent(windowWidth, contentHeight, wantScrollbar);
+				if ((mInsertStartIdx != -1) && (!IsInPanel()))
+				{
+					UpdateWindow(ref mListWindow, mAutoCompleteListWidget, mInsertStartIdx, windowWidth, windowHeight);
+					mAutoCompleteListWidget.mWantHeight = windowHeight;
+				}
+				mAutoCompleteListWidget.UpdateScrollbars();
+				mAutoCompleteListWidget.CenterSelection();
+				mAutoCompleteListWidget.UpdateWidth();
+			}
+			else
+			{
+				if ((mListWindow == null) || (mListWindow.mRootWidget != mAutoCompleteListWidget))
+			    {
+					if (IsInPanel())
+					{
+						gApp.mAutoCompletePanel.Unbind(this);
+						if (mInvokeWidget != null)
+						{
+							if (mInvokeWidget.mParent != null)
+								mInvokeWidget.RemoveSelf();
+							delete mInvokeWidget;
+							mInvokeWidget = null;
+						}
+					}
+					delete mAutoCompleteListWidget;
+				}
+			    if (mListWindow != null)
+			    {
+			        mListWindow.Close();
+			        mListWindow = null;
+			    }
+			    mAutoCompleteListWidget = null;
+			}
+		}
+
         public void SetInfo(String info, bool clearList = true, int32 textOffset = 0, bool changedAfterInfo = false)
         {
 			scope AutoBeefPerf("AutoComplete.SetInfo");
@@ -2196,7 +2266,7 @@ namespace IDE.ui
             {
                 if (mAutoCompleteListWidget != null)
                 {
-					mAutoCompleteListWidget.mIgnoreMove++;
+					mIgnoreMove++;
 					if (IsInPanel())
 					{
 						mAutoCompleteListWidget.RemoveSelf();
@@ -2210,6 +2280,7 @@ namespace IDE.ui
 					else
 						delete mAutoCompleteListWidget;
                     mAutoCompleteListWidget = null;
+					mIgnoreMove--;
                 }
             }
             if (mAutoCompleteListWidget == null)
@@ -2434,6 +2505,7 @@ namespace IDE.ui
 
 					var invokeEntry = new InvokeWidget.Entry();
 					invokeEntry.mText = new String(entryDisplay);
+					invokeEntry.mArgMatchCount = int32.Parse(entryInsert).GetValueOrDefault();
 					if (!documentation.IsEmpty)
 						invokeEntry.mDocumentation = new String(documentation);
 					mInvokeWidget.AddEntry(invokeEntry);                            
@@ -2846,6 +2918,14 @@ namespace IDE.ui
 			}
 		}
 
+		public void GetInsertText(String outStr)
+		{
+			if (mAutoCompleteListWidget != null)
+			{
+				var entry = mAutoCompleteListWidget.mEntryList[mAutoCompleteListWidget.mSelectIdx];
+				outStr.Append(entry.mEntryInsert ?? entry.mEntryDisplay);
+			}
+		}
 
         public void InsertSelection(char32 keyChar, String insertType = null, String insertStr = null)
         {

+ 5 - 0
IDEHelper/Compiler/BfAst.cpp

@@ -301,6 +301,11 @@ void BfStructuralVisitor::Visit(BfTupleTypeRef* typeRef)
 	Visit(typeRef->ToBase());
 }
 
+void BfStructuralVisitor::Visit(BfTagTypeRef* typeRef)
+{
+	Visit(typeRef->ToBase());
+}
+
 void BfStructuralVisitor::Visit(BfDelegateTypeRef* typeRef)
 {
 	Visit(typeRef->ToBase());

+ 11 - 0
IDEHelper/Compiler/BfAst.h

@@ -389,6 +389,7 @@ class BfVarRefTypeReference;
 class BfLetTypeReference;
 class BfGenericInstanceTypeRef;
 class BfTupleTypeRef;
+class BfTagTypeRef;
 class BfDelegateTypeRef;
 class BfExprModTypeRef;
 class BfCommentNode;
@@ -561,6 +562,7 @@ public:
 	virtual void Visit(BfArrayTypeRef* typeRef);
 	virtual void Visit(BfGenericInstanceTypeRef* typeRef);
 	virtual void Visit(BfTupleTypeRef* typeRef);
+	virtual void Visit(BfTagTypeRef* typeRef);
 	virtual void Visit(BfDelegateTypeRef* typeRef);
 	virtual void Visit(BfExprModTypeRef* declTypeRef);
 	virtual void Visit(BfPointerTypeRef* typeRef);
@@ -2667,6 +2669,15 @@ public:
 	}
 };	BF_AST_DECL(BfTupleTypeRef, BfElementedTypeRef);
 
+class BfTagTypeRef : public BfTypeReference
+{
+public:
+	BF_AST_TYPE(BfTagTypeRef, BfTypeReference);
+
+	BfIdentifierNode* mTagNode;
+	BfIdentifierNode* mNameNode;
+};	BF_AST_DECL(BfTagTypeRef, BfTypeReference);
+
 class BfDelegateTypeRef : public BfTypeReference
 {
 public:

+ 25 - 10
IDEHelper/Compiler/BfAutoComplete.cpp

@@ -797,12 +797,21 @@ void BfAutoComplete::AddField(BfTypeInstance* typeInst, BfFieldDef* fieldDef, Bf
 		{
 			mModule->PopulateType(typeInst);
 
-			String str;
-			str += mModule->TypeToString(fieldInstance->mResolvedType);
-			str += " ";
-			str += mModule->TypeToString(typeInst);
-			str += ".";
-			str += fieldDef->mName;
+			bool isTag = typeInst->IsEnum() && typeInst->IsOnDemand();
+
+			String str;			
+			if (!isTag)
+			{
+				if (!fieldInstance->GetFieldDef()->IsEnumCaseEntry())
+				{
+					str += mModule->TypeToString(fieldInstance->mResolvedType);
+					str += " ";
+				}
+				str += mModule->TypeToString(typeInst);
+				str += ".";
+				str += fieldDef->mName;
+			}
+
 			if (entryAdded->mDocumentation != NULL)
 			{
 				str += "\x04";
@@ -813,7 +822,9 @@ void BfAutoComplete::AddField(BfTypeInstance* typeInst, BfFieldDef* fieldDef, Bf
 				str += "\x05";
 				documentation->GetDocString(str);
 			}
-			entryAdded->mDocumentation = mAlloc.AllocString(str);
+
+			if (!str.IsEmpty())
+				entryAdded->mDocumentation = mAlloc.AllocString(str);
 		}
 
 		if ((mIsGetDefinition) && (mDefType == NULL))
@@ -1270,7 +1281,11 @@ void BfAutoComplete::AddEnumTypeMembers(BfTypeInstance* typeInst, const StringIm
 			AutoCompleteEntry entry(hasPayload ? "payloadEnum" : "value", fieldDef->mName);
 			if (auto entryAdded = AddEntry(entry, filter))
 			{
-				if (CheckDocumentation(entryAdded, fieldDef->GetFieldDeclaration()->mDocumentation))
+				auto fieldDecl = fieldDef->GetFieldDeclaration();
+				if (fieldDecl == NULL)
+					continue;
+
+				if (CheckDocumentation(entryAdded, fieldDecl->mDocumentation))
 				{
 				}
 
@@ -1278,8 +1293,8 @@ void BfAutoComplete::AddEnumTypeMembers(BfTypeInstance* typeInst, const StringIm
 				{
 					mDefType = typeInst->mTypeDef;
 					mDefField = fieldDef;
-					if (fieldDef->mFieldDeclaration != NULL)
-						SetDefinitionLocation(fieldDef->GetFieldDeclaration()->mNameNode);
+					if (fieldDecl != NULL)
+						SetDefinitionLocation(fieldDecl->mNameNode);
 				}
 			}
 		}

+ 4 - 0
IDEHelper/Compiler/BfAutoComplete.h

@@ -137,6 +137,8 @@ public:
 		BfTypeInstance* mTypeInstance;
 		BfTypeVector mGenericArguments;
 		BfMethodInstance* mCurMethodInstance;
+		bool mIsMatch;
+		int mArgMatchCount;
 
 		MethodMatchEntry()
 		{
@@ -144,6 +146,8 @@ public:
 			mPayloadEnumField = NULL;
 			mTypeInstance = NULL;
 			mCurMethodInstance = NULL;
+			mIsMatch = false;
+			mArgMatchCount = false;
 		}
 	};
 

+ 3 - 1
IDEHelper/Compiler/BfCompiler.cpp

@@ -8608,7 +8608,9 @@ void BfCompiler::GenerateAutocompleteInfo()
 					}
 				}
 
-				autoCompleteResultString += "invoke\t" + methodText + "\n";
+				autoCompleteResultString += "invoke\t" + methodText;
+				autoCompleteResultString += StrFormat("\t%d", methodEntry.mArgMatchCount);
+				autoCompleteResultString += "\n";
 
 				idx++;
 			}

+ 8 - 0
IDEHelper/Compiler/BfElementVisitor.cpp

@@ -447,6 +447,14 @@ void BfElementVisitor::Visit(BfTupleTypeRef* typeRef)
 	VisitChild(typeRef->mCloseParen);
 }
 
+void BfElementVisitor::Visit(BfTagTypeRef* typeRef)
+{
+	Visit(typeRef->ToBase());
+
+	VisitChild(typeRef->mTagNode);
+	VisitChild(typeRef->mNameNode);
+}
+
 void BfElementVisitor::Visit(BfExprModTypeRef* typeRef)
 {
 	Visit(typeRef->ToBase());

+ 1 - 0
IDEHelper/Compiler/BfElementVisitor.h

@@ -64,6 +64,7 @@ public:
 	virtual void Visit(BfArrayTypeRef* typeRef);
 	virtual void Visit(BfGenericInstanceTypeRef* typeRef);
 	virtual void Visit(BfTupleTypeRef* typeRef);
+	virtual void Visit(BfTagTypeRef* typeRef);
 	virtual void Visit(BfExprModTypeRef* typeRef);
 	virtual void Visit(BfDelegateTypeRef* typeRef);
 	virtual void Visit(BfPointerTypeRef* typeRef);

+ 10 - 4
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -1680,7 +1680,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
 	BP_ZONE("BfMethodMatcher::CheckMethod");
 
 	BackupMatchKind curMatchKind = BackupMatchKind_None;
-	bool hadMatch = false;
+	bool hadMatch = false;	
 
 	// Never consider overrides - they only get found at original method declaration
 	//  mBypassVirtual gets set when we are doing an explicit "base" call, or when we are a struct --
@@ -2599,12 +2599,16 @@ NoMatch:
 	}
 
 Done:
-	if ((autoComplete != NULL) && (autoComplete->mIsCapturingMethodMatchInfo) && (genericArgumentsSubstitute != NULL))
+	if ((autoComplete != NULL) && (autoComplete->mIsCapturingMethodMatchInfo))
 	{
 		auto methodMatchInfo = autoComplete->mMethodMatchInfo;
 		if (!methodMatchInfo->mInstanceList.IsEmpty())
-		{
-			methodMatchInfo->mInstanceList[methodMatchInfo->mInstanceList.size() - 1].mGenericArguments = *genericArgumentsSubstitute;
+		{			
+			auto& matchInstance = methodMatchInfo->mInstanceList[methodMatchInfo->mInstanceList.size() - 1];
+			matchInstance.mArgMatchCount = argMatchCount;
+			matchInstance.mIsMatch = hadMatch;
+			if (genericArgumentsSubstitute != NULL)
+				matchInstance.mGenericArguments = *genericArgumentsSubstitute;
 		}
 	}
 
@@ -5249,6 +5253,8 @@ BfTypedValue BfExprEvaluator::LoadField(BfAstNode* targetSrc, BfTypedValue targe
 		BF_ASSERT(fieldInstance->mConstIdx != -1);
 
 		auto foreignConst = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx);
+		if (resolvedFieldType->IsValuelessType())
+			return BfTypedValue(BfIRValue::sValueless, resolvedFieldType);
 		auto retVal = mModule->ConstantToCurrent(foreignConst, typeInstance->mConstHolder, resolvedFieldType);
 		return BfTypedValue(retVal, resolvedFieldType);
 	}

+ 7 - 2
IDEHelper/Compiler/BfIRBuilder.cpp

@@ -928,6 +928,10 @@ BfIRValue BfIRConstHolder::CreateConst(BfConstant* fromConst, BfIRConstHolder* f
 	{
 		return CreateConstArrayZero(fromConst->mInt32);
 	}
+	else if (fromConst->mTypeCode == BfTypeCode_None)
+	{
+		return CreateConst(fromConst->mTypeCode, 0);
+	}
 	else if ((IsInt(fromConst->mTypeCode)) || (fromConst->mTypeCode == BfTypeCode_Boolean) || (fromConst->mTypeCode == BfTypeCode_StringId))
 	{
 		return CreateConst(fromConst->mTypeCode, fromConst->mUInt64);
@@ -975,7 +979,7 @@ BfIRValue BfIRConstHolder::CreateConst(BfConstant* fromConst, BfIRConstHolder* f
 		box->mTarget = copiedTarget.mId;
 		box->mToType = fromBox->mToType;
 		copiedConst = (BfConstant*)box;
-	}
+	}	
 	else
 	{
 		BF_FATAL("not handled");
@@ -3283,7 +3287,8 @@ void BfIRBuilder::CreateDbgTypeDefinition(BfType* type)
 						if (fieldInstance->mConstIdx != -1)
 						{
 							constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx);
-							staticValue = mModule->ConstantToCurrent(constant, typeInstance->mConstHolder, resolvedFieldType);
+							if (!resolvedFieldType->IsValuelessType())
+								staticValue = mModule->ConstantToCurrent(constant, typeInstance->mConstHolder, resolvedFieldType);
 						}
 
 						if (fieldInstance->mResolvedType->IsComposite())

+ 6 - 3
IDEHelper/Compiler/BfModule.cpp

@@ -21841,10 +21841,10 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup,
 				mBfIRBuilder->SaveDebugLocation();
 				mBfIRBuilder->ClearDebugLocation();
 				BfIRValue fromBool;
-				if (!mCurTypeInstance->IsTypedPrimitive())
+				if ((!mCurTypeInstance->IsTypedPrimitive()) || (mCurTypeInstance->IsValuelessType()))
 				{
 					fromBool = GetDefaultValue(methodInstance->mReturnType);
-				}
+				}				
 				else
 				{
 					auto andResult = mBfIRBuilder->CreateAnd(mCurMethodState->mLocals[0]->mValue, mCurMethodState->mLocals[1]->mValue);
@@ -21872,7 +21872,10 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup,
 			mBfIRBuilder->ClearDebugLocation();
 			BfIRValue fromBool;
 			mBfIRBuilder->RestoreDebugLocation();
-			ret = mBfIRBuilder->CreateRet(GetThis().mValue);
+			if (!mCurTypeInstance->IsValuelessType())
+				ret = mBfIRBuilder->CreateRet(GetThis().mValue);
+			else
+				mBfIRBuilder->CreateRetVoid();
 			//ExtendLocalLifetimes(0);
 			EmitLifetimeEnds(&mCurMethodState->mHeadScope);
 

+ 23 - 1
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -3600,7 +3600,9 @@ void BfModule::DoPopulateType_FinishEnum(BfTypeInstance* typeInstance, bool unde
 		{
 			BfTypeCode typeCode;
 
-			if ((min >= -0x80) && (max <= 0x7F))
+			if ((min == 0) && (max == 0))
+				typeCode = BfTypeCode_None;
+			else if ((min >= -0x80) && (max <= 0x7F))
 				typeCode = BfTypeCode_Int8;
 			else if ((min >= 0) && (max <= 0xFF))
 				typeCode = BfTypeCode_UInt8;
@@ -12232,6 +12234,19 @@ BfType* BfModule::ResolveTypeRef_Ref(BfTypeReference* typeRef, BfPopulateType po
 
 		return ResolveTypeResult(typeRef, tupleType, populateType, resolveFlags);
 	}
+	else if (auto tagTypeRef = BfNodeDynCast<BfTagTypeRef>(typeRef))
+	{
+		auto baseType = (BfTypeInstance*)ResolveTypeDef(mContext->mCompiler->mEnumTypeDef, BfPopulateType_Identity);
+
+		BfTagType* tagType = new BfTagType();
+		tagType->Init(baseType->mTypeDef->mProject, baseType, tagTypeRef->mNameNode->ToString());		
+
+		resolvedEntry->mValue = tagType;
+		BF_ASSERT(BfResolvedTypeSet::Hash(tagType, &lookupCtx) == resolvedEntry->mHashCode);
+		populateModule->InitType(tagType, populateType);
+
+		return ResolveTypeResult(typeRef, tagType, populateType, resolveFlags);
+	}
 	else if (auto nullableTypeRef = BfNodeDynCast<BfNullableTypeRef>(typeRef))
 	{
 		BfTypeReference* elementTypeRef = nullableTypeRef->mElementType;
@@ -15781,6 +15796,13 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF
 		str += ")";
 		return;
 	}
+	else if ((resolvedType->IsOnDemand()) && (resolvedType->IsEnum()))
+	{
+		auto typeInst = resolvedType->ToTypeInstance();
+		str += "tag ";
+		str += typeInst->mTypeDef->mFields[0]->mName;
+		return;
+	}
 	else if (resolvedType->IsDelegateFromTypeRef() || resolvedType->IsFunctionFromTypeRef())
 	{
 		SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance);

+ 9 - 0
IDEHelper/Compiler/BfPrinter.cpp

@@ -1674,6 +1674,15 @@ void BfPrinter::Visit(BfTupleTypeRef* typeRef)
 	VisitChild(typeRef->mCloseParen);
 }
 
+void BfPrinter::Visit(BfTagTypeRef* typeRef)
+{
+	Visit((BfAstNode*)typeRef);
+
+	VisitChild(typeRef->mTagNode);
+	ExpectSpace();
+	VisitChild(typeRef->mNameNode);
+}
+
 void BfPrinter::Visit(BfDelegateTypeRef* typeRef)
 {
 	Visit((BfAstNode*)typeRef);

+ 1 - 0
IDEHelper/Compiler/BfPrinter.h

@@ -167,6 +167,7 @@ public:
 	virtual void Visit(BfArrayTypeRef* typeRef) override;
 	virtual void Visit(BfGenericInstanceTypeRef* typeRef) override;
 	virtual void Visit(BfTupleTypeRef * typeRef) override;
+	virtual void Visit(BfTagTypeRef* typeRef) override;
 	virtual void Visit(BfDelegateTypeRef* typeRef) override;
 	virtual void Visit(BfPointerTypeRef* typeRef) override;
 	virtual void Visit(BfNullableTypeRef* typeRef) override;

+ 27 - 7
IDEHelper/Compiler/BfReducer.cpp

@@ -937,7 +937,7 @@ bool BfReducer::IsTypeReference(BfAstNode* checkNode, BfToken successToken, int
 			// Ignore
 		}
 		else if ((checkNode->IsA<BfIdentifierNode>()) || (checkNode->IsA<BfMemberReferenceExpression>()))
-		{
+		{			
 			// Identifier is always allowed in tuple (parenDepth == 0), because it's potentially the field name
 			//  (successToken == BfToken_RParen) infers we are already checking inside parentheses, such as
 			//  when we see a potential cast expression
@@ -954,8 +954,15 @@ bool BfReducer::IsTypeReference(BfAstNode* checkNode, BfToken successToken, int
 				hadUnexpectedIdentifier = true;
 			}
 
-			hadIdentifier = true;
-			identifierExpected = false;
+// 			if (checkNode->Equals("tag"))
+// 			{
+// 				// Keep looking for tag name				
+// 			}
+// 			else
+			{
+				hadIdentifier = true;
+				identifierExpected = false;
+			}
 		}
 		else if (checkNode->IsA<BfBlock>())
 		{
@@ -5195,6 +5202,19 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF
 	BfTypeReference* typeRef = BfNodeDynCast<BfTypeReference>(firstNode);
 	if (typeRef == NULL)
 	{
+// 		if (identifierNode->Equals("tag"))
+// 		{
+// 			auto rightIdentifer = ExpectIdentifierAfter(identifierNode);
+// 			if (rightIdentifer != NULL)				
+// 			{
+// 				auto tagTypeRef = mAlloc->Alloc<BfTagTypeRef>();
+// 				ReplaceNode(identifierNode, tagTypeRef);
+// 				tagTypeRef->mTagNode = identifierNode;
+// 				MEMBER_SET(tagTypeRef, mNameNode, rightIdentifer);
+// 				return tagTypeRef;
+// 			}
+// 		}
+
 		typeRef = DoCreateNamedTypeRef(identifierNode);
 	}
 
@@ -5250,7 +5270,7 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF
 					{
 						auto rightIdentifer = ExpectIdentifierAfter(qualifiedTypeRef);
 						if (rightIdentifer == NULL)
-							return qualifiedTypeRef;
+							return qualifiedTypeRef;						
 
 						auto namedTypeRef = mAlloc->Alloc<BfNamedTypeReference>();
 						namedTypeRef->mNameNode = rightIdentifer;
@@ -7346,7 +7366,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept
 			if (openToken == NULL)
 				return indexerDeclaration;
 			MEMBER_SET(indexerDeclaration, mOpenBracket, openToken);
-			auto endToken = ParseMethodParams(indexerDeclaration, &params, &commas, BfToken_RBracket, true);
+			auto endToken = ParseMethodParams(indexerDeclaration, &params, &commas, BfToken_RBracket, false);
 			if (endToken == NULL)
 				return indexerDeclaration;
 			MEMBER_SET(indexerDeclaration, mCloseBracket, endToken);
@@ -7780,7 +7800,7 @@ BfLambdaBindExpression* BfReducer::CreateLambdaBindExpression(BfAstNode* allocNo
 		if (auto tokenNode = BfNodeDynCast<BfTokenNode>(nextNode))
 			isRParen = tokenNode->GetToken() == BfToken_RParen;
 		if (!isRParen)
-		{
+		{			
 			auto nameIdentifier = ExpectIdentifierAfter(lambdaBindExpr, "parameter name");
 			if (nameIdentifier == NULL)
 				return lambdaBindExpr;
@@ -10028,7 +10048,7 @@ bool BfReducer::ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayIm
 		}
 	}
 
-	methodDeclaration->mCloseParen = ParseMethodParams(methodDeclaration, params, commas, BfToken_RParen, true);
+	methodDeclaration->mCloseParen = ParseMethodParams(methodDeclaration, params, commas, BfToken_RParen, false);
 
 	// RParen
 	if (methodDeclaration->mCloseParen == NULL)

+ 101 - 0
IDEHelper/Compiler/BfResolvedTypeUtils.cpp

@@ -2987,6 +2987,79 @@ void BfTupleType::Finish()
 
 //////////////////////////////////////////////////////////////////////////
 
+BfTagType::BfTagType()
+{
+	mCreatedTypeDef = false;
+	mSource = NULL;
+	mTypeDef = NULL;	
+}
+
+BfTagType::~BfTagType()
+{
+	mMethodInstanceGroups.Clear();
+	if (mCreatedTypeDef)
+	{
+		delete mTypeDef;
+		mTypeDef = NULL;
+	}
+	delete mSource;
+}
+
+void BfTagType::Init(BfProject* bfProject, BfTypeInstance* valueTypeInstance, const StringImpl& name)
+{
+	auto srcTypeDef = valueTypeInstance->mTypeDef;
+	auto system = valueTypeInstance->mModule->mSystem;
+
+	if (mTypeDef == NULL)
+		mTypeDef = new BfTypeDef();
+	for (auto field : mTypeDef->mFields)
+		delete field;
+	mTypeDef->mFields.Clear();
+	mTypeDef->mSystem = system;
+	mTypeDef->mProject = bfProject;
+	mTypeDef->mTypeCode = srcTypeDef->mTypeCode;
+	mTypeDef->mName = system->mEmptyAtom;
+	mTypeDef->mSystem = system;
+
+	mTypeDef->mHash = srcTypeDef->mHash;
+	mTypeDef->mSignatureHash = srcTypeDef->mSignatureHash;
+	mTypeDef->mTypeCode = BfTypeCode_Enum;
+
+	mCreatedTypeDef = true;
+
+	auto field = BfDefBuilder::AddField(mTypeDef, NULL, name);
+	field->mIsStatic = true;
+	field->mIsConst = true;
+}
+
+void BfTagType::Dispose()
+{
+	if (mCreatedTypeDef)
+	{
+		delete mTypeDef;
+		mTypeDef = NULL;
+		mCreatedTypeDef = false;
+	}
+	BfTypeInstance::Dispose();
+}
+
+void BfTagType::Finish()
+{
+	BF_ASSERT(!mTypeFailed);
+
+	auto bfSystem = mTypeDef->mSystem;
+	mSource = new BfSource(bfSystem);
+	mTypeDef->mSource = mSource;
+	mTypeDef->mSource->mRefCount++;
+
+	BfDefBuilder bfDefBuilder(bfSystem);
+	bfDefBuilder.mCurTypeDef = mTypeDef;
+	bfDefBuilder.mCurDeclaringTypeDef = mTypeDef;
+	bfDefBuilder.FinishTypeDef(true);
+}
+
+//////////////////////////////////////////////////////////////////////////
+
 BfBoxedType::~BfBoxedType()
 {
 	//if ((mTypeDef != NULL) && (mTypeDef->mEmitParent != NULL))
@@ -3132,6 +3205,7 @@ BfResolvedTypeSet::~BfResolvedTypeSet()
 #define HASH_CONSTEXPR 12
 #define HASH_GLOBAL 13
 #define HASH_DOTDOTDOT 14
+#define HASH_TAG 15
 
 BfVariant BfResolvedTypeSet::EvaluateToVariant(LookupContext* ctx, BfExpression* expr, BfType*& outType)
 {
@@ -3234,6 +3308,13 @@ int BfResolvedTypeSet::DoHash(BfType* type, LookupContext* ctx, bool allowRef, i
 
 		return hashVal;
 	}
+	else if ((type->IsEnum()) && (type->IsOnDemand()))
+	{
+		BfTypeInstance* typeInstance = type->ToTypeInstance();
+		auto fieldName = typeInstance->mTypeDef->mFields[0]->mName;		
+		int nameHash = (int)Hash64(fieldName.c_str(), (int)fieldName.length());
+		return nameHash ^ HASH_TAG;
+	}
 	else if (type->IsTypeInstance())
 	{
 		BfTypeInstance* typeInst = (BfTypeInstance*)type;
@@ -4156,6 +4237,17 @@ int BfResolvedTypeSet::DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHa
 		ctx->mFailed = true;
 		return 0;
 	}
+	else if (auto tagTypeRef = BfNodeDynCastExact<BfTagTypeRef>(typeRef))
+	{
+		int nameHash = 0;
+		if (tagTypeRef->mNameNode != NULL)
+		{
+			auto fieldName = tagTypeRef->mNameNode;
+			const char* nameStr = fieldName->GetSourceData()->mSrc + fieldName->GetSrcStart();
+			nameHash = (int)Hash64(nameStr, fieldName->GetSrcLength());
+		}
+		return nameHash ^ HASH_TAG;
+	}
 	else
 	{
 		BF_FATAL("Not handled");
@@ -4839,6 +4931,15 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfTypeReference* rhs, LookupContext*
 
 		return true;
 	}
+	else if ((lhs->IsEnum()) && (lhs->IsOnDemand()))
+	{
+		BfTypeInstance* typeInstance = lhs->ToTypeInstance();
+		auto fieldName = typeInstance->mTypeDef->mFields[0]->mName;		
+		auto tagTypeRef = BfNodeDynCastExact<BfTagTypeRef>(rhs);
+		if (tagTypeRef == NULL)
+			return false;
+		return tagTypeRef->mNameNode->Equals(fieldName);
+	}
 	else if (lhs->IsTypeInstance())
 	{
 		BfTypeInstance* lhsInst = (BfTypeInstance*) lhs;

+ 18 - 0
IDEHelper/Compiler/BfResolvedTypeUtils.h

@@ -2401,6 +2401,24 @@ public:
 	virtual int GetGenericDepth() override { return mGenericDepth; }
 };
 
+class BfTagType : public BfTypeInstance
+{
+public:
+	bool mCreatedTypeDef;
+	String mNameAdd;
+	BfSource* mSource;	
+
+public:
+	BfTagType();
+	~BfTagType();
+
+	void Init(BfProject* bfProject, BfTypeInstance* valueTypeInstance, const StringImpl& name);
+	virtual void Dispose() override;	
+	void Finish();
+
+	virtual bool IsOnDemand() override { return true; }
+};
+
 class BfConcreteInterfaceType : public BfType
 {
 public:

+ 11 - 0
IDEHelper/Compiler/BfSourceClassifier.cpp

@@ -329,6 +329,17 @@ void BfSourceClassifier::Visit(BfNamedTypeReference* typeRef)
 	}
 }
 
+void BfSourceClassifier::Visit(BfTagTypeRef* typeRef)
+{
+	Visit((BfAstNode*)typeRef);
+
+	VisitChild(typeRef->mTagNode);
+	SetElementType(typeRef->mTagNode, BfSourceElementType_Keyword);
+
+	VisitChild(typeRef->mNameNode);
+	SetElementType(typeRef->mNameNode, BfSourceElementType_Type);
+}
+
 void BfSourceClassifier::Visit(BfQualifiedTypeReference* qualifiedType)
 {
 	Visit((BfAstNode*)qualifiedType);

+ 1 - 0
IDEHelper/Compiler/BfSourceClassifier.h

@@ -113,6 +113,7 @@ public:
 	virtual void Visit(BfArrayTypeRef* arrayType) override;
 	virtual void Visit(BfPointerTypeRef* pointerType) override;
 	virtual void Visit(BfNamedTypeReference* typeRef) override;
+	virtual void Visit(BfTagTypeRef* typeRef) override;
 	virtual void Visit(BfGenericInstanceTypeRef* typeRef) override;
 	virtual void Visit(BfLocalMethodDeclaration * methodDecl) override;
 	virtual void Visit(BfLiteralExpression* literalExpr) override;

+ 6 - 0
IDEHelper/Compiler/BfSystem.cpp

@@ -427,6 +427,12 @@ void BfParameterDef::SetName(BfAstNode* nameNode)
 
 //////////////////////////////////////////////////////////////////////////
 
+bool BfFieldDef::IsEnumCaseEntry()
+{
+	return ((mFieldDeclaration != NULL) && (BfNodeIsA<BfEnumEntryDeclaration>(mFieldDeclaration))) ||
+		((mFieldDeclaration == NULL) && (mIsConst) && (mDeclaringType->mTypeCode == BfTypeCode_Enum));
+}
+
 bool BfPropertyDef::IsVirtual()
 {
 	if (((BfPropertyDeclaration*)mFieldDeclaration)->mVirtualSpecifier)

+ 1 - 4
IDEHelper/Compiler/BfSystem.h

@@ -655,10 +655,7 @@ public:
 		return (mName[0] >= '0') && (mName[0] <= '9');
 	}
 
-	bool IsEnumCaseEntry()
-	{
-		return (mFieldDeclaration != NULL) && (BfNodeIsA<BfEnumEntryDeclaration>(mFieldDeclaration));
-	}
+	bool IsEnumCaseEntry();
 
 	bool IsNonConstStatic()
 	{