Quellcode durchsuchen

Inline anonymous type declarations

Brian Fiete vor 6 Monaten
Ursprung
Commit
958fc30310

+ 19 - 2
IDEHelper/Compiler/BfAst.cpp

@@ -236,6 +236,11 @@ void BfStructuralVisitor::Visit(BfTypeReference* typeRef)
 	Visit(typeRef->ToBase());
 }
 
+void BfStructuralVisitor::Visit(BfInlineTypeReference* typeRef)
+{
+	Visit(typeRef->ToBase());
+}
+
 void BfStructuralVisitor::Visit(BfNamedTypeReference* typeRef)
 {
 	Visit(typeRef->ToBase());
@@ -1233,14 +1238,21 @@ void BfBlock::SetSize(int wantSize)
 
 //////////////////////////////////////////////////////////////////////////
 
+bool BfTypeDeclaration::IsAnonymous()
+{
+	return (mAnonymousName != NULL);
+}
+
+//////////////////////////////////////////////////////////////////////////
+
 bool BfTypeReference::IsNamedTypeReference()
 {
-	return IsA<BfNamedTypeReference>() || IsA<BfDirectStrTypeReference>();
+	return IsA<BfNamedTypeReference>() || IsA<BfDirectStrTypeReference>() || IsA<BfInlineTypeReference>();
 }
 
 bool BfTypeReference::IsTypeDefTypeReference()
 {
-	return IsA<BfNamedTypeReference>() || IsA<BfDirectStrTypeReference>() || IsA<BfDirectTypeDefReference>();
+	return IsA<BfNamedTypeReference>() || IsA<BfDirectStrTypeReference>() || IsA<BfInlineTypeReference>() || IsA<BfDirectTypeDefReference>();
 }
 
 String BfTypeReference::ToCleanAttributeString()
@@ -1657,6 +1669,11 @@ bool Beefy::BfTokenIsKeyword(BfToken token)
 	return (token >= BfToken_Abstract) && (token <= BfToken_Yield);
 }
 
+bool Beefy::BfTokenIsTypeDecl(BfToken token)
+{
+	return (token == BfToken_Struct) || (token == BfToken_Class) || (token == BfToken_Interface) || (token == BfToken_Enum);
+}
+
 BfBinaryOp Beefy::BfAssignOpToBinaryOp(BfAssignmentOp assignmentOp)
 {
 	switch (assignmentOp)

+ 17 - 0
IDEHelper/Compiler/BfAst.h

@@ -381,6 +381,7 @@ class BfReturnStatement;
 class BfYieldStatement;
 class BfUnaryOperatorExpression;
 class BfBinaryOperatorExpression;
+class BfInlineTypeReference;
 class BfArrayTypeRef;
 class BfPointerTypeRef;
 class BfDotTypeReference;
@@ -549,6 +550,7 @@ public:
 	virtual void Visit(BfInitializerExpression* collectionInitExpr);
 	virtual void Visit(BfCollectionInitializerExpression* collectionInitExpr);
 	virtual void Visit(BfTypeReference* typeRef);
+	virtual void Visit(BfInlineTypeReference* typeRef);
 	virtual void Visit(BfNamedTypeReference* typeRef);
 	virtual void Visit(BfQualifiedTypeReference* qualifiedType);
 	virtual void Visit(BfDotTypeReference* typeRef);
@@ -2147,6 +2149,7 @@ public:
 	ASTREF(BfTokenNode*) mCtorCloseParen;
 	BfSizedArray<ASTREF(BfExpression*)> mArguments;
 	BfSizedArray<ASTREF(BfTokenNode*)> mCommas;
+	bool mIsMultiUse; // For anonymous types and also another use like a field decl
 
 	ASTREF(BfAttributeDirective*) mNextAttribute;
 
@@ -2442,10 +2445,15 @@ public:
 	BfGenericParamsDeclaration* mGenericParams;
 	BfGenericConstraintsDeclaration* mGenericConstraintsDeclaration;
 	bool mIgnoreDeclaration;
+	char* mAnonymousName;
 
 	BfTokenNode* mColonToken;
 	BfSizedArray<ASTREF(BfTypeReference*)> mBaseClasses;
 	BfSizedArray<ASTREF(BfAstNode*)> mBaseClassCommas;
+	BfSizedArray<BfTypeDeclaration*> mAnonymousTypes;
+	
+	bool IsAnonymous();	
+
 };	BF_AST_DECL(BfTypeDeclaration, BfAstNode);
 
 class BfTypeAliasDeclaration : public BfTypeDeclaration
@@ -2468,6 +2476,14 @@ public:
 	String ToCleanAttributeString();
 };	BF_AST_DECL(BfTypeReference, BfAstNode);
 
+class BfInlineTypeReference : public BfTypeReference
+{
+public:
+	BF_AST_TYPE(BfInlineTypeReference, BfTypeReference);
+	
+	BfTypeDeclaration* mTypeDeclaration;
+};	BF_AST_DECL(BfInlineTypeReference, BfTypeReference);
+
 class BfDirectTypeReference : public BfTypeReference
 {
 public:
@@ -3568,6 +3584,7 @@ public:
 
 const char* BfTokenToString(BfToken token);
 bool BfTokenIsKeyword(BfToken token);
+bool BfTokenIsTypeDecl(BfToken token);
 BfBinaryOp BfAssignOpToBinaryOp(BfAssignmentOp assignmentOp);
 BfBinaryOp BfGetOppositeBinaryOp(BfBinaryOp origOp);
 BfBinaryOp BfGetFlippedBinaryOp(BfBinaryOp origOp);

+ 1 - 0
IDEHelper/Compiler/BfAutoComplete.cpp

@@ -223,6 +223,7 @@ BfAutoComplete::BfAutoComplete(BfResolveType resolveType, bool doFuzzyAutoComple
 BfAutoComplete::~BfAutoComplete()
 {
 	Clear();
+	RemoveMethodMatchInfo();
 }
 
 void BfAutoComplete::SetModule(BfModule* module)

+ 27 - 11
IDEHelper/Compiler/BfDefBuilder.cpp

@@ -795,10 +795,16 @@ void BfDefBuilder::Visit(BfMethodDeclaration* methodDeclaration)
 	}
 }
 
-void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef* methodDef)
+void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef* methodDef, bool checkReturnType)
 {
-	while (attributes != NULL)
+	if (checkReturnType)
 	{
+		if (auto inlineTypeRef = BfNodeDynCast<BfInlineTypeReference>(methodDef->mReturnTypeRef))
+			ParseAttributes(inlineTypeRef->mTypeDeclaration->mAttributes, methodDef, false);
+	}
+
+	while (attributes != NULL)
+	{		
 		if (attributes->mAttributeTypeRef != NULL)
 		{
 			auto typeRefName = attributes->mAttributeTypeRef->ToCleanAttributeString();
@@ -1434,13 +1440,11 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 	}
 
 	BF_ASSERT(typeDeclaration->GetSourceData() == mCurSource->mSourceData);
-
-	if ((typeDeclaration->mTypeNode != NULL) && (typeDeclaration->mNameNode == NULL))
-		return;
-
+	
     /*if (typeDeclaration->mNameNode != NULL)
         OutputDebugStrF("Decl: %s\n", typeDeclaration->mNameNode->ToString().c_str());*/
 
+	bool isAnonymous = typeDeclaration->IsAnonymous();
 	bool isAutoCompleteTempType = false;
 	if (mResolvePassData != NULL)
 	{
@@ -1511,10 +1515,17 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 	}
 	if (typeDeclaration->mNameNode == NULL)
 	{
-		// Global
-		mCurTypeDef->mName = mSystem->mGlobalsAtom;
-		mCurTypeDef->mName->Ref();
-		BF_ASSERT(mCurTypeDef->mSystem != NULL);
+		if (typeDeclaration->mStaticSpecifier != NULL)
+		{
+			// Global
+			mCurTypeDef->mName = mSystem->mGlobalsAtom;
+			mCurTypeDef->mName->Ref();
+			BF_ASSERT(mCurTypeDef->mSystem != NULL);
+		}
+		else
+		{			
+			mCurTypeDef->mName = mSystem->GetAtom(typeDeclaration->mAnonymousName);
+		}
 	}
 	else
 	{
@@ -1527,7 +1538,7 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 
 	BfLogSys(mCurSource->mSystem, "DefBuilder %p %p TypeDecl:%s\n", mCurTypeDef, mCurSource, mCurTypeDef->mName->ToString().mPtr);
 
-	mCurTypeDef->mProtection = (outerTypeDef == NULL) ? BfProtection_Public : BfProtection_Private;
+	mCurTypeDef->mProtection = ((outerTypeDef == NULL) || (isAnonymous)) ? BfProtection_Public : BfProtection_Private;
 	if (typeDeclaration->mProtectionSpecifier != NULL)
 	{
 		if ((outerTypeDef == NULL) &&
@@ -1956,6 +1967,11 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration)
 		}
 	}
 
+	for (auto& anonTypeDecl : typeDeclaration->mAnonymousTypes)
+	{
+		VisitChildNoRef(anonTypeDecl);
+	}
+
 	FinishTypeDef(mCurTypeDef->mTypeCode == BfTypeCode_Enum);
 
 	// Map methods into the correct index from previous revision

+ 1 - 1
IDEHelper/Compiler/BfDefBuilder.h

@@ -56,7 +56,7 @@ public:
 	static void AddParam(BfMethodDef* methodDef, BfTypeReference* typeRef, const StringImpl& paramName);
 	BfTypeDef* ComparePrevTypeDef(BfTypeDef* prevTypeDef, BfTypeDef* checkTypeDef);
 	void FinishTypeDef(bool wantsToString);
-	void ParseAttributes(BfAttributeDirective* attributes, BfMethodDef* methodDef);
+	void ParseAttributes(BfAttributeDirective* attributes, BfMethodDef* methodDef, bool checkReturnType = true);
 	void ParseAttributes(BfAttributeDirective* attributes, BfTypeDef* typeDef);
 	BfMethodDef* CreateMethodDef(BfMethodDeclaration* methodDecl, BfMethodDef* outerMethodDef = NULL);
 	BfError* Fail(const StringImpl& errorStr, BfAstNode* refNode);

+ 7 - 0
IDEHelper/Compiler/BfElementVisitor.cpp

@@ -325,6 +325,13 @@ void BfElementVisitor::Visit(BfTypeReference* typeRef)
 	Visit(typeRef->ToBase());
 }
 
+void BfElementVisitor::Visit(BfInlineTypeReference* typeRef)
+{
+	Visit(typeRef->ToBase());
+
+	VisitChild(typeRef->mTypeDeclaration);
+}
+
 void BfElementVisitor::Visit(BfNamedTypeReference* typeRef)
 {
 	Visit(typeRef->ToBase());

+ 1 - 0
IDEHelper/Compiler/BfElementVisitor.h

@@ -51,6 +51,7 @@ public:
 	virtual void Visit(BfInitializerExpression* initExpr);
 	virtual void Visit(BfCollectionInitializerExpression* collectionInitExpr);
 	virtual void Visit(BfTypeReference* typeRef);
+	virtual void Visit(BfInlineTypeReference* typeRef);
 	virtual void Visit(BfNamedTypeReference* typeRef);
 	virtual void Visit(BfQualifiedTypeReference* qualifiedType);
 	virtual void Visit(BfDotTypeReference* typeRef);

+ 57 - 5
IDEHelper/Compiler/BfModule.cpp

@@ -2350,7 +2350,7 @@ bool BfModule::TryLocalVariableInit(BfLocalVariable* localVar)
 void BfModule::LocalVariableDone(BfLocalVariable* localVar, bool isMethodExit)
 {
 	BfAstNode* localNameNode = localVar->mNameNode;
-	if (localVar->mIsThis)
+	if ((localVar->mIsThis) && (mCurMethodInstance != NULL))
 	{
 		localNameNode = mCurMethodInstance->mMethodDef->GetRefNode();
 	}
@@ -12137,7 +12137,7 @@ BfIRValue BfModule::ConstantToCurrent(BfConstant* constant, BfIRConstHolder* con
 	return mBfIRBuilder->CreateConst(constant, constHolder);
 }
 
-void BfModule::ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget)
+void BfModule::ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget, bool force)
 {
 	if (attrTarget == BfAttributeTargets_SkipValidate)
 		return;
@@ -12149,6 +12149,9 @@ void BfModule::ValidateCustomAttributes(BfCustomAttributes* customAttributes, Bf
 
 		if ((customAttribute.mType->mAttributeData->mAttributeTargets & attrTarget) == 0)
 		{
+			if ((customAttribute.mIsMultiUse) && (!force))
+				continue;
+
 			Fail(StrFormat("Attribute '%s' is not valid on this declaration type. It is only valid on %s.",
 				customAttribute.GetRefNode()->ToString().c_str(), GetAttributesTargetListString(customAttribute.mType->mAttributeData->mAttributeTargets).c_str()), customAttribute.mRef->mAttributeTypeRef);	// CS0592
 		}
@@ -12222,6 +12225,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 		customAttribute.mAwaitingValidation = true;
 		customAttribute.mDeclaringType = activeTypeDef;
 		customAttribute.mRef = attributesDirective;
+		customAttribute.mIsMultiUse = attributesDirective->mIsMultiUse;
 
 		if (attributesDirective->mAttrOpenToken != NULL)
 			targetOverride = (BfAttributeTargets)0;
@@ -23430,7 +23434,7 @@ void BfModule::GetMethodCustomAttributes(BfMethodInstance* methodInstance)
 	auto typeInstance = methodInstance->GetOwner();
 
 	if (typeInstance->IsInstanceOf(mCompiler->mValueTypeTypeDef))
-		return;
+		return;	
 
 	BfTypeState typeState(typeInstance);
 	SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
@@ -23458,7 +23462,7 @@ void BfModule::GetMethodCustomAttributes(BfMethodInstance* methodInstance)
 
 		if ((methodInstance == methodInstance->mMethodInstanceGroup->mDefault) && (methodInstance->mMethodInstanceGroup->mDefaultCustomAttributes != NULL))
 		{
-			// Take over prevoiusly-generated custom attributes
+			// Take over previously-generated custom attributes
 			methodInstance->mMethodInfoEx->mMethodCustomAttributes->mCustomAttributes = methodInstance->mMethodInstanceGroup->mDefaultCustomAttributes;
 			methodInstance->mMethodInstanceGroup->mDefaultCustomAttributes = NULL;
 		}
@@ -23479,7 +23483,55 @@ void BfModule::GetMethodCustomAttributes(BfMethodInstance* methodInstance)
 		}
 	}
 
-	customAttributes = methodInstance->GetCustomAttributes();
+	if (methodDeclaration != NULL)
+	{
+		if (auto inlineTypeRef = BfNodeDynCast<BfInlineTypeReference>(methodDeclaration->mReturnType))
+		{
+			if (inlineTypeRef->mTypeDeclaration->mAttributes != NULL)
+			{
+				// Apply multiuse attributes from anonymous return type
+				auto returnType = ResolveTypeRef(inlineTypeRef);
+				if ((returnType != NULL) && (returnType->ToTypeInstance()))
+				{
+					auto returnTypeInst = returnType->ToTypeInstance();
+					if ((returnTypeInst->IsAnonymous()) && (returnTypeInst->mCustomAttributes != NULL))
+					{
+						bool hasPendingAttributes = false;
+						for (const auto& customAttribute : returnTypeInst->mCustomAttributes->mAttributes)
+						{
+							if (customAttribute.mAwaitingValidation)
+							{
+								hasPendingAttributes = true;
+								break;
+							}
+						}
+
+						if (hasPendingAttributes)
+						{
+							if (methodInstance->GetMethodInfoEx()->mMethodCustomAttributes == NULL)
+								methodInstance->mMethodInfoEx->mMethodCustomAttributes = new BfMethodCustomAttributes();
+
+							if (methodInstance->mMethodInfoEx->mMethodCustomAttributes->mCustomAttributes == NULL)
+								methodInstance->mMethodInfoEx->mMethodCustomAttributes->mCustomAttributes = new BfCustomAttributes();
+
+							for (const auto& customAttribute : returnTypeInst->mCustomAttributes->mAttributes)
+							{
+								if (!customAttribute.mAwaitingValidation)
+									continue;
+
+								BfCustomAttribute copiedCustomAttribute = customAttribute;
+								copiedCustomAttribute.mIsMultiUse = false;
+								methodInstance->mMethodInfoEx->mMethodCustomAttributes->mCustomAttributes->mAttributes.Add(copiedCustomAttribute);
+							}
+							ValidateCustomAttributes(methodInstance->mMethodInfoEx->mMethodCustomAttributes->mCustomAttributes, attrTarget);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	customAttributes = methodInstance->GetCustomAttributes();	
 	if (customAttributes == NULL)
 	{
 		auto owner = methodInstance->GetOwner();

+ 1 - 1
IDEHelper/Compiler/BfModule.h

@@ -1676,7 +1676,7 @@ public:
 	bool HasUnactializedConstant(BfConstant* constant, BfIRConstHolder* constHolder);
 	BfTypedValue GetTypedValueFromConstant(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType);
 	BfIRValue ConstantToCurrent(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType, bool allowUnactualized = false);
-	void ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget);
+	void ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget, bool force = false);
 	void GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, BfGetCustomAttributesFlags flags = BfGetCustomAttributesFlags_None, BfCaptureInfo* captureInfo = NULL);
 	BfCustomAttributes* GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, BfGetCustomAttributesFlags flags = BfGetCustomAttributesFlags_None, BfCaptureInfo* captureInfo = NULL);
 	BfCustomAttributes* GetCustomAttributes(BfTypeDef* typeDef);

+ 57 - 10
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -5077,10 +5077,13 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 					// Handled elsewhere
 				}
 				else
-				{
+				{					
 					SetAndRestoreValue<BfFieldDef*> prevTypeRef(mContext->mCurTypeState->mCurFieldDef, fieldDef);
+					fieldInstance->mCustomAttributes = GetCustomAttributes(fieldDef->GetFieldDeclaration()->mAttributes, fieldDef->mIsStatic ? BfAttributeTargets_StaticField : BfAttributeTargets_Field);					
+				}
 
-					fieldInstance->mCustomAttributes = GetCustomAttributes(fieldDef->GetFieldDeclaration()->mAttributes, fieldDef->mIsStatic ? BfAttributeTargets_StaticField : BfAttributeTargets_Field);
+				if (fieldInstance->mCustomAttributes != NULL)
+				{
 					for (auto customAttr : fieldInstance->mCustomAttributes->mAttributes)
 					{
 						if (TypeToString(customAttr.mType) == "System.ThreadStaticAttribute")
@@ -5094,6 +5097,38 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 				}
 			}
 
+			if ((fieldInstance->mResolvedType != NULL) && (fieldInstance->mResolvedType->IsTypeInstance()) && (fieldInstance->mResolvedType->ToTypeInstance()->IsAnonymous()))
+			{
+				auto fieldTypeInst = fieldInstance->mResolvedType->ToTypeInstance();				
+				if ((fieldTypeInst->IsAnonymous()) && (fieldTypeInst->mCustomAttributes != NULL))
+				{
+					bool hasPendingAttributes = false;
+					for (const auto& customAttribute : fieldTypeInst->mCustomAttributes->mAttributes)
+					{
+						if (customAttribute.mAwaitingValidation)
+						{
+							hasPendingAttributes = true;
+							break;
+						}
+					}
+									 
+					if (hasPendingAttributes)
+					{
+						fieldInstance->mCustomAttributes = new BfCustomAttributes();
+						for (const auto& customAttribute : fieldTypeInst->mCustomAttributes->mAttributes)
+						{
+							if (!customAttribute.mAwaitingValidation)
+								continue;
+										 
+							BfCustomAttribute copiedCustomAttribute = customAttribute;
+							copiedCustomAttribute.mIsMultiUse = false;
+							fieldInstance->mCustomAttributes->mAttributes.Add(copiedCustomAttribute);
+						}
+						ValidateCustomAttributes(fieldInstance->mCustomAttributes, fieldDef->mIsStatic ? BfAttributeTargets_StaticField : BfAttributeTargets_Field);
+					}
+				}																					
+			}
+
 			if (resolvedFieldType == NULL)
 			{
 				if ((underlyingType != NULL) || (typeInstance->IsPayloadEnum()))
@@ -8445,6 +8480,7 @@ BfType* BfModule::ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopu
 	BfNamedTypeReference* namedTypeRef = NULL;
 	BfGenericInstanceTypeRef* genericTypeRef = NULL;
 	BfDirectStrTypeReference* directStrTypeRef = NULL;
+	BfInlineTypeReference* inlineTypeRef = NULL;
 	BfIdentifierNode* identifierNode = NULL;
 	if ((namedTypeRef = BfNodeDynCast<BfNamedTypeReference>(typeRef)))
 	{
@@ -8463,17 +8499,24 @@ BfType* BfModule::ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopu
 	{
 		//
 	}
+	else if ((inlineTypeRef = BfNodeDynCastExact<BfInlineTypeReference>(typeRef)))
+	{
+		//
+	}
 
-	BF_ASSERT((identifierNode != NULL) || (namedTypeRef != NULL) || (directStrTypeRef != NULL));
+	BF_ASSERT((identifierNode != NULL) || (namedTypeRef != NULL) || (directStrTypeRef != NULL) || (inlineTypeRef != NULL));
 
 	auto usedOuterType = outerType;
 	if (nestedTypeDef == NULL)
 	{
+		String tempStr;
 		StringView findName;
 		if (namedTypeRef != NULL)
 			findName = namedTypeRef->mNameNode->ToStringView();
 		else if (identifierNode != NULL)
 			findName = identifierNode->ToStringView();
+		else if (inlineTypeRef != NULL)		
+			findName = inlineTypeRef->mTypeDeclaration->mAnonymousName;		
 		else
 			findName = directStrTypeRef->mTypeName;
 
@@ -10468,17 +10511,18 @@ BfTypeDef* BfModule::FindTypeDef(BfTypeReference* typeRef, BfTypeInstance* typeI
 	if (auto elementedType = BfNodeDynCast<BfElementedTypeRef>(typeRef))
 		return FindTypeDef(elementedType->mElementType, typeInstanceOverride, error);
 
-	BF_ASSERT(typeRef->IsA<BfNamedTypeReference>() || typeRef->IsA<BfQualifiedTypeReference>() || typeRef->IsA<BfDirectStrTypeReference>());
+	BF_ASSERT(typeRef->IsA<BfNamedTypeReference>() || typeRef->IsA<BfQualifiedTypeReference>() || typeRef->IsA<BfDirectStrTypeReference>() || typeRef->IsA<BfInlineTypeReference>());
 	auto namedTypeRef = BfNodeDynCast<BfNamedTypeReference>(typeRef);
 
 	StringView findNameStr;
 	if (namedTypeRef != NULL)
 		findNameStr = namedTypeRef->mNameNode->ToStringView();
 	else
-	{
-		auto directStrTypeDef = BfNodeDynCastExact<BfDirectStrTypeReference>(typeRef);
-		if (directStrTypeDef != NULL)
+	{		
+		if (auto directStrTypeDef = BfNodeDynCastExact<BfDirectStrTypeReference>(typeRef))
 			findNameStr = directStrTypeDef->mTypeName;
+		else if (auto inlineTypeRef = BfNodeDynCastExact<BfInlineTypeReference>(typeRef))
+			findNameStr = inlineTypeRef->mTypeDeclaration->mAnonymousName;
 		else
 			BFMODULE_FATAL(this, "Error?");
 	}
@@ -10943,7 +10987,7 @@ BfType* BfModule::ResolveTypeRef_Ref(BfTypeReference* typeRef, BfPopulateType po
 	{
 		Fail("Invalid use of 'var ref'. Generally references are generated with a 'var' declaration with 'ref' applied to the initializer", typeRef);
 		return NULL;
-	}
+	}	
 
 	if (mNoResolveGenericParams)
 		resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_NoResolveGenericParam);
@@ -10989,13 +11033,16 @@ BfType* BfModule::ResolveTypeRef_Ref(BfTypeReference* typeRef, BfPopulateType po
 		// Check generics first
 		auto namedTypeRef = BfNodeDynCastExact<BfNamedTypeReference>(typeRef);
 		auto directStrTypeRef = BfNodeDynCastExact<BfDirectStrTypeReference>(typeRef);
-		if (((namedTypeRef != NULL) && (namedTypeRef->mNameNode != NULL)) || (directStrTypeRef != NULL))
+		auto inlineStrTypeRef = BfNodeDynCastExact<BfInlineTypeReference>(typeRef);
+		if (((namedTypeRef != NULL) && (namedTypeRef->mNameNode != NULL)) || (directStrTypeRef != NULL) || (inlineStrTypeRef != NULL))
 		{
 			StringView findName;
 			if (namedTypeRef != NULL)
 				findName = namedTypeRef->mNameNode->ToStringView();
-			else
+			else if (directStrTypeRef != NULL)
 				findName = directStrTypeRef->mTypeName;
+			else
+				findName = inlineStrTypeRef->mTypeDeclaration->mAnonymousName;
 			if (findName == "Self")
 			{
 				BfType* selfType = mCurTypeInstance;

+ 61 - 1
IDEHelper/Compiler/BfParser.cpp

@@ -105,6 +105,38 @@ return 0;
 
 //////////////////////////////////////////////////////////////////////////
 
+static CritSect gParseFileDataCrit;
+static Array<int> gFreeIds;
+static int gCurFreeId;
+
+int BfParseFileData::GetUniqueId(int idx)
+{
+	AutoCrit autoCrit(gParseFileDataCrit);
+	while (idx >= mUniqueIDList.size())
+	{
+		if (!gFreeIds.IsEmpty())
+		{
+			mUniqueIDList.Add(gFreeIds.back());
+			gFreeIds.pop_back();
+		}
+		else
+			mUniqueIDList.Add(gCurFreeId++);
+	}
+	return mUniqueIDList[idx];
+}
+
+BfParseFileData::~BfParseFileData()
+{
+	if (!mUniqueIDList.IsEmpty())
+	{
+		AutoCrit autoCrit(gParseFileDataCrit);
+		for (auto id : mUniqueIDList)
+			gFreeIds.Add(id);
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////
+
 BfParserCache* Beefy::gBfParserCache = NULL;
 
 bool BfParserCache::DataEntry::operator==(const LookupEntry& lookup) const
@@ -201,14 +233,39 @@ BfParserData::BfParserData()
 	mCharIdData = NULL;
 	mUniqueParser = NULL;
 	mDidReduce = false;
+	mParseFileData = NULL;
 }
 
 BfParserData::~BfParserData()
 {
+	if (mParseFileData != NULL)
+	{
+		BF_ASSERT(mParseFileData->mRefCount >= 0);
+		mParseFileData->mRefCount--;
+		if (mParseFileData->mRefCount == 0)
+		{
+			delete mParseFileData;
+			gBfParserCache->mParseFileDataMap.Remove(mFileName);
+		}
+	}
+
 	delete[] mJumpTable;
 	delete[] mCharIdData;
 }
 
+void BfParserData::InitFileData()
+{
+	BF_ASSERT(mParseFileData == NULL);
+
+	BfParseFileData** valuePtr = NULL;
+	if (gBfParserCache->mParseFileDataMap.TryAdd(mFileName, NULL, &valuePtr))
+	{
+		*valuePtr = new BfParseFileData();
+	}
+	mParseFileData = *valuePtr;
+	mParseFileData->mRefCount++;
+}
+
 int BfParserData::GetCharIdAtIndex(int findIndex)
 {
 	if (mCharIdData == NULL)
@@ -328,7 +385,7 @@ void BfParserData::Deref()
 	mRefCount--;
 	BF_ASSERT(mRefCount >= 0);
 	if (mRefCount == 0)
-	{
+	{		
 		AutoCrit autoCrit(gBfParserCache->mCritSect);
 		BfParserCache::DataEntry dataEntry;
 		dataEntry.mParserData = this;
@@ -413,6 +470,8 @@ BfParser::~BfParser()
 	}
 	else if (mParserData->mRefCount == 0)
 	{
+
+
 		// Just never got added to the cache
 		delete mParserData;
 	}
@@ -510,6 +569,7 @@ void BfParser::Init(uint64 cacheHash)
 	mParserData = new BfParserData();
 	mSourceData = mParserData;
 	mParserData->mFileName = mFileName;
+	mParserData->InitFileData();
 	if (mDataId != -1)
 		mParserData->mDataId = mDataId;
 	else

+ 20 - 1
IDEHelper/Compiler/BfParser.h

@@ -62,6 +62,22 @@ enum MaybeBool
 	MaybeBool_True = 1,
 };
 
+class BfParseFileData
+{
+public:
+	Array<int> mUniqueIDList;
+	int mRefCount;
+
+public:
+	BfParseFileData()
+	{
+		mRefCount = 0;
+	}
+	~BfParseFileData();
+
+	int GetUniqueId(int idx);
+};
+
 class BfParserData : public BfSourceData
 {
 public:
@@ -81,8 +97,9 @@ public:
 	OwnedVector<String> mStringLiterals;
 	Dictionary<int, BfParserWarningEnabledChange> mWarningEnabledChanges;
 	std::set<int> mUnwarns;
+	BfParseFileData* mParseFileData;
 	bool mFailed; // Don't cache if there's a warning or an error
-	bool mDidReduce;
+	bool mDidReduce;	
 
 public:
 	BfParserData();
@@ -94,6 +111,7 @@ public:
 		return this;
 	}
 
+	void InitFileData();
 	virtual BfParser* ToParser() override;
 	int GetCharIdAtIndex(int findIndex);
 	void GetLineCharAtIdx(int idx, int& line, int& lineChar);
@@ -130,6 +148,7 @@ public:
 	int mRefCount;
 	BfAstAllocManager mAstAllocManager;
 	HashSet<DataEntry> mEntries;
+	Dictionary<String, BfParseFileData*> mParseFileDataMap;
 
 public:
 	BfParserCache();

+ 206 - 10
IDEHelper/Compiler/BfReducer.cpp

@@ -47,6 +47,7 @@ BfReducer::BfReducer()
 	mSystem = NULL;
 	mResolvePassData = NULL;
 	mMethodDepth = 0;
+	mCurUniqueIdx = 0;
 	mDocumentCheckIdx = 0;
 	mTypeMemberNodeStart = NULL;
 }
@@ -403,6 +404,39 @@ bool BfReducer::IsTypeReference(BfAstNode* checkNode, BfToken successToken, int
 				mVisitorPos.mReadPos = startNode;
 				return true;
 			}
+			else if ((checkToken == BfToken_Struct) || (checkToken == BfToken_Class) || (checkToken == BfToken_Interface) || (checkToken == BfToken_Enum))
+			{
+				checkIdx++;
+				auto nextNode = mVisitorPos.Get(checkIdx);
+				if (auto block = BfNodeDynCast<BfBlock>(nextNode))
+				{
+					if (outEndNode != NULL)
+						*outEndNode = checkIdx;
+					return true;
+				}
+
+				if (auto tokenNode = BfNodeDynCast<BfTokenNode>(nextNode))
+				{
+					if (tokenNode->mToken == BfToken_Colon)
+					{
+						while (true)
+						{
+							checkIdx++;
+							auto checkNode = mVisitorPos.Get(checkIdx);
+							if (checkNode == NULL)
+								return false;
+							if (auto block = BfNodeDynCast<BfBlock>(checkNode))
+							{
+								if (outEndNode != NULL)
+									*outEndNode = checkIdx;
+								return true;
+							}
+						}
+					}
+				}
+
+				return false;
+			}
 			else
 				return false;
 		}
@@ -4360,6 +4394,7 @@ BfAstNode* BfReducer::DoCreateStatement(BfAstNode* node, CreateStmtFlags createS
 						ReplaceNode(typeRef, methodDecl);
 						methodDecl->mDocumentation = FindDocumentation(methodDecl);
 						methodDecl->mReturnType = typeRef;
+						CheckMultiuseAttributeTypeRef(methodDecl->mReturnType);
 
 						BfDeferredAstSizedArray<BfParameterDeclaration*> params(methodDecl->mParams, mAlloc);
 						BfDeferredAstSizedArray<BfTokenNode*> commas(methodDecl->mCommas, mAlloc);
@@ -5105,6 +5140,71 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF
 					if ((createTypeRefFlags & CreateTypeRefFlags_EarlyExit) != 0)
 						return delegateTypeRef;
 				}
+				else if ((BfTokenIsTypeDecl(token)) || (token == BfToken_LBracket))
+				{
+					BfAttributeDirective* attributes = NULL;
+					if (token == BfToken_LBracket)
+					{
+						attributes = CreateAttributeDirective(tokenNode);
+						if (attributes == NULL)
+							return NULL;
+						mVisitorPos.MoveNext();
+ 						bool isValid = false;
+
+						auto nextNode = mVisitorPos.GetCurrent();
+						tokenNode = BfNodeDynCast<BfTokenNode>(nextNode);
+						if (tokenNode != NULL)
+						{
+							token = tokenNode->mToken;
+							if (BfTokenIsTypeDecl(token))
+								isValid = true;
+						}
+						if (!isValid)
+						{
+							AddErrorNode(attributes);
+							return NULL;
+						}
+					}
+
+					bool attribsApply = false;
+					if ((mTypeMemberNodeStart != NULL) && (mTypeMemberNodeStart->mSrcEnd == tokenNode->mTriviaStart))
+						attribsApply = true;
+					auto typeDeclNode = CreateTopLevelObject(tokenNode, attributes, attribsApply ? mTypeMemberNodeStart : NULL, true);
+					if (typeDeclNode == NULL)
+					{
+						if (attributes != NULL)
+							AddErrorNode(attributes);
+						return NULL;
+					}
+
+					auto typeDecl = BfNodeDynCast<BfTypeDeclaration>(typeDeclNode);
+					if (typeDecl == NULL)
+					{
+						if (attributes != NULL)
+							AddErrorNode(attributes);
+						AddErrorNode(typeDeclNode);
+						return NULL;
+					}
+
+					String name;
+					auto parserData = typeDecl->GetParserData();
+					name = "Anon_";					
+
+ 					auto parseFileData = parserData->mParseFileData;
+					int uniqueId = parseFileData->GetUniqueId(mCurUniqueIdx++);
+					name += StrFormat("%d", uniqueId);
+
+ 					int len = (int)name.length() + 1;
+ 					typeDecl->mAnonymousName = (char*)mAlloc->AllocBytes(len);
+ 					memcpy(typeDecl->mAnonymousName, name.c_str(), len);
+
+					if (mCurTypeState != NULL)
+						mCurTypeState->mAnonymousTypeDecls.Add(typeDecl);
+					auto typeRef = mAlloc->Alloc<BfInlineTypeReference>();
+					ReplaceNode(typeDecl, typeRef);
+					typeRef->mTypeDeclaration = typeDecl;
+					return typeRef;
+				}				
 				else if ((token == BfToken_Comptype) || (token == BfToken_Decltype))
 				{
 					auto declTypeRef = mAlloc->Alloc<BfExprModTypeRef>();
@@ -5881,6 +5981,12 @@ BfStatement* BfReducer::CreateAttributedStatement(BfTokenNode* tokenNode, Create
 			(checkNode->IsA<BfStringInterpolationExpression>()) ||
  			(checkNode->IsA<BfBlock>()))
 		{
+			if (auto varDecl = BfNodeDynCast<BfVariableDeclaration>(checkNode))
+			{
+				if (CheckInlineTypeRefAttribute(varDecl->mTypeRef, attrib))
+					return BfNodeDynCast<BfStatement>(stmt);
+			}
+
 			BfAttributedStatement* attribStmt = mAlloc->Alloc<BfAttributedStatement>();
 			ReplaceNode(attrib, attribStmt);
 			attribStmt->mAttributes = attrib;
@@ -6169,6 +6275,8 @@ BfFieldDeclaration* BfReducer::CreateFieldDeclaration(BfTokenNode* tokenNode, Bf
 		MoveNode(fieldDeclaration->mNameNode, fieldDeclaration);
 		//mVisitorPos.MoveNext();
 	}
+	CheckMultiuseAttributeTypeRef(fieldDeclaration->mTypeRef);
+
 	BfToken token = tokenNode->GetToken();
 	if (token == BfToken_AssignEquals)
 	{
@@ -6273,6 +6381,26 @@ BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, bool declStarted, i
 			Fail("Invalid target for attributes", memberNode);
 			return memberNode;
 		}
+		
+		memberNode->mTriviaStart = attributes->mTriviaStart;
+		memberNode->mSrcStart = attributes->mSrcStart;
+
+		if (auto fieldDecl = BfNodeDynCast<BfFieldDeclaration>(member))
+		{
+			if (CheckInlineTypeRefAttribute(fieldDecl->mTypeRef, attributes))
+			{
+				return member;
+			}
+		}
+
+		if (auto methodDecl = BfNodeDynCast<BfMethodDeclaration>(member))
+		{
+			if (CheckInlineTypeRefAttribute(methodDecl->mReturnType, attributes))
+			{
+				return member;
+			}
+		}
+		
 
 		ReplaceNode(attributes, member);
 		member->mAttributes = attributes;
@@ -6291,6 +6419,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, bool declStarted, i
 		if (typeRef == NULL)
 			return operatorDecl;
 		MEMBER_SET_CHECKED(operatorDecl, mReturnType, typeRef);
+		CheckMultiuseAttributeTypeRef(operatorDecl->mReturnType);
 		operatorDecl->mIsConvOperator = true;
 
 		ParseMethod(operatorDecl, &params, &commas);
@@ -7061,10 +7190,19 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept
 			}
 		}
 
+		if ((token == BfToken_Struct) || (token == BfToken_Class) || (token == BfToken_Interface) || (token == BfToken_Enum))
+		{
+			int endNodeIdx = -1;
+			if (IsTypeReference(node, BfToken_None, -1, &endNodeIdx))
+			{
+				isTypeRef = true;
+			}			
+		}
+
 		if ((token == BfToken_LBracket) && (depth > 0))
 		{
-			Fail("Unexpected custom attribute", node);
-			return NULL;
+			// The only valid option is an attributed type reference
+			isTypeRef = true;
 		}
 
 		if (isTypeRef)
@@ -7218,6 +7356,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept
 							ReplaceNode(nameIdentifier, methodDeclaration);
 						methodDeclaration->mDocumentation = FindDocumentation(mTypeMemberNodeStart);
 						MEMBER_SET(methodDeclaration, mReturnType, typeRef);
+						CheckMultiuseAttributeTypeRef(methodDeclaration->mReturnType);
 						MEMBER_SET(methodDeclaration, mExplicitInterface, explicitInterface);
 						MEMBER_SET(methodDeclaration, mExplicitInterfaceDotToken, explicitInterfaceDot);
 						return methodDeclaration;
@@ -7235,6 +7374,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept
 			BfDeferredAstSizedArray<BfTokenNode*> commas(operatorDecl->mCommas, mAlloc);
 			ReplaceNode(typeRef, operatorDecl);
 			operatorDecl->mReturnType = typeRef;
+			CheckMultiuseAttributeTypeRef(operatorDecl->mReturnType);
 			mVisitorPos.MoveNext();
 
 			MEMBER_SET(operatorDecl, mOperatorToken, nextToken);
@@ -7394,6 +7534,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept
 					ReplaceNode(typeRef, propDecl);
 					propDecl->mDocumentation = FindDocumentation(mTypeMemberNodeStart);
 					propDecl->mTypeRef = typeRef;
+					CheckMultiuseAttributeTypeRef(propDecl->mTypeRef);
 
 					if (explicitInterface != NULL)
 					{
@@ -7553,6 +7694,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept
 						ReplaceNode(typeRef, fieldDecl);
 						fieldDecl->mDocumentation = FindDocumentation(mTypeMemberNodeStart);
 						fieldDecl->mTypeRef = typeRef;
+						CheckMultiuseAttributeTypeRef(fieldDecl->mTypeRef);
 						return fieldDecl;
 					}
 				}
@@ -7584,6 +7726,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, bool declStarted, int dept
 			}
 
 			methodDeclaration->mReturnType = typeRef;
+			CheckMultiuseAttributeTypeRef(methodDeclaration->mReturnType);
 			MEMBER_SET_CHECKED(methodDeclaration, mNameNode, nameIdentifier);
 			mCurMethodDecl = methodDeclaration;
 			ParseMethod(methodDeclaration, &params, &commas);
@@ -7990,6 +8133,47 @@ BfScopedInvocationTarget* BfReducer::CreateScopedInvocationTarget(BfAstNode*& ta
 	return scopedInvocationTarget;
 }
 
+bool BfReducer::CheckInlineTypeRefAttribute(BfAstNode* typeRef, BfAttributeDirective* attributes)
+{
+	if (attributes == NULL)
+		return false;
+
+	if (auto inlineTypeRef = BfNodeDynCast<BfInlineTypeReference>(typeRef))
+	{
+		auto checkAttribute = attributes;
+		while (checkAttribute != NULL)
+		{
+			checkAttribute->mIsMultiUse = true;
+			checkAttribute = checkAttribute->mNextAttribute;
+		}
+
+		auto typeDecl = inlineTypeRef->mTypeDeclaration;				
+		typeDecl->mTriviaStart = attributes->mTriviaStart;
+		typeDecl->mSrcStart = attributes->mSrcStart;
+		typeDecl->mAttributes = attributes;
+
+		if ((typeDecl->mIgnoreDeclaration) && (IsNodeRelevant(typeDecl)))
+			typeDecl->mIgnoreDeclaration = false;
+
+		return true;
+	}
+
+	return false;
+}
+
+void BfReducer::CheckMultiuseAttributeTypeRef(BfAstNode* typeRef)
+{
+	if (auto inlineTypeRef = BfNodeDynCast<BfInlineTypeReference>(typeRef))
+	{
+		auto checkAttribute = inlineTypeRef->mTypeDeclaration->mAttributes;
+		while (checkAttribute != NULL)
+		{
+			checkAttribute->mIsMultiUse = true;
+			checkAttribute = checkAttribute->mNextAttribute;
+		}
+	}	
+}
+
 bool BfReducer::SetProtection(BfAstNode* parentNode, BfAstNode*& protectionNodeRef, BfTokenNode* tokenNode)
 {
 	bool failed = false;
@@ -8648,7 +8832,7 @@ BfAstNode* BfReducer::HandleTopLevel(BfBlock* node)
 	return node;
 }
 
-BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDirective* attributes, BfAstNode* deferredHeadNode)
+BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDirective* attributes, BfAstNode* deferredHeadNode, bool isAnonymous)
 {
 	AssertCurrentNode(tokenNode);
 
@@ -8992,9 +9176,12 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi
 
 	case BfToken_Delegate:
 	case BfToken_Function:
-	{
+	{		
 		auto typeDeclaration = mAlloc->Alloc<BfTypeDeclaration>();
+		
 		SetAndRestoreValue<BfTypeDeclaration*> prevTypeDecl(mCurTypeDecl, typeDeclaration);
+		CurTypeState curTypeState(typeDeclaration, mAlloc);		
+		SetAndRestoreValue<CurTypeState*> prevTypeState(mCurTypeState, &curTypeState);
 
 		ReplaceNode(tokenNode, typeDeclaration);
 		typeDeclaration->mDocumentation = FindDocumentation(typeDeclaration);
@@ -9006,6 +9193,7 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi
 
 		auto methodDecl = mAlloc->Alloc<BfMethodDeclaration>();
 		MEMBER_SET(methodDecl, mReturnType, retType);
+		CheckMultiuseAttributeTypeRef(methodDecl->mReturnType);
 		BfDeferredAstSizedArray<BfParameterDeclaration*> params(methodDecl->mParams, mAlloc);
 		BfDeferredAstSizedArray<BfTokenNode*> commas(methodDecl->mCommas, mAlloc);
 		methodDecl->mDocumentation = FindDocumentation(methodDecl);
@@ -9121,11 +9309,16 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi
 		if ((tokenNode->GetToken() == BfToken_Enum) && (isSimpleEnum))
 			break;
 
-		auto identifierNode = ExpectIdentifierAfter(tokenNode);
-		if (identifierNode == NULL)
+		BfIdentifierNode* identifierNode = NULL;
+
+		if (!isAnonymous)
 		{
-			AddErrorNode(tokenNode);
-			return NULL;
+			identifierNode = ExpectIdentifierAfter(tokenNode);
+			if (identifierNode == NULL)
+			{
+				AddErrorNode(tokenNode);
+				return NULL;
+			}
 		}
 
 		// We put extra effort in here to continue after failure, since 'return NULL' failure
@@ -9138,7 +9331,8 @@ BfAstNode* BfReducer::CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDi
 		typeDeclaration->mTypeNode = tokenNode;
 		typeDeclaration->mNameNode = identifierNode;
 		ReplaceNode(tokenNode, typeDeclaration);
-		MoveNode(identifierNode, typeDeclaration);
+		if (identifierNode != NULL)
+			MoveNode(identifierNode, typeDeclaration);
 		typeDeclaration->mDocumentation = FindDocumentation(mTypeMemberNodeStart);
 
 		auto nextNode = mVisitorPos.GetNext();
@@ -10645,8 +10839,10 @@ void BfReducer::HandleBlock(BfBlock* block, bool allowEndingExpression)
 void BfReducer::HandleTypeDeclaration(BfTypeDeclaration* typeDecl, BfAttributeDirective* attributes, BfAstNode* deferredHeadNode)
 {
 	SetAndRestoreValue<BfTypeDeclaration*> prevTypeDecl(mCurTypeDecl, typeDecl);
+	CurTypeState curTypeState(typeDecl, mAlloc);
+	SetAndRestoreValue<CurTypeState*> prevTypeState(mCurTypeState, &curTypeState);
 	SetAndRestoreValue<BfVisitorPos> prevVisitorPos(mVisitorPos, BfVisitorPos(BfNodeDynCast<BfBlock>(typeDecl->mDefineNode)));
-
+	
 	if (attributes != NULL)
 	{
 		MEMBER_SET(typeDecl, mAttributes, attributes);

+ 40 - 3
IDEHelper/Compiler/BfReducer.h

@@ -129,6 +129,39 @@ public:
 		}
 	};
 
+	struct CurTypeState
+	{
+	public:		
+		BfTypeDeclaration* mTypeDeclaration;
+		BfAstAllocator* mAlloc;
+		Array<BfTypeDeclaration*> mAnonymousTypeDecls;
+
+	public:
+		CurTypeState()
+		{
+			mTypeDeclaration = NULL;
+			mAlloc = NULL;
+		}
+
+		CurTypeState(BfTypeDeclaration* typeDecl, BfAstAllocator* alloc)
+		{
+			mTypeDeclaration = typeDecl;
+			mAlloc = alloc;
+		}
+
+		~CurTypeState()
+		{			
+			if ((mTypeDeclaration != NULL) && (mAnonymousTypeDecls.mSize > 0))
+			{				
+				BF_ASSERT(mTypeDeclaration->mAnonymousTypes.mSize == 0);
+				mTypeDeclaration->mAnonymousTypes.mSize = (int)mAnonymousTypeDecls.size();				
+				mTypeDeclaration->mAnonymousTypes.mVals = (BfTypeDeclaration**)mAlloc->AllocBytes(mAnonymousTypeDecls.mSize * sizeof(BfTypeDeclaration*), sizeof(BfTypeDeclaration*));
+				for (int i = 0; i < mAnonymousTypeDecls.mSize; i++)
+					mTypeDeclaration->mAnonymousTypes.mVals[i] = mAnonymousTypeDecls[i];				
+			}
+		}
+	};
+
 public:
 	BfAstAllocator* mAlloc;
 	BfSystem* mSystem;
@@ -138,10 +171,12 @@ public:
 	BfAstNode* mTypeMemberNodeStart;
 	int mClassDepth;
 	int mMethodDepth;
+	int mCurUniqueIdx;
 	BfTypeDeclaration* mCurTypeDecl;
+	CurTypeState* mCurTypeState;
 	BfTypeDeclaration* mLastTypeDecl;
 	BfMethodDeclaration* mCurMethodDecl;
-	BfAstNode* mLastBlockNode;
+	BfAstNode* mLastBlockNode;	
 	bool mStmtHasError;
 	bool mPrevStmtHadError;
 	bool mCompatMode; // Does C++ compatible parsing
@@ -179,7 +214,9 @@ public:
 	bool IsNodeRelevant(BfAstNode* startNode, BfAstNode* endNode);
 	void MoveNode(BfAstNode* srcNode, BfAstNode* newOwner);
 	void ReplaceNode(BfAstNode* prevNode, BfAstNode* newNode);
-
+	
+	bool CheckInlineTypeRefAttribute(BfAstNode* typeRef, BfAttributeDirective* attributes);
+	void CheckMultiuseAttributeTypeRef(BfAstNode* typeRef);
 	bool SetProtection(BfAstNode* parentNode, BfAstNode*& protectionNodeRef, BfTokenNode* tokenNode);
 	BfAstNode* CreateAllocNode(BfTokenNode* newNode);
 	BfAstNode* ReplaceTokenStarter(BfAstNode* astNode, int idx = -1, bool allowIn = false);
@@ -238,7 +275,7 @@ public:
 	BfWhileStatement* CreateWhileStatement(BfAstNode* node);
 	BfDoStatement* CreateDoStatement(BfAstNode* node);
 	BfRepeatStatement* CreateRepeatStatement(BfAstNode* node);
-	BfAstNode* CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDirective* attributes, BfAstNode* deferredHeadNode = NULL);
+	BfAstNode* CreateTopLevelObject(BfTokenNode* tokenNode, BfAttributeDirective* attributes, BfAstNode* deferredHeadNode = NULL, bool isAnonymous = false);
 	BfAstNode* HandleTopLevel(BfBlock* node);
 	BfInlineAsmStatement* CreateInlineAsmStatement(BfAstNode* asmNode);
 

+ 14 - 0
IDEHelper/Compiler/BfResolvedTypeUtils.cpp

@@ -2450,6 +2450,11 @@ bool BfTypeInstance::GetResultInfo(BfType*& valueType, int& okTagId)
 	return false;
 }
 
+bool BfTypeInstance::IsAnonymous()
+{
+	return (mTypeDef->mTypeDeclaration != NULL) && (mTypeDef->mTypeDeclaration->IsAnonymous());
+}
+
 void BfTypeInstance::ReportMemory(MemReporter* memReporter)
 {
 	if (mGenericTypeInfo != NULL)
@@ -4249,6 +4254,13 @@ int BfResolvedTypeSet::DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHa
 		}
 		return nameHash ^ HASH_TAG;
 	}
+// 	else if (auto inlineTypeRef = BfNodeDynCastExact<BfInlineTypeReference>(typeRef))
+// 	{
+// 		String name;
+// 		inlineTypeRef->mTypeDeclaration->GetAnonymousName(name);
+// 		int nameHash = (int)Hash64(name.c_str(), (int)name.length());
+// 		return nameHash ^ HASH_TAG;
+// 	}
 	else
 	{
 		BF_FATAL("Not handled");
@@ -5552,6 +5564,8 @@ String BfTypeUtils::TypeToString(BfAstNode* typeRefNode)
 	}
 	if (auto directStrTypeName = BfNodeDynCast<BfDirectStrTypeReference>(typeRef))
 		return directStrTypeName->mTypeName;
+	if (auto inlineTypeRef = BfNodeDynCast<BfInlineTypeReference>(typeRef))
+		return inlineTypeRef->mTypeDeclaration->mAnonymousName;
 
 	if (auto tupleTypeRef = BfNodeDynCast<BfTupleTypeRef>(typeRef))
 	{

+ 2 - 0
IDEHelper/Compiler/BfResolvedTypeUtils.h

@@ -2205,6 +2205,7 @@ public:
 	bool HasBeenInstantiated() { return mHasBeenInstantiated || ((mAlwaysIncludeFlags & BfAlwaysIncludeFlag_AssumeInstantiated) != 0); }
 	bool IncludeAllMethods() { return ((mAlwaysIncludeFlags & BfAlwaysIncludeFlag_IncludeAllMethods) != 0); }
 	bool DefineStateAllowsStaticMethods() { return mDefineState >= BfTypeDefineState_HasInterfaces_Direct; }
+	bool IsAnonymous();
 
 	virtual void ReportMemory(MemReporter* memReporter) override;
 };
@@ -2669,6 +2670,7 @@ public:
 	Array<BfCustomAttributeSetProperty> mSetProperties;
 	Array<BfCustomAttributeSetField> mSetField;
 	bool mAwaitingValidation;
+	bool mIsMultiUse;
 
 	BfAstNode* GetRefNode()
 	{

+ 1 - 1
IDEHelper/Compiler/BfSourceClassifier.cpp

@@ -662,7 +662,7 @@ void BfSourceClassifier::Visit(BfTypeDeclaration* typeDeclaration)
 
 	SetAndRestoreValue<BfAstNode*> prevMember(mCurMember, typeDeclaration);
 
-	if (mSkipTypeDeclarations)
+	if ((mSkipTypeDeclarations) && (!typeDeclaration->IsAnonymous()))
 	{
 		if (auto defineBlock = BfNodeDynCast<BfBlock>(typeDeclaration->mDefineNode))
 		{

+ 13 - 1
IDEHelper/Compiler/BfSystem.cpp

@@ -1984,6 +1984,8 @@ BfSystem::BfSystem()
 		gPerfManager = new PerfManager();
 	//gPerfManager->StartRecording();
 
+	mAnonymousAtomCount = 0;
+	mCurUniqueId = 0;
 	mAtomUpdateIdx = 0;
 	mAtomCreateIdx = 0;
 	mTypeMapVersion = 1;
@@ -2094,7 +2096,7 @@ BfSystem::~BfSystem()
 	typeDef->mHash = typeCode + 1000; \
 	mSystemTypeDefs[name] = typeDef;
 
-BfAtom* BfSystem::GetAtom(const StringImpl& string)
+BfAtom* BfSystem::GetAtom(const StringImpl& string, BfAtom::Kind kind)
 {
 	StringView* stringPtr = NULL;
 	BfAtom* atom = NULL;
@@ -2111,6 +2113,7 @@ BfAtom* BfSystem::GetAtom(const StringImpl& string)
 		}
 #endif
 		mAtomCreateIdx++;
+		atom->mKind = kind;
 		atom->mIsSystemType = false;
 		atom->mAtomUpdateIdx = ++mAtomUpdateIdx;
 		atom->mString = *stringPtr;
@@ -2121,6 +2124,9 @@ BfAtom* BfSystem::GetAtom(const StringImpl& string)
 		for (char c : string)
 			atom->mHash = ((atom->mHash ^ c) << 5) - atom->mHash;
 
+		if (kind == BfAtom::Kind_Anon)
+			mAnonymousAtomCount++;
+
 		BfLogSys(this, "Atom Allocated %p %s\n", atom, string.c_str());
 
 		return atom;
@@ -2152,6 +2158,12 @@ void BfSystem::ReleaseAtom(BfAtom* atom)
 {
 	if (--atom->mRefCount == 0)
 	{
+		if (atom->mKind == BfAtom::Kind_Anon)
+		{
+			mAnonymousAtomCount--;
+			BF_ASSERT(mAnonymousAtomCount >= 0);
+		}
+
 		mAtomGraveyard.push_back(atom);
 		return;
 	}

+ 11 - 1
IDEHelper/Compiler/BfSystem.h

@@ -48,8 +48,16 @@ typedef HashSet<BfProject*> BfProjectSet;
 
 class BfAtom
 {
+public:
+	enum Kind
+	{
+		Kind_Normal,
+		Kind_Anon
+	};
+
 public:
 	StringView mString;
+	Kind mKind;
 	int mRefCount;
 	int mPendingDerefCount;
 	int mHash;
@@ -1783,6 +1791,8 @@ public:
 	Array<BfAtom*> mAtomGraveyard;
 	uint32 mAtomUpdateIdx;
 	int32 mTypeMapVersion; // Increment when we add any new types or namespaces
+	int32 mAnonymousAtomCount;
+	int32 mCurUniqueId;
 
 	OwnedVector<BfMethodDef> mMethodGraveyard;
 	OwnedVector<BfFieldDef> mFieldGraveyard;
@@ -1830,7 +1840,7 @@ public:
 	BfSystem();
 	~BfSystem();
 
-	BfAtom* GetAtom(const StringImpl& string);
+	BfAtom* GetAtom(const StringImpl& string, BfAtom::Kind kind = BfAtom::Kind_Normal);
 	BfAtom* FindAtom(const StringImpl& string); // Doesn't create a ref
 	BfAtom* FindAtom(const StringView& string); // Doesn't create a ref
 	void ReleaseAtom(BfAtom* atom);

+ 44 - 0
IDEHelper/Tests/src/Anonymous.bf

@@ -0,0 +1,44 @@
+using System;
+namespace Tests;
+
+class Anonymous
+{
+	struct StructA
+	{
+		public [Union] struct { public int mX, mY; } mVals;
+
+		[CRepr, SkipCall] struct { public int mA, mB; } GetVals()
+		{
+			decltype(GetVals()) retVals;
+			retVals.mA = 1;
+			retVals.mB = 2;
+			return retVals;
+		}
+	}
+
+	struct StructB
+	{
+		[Union]
+		public using struct
+		{
+			public int mX;
+			public int mY;
+		} mCoords;
+	}
+
+	[Test]
+	public static void TestBasics()
+	{
+		StructA sa = default;
+		sa.mVals.mX = 123;
+		Test.Assert(sa.mVals.mY == 123);
+		
+		var val = sa.[Friend]GetVals();
+		Test.Assert(val.mA == 0);
+		Test.Assert(val.mB == 0);
+
+		StructB sb = default;
+		sb.mX = 345;
+		Test.Assert(sb.mY == 345);
+	}
+}