瀏覽代碼

Comptime improvments, IOn<X> interfaces, const payload enum

Brian Fiete 3 年之前
父節點
當前提交
f37fb2c1b7

+ 2 - 2
BeefLibs/Beefy2D/src/Utils.bf

@@ -181,8 +181,8 @@ namespace Beefy
 			}
 
 			int fileLen = (.)sr.Length;
-			if (sr.TryRead(.((.)outBuffer.PrepareBuffer(fileLen), fileLen)) case .Err(let readErr))
-				return .Err(.ReadError(readErr));
+			if (sr.TryRead(.((.)outBuffer.PrepareBuffer(fileLen), fileLen)) case .Err)
+				return .Err(.ReadError(.Unknown));
 
 			if (onPreFilter != null)
 				onPreFilter();

+ 20 - 0
BeefLibs/corlib/src/Attribute.bf

@@ -540,6 +540,26 @@ namespace System
 		}
 	}
 
+	interface IOnTypeInit
+	{
+		void OnTypeInit(Type type, Self* prev) mut;
+	}
+
+	interface IOnTypeDone
+	{
+		void OnTypeDone(Type type, Self* prev) mut;
+	}
+
+	interface IOnFieldInit
+	{
+		void OnFieldInit(ComptimeFieldInfo type, Self* prev) mut;
+	}
+
+	interface IOnMethodInit
+	{
+		void OnMethodInit(ComptimeMethodInfo type, Self* prev) mut;
+	}
+
 	interface IComptimeTypeApply
 	{
 		void ApplyToType(Type type);

+ 2 - 2
BeefLibs/corlib/src/IO/File.bf

@@ -44,8 +44,8 @@ namespace System.IO
 					if (bytes == 0)
 						return .Ok;
 					outData.AddRange(.(&buffer, bytes));
-				case .Err(let err):
-					return .Err(err);
+				case .Err:
+					return .Err(.Unknown);
 				}
 			}
 		}

+ 27 - 0
BeefLibs/corlib/src/Reflection/CEMethodInfo.bf

@@ -150,4 +150,31 @@ namespace System.Reflection
 			}
 		}
 	}
+
+	[Ordered]
+	struct ComptimeFieldInfo
+	{
+		int64 mNativeFieldInstance;
+		TypeId mOwner;
+		TypeId mTypeId;
+		int32 mFieldIdx;
+		FieldFlags mFlags;
+
+		public StringView Name
+		{
+			get
+			{
+				if (Compiler.IsComptime)
+					return Type.[Friend]Comptime_Field_GetName(mNativeFieldInstance);
+				return "?";
+			}
+		}
+
+		public Type Owner => Type.[Friend]GetType_((.)mOwner);
+		public Type FieldType => Type.[Friend]GetType_((.)mTypeId);
+		public int FieldIdx => mFieldIdx;
+		public bool IsConst => mFlags.HasFlag(.Const);
+		public bool IsStatic => mFlags.HasFlag(.Static);
+		public bool IsInstanceField => !mFlags.HasFlag(.Static) && !mFlags.HasFlag(.Const);
+	}
 }

+ 11 - 0
BeefLibs/corlib/src/Type.bf

@@ -159,6 +159,7 @@ namespace System
 					 .Int16,
 					 .Int32,
 					 .Int64,
+					 .Int,
 					 .Float,
 					 .Double:
 					return true;
@@ -483,6 +484,15 @@ namespace System
 			}
 		}
 
+		public virtual int32 BitSize
+		{
+			[Error("This property can only be accessed directly from a typeof() expression")]
+			get
+			{
+				return 0;
+			}
+		}
+
         public int32 GetTypeId()
         {
             return (int32)mTypeId;
@@ -497,6 +507,7 @@ namespace System
 		static extern int64 Comptime_GetMethod(int32 typeId, int32 methodIdx);
 		static extern String Comptime_Method_ToString(int64 methodHandle);
 		static extern String Comptime_Method_GetName(int64 methodHandle);
+		static extern String Comptime_Field_GetName(int64 fieldHandle);
 		static extern ComptimeMethodInfo.Info Comptime_Method_GetInfo(int64 methodHandle);
 		static extern ComptimeMethodInfo.ParamInfo Comptime_Method_GetParamInfo(int64 methodHandle, int32 paramIdx);
 

+ 21 - 0
IDE/mintest/minlib/src/System/Attribute.bf

@@ -1,3 +1,4 @@
+using System.Reflection;
 namespace System
 {
     public struct Attribute
@@ -495,6 +496,26 @@ namespace System
 		}
 	}
 
+	interface IOnTypeInit
+	{
+		void OnTypeInit(Type type, Self* prev) mut;
+	}
+
+	interface IOnTypeDone
+	{
+		void OnTypeDone(Type type, Self* prev) mut;
+	}
+
+	interface IOnFieldInit
+	{
+		void OnFieldInit(ComptimeFieldInfo type, Self* prev) mut;
+	}
+
+	interface IOnMethodInit
+	{
+		void OnMethodInit(ComptimeMethodInfo type, Self* prev) mut;
+	}
+
 	interface IComptimeTypeApply
 	{
 		void ApplyToType(Type type);

+ 14 - 0
IDE/mintest/minlib/src/System/Reflection/FieldInfo.bf

@@ -327,4 +327,18 @@ namespace System.Reflection
 			}
 	    }
 	}
+
+	struct ComptimeMethodInfo
+	{
+		public int64 mNativeMethodInstance;
+	}
+
+	struct ComptimeFieldInfo
+	{
+		int64 mNativeFieldInstance;
+		TypeId mOwner;
+		TypeId mTypeId;
+		int32 mFieldIdx;
+		FieldFlags mFlags;
+	}
 }

+ 14 - 0
IDEHelper/Compiler/BfCompiler.cpp

@@ -430,6 +430,11 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
 	mIHashableTypeDef = NULL;
 	mIComptimeTypeApply = NULL;
 	mIComptimeMethodApply = NULL;
+	mComptimeFieldInfoTypeDef = NULL;
+	mIOnTypeInitTypeDef = NULL;
+	mIOnTypeDoneTypeDef = NULL;
+	mIOnFieldInitTypeDef = NULL;
+	mIOnMethodInitTypeDef = NULL;
 	mLinkNameAttributeTypeDef = NULL;
 	mCallingConventionAttributeTypeDef = NULL;
 	mMethodRefTypeDef = NULL;
@@ -5007,6 +5012,9 @@ void BfCompiler::GetSymbolReferences()
 
 				if ((fieldDef->mIsConst) && (fieldDef->mInitializer != NULL))
 				{
+					BfMethodState methodState;
+					methodState.mTempKind = BfMethodState::TempKind_Static;
+					SetAndRestoreValue<BfMethodState*> prevMethodState(module->mCurMethodState, &methodState);					
 					BfConstResolver constResolver(module); 
 					constResolver.Resolve(fieldDef->mInitializer);
 				}
@@ -6825,6 +6833,12 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
 	mIHashableTypeDef = _GetRequiredType("System.IHashable");
 	mIComptimeTypeApply = _GetRequiredType("System.IComptimeTypeApply");
 	mIComptimeMethodApply = _GetRequiredType("System.IComptimeMethodApply");
+	mComptimeFieldInfoTypeDef = _GetRequiredType("System.Reflection.ComptimeFieldInfo");
+	mIOnTypeInitTypeDef = _GetRequiredType("System.IOnTypeInit");
+	mIOnTypeDoneTypeDef = _GetRequiredType("System.IOnTypeDone");
+	mIOnFieldInitTypeDef = _GetRequiredType("System.IOnFieldInit");
+	mIOnMethodInitTypeDef = _GetRequiredType("System.IOnMethodInit");
+
 	mLinkNameAttributeTypeDef = _GetRequiredType("System.LinkNameAttribute");
 	mCallingConventionAttributeTypeDef = _GetRequiredType("System.CallingConventionAttribute");
 	mMethodRefTypeDef = _GetRequiredType("System.MethodReference", 1);

+ 5 - 0
IDEHelper/Compiler/BfCompiler.h

@@ -390,6 +390,11 @@ public:
 	BfTypeDef* mIHashableTypeDef;
 	BfTypeDef* mIComptimeTypeApply;
 	BfTypeDef* mIComptimeMethodApply;
+	BfTypeDef* mComptimeFieldInfoTypeDef;
+	BfTypeDef* mIOnTypeInitTypeDef;
+	BfTypeDef* mIOnTypeDoneTypeDef;
+	BfTypeDef* mIOnFieldInitTypeDef;
+	BfTypeDef* mIOnMethodInitTypeDef;
 	
 	BfTypeDef* mMethodRefTypeDef;
 	BfTypeDef* mNullableTypeDef;

+ 19 - 1
IDEHelper/Compiler/BfContext.cpp

@@ -1684,6 +1684,24 @@ void BfContext::DeleteType(BfType* type, bool deferDepRebuilds)
 
  	BfLogSysM("Deleting Type: %p %s\n", type, mScratchModule->TypeToString(type).c_str());
 	
+	if (typeInst != NULL)
+	{
+		for (auto& methodInstGroup : typeInst->mMethodInstanceGroups)
+		{
+			if ((methodInstGroup.mDefault != NULL) && (methodInstGroup.mDefault->mInCEMachine))
+				mCompiler->mCEMachine->RemoveMethod(methodInstGroup.mDefault);
+			if (methodInstGroup.mMethodSpecializationMap != NULL)
+			{
+				for (auto& methodSpecializationItr : *methodInstGroup.mMethodSpecializationMap)
+				{
+					auto methodInstance = methodSpecializationItr.mValue;
+					if (methodInstance->mInCEMachine)
+						mCompiler->mCEMachine->RemoveMethod(methodInstance);
+				}
+			}
+		}
+	}
+
 	// All dependencies cause rebuilds when we delete types	
 	if (dType != NULL)
 	{
@@ -1775,7 +1793,7 @@ void BfContext::DeleteType(BfType* type, bool deferDepRebuilds)
 
  		for (auto dependentType : rebuildTypeQueue)
  			RebuildType(dependentType);
-	}
+	}	
 }
 
 void BfContext::UpdateAfterDeletingTypes()

+ 56 - 27
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -2296,26 +2296,8 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
 		if (mModule->mCurMethodInstance != NULL)
 			allowSpecializeFail = mModule->mCurMethodInstance->mIsUnspecialized;
 
-// 		if (mModule->mModuleName == "BeefTest_TestProgram")
-// 		{
-// 			OutputDebugStrF("?Prv: %s\n      %s\n?New: %s\n      %s\n\n", 				
-// 				mModule->MethodToString(prevMethodInstance, BfMethodNameFlag_None, &mBestMethodGenericArguments).c_str(),
-// 				mModule->MethodToString(prevMethodInstance, BfMethodNameFlag_None).c_str(),
-// 				mModule->MethodToString(methodInstance, BfMethodNameFlag_None, genericArgumentsSubstitute).c_str(),
-// 				mModule->MethodToString(methodInstance, BfMethodNameFlag_None).c_str());
-// 		}
-
 		CompareMethods(prevMethodInstance, &mBestMethodGenericArguments, methodInstance, genericArgumentsSubstitute, &isBetter, &isWorse, allowSpecializeFail);		
 
-// 		if (mModule->mModuleName == "BeefTest_TestProgram")
-// 		{
-// 			OutputDebugStrF("%sPrv: %s\n      %s\n%sNew: %s\n      %s\n\n", 				
-// 				isWorse ? "*" : " ", mModule->MethodToString(prevMethodInstance, BfMethodNameFlag_None, &mBestMethodGenericArguments).c_str(),
-// 				mModule->MethodToString(prevMethodInstance, BfMethodNameFlag_None).c_str(),
-// 				isBetter ? "*" : " ", mModule->MethodToString(methodInstance, BfMethodNameFlag_None, genericArgumentsSubstitute).c_str(),
-// 				mModule->MethodToString(methodInstance, BfMethodNameFlag_None).c_str());
-// 		}
-
 		// If we had both a 'better' and 'worse', that's ambiguous because the methods are each better in different ways (not allowed)
 		//  And if neither better nor worse then they are equally good, which is not allowed either
 		if (((!isBetter) && (!isWorse)) || ((isBetter) && (isWorse)))
@@ -7421,7 +7403,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 					argValue = mModule->Cast(refNode, argValue, underlyingType);
 				}
 				else
-					argValue = mModule->Cast(refNode, argValue, underlyingType);
+					argValue = mModule->Cast(refNode, argValue, underlyingType, ((mBfEvalExprFlags & BfEvalExprFlags_Comptime) != 0) ? BfCastFlags_WantsConst : BfCastFlags_None);
 				if (argValue)
 					argValue = mModule->ToRef(argValue, (BfRefType*)wantType);
 			}
@@ -7430,10 +7412,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 				if (mModule->mCurMethodState != NULL)
 				{
 					SetAndRestoreValue<BfScopeData*> prevScopeData(mModule->mCurMethodState->mOverrideScope, boxScopeData);
-					argValue = mModule->Cast(refNode, argValue, wantType);
+					argValue = mModule->Cast(refNode, argValue, wantType, ((mBfEvalExprFlags & BfEvalExprFlags_Comptime) != 0) ? BfCastFlags_WantsConst : BfCastFlags_None);
 				}
 				else
-					argValue = mModule->Cast(refNode, argValue, wantType);
+					argValue = mModule->Cast(refNode, argValue, wantType, ((mBfEvalExprFlags & BfEvalExprFlags_Comptime) != 0) ? BfCastFlags_WantsConst : BfCastFlags_None);
 			}
 
 			if (!argValue)
@@ -8145,10 +8127,8 @@ BfTypedValue BfExprEvaluator::CheckEnumCreation(BfAstNode* targetSrc, BfTypeInst
 						constFailed = true;
 					continue;
 				}
-				if (argValue.IsValuelessType())
-				{					
+				if (resolvedFieldType->IsValuelessType())
 					continue;
-				}
 
 				// Used receiving value?
 				if (argValue.mValue == receivingValue.mValue)
@@ -8167,7 +8147,7 @@ BfTypedValue BfExprEvaluator::CheckEnumCreation(BfAstNode* targetSrc, BfTypeInst
 				{
 					// argValue can have a value even if tuplePtr does not have a value. This can happen if we are assigning to a (void) tuple,
 					//  but we have a value that needs to be attempted to be casted to void					
-					argValue = mModule->Cast(argValues.mResolvedArgs[tupleFieldIdx].mExpression, argValue, resolvedFieldType);
+					argValue = mModule->Cast(argValues.mResolvedArgs[tupleFieldIdx].mExpression, argValue, resolvedFieldType, wantConst ? BfCastFlags_WantsConst : BfCastFlags_None);
 					if (wantConst)
 					{
 						if (!argValue.mValue.IsConst())
@@ -10777,9 +10757,55 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie
 			}
 		}
 	}
+	else if (memberName == "BitSize")
+	{
+		auto int32Type = mModule->GetPrimitiveType(BfTypeCode_Int32);
+
+		BfType* checkType = type;
+		if (checkType->IsTypedPrimitive())
+			checkType = checkType->GetUnderlyingType();
+
+		if (checkType->IsGenericParam())
+		{			
+			mResult = mModule->GetDefaultTypedValue(int32Type, false, Beefy::BfDefaultValueKind_Undef);
+			return true;			
+		}
+		
+		if ((typeInstance != NULL) && (typeInstance->IsEnum()))
+		{
+			if (typeInstance->mTypeInfoEx != NULL)
+			{
+				int64 minValue = typeInstance->mTypeInfoEx->mMinValue;
+				if (minValue < 0)
+					minValue = ~minValue;
+				int64 maxValue = typeInstance->mTypeInfoEx->mMaxValue;
+				if (maxValue < 0)
+					maxValue = ~maxValue;
+				uint64 value = (uint64)minValue | (uint64)maxValue;
+
+				int bitCount = 1;
+				if (typeInstance->mTypeInfoEx->mMinValue < 0)
+					bitCount++;
+
+				while (value >>= 1)
+					bitCount++;
+
+				mModule->AddDependency(typeInstance, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_ReadFields);
+				mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Int32, bitCount), int32Type);
+				return true;
+			}
+		}
+
+		int bitSize = checkType->mSize * 8;
+		if (checkType->GetTypeCode() == BfTypeCode_Boolean)
+			bitSize = 1;
+		mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Int32, bitSize), int32Type);
+		return true;
+	}
 	else if ((memberName == "MinValue") || (memberName == "MaxValue"))
 	{
 		bool isMin = memberName == "MinValue";
+		bool isBitSize = memberName == "BitSize";
 		
 		BfType* checkType = type;
 		if (checkType->IsTypedPrimitive())
@@ -10833,6 +10859,7 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie
 			{
 				if (typeInstance->mTypeInfoEx != NULL)
 				{
+					mModule->AddDependency(typeInstance, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_ReadFields);
 					mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(primType->mTypeDef->mTypeCode, isMin ? (uint64)typeInstance->mTypeInfoEx->mMinValue : (uint64)typeInstance->mTypeInfoEx->mMaxValue), typeInstance);
 					return true;
 				}
@@ -20693,7 +20720,7 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
 			else if (!CheckModifyResult(mResult, unaryOpExpr, "take address of", false, true))
 			{
 				if (!mResult.IsAddr())
-					mResult = mModule->MakeAddressable(mResult);
+					mResult = mModule->MakeAddressable(mResult, false, true);
 				mResult = BfTypedValue(mResult.mValue, ptrType, false);
 			}
 			else
@@ -21409,7 +21436,9 @@ void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExp
 		ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval);
 
 		mResult = BfTypedValue(alloca, allocType, true);
-		MatchConstructor(opToken, NULL, mResult, allocType, argValues, true, false);
+		auto result = MatchConstructor(opToken, NULL, mResult, allocType, argValues, true, false);
+		if ((result) && (!result.mType->IsVoid()))
+			mResult = result;
 
 		return;
 	}

+ 50 - 10
IDEHelper/Compiler/BfIRBuilder.cpp

@@ -1001,13 +1001,23 @@ bool BfIRConstHolder::WriteConstant(BfIRValue val, void* ptr, BfType* type)
 					return false;
 			}
 
-			for (auto& fieldInstance : typeInst->mFieldInstances)
+			if (typeInst->IsUnion())
 			{
-				if (fieldInstance.mDataOffset < 0)
-					continue;				
-				if (!WriteConstant(aggConstant->mValues[fieldInstance.mDataIdx], (uint8*)ptr + fieldInstance.mDataOffset, fieldInstance.mResolvedType))
+				auto innerType = typeInst->GetUnionInnerType();
+				if (!WriteConstant(aggConstant->mValues[1], (uint8*)ptr, innerType))
 					return false;
 			}
+
+			if ((!typeInst->IsUnion()) || (typeInst->IsPayloadEnum()))
+			{
+				for (auto& fieldInstance : typeInst->mFieldInstances)
+				{
+					if (fieldInstance.mDataOffset < 0)
+						continue;
+					if (!WriteConstant(aggConstant->mValues[fieldInstance.mDataIdx], (uint8*)ptr + fieldInstance.mDataOffset, fieldInstance.mResolvedType))
+						return false;
+				}
+			}
 		}
 		return true;
 	}
@@ -1110,15 +1120,27 @@ BfIRValue BfIRConstHolder::ReadConstant(void* ptr, BfType* type)
 			irValues.Add(val);
 		}
 
-		for (auto& fieldInstance : typeInst->mFieldInstances)
+		if (typeInst->IsUnion())
 		{
-			if (fieldInstance.mDataOffset < 0)
-				continue;
-			auto val = ReadConstant((uint8*)ptr + fieldInstance.mDataOffset, fieldInstance.mResolvedType);
+			auto innerType = typeInst->GetUnionInnerType();
+			auto val = ReadConstant(ptr, innerType);
 			if (!val)
 				return BfIRValue();
 			irValues.Add(val);
 		}
+
+		if ((!typeInst->IsUnion()) || (typeInst->IsPayloadEnum()))
+		{
+			for (auto& fieldInstance : typeInst->mFieldInstances)
+			{
+				if (fieldInstance.mDataOffset < 0)
+					continue;
+				auto val = ReadConstant((uint8*)ptr + fieldInstance.mDataOffset, fieldInstance.mResolvedType);
+				if (!val)
+					return BfIRValue();
+				irValues.Add(val);
+			}
+		}
 		BfIRType irType;
 		irType.mKind = BfIRTypeData::TypeKind_TypeId;
 		irType.mId = type->mTypeId;
@@ -1656,6 +1678,15 @@ String BfIRBuilder::ToString(BfIRValue irValue)
 		{
 			return ToString(constant->mIRType) + " zeroinitializer";
 		}
+		else if (constant->mConstType == BfConstType_AggCE)
+		{
+			auto constAgg = (BfConstantAggCE*)constant;
+			return ToString(constAgg->mType) + StrFormat(" aggCe@%p", constAgg->mCEAddr);
+		}
+		else if (constant->mConstType == BfConstType_ArrayZero8)
+		{
+			return StrFormat("zero8[%d]", constant->mInt32);
+		}
 		else if (constant->mConstType == BfConstType_TypeOf)
 		{
 			auto typeofConst = (BfTypeOf_Const*)constant;
@@ -1666,6 +1697,7 @@ String BfIRBuilder::ToString(BfIRValue irValue)
 			auto typeofConst = (BfTypeOf_WithData_Const*)constant;
 			return "typeof_withData " + mModule->TypeToString(typeofConst->mType);
 		}
+
 		else
 		{
 			BF_FATAL("Unhandled");
@@ -1783,7 +1815,15 @@ String BfIRBuilder::ToString(BfIRType irType)
 	}
 	else if (irType.mKind == BfIRTypeData::TypeKind_TypeId)
 	{
-		return StrFormat("Type Id %d (%s)", irType.mId, mModule->TypeToString(mModule->mContext->mTypes[irType.mId]).c_str());
+		return StrFormat("Type#%d:%s", irType.mId, mModule->TypeToString(mModule->mContext->mTypes[irType.mId]).c_str());
+	}
+	else if (irType.mKind == BfIRTypeData::TypeKind_TypeInstId)
+	{
+		return StrFormat("TypeInst#%d:%s", irType.mId, mModule->TypeToString(mModule->mContext->mTypes[irType.mId]).c_str());
+	}
+	else if (irType.mKind == BfIRTypeData::TypeKind_TypeInstPtrId)
+	{
+		return StrFormat("TypeInstPtr#%d:%s", irType.mId, mModule->TypeToString(mModule->mContext->mTypes[irType.mId]).c_str());
 	}
 	else
 	{
@@ -3940,7 +3980,7 @@ BfIRType BfIRBuilder::MapTypeInst(BfTypeInstance* typeInst, BfIRPopulateType pop
 		PopulateType(typeInst, populateType);
 	}
 
-	if (!mIgnoreWrites)
+	if ((!mIgnoreWrites) && (populateType != BfIRPopulateType_Identity))
 		BF_ASSERT(mTypeMap.ContainsKey(typeInst));
 	BfIRType retType;
 	retType.mKind = BfIRType::TypeKind_TypeInstId;

+ 63 - 60
IDEHelper/Compiler/BfModule.cpp

@@ -6477,19 +6477,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 		}		
 	}
 		
-	SizedArray<BfIRValue, 16> fieldTypes;
-
-	enum FieldFlags
-	{
-		FieldFlags_Protected = 3,
-		FieldFlags_Public = 6,
-		FieldFlags_Static = 0x10,
-		FieldFlags_Const = 0x40,
-		FieldFlags_SpecialName = 0x80,
-		FieldFlags_EnumPayload = 0x100,
-		FieldFlags_EnumDiscriminator = 0x200,
-		FieldFlags_EnumCase = 0x400
-	};
+	SizedArray<BfIRValue, 16> fieldTypes;	
 
 	bool is32Bit = mCompiler->mSystem->mPtrSize == 4;
 
@@ -6509,7 +6497,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 					GetConstValue(payloadType->mTypeId, typeIdType), // mFieldTypeId
 					GetConstValue(0, intPtrType), // mData
 					GetConstValue(0, intPtrType), // mDataHi
-					GetConstValue(FieldFlags_SpecialName | FieldFlags_EnumPayload, shortType), // mFlags
+					GetConstValue(BfFieldFlags_SpecialName | BfFieldFlags_EnumPayload, shortType), // mFlags
 					GetConstValue(-1, intType), // mCustomAttributesIdx
 				};
 			}
@@ -6521,7 +6509,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 					payloadNameConst, // mName
 					GetConstValue(payloadType->mTypeId, typeIdType), // mFieldTypeId
 					GetConstValue(0, intPtrType), // mData					
-					GetConstValue(FieldFlags_SpecialName | FieldFlags_EnumPayload, shortType), // mFlags
+					GetConstValue(BfFieldFlags_SpecialName | BfFieldFlags_EnumPayload, shortType), // mFlags
 					GetConstValue(-1, intType), // mCustomAttributesIdx
 				};
 			}
@@ -6542,7 +6530,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 				GetConstValue(dscrType->mTypeId, typeIdType), // mFieldTypeId
 				GetConstValue(BF_ALIGN(payloadType->mSize, dscrType->mAlign), intPtrType), // mData
 				GetConstValue(0, intPtrType), // mDataHi
-				GetConstValue(FieldFlags_SpecialName | FieldFlags_EnumDiscriminator, shortType), // mFlags
+				GetConstValue(BfFieldFlags_SpecialName | BfFieldFlags_EnumDiscriminator, shortType), // mFlags
 				GetConstValue(-1, intType), // mCustomAttributesIdx
 			};
 		}
@@ -6554,7 +6542,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 				dscrNameConst, // mName	
 				GetConstValue(dscrType->mTypeId, typeIdType), // mFieldTypeId
 				GetConstValue(BF_ALIGN(payloadType->mSize, dscrType->mAlign), intPtrType), // mData
-				GetConstValue(FieldFlags_SpecialName | FieldFlags_EnumDiscriminator, shortType), // mFlags
+				GetConstValue(BfFieldFlags_SpecialName | BfFieldFlags_EnumDiscriminator, shortType), // mFlags
 				GetConstValue(-1, intType), // mCustomAttributesIdx
 			};
 		}
@@ -6581,18 +6569,18 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
 		else
 			typeId = fieldType->mTypeId;		
 
-		FieldFlags fieldFlags = (FieldFlags)0;
+		BfFieldFlags fieldFlags = (BfFieldFlags)0;
 
 		if (fieldDef->mProtection == BfProtection_Protected)
-			fieldFlags = (FieldFlags)(fieldFlags | FieldFlags_Protected);
+			fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_Protected);
 		if (fieldDef->mProtection == BfProtection_Public)
-			fieldFlags = (FieldFlags)(fieldFlags | FieldFlags_Public);
+			fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_Public);
 		if (fieldDef->mIsStatic)
-			fieldFlags = (FieldFlags)(fieldFlags | FieldFlags_Static);
+			fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_Static);
 		if (fieldDef->mIsConst)
-			fieldFlags = (FieldFlags)(fieldFlags | FieldFlags_Const);
+			fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_Const);
 		if (fieldDef->IsEnumCaseEntry())
-			fieldFlags = (FieldFlags)(fieldFlags | FieldFlags_EnumCase);
+			fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_EnumCase);
 
 		int customAttrIdx = _HandleCustomAttrs(fieldInstance->mCustomAttributes);
 		BfIRValue constValue;
@@ -11319,7 +11307,7 @@ BfIRValue BfModule::ConstantToCurrent(BfConstant* constant, BfIRConstHolder* con
 			{
 				newVals.Add(ConstantToCurrent(constHolder->GetConstant(val), constHolder, elementType));
 			}
-		}
+		}		
 		else
 		{
 			auto wantTypeInst = wantType->ToTypeInstance();
@@ -11329,19 +11317,32 @@ BfIRValue BfModule::ConstantToCurrent(BfConstant* constant, BfIRConstHolder* con
 				newVals.Add(baseVal);
 			}
 
-			for (auto& fieldInstance : wantTypeInst->mFieldInstances)
+			if (wantType->IsUnion())
 			{
-				if (fieldInstance.mDataIdx < 0)
-					continue;				
-				auto val = constArray->mValues[fieldInstance.mDataIdx];
-				BfIRValue memberVal = ConstantToCurrent(constHolder->GetConstant(val), constHolder, fieldInstance.mResolvedType);
-				if (fieldInstance.mDataIdx == newVals.mSize)
-					newVals.Add(memberVal);
-				else
+				auto innerType = wantType->ToTypeInstance()->GetUnionInnerType();
+				if (!innerType->IsValuelessType())
 				{
-					while (fieldInstance.mDataIdx >= newVals.mSize)
-						newVals.Add(BfIRValue());
-					newVals[fieldInstance.mDataIdx] = memberVal;
+					auto val = ConstantToCurrent(constHolder->GetConstant(constArray->mValues[1]), constHolder, innerType);
+					newVals.Add(val);
+				}
+			}
+
+			if ((!wantType->IsUnion()) || (wantType->IsPayloadEnum()))
+			{
+				for (auto& fieldInstance : wantTypeInst->mFieldInstances)
+				{
+					if (fieldInstance.mDataIdx < 0)
+						continue;
+					auto val = constArray->mValues[fieldInstance.mDataIdx];
+					BfIRValue memberVal = ConstantToCurrent(constHolder->GetConstant(val), constHolder, fieldInstance.mResolvedType);
+					if (fieldInstance.mDataIdx == newVals.mSize)
+						newVals.Add(memberVal);
+					else
+					{
+						while (fieldInstance.mDataIdx >= newVals.mSize)
+							newVals.Add(BfIRValue());
+						newVals[fieldInstance.mDataIdx] = memberVal;
+					}
 				}
 			}
 
@@ -11539,7 +11540,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 		BfConstResolver constResolver(this);
 		if (allowNonConstArgs)
 			constResolver.mBfEvalExprFlags = (BfEvalExprFlags)(constResolver.mBfEvalExprFlags | BfEvalExprFlags_AllowNonConst);
-				
+
 		bool inPropSet = false;
 		SizedArray<BfResolvedArg, 2> argValues;
 		for (BfExpression* arg : attributesDirective->mArguments)
@@ -11743,6 +11744,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri
 		}			
 					
 		BfMethodMatcher methodMatcher(attributesDirective, this, "", argValues, BfMethodGenericArguments());
+		methodMatcher.mBfEvalExprFlags = constResolver.mBfEvalExprFlags;
 		attrTypeDef = attrTypeInst->mTypeDef;
 
 		bool success = true;
@@ -12969,6 +12971,7 @@ bool BfModule::IsCompatibleInterfaceMethod(BfMethodInstance* iMethodInst, BfMeth
 	if (iMethodInst->GetParamCount() != methodInstance->GetParamCount())
 		return false;	
 
+	auto selfType = methodInstance->GetOwner();
 	for (int paramIdx = 0; paramIdx < (int)iMethodInst->GetParamCount(); paramIdx++)
 	{
 		if (iMethodInst->GetParamKind(paramIdx) != methodInstance->GetParamKind(paramIdx))
@@ -12977,12 +12980,10 @@ bool BfModule::IsCompatibleInterfaceMethod(BfMethodInstance* iMethodInst, BfMeth
 		BfType* iParamType = iMethodInst->GetParamType(paramIdx);
 		BfType* methodParamType = methodInstance->GetParamType(paramIdx);
 
-		if (iParamType->IsSelf())
-		{
-			if (methodParamType != methodInstance->GetOwner())
-				return false;
-		}
-		else if (!iParamType->IsGenericParam())
+		iParamType = ResolveSelfType(iParamType, selfType);
+		methodParamType = ResolveSelfType(methodParamType, selfType);
+
+		if (!iParamType->IsGenericParam())
 		{
 			if (methodParamType != iParamType)
 				return false;
@@ -13730,6 +13731,9 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM
 					// We haven't processed it yet
 					_SetReified();
 					CheckHotMethod(methodInstance, "");
+
+					if (methodInstance->mMethodProcessRequest == NULL)
+						AddMethodToWorkList(methodInstance);
 				}
 			}
 		}
@@ -24120,28 +24124,27 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo
 			if (iMethodInst->mMethodDef->mName == methodInstance->mMethodDef->mName)
 				hadNameMatch = iMethodInst;
 
-			bool doesMethodSignatureMatch = CompareMethodSignatures(iMethodInst, methodInstance);
-				
+			bool doesMethodSignatureMatch = CompareMethodSignatures(iMethodInst, methodInstance);			
 			if ((!doesMethodSignatureMatch) && (iMethodInst->GetNumGenericParams() == 0) && (interfaceMethodEntry->mMethodRef.IsNull()))
 			{
 				doesMethodSignatureMatch = IsCompatibleInterfaceMethod(iMethodInst, methodInstance);
 			}
 
- 			if ((doesMethodSignatureMatch) && (methodInstance->GetOwner()->IsValueType()))
- 			{
- 				if ((!iMethodInst->mMethodDef->mIsMutating) && (methodInstance->mMethodDef->mIsMutating))
- 				{
- 					if ((methodInstance->mMethodInfoEx != NULL) && (methodInstance->mMethodInfoEx->mExplicitInterface == ifaceInst))
- 					{						
- 						auto error = mCompiler->mPassInstance->Fail(StrFormat("Implementation method '%s' cannot specify 'mut' because the interface method does not allow it",
- 							MethodToString(methodInstance).c_str()), methodInstance->mMethodDef->GetMutNode());
- 						if (error != NULL)
- 							mCompiler->mPassInstance->MoreInfo(StrFormat("Declare the interface method as 'mut' to allow matching 'mut' implementations"), iMethodInst->mMethodDef->mMethodDeclaration);
- 						showedError = true;						
- 					}
- 				}
- 			}
-						
+			if ((doesMethodSignatureMatch) && (methodInstance->GetOwner()->IsValueType()))
+			{
+				if ((!iMethodInst->mMethodDef->mIsMutating) && (methodInstance->mMethodDef->mIsMutating))
+				{
+					if ((methodInstance->mMethodInfoEx != NULL) && (methodInstance->mMethodInfoEx->mExplicitInterface == ifaceInst))
+					{
+						auto error = mCompiler->mPassInstance->Fail(StrFormat("Implementation method '%s' cannot specify 'mut' because the interface method does not allow it",
+							MethodToString(methodInstance).c_str()), methodInstance->mMethodDef->GetMutNode());
+						if (error != NULL)
+							mCompiler->mPassInstance->MoreInfo(StrFormat("Declare the interface method as 'mut' to allow matching 'mut' implementations"), iMethodInst->mMethodDef->mMethodDeclaration);
+						showedError = true;
+					}
+				}
+			}
+			 									
 			if (doesMethodSignatureMatch)
 			{										
 				usedMethod = true;
@@ -24455,7 +24458,7 @@ void BfModule::DbgFinish()
 	BfIRValue linkMarker;
 	
 	if (mBfIRBuilder->DbgHasInfo())
-	{		
+	{
 		bool needForceLinking = false;
 		for (auto& ownedType : mOwnedTypeInstances)
 		{

+ 3 - 2
IDEHelper/Compiler/BfModule.h

@@ -102,7 +102,8 @@ enum BfCastFlags
 	BfCastFlags_PreferAddr = 0x400,
 	BfCastFlags_WarnOnBox = 0x800,
 	BfCastFlags_IsCastCheck = 0x1000,
-	BfCastFlags_IsConstraintCheck = 0x2000,	
+	BfCastFlags_IsConstraintCheck = 0x2000,
+	BfCastFlags_WantsConst = 0x4000
 };
 
 enum BfCastResultFlags
@@ -1762,7 +1763,7 @@ public:
 	void FinishCEParseContext(BfAstNode* refNode, BfTypeInstance* typeInstance, BfCEParseContext* ceParseContext);
 	BfCEParseContext CEEmitParse(BfTypeInstance* typeInstance, const StringImpl& src);
 	void UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, const StringImpl& ctxString, BfAstNode* refNode);
-	void HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCustomAttributes* customAttributes, HashSet<BfTypeInstance*> foundAttributes, bool underlyingTypeDeferred);
+	void HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfFieldInstance* fieldInstance, BfCustomAttributes* customAttributes, Dictionary<BfTypeInstance*, BfIRValue>& foundAttributes, bool underlyingTypeDeferred);
 	void CEMixin(BfAstNode* refNode, const StringImpl& src);
 	void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred);
 	void DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers, bool underlyingTypeDeferred);

+ 322 - 191
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -2139,96 +2139,181 @@ void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeIn
 	}
 }
 
-void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCustomAttributes* customAttributes, HashSet<BfTypeInstance*> foundAttributes, bool underlyingTypeDeferred)
+void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfFieldInstance* fieldInstance, BfCustomAttributes* customAttributes, Dictionary<BfTypeInstance*, BfIRValue>& prevAttrInstances, bool underlyingTypeDeferred)
 {
-	BfTypeInstance* iComptimeTypeApply = NULL;
 	for (auto& customAttribute : customAttributes->mAttributes)
 	{			
 		auto attrType = customAttribute.mType;
-		mContext->mUnreifiedModule->PopulateType(attrType, BfPopulateType_DataAndMethods);
-		if (attrType->mDefineState < BfTypeDefineState_DefinedAndMethodsSlotted)
-			continue;
+		
+		BfMethodInstance* methodInstance = NULL;
+		bool isFieldApply = false;
+		BfIRValue irValue;
+		int checkDepth = 0;
+		auto checkAttrType = attrType;
+		while (checkAttrType != NULL)
+		{
+			mContext->mUnreifiedModule->PopulateType(checkAttrType, BfPopulateType_DataAndMethods);
+			if (checkAttrType->mDefineState < BfTypeDefineState_DefinedAndMethodsSlotted)
+				break;
 
-		for (auto& ifaceEntry : attrType->mInterfaces)
-		{
-			if (iComptimeTypeApply == NULL)
-				iComptimeTypeApply = ResolveTypeDef(mCompiler->mIComptimeTypeApply)->ToTypeInstance();
-			if (ifaceEntry.mInterfaceType != iComptimeTypeApply)
-				continue;
+			for (auto& ifaceEntry : checkAttrType->mInterfaces)
+			{
+				isFieldApply = false;
+				isFieldApply = (ceEmitContext != NULL) && (ifaceEntry.mInterfaceType->IsInstanceOf(mCompiler->mIOnFieldInitTypeDef));
+				
+				if ((isFieldApply) ||
+					((ceEmitContext != NULL) && (ifaceEntry.mInterfaceType->IsInstanceOf(mCompiler->mIComptimeTypeApply))) ||
+					((ceEmitContext != NULL) && (ifaceEntry.mInterfaceType->IsInstanceOf(mCompiler->mIOnTypeInitTypeDef))) ||
+					((ceEmitContext == NULL) && (ifaceEntry.mInterfaceType->IsInstanceOf(mCompiler->mIOnTypeDoneTypeDef))))
+				{
+					 // Passes
+				}
+				else				
+					continue;
+
+				prevAttrInstances.TryGetValue(checkAttrType, &irValue);
+				methodInstance = checkAttrType->mInterfaceMethodTable[ifaceEntry.mStartInterfaceTableIdx].mMethodRef;
+				break;
+			}
+			if (methodInstance != NULL)
+				break;
 
-			if (!foundAttributes.Add(attrType))
-				continue;						
+			checkAttrType = checkAttrType->mBaseType;
+			checkDepth++;
+		}
 
-			BfMethodInstance* methodInstance = attrType->mInterfaceMethodTable[ifaceEntry.mStartInterfaceTableIdx].mMethodRef;
-			if (methodInstance == NULL)
-				continue;
+		if (methodInstance == NULL)
+			continue;
 
-			SetAndRestoreValue<CeEmitContext*> prevEmitContext(mCompiler->mCEMachine->mCurEmitContext, ceEmitContext);
-			auto ceContext = mCompiler->mCEMachine->AllocContext();
+		SetAndRestoreValue<CeEmitContext*> prevEmitContext(mCompiler->mCEMachine->mCurEmitContext, ceEmitContext);
+		auto ceContext = mCompiler->mCEMachine->AllocContext();
 			
-			BfIRValue attrVal = ceContext->CreateAttribute(customAttribute.mRef, this, typeInstance->mConstHolder, &customAttribute);
+		BfIRValue attrVal = ceContext->CreateAttribute(customAttribute.mRef, this, typeInstance->mConstHolder, &customAttribute);
+		for (int baseIdx = 0; baseIdx < checkDepth; baseIdx++)
+			attrVal = mBfIRBuilder->CreateExtractValue(attrVal, 0);
 
-			SizedArray<BfIRValue, 1> args;
-			if (!attrType->IsValuelessType())
-				args.Add(attrVal);
+		SizedArray<BfIRValue, 1> args;
+		if (!attrType->IsValuelessType())
+			args.Add(attrVal);
+		if (isFieldApply)
+		{
+			auto fieldDef = fieldInstance->GetFieldDef();
+			BfFieldFlags fieldFlags = (BfFieldFlags)0;
+
+			if (fieldDef->mProtection == BfProtection_Protected)
+				fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_Protected);
+			if (fieldDef->mProtection == BfProtection_Public)
+				fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_Public);
+			if (fieldDef->mIsStatic)
+				fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_Static);
+			if (fieldDef->mIsConst)
+				fieldFlags = (BfFieldFlags)(fieldFlags | BfFieldFlags_Const);
+
+			auto fieldInfoType = ResolveTypeDef(mCompiler->mComptimeFieldInfoTypeDef);
+			if (fieldInfoType != NULL)
+			{
+				SizedArray<BfIRValue, 9> fieldData =
+				{			
+					mBfIRBuilder->CreateConstAggZero(mBfIRBuilder->MapType(fieldInfoType, BfIRPopulateType_Identity)),
+					GetConstValue((uint64)(intptr)fieldInstance, GetPrimitiveType(BfTypeCode_Int64)), // mNativeFieldInstance
+					GetConstValue(typeInstance->mTypeId, GetPrimitiveType(BfTypeCode_Int32)), // mOwner
+					GetConstValue((fieldInstance->mResolvedType != NULL) ? fieldInstance->mResolvedType->mTypeId : 0, GetPrimitiveType(BfTypeCode_Int32)), // mTypeId
+					GetConstValue(fieldDef->mIdx, GetPrimitiveType(BfTypeCode_Int32)), // mFieldIdx
+					GetConstValue((int)fieldFlags, GetPrimitiveType(BfTypeCode_Int16)), // mFieldFlags
+				};				
+				FixConstValueParams(fieldInfoType->ToTypeInstance(), fieldData);
+				auto fieldDataAgg = mBfIRBuilder->CreateConstAgg(mBfIRBuilder->MapType(fieldInfoType, BfIRPopulateType_Identity), fieldData);
+				args.Add(fieldDataAgg);
+			}
+		}
+		else
 			args.Add(mBfIRBuilder->CreateTypeOf(typeInstance));
 
-			DoPopulateType_CeCheckEnum(typeInstance, underlyingTypeDeferred);
-			auto result = ceContext->Call(customAttribute.mRef, this, methodInstance, args, CeEvalFlags_None, NULL);
+		if (methodInstance->GetParamCount() > 1)
+		{
+			if (irValue)
+				args.Add(irValue);
+			else
+				args.Add(mBfIRBuilder->CreateConstNull());
+		}
+		else
+		{
+			// Only allow a single instance
+			if (irValue)
+				continue;
+		}
 
-			if (typeInstance->mDefineState == BfTypeDefineState_DefinedAndMethodsSlotted)
-				return;
+		DoPopulateType_CeCheckEnum(typeInstance, underlyingTypeDeferred);			
+		if (fieldInstance != NULL)
+			mCompiler->mCEMachine->mFieldInstanceSet.Add(fieldInstance);
+		BfTypedValue result;
+		///
+		{
+			SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true);
+			result = ceContext->Call(customAttribute.mRef, this, methodInstance, args, CeEvalFlags_ForceReturnThis, NULL);
+		}
+		if (fieldInstance != NULL)
+			mCompiler->mCEMachine->mFieldInstanceSet.Remove(fieldInstance);
+		if (result.mType == methodInstance->GetOwner())
+			prevAttrInstances[methodInstance->GetOwner()] = result.mValue;
 
-			if (typeInstance->mDefineState != BfTypeDefineState_CETypeInit)
-			{
-				// We populated before we could finish
-				AssertErrorState();
-			}
-			else
+		if (ceEmitContext == NULL)
+			continue;
+
+		if (typeInstance->mDefineState == BfTypeDefineState_DefinedAndMethodsSlotted)
+			return;		
+
+		if (typeInstance->mDefineState != BfTypeDefineState_CETypeInit)
+		{
+			// We populated before we could finish
+			AssertErrorState();
+		}
+		else
+		{
+			auto owner = methodInstance->GetOwner();
+			int typeId = owner->mTypeId;
+			if ((!result) && (mCompiler->mFastFinish))
 			{
-				auto owner = methodInstance->GetOwner();
-				int typeId = owner->mTypeId;
-				if ((!result) && (mCompiler->mFastFinish))
+				if ((typeInstance->mCeTypeInfo != NULL) && (typeInstance->mCeTypeInfo->mNext == NULL))
+					typeInstance->mCeTypeInfo->mNext = new BfCeTypeInfo();
+				if ((typeInstance->mCeTypeInfo != NULL) && (typeInstance->mCeTypeInfo->mNext != NULL))
+					typeInstance->mCeTypeInfo->mNext->mFailed = true;
+				if (typeInstance->mCeTypeInfo != NULL)
 				{
-					if ((typeInstance->mCeTypeInfo != NULL) && (typeInstance->mCeTypeInfo->mNext == NULL))
-						typeInstance->mCeTypeInfo->mNext = new BfCeTypeInfo();
-					if ((typeInstance->mCeTypeInfo != NULL) && (typeInstance->mCeTypeInfo->mNext != NULL))
-						typeInstance->mCeTypeInfo->mNext->mFailed = true;
-					if (typeInstance->mCeTypeInfo != NULL)
+					BfCeTypeEmitEntry* entry = NULL;
+					if (typeInstance->mCeTypeInfo->mTypeIFaceMap.TryGetValue(typeId, &entry))
 					{
-						BfCeTypeEmitEntry* entry = NULL;
-						if (typeInstance->mCeTypeInfo->mTypeIFaceMap.TryGetValue(typeId, &entry))
-						{
-							ceEmitContext->mEmitData = entry->mEmitData;
-						}
+						ceEmitContext->mEmitData = entry->mEmitData;
 					}
 				}
-				else if (ceEmitContext->HasEmissions())
-				{
-					if (typeInstance->mCeTypeInfo == NULL)
-						typeInstance->mCeTypeInfo = new BfCeTypeInfo();
-					if (typeInstance->mCeTypeInfo->mNext == NULL)
-						typeInstance->mCeTypeInfo->mNext = new BfCeTypeInfo();
-
-					BfCeTypeEmitEntry entry;
-					entry.mEmitData = ceEmitContext->mEmitData;
-					typeInstance->mCeTypeInfo->mNext->mTypeIFaceMap[typeId] = entry;
-				}
+			}
+			else if (ceEmitContext->HasEmissions())
+			{
+				if (typeInstance->mCeTypeInfo == NULL)
+					typeInstance->mCeTypeInfo = new BfCeTypeInfo();
+				if (typeInstance->mCeTypeInfo->mNext == NULL)
+					typeInstance->mCeTypeInfo->mNext = new BfCeTypeInfo();
 
-				if ((ceEmitContext->HasEmissions()) && (!mCompiler->mFastFinish))
-				{
-					String ctxStr = "comptime ApplyToType of ";
-					ctxStr += TypeToString(attrType);
-					ctxStr += " to ";
-					ctxStr += TypeToString(typeInstance);
-					ctxStr += " ";
-					ctxStr += customAttribute.mRef->LocationToString();
-					UpdateCEEmit(ceEmitContext, typeInstance, ctxStr, customAttribute.mRef);
-				}
+				BfCeTypeEmitEntry entry;
+				entry.mEmitData = ceEmitContext->mEmitData;
+				typeInstance->mCeTypeInfo->mNext->mTypeIFaceMap[typeId] = entry;
 			}
 
-			mCompiler->mCEMachine->ReleaseContext(ceContext);
+			if ((ceEmitContext->HasEmissions()) && (!mCompiler->mFastFinish))
+			{
+				String ctxStr = "comptime ";
+				ctxStr += methodInstance->mMethodDef->mName;
+				ctxStr += " of ";
+				ctxStr += TypeToString(attrType);
+				ctxStr += " to ";
+				ctxStr += TypeToString(typeInstance);
+				ctxStr += " ";
+				ctxStr += customAttribute.mRef->LocationToString();
+				UpdateCEEmit(ceEmitContext, typeInstance, ctxStr, customAttribute.mRef);
+			}
 		}
+
+		mCompiler->mCEMachine->ReleaseContext(ceContext);					
 	}
 }
 
@@ -2306,16 +2391,17 @@ void BfModule::CEMixin(BfAstNode* refNode, const StringImpl& code)
 
 void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred)
 {			
-	HashSet<BfTypeInstance*> foundAttributes;
+	Dictionary<BfTypeInstance*, BfIRValue> prevAttrInstances;
+	
+	if (typeInstance->mCustomAttributes != NULL)
+		HandleCEAttributes(ceEmitContext, typeInstance, NULL, typeInstance->mCustomAttributes, prevAttrInstances, underlyingTypeDeferred);
+
 	if (ceEmitContext != NULL)
 	{
-		if (typeInstance->mCustomAttributes != NULL)
-			HandleCEAttributes(ceEmitContext, typeInstance, typeInstance->mCustomAttributes, foundAttributes, underlyingTypeDeferred);
-
 		for (auto& fieldInstance : typeInstance->mFieldInstances)
 		{
 			if (fieldInstance.mCustomAttributes != NULL)
-				HandleCEAttributes(ceEmitContext, typeInstance, fieldInstance.mCustomAttributes, foundAttributes, underlyingTypeDeferred);
+				HandleCEAttributes(ceEmitContext, typeInstance, &fieldInstance, fieldInstance.mCustomAttributes, prevAttrInstances, underlyingTypeDeferred);
 		}
 	}	
 
@@ -2357,7 +2443,7 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance*
 		if (onCompileAttribute == NULL)
 			continue;
 
-		HandleCEAttributes(ceEmitContext, typeInstance, customAttributes, foundAttributes, underlyingTypeDeferred);
+		HandleCEAttributes(ceEmitContext, typeInstance, NULL, customAttributes, prevAttrInstances, underlyingTypeDeferred);
 
 		if (onCompileAttribute->mCtorArgs.size() < 1)
 			continue;
@@ -2477,114 +2563,155 @@ void BfModule::DoCEEmit(BfMethodInstance* methodInstance)
 
 	CeEmitContext ceEmitContext;
 	ceEmitContext.mMethodInstance = methodInstance;
+	
+	Dictionary<BfTypeInstance*, BfIRValue> prevAttrInstances;
 
-	BfTypeInstance* iComptimeMethodApply = NULL;
 	for (auto& customAttribute : customAttributes->mAttributes)
 	{
 		auto attrType = customAttribute.mType;
-		mContext->mUnreifiedModule->PopulateType(attrType, BfPopulateType_DataAndMethods);
-		if (attrType->mDefineState < BfTypeDefineState_DefinedAndMethodsSlotted)
-			continue;
+		
+		BfMethodInstance* applyMethodInstance = NULL;
+		BfIRValue irValue;
+		int checkDepth = 0;
+		auto checkAttrType = attrType;
 
-		for (auto& ifaceEntry : attrType->mInterfaces)
+		while (checkAttrType != NULL)
 		{
-			if (iComptimeMethodApply == NULL)
-				iComptimeMethodApply = ResolveTypeDef(mCompiler->mIComptimeMethodApply)->ToTypeInstance();
-			if (ifaceEntry.mInterfaceType != iComptimeMethodApply)
-				continue;
+			mContext->mUnreifiedModule->PopulateType(checkAttrType, BfPopulateType_DataAndMethods);
+			if (checkAttrType->mDefineState < BfTypeDefineState_DefinedAndMethodsSlotted)
+				break;
 
-// 			if (!foundAttributes.Add(attrType))
-// 				continue;
+			for (auto& ifaceEntry : checkAttrType->mInterfaces)
+			{
+				if ((!ifaceEntry.mInterfaceType->IsInstanceOf(mCompiler->mIComptimeMethodApply)) &&
+					(!ifaceEntry.mInterfaceType->IsInstanceOf(mCompiler->mIOnMethodInitTypeDef)))
+					continue;
 
-			BfMethodInstance* applyMethodInstance = attrType->mInterfaceMethodTable[ifaceEntry.mStartInterfaceTableIdx].mMethodRef;
-			if (applyMethodInstance == NULL)
-				continue;
+				prevAttrInstances.TryGetValue(checkAttrType, &irValue);
+				applyMethodInstance = checkAttrType->mInterfaceMethodTable[ifaceEntry.mStartInterfaceTableIdx].mMethodRef;
+				break;
+			}
+
+			if (applyMethodInstance != NULL)
+				break;
+
+			checkAttrType = checkAttrType->mBaseType;
+			checkDepth++;
+		}
+
+		if (applyMethodInstance == NULL)
+			continue;					
 
-			SetAndRestoreValue<CeEmitContext*> prevEmitContext(mCompiler->mCEMachine->mCurEmitContext, &ceEmitContext);
-			auto ceContext = mCompiler->mCEMachine->AllocContext();
+		SetAndRestoreValue<CeEmitContext*> prevEmitContext(mCompiler->mCEMachine->mCurEmitContext, &ceEmitContext);
+		auto ceContext = mCompiler->mCEMachine->AllocContext();
 
-			BfIRValue attrVal = ceContext->CreateAttribute(customAttribute.mRef, this, typeInstance->mConstHolder, &customAttribute);
+		BfIRValue attrVal = ceContext->CreateAttribute(customAttribute.mRef, this, typeInstance->mConstHolder, &customAttribute);
+		for (int baseIdx = 0; baseIdx < checkDepth; baseIdx++)
+			attrVal = mBfIRBuilder->CreateExtractValue(attrVal, 0);
 
-			SizedArray<BfIRValue, 1> args;
-			if (!attrType->IsValuelessType())
-				args.Add(attrVal);
-			args.Add(mBfIRBuilder->CreateConst(BfTypeCode_UInt64, (uint64)(intptr)methodInstance));
-			mCompiler->mCEMachine->mMethodInstanceSet.Add(methodInstance);
+		SizedArray<BfIRValue, 1> args;
+		if (!attrType->IsValuelessType())
+			args.Add(attrVal);
+		args.Add(mBfIRBuilder->CreateConst(BfTypeCode_UInt64, (uint64)(intptr)methodInstance));
+		if (applyMethodInstance->GetParamCount() > 1)
+		{
+			if (irValue)
+				args.Add(irValue);
+			else
+				args.Add(mBfIRBuilder->CreateConstNull());
+		}
+		else
+		{
+			// Only allow a single instance
+			if (irValue)
+				continue;
+		}
+
+		mCompiler->mCEMachine->mMethodInstanceSet.Add(methodInstance);
 
-			//TESTING
+		//TESTING
 // 			mCompiler->mCEMachine->ReleaseContext(ceContext);			
 // 			ceContext = mCompiler->mCEMachine->AllocContext();
 // 			ceContext->mMemory.mSize = ceContext->mMemory.mAllocSize;
+			
 
-			auto activeTypeDef = typeInstance->mTypeDef;			
-			auto result = ceContext->Call(customAttribute.mRef, this, applyMethodInstance, args, CeEvalFlags_None, NULL);
+		auto activeTypeDef = typeInstance->mTypeDef;			
+		
+		//auto result = ceContext->Call(customAttribute.mRef, this, applyMethodInstance, args, CeEvalFlags_None, NULL);
+		BfTypedValue result;
+		///
+		{
+			SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true);
+			result = ceContext->Call(customAttribute.mRef, this, applyMethodInstance, args, CeEvalFlags_ForceReturnThis, NULL);
+		}		
+		if (result.mType == methodInstance->GetOwner())
+			prevAttrInstances[methodInstance->GetOwner()] = result.mValue;
 
-			if ((!result) && (mCompiler->mFastFinish))
-			{
-				methodInstance->mCeCancelled = true;
-			}
+		if ((!result) && (mCompiler->mFastFinish))
+		{
+			methodInstance->mCeCancelled = true;
+		}
 
-			if ((!ceEmitContext.mEmitData.IsEmpty()) || (!ceEmitContext.mExitEmitData.IsEmpty()))
-			{
-				String src;				
-				src += "// Code emission in comptime ApplyToMethod of ";
-				src += TypeToString(attrType);
-				src += " to ";
-				src += MethodToString(methodInstance);
-				src += " ";
-				src += customAttribute.mRef->LocationToString();
-				src += "\n";
+		if ((!ceEmitContext.mEmitData.IsEmpty()) || (!ceEmitContext.mExitEmitData.IsEmpty()))
+		{
+			String src;				
+			src += "// Code emission in comptime ApplyToMethod of ";
+			src += TypeToString(attrType);
+			src += " to ";
+			src += MethodToString(methodInstance);
+			src += " ";
+			src += customAttribute.mRef->LocationToString();
+			src += "\n";
 				
-				//auto emitTypeDef = typeInstance->mCeTypeInfo->mNext->mTypeDef;
-				//auto emitParser = emitTypeDef->mSource->ToParser();
-
-				//auto emitParser = activeTypeDef->mEmitParser;
+			//auto emitTypeDef = typeInstance->mCeTypeInfo->mNext->mTypeDef;
+			//auto emitParser = emitTypeDef->mSource->ToParser();
 
-				BfReducer bfReducer;
-				//bfReducer.mSource = emitParser;
-				bfReducer.mPassInstance = mCompiler->mPassInstance;				
-				bfReducer.mSystem = mSystem;
-				bfReducer.mCurTypeDecl = activeTypeDef->mTypeDeclaration;
-				bfReducer.mCurMethodDecl = BfNodeDynCast<BfMethodDeclaration>(methodInstance->mMethodDef->mMethodDeclaration);
+			//auto emitParser = activeTypeDef->mEmitParser;
 
-				if (!ceEmitContext.mEmitData.IsEmpty())
-				{
-					SetAndRestoreValue<BfAstNode*> prevCustomAttribute(mCurMethodState->mEmitRefNode, customAttribute.mRef);
+			BfReducer bfReducer;
+			//bfReducer.mSource = emitParser;
+			bfReducer.mPassInstance = mCompiler->mPassInstance;				
+			bfReducer.mSystem = mSystem;
+			bfReducer.mCurTypeDecl = activeTypeDef->mTypeDeclaration;
+			bfReducer.mCurMethodDecl = BfNodeDynCast<BfMethodDeclaration>(methodInstance->mMethodDef->mMethodDeclaration);
 
-					String entrySrc = src;
-					if (mCurTypeInstance->mTypeDef->mEmitParent != NULL)
-						entrySrc += "\n\n";
-					entrySrc += src;
-					entrySrc += ceEmitContext.mEmitData;
-					BfCEParseContext ceParseContext = CEEmitParse(typeInstance, entrySrc);
-					auto emitParser = mCurTypeInstance->mTypeDef->mSource->ToParser();
-					bfReducer.mSource = emitParser;
-					bfReducer.mAlloc = emitParser->mAlloc;
-					bfReducer.HandleBlock(emitParser->mRootNode, false);
-					Visit(emitParser->mRootNode);
-					FinishCEParseContext(customAttribute.mRef, typeInstance, &ceParseContext);
-				}
+			if (!ceEmitContext.mEmitData.IsEmpty())
+			{
+				SetAndRestoreValue<BfAstNode*> prevCustomAttribute(mCurMethodState->mEmitRefNode, customAttribute.mRef);
 
-				if (!ceEmitContext.mExitEmitData.IsEmpty())
-				{
-					String exitSrc;
-					if (mCurTypeInstance->mTypeDef->mEmitParent != NULL)
-						exitSrc += "\n\n";
-					exitSrc += src;
-					exitSrc += ceEmitContext.mExitEmitData;
-					BfCEParseContext ceParseContext = CEEmitParse(typeInstance, exitSrc);
-					auto emitParser = mCurTypeInstance->mTypeDef->mSource->ToParser();
-					bfReducer.mSource = emitParser;
-					bfReducer.mAlloc = emitParser->mAlloc;
-					bfReducer.HandleBlock(emitParser->mRootNode, false);
-					auto deferredBlock = AddDeferredBlock(emitParser->mRootNode, &mCurMethodState->mHeadScope);
-					deferredBlock->mEmitRefNode = customAttribute.mRef;
-					FinishCEParseContext(customAttribute.mRef, typeInstance, &ceParseContext);
-				}
+				String entrySrc = src;
+				if (mCurTypeInstance->mTypeDef->mEmitParent != NULL)
+					entrySrc += "\n\n";
+				entrySrc += src;
+				entrySrc += ceEmitContext.mEmitData;
+				BfCEParseContext ceParseContext = CEEmitParse(typeInstance, entrySrc);
+				auto emitParser = mCurTypeInstance->mTypeDef->mSource->ToParser();
+				bfReducer.mSource = emitParser;
+				bfReducer.mAlloc = emitParser->mAlloc;
+				bfReducer.HandleBlock(emitParser->mRootNode, false);
+				Visit(emitParser->mRootNode);
+				FinishCEParseContext(customAttribute.mRef, typeInstance, &ceParseContext);
 			}
 
-			mCompiler->mCEMachine->ReleaseContext(ceContext);
+			if (!ceEmitContext.mExitEmitData.IsEmpty())
+			{
+				String exitSrc;
+				if (mCurTypeInstance->mTypeDef->mEmitParent != NULL)
+					exitSrc += "\n\n";
+				exitSrc += src;
+				exitSrc += ceEmitContext.mExitEmitData;
+				BfCEParseContext ceParseContext = CEEmitParse(typeInstance, exitSrc);
+				auto emitParser = mCurTypeInstance->mTypeDef->mSource->ToParser();
+				bfReducer.mSource = emitParser;
+				bfReducer.mAlloc = emitParser->mAlloc;
+				bfReducer.HandleBlock(emitParser->mRootNode, false);
+				auto deferredBlock = AddDeferredBlock(emitParser->mRootNode, &mCurMethodState->mHeadScope);
+				deferredBlock->mEmitRefNode = customAttribute.mRef;
+				FinishCEParseContext(customAttribute.mRef, typeInstance, &ceParseContext);
+			}
 		}
+
+		mCompiler->mCEMachine->ReleaseContext(ceContext);	
 	}
 }
 
@@ -4183,15 +4310,46 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 			if (!fieldInstance->mFieldIncluded)
 				continue;
 
+			if (fieldInstance->mCustomAttributes != NULL)
+			{
+				// Already handled
+			}
+			else if ((fieldDef != NULL) && (fieldDef->mFieldDeclaration != NULL) && (fieldDef->mFieldDeclaration->mAttributes != NULL))
+			{
+				if (auto propDecl = BfNodeDynCast<BfPropertyDeclaration>(fieldDef->mFieldDeclaration))
+				{
+					// Handled elsewhere
+				}
+				else
+				{
+					BfTypeState typeState;
+					typeState.mPrevState = mContext->mCurTypeState;
+					typeState.mCurFieldDef = fieldDef;
+					typeState.mCurTypeDef = fieldDef->mDeclaringType;
+					typeState.mType = typeInstance;
+					SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
+
+					fieldInstance->mCustomAttributes = GetCustomAttributes(fieldDef->mFieldDeclaration->mAttributes, fieldDef->mIsStatic ? BfAttributeTargets_StaticField : BfAttributeTargets_Field);
+
+					for (auto customAttr : fieldInstance->mCustomAttributes->mAttributes)
+					{
+						if (TypeToString(customAttr.mType) == "System.ThreadStaticAttribute")
+						{
+							if ((!fieldDef->mIsStatic) || (fieldDef->mIsConst))
+							{
+								Fail("ThreadStatic attribute can only be used on static fields", fieldDef->mFieldDeclaration->mAttributes);
+							}
+						}
+					}
+				}
+			}
+
 			if (resolvedFieldType == NULL)
 			{
 				if ((underlyingType != NULL) || (typeInstance->IsPayloadEnum()))
 					continue;
 			}
 
-			if (!fieldInstance->mFieldIncluded)
-				continue;
-
 			if (fieldDef == NULL)
 				continue;
 
@@ -4226,6 +4384,8 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 					}
 				}
 			}
+
+
 		}
 		
 		bool tryCE = true;
@@ -4473,38 +4633,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
 					AddDependency(resolvedFieldType, typeInstance, BfDependencyMap::DependencyFlag_StaticValue);
 			}
 
-			auto fieldDef = fieldInstance->GetFieldDef();
-
-			BF_ASSERT(fieldInstance->mCustomAttributes == NULL);			
-			if ((fieldDef != NULL) && (fieldDef->mFieldDeclaration != NULL) && (fieldDef->mFieldDeclaration->mAttributes != NULL))
-			{	
-				if (auto propDecl = BfNodeDynCast<BfPropertyDeclaration>(fieldDef->mFieldDeclaration))
-				{
-					// Handled elsewhere
-				}
-				else
-				{
-					BfTypeState typeState;
-					typeState.mPrevState = mContext->mCurTypeState;
-					typeState.mCurFieldDef = fieldDef;
-					typeState.mCurTypeDef = fieldDef->mDeclaringType;
-					typeState.mType = typeInstance;
-					SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
-
-					fieldInstance->mCustomAttributes = GetCustomAttributes(fieldDef->mFieldDeclaration->mAttributes, fieldDef->mIsStatic ? BfAttributeTargets_StaticField : BfAttributeTargets_Field);
-
-					for (auto customAttr : fieldInstance->mCustomAttributes->mAttributes)
-					{
-						if (TypeToString(customAttr.mType) == "System.ThreadStaticAttribute")
-						{
-							if ((!fieldDef->mIsStatic) || (fieldDef->mIsConst))
-							{
-								Fail("ThreadStatic attribute can only be used on static fields", fieldDef->mFieldDeclaration->mAttributes);
-							}
-						}
-					}
-				}
-			}
+			auto fieldDef = fieldInstance->GetFieldDef();			
 
 			if (fieldInstance->mResolvedType != NULL)
 			{
@@ -12896,7 +13025,9 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 		{
 			BfTypedValue result;
 			BfExprEvaluator exprEvaluator(this);
-			exprEvaluator.mBfEvalExprFlags = BfEvalExprFlags_FromConversionOp;			
+			exprEvaluator.mBfEvalExprFlags = BfEvalExprFlags_FromConversionOp;
+			if ((castFlags & BfCastFlags_WantsConst) != 0)
+				exprEvaluator.mBfEvalExprFlags = (BfEvalExprFlags)(exprEvaluator.mBfEvalExprFlags | BfEvalExprFlags_Comptime);
 
 			auto methodDeclaration = BfNodeDynCast<BfMethodDeclaration>(methodMatcher.mBestMethodDef->mMethodDeclaration);
 			if ((methodDeclaration != NULL) && (methodDeclaration->mBody == NULL))

+ 26 - 2
IDEHelper/Compiler/BfResolvedTypeUtils.h

@@ -1383,9 +1383,11 @@ public:
 public:
 	BfFieldDef* GetFieldDef();	
 
-	BfFieldInstance(const BfFieldInstance& copyFrom)
+	BfFieldInstance(BfFieldInstance&& copyFrom)
 	{
-		BF_ASSERT(copyFrom.mCustomAttributes == NULL);		
+		mCustomAttributes = copyFrom.mCustomAttributes;
+		copyFrom.mCustomAttributes = NULL;
+
 		mOwner = copyFrom.mOwner;		
 		mResolvedType = copyFrom.mResolvedType;
 		
@@ -1404,6 +1406,28 @@ public:
 		mLastRevisionReferenced = copyFrom.mLastRevisionReferenced;		
 	}
 
+	BfFieldInstance(const BfFieldInstance& copyFrom)
+	{
+		BF_ASSERT(copyFrom.mCustomAttributes == NULL);
+
+		mOwner = copyFrom.mOwner;
+		mResolvedType = copyFrom.mResolvedType;
+
+		mCustomAttributes = copyFrom.mCustomAttributes;
+		mConstIdx = copyFrom.mConstIdx;
+		mFieldIdx = copyFrom.mFieldIdx;
+		mDataIdx = copyFrom.mDataIdx;
+		mMergedDataIdx = copyFrom.mMergedDataIdx;
+		mDataOffset = copyFrom.mDataOffset;
+		mDataSize = copyFrom.mDataSize;
+		mFieldIncluded = copyFrom.mFieldIncluded;
+		mIsEnumPayloadCase = copyFrom.mIsEnumPayloadCase;
+		mIsThreadLocal = copyFrom.mIsThreadLocal;
+		mIsInferredType = copyFrom.mIsInferredType;
+		mHadConstEval = copyFrom.mHadConstEval;
+		mLastRevisionReferenced = copyFrom.mLastRevisionReferenced;
+	}
+
 	BfFieldInstance()
 	{
 		mFieldIdx = -1;

+ 1 - 1
IDEHelper/Compiler/BfStmtEvaluator.cpp

@@ -2981,7 +2981,7 @@ BfTypedValue BfModule::HandleCaseBind(BfTypedValue enumVal, const BfTypedValue&
 				if (type->IsEnum())
 				{
 					auto enumType = (BfTypeInstance*)type;
-					for (auto fieldInstance : enumType->mFieldInstances)
+					for (auto& fieldInstance : enumType->mFieldInstances)
 					{
 						auto fieldDef = fieldInstance.GetFieldDef();
 						if ((fieldDef != NULL) && (fieldDef->IsEnumCaseEntry()) && (fieldDef->mName == findName))

+ 12 - 0
IDEHelper/Compiler/BfSystem.h

@@ -1471,6 +1471,18 @@ enum BfOptionFlags
 
 };
 
+enum BfFieldFlags
+{
+	BfFieldFlags_Protected = 3,
+	BfFieldFlags_Public = 6,
+	BfFieldFlags_Static = 0x10,
+	BfFieldFlags_Const = 0x40,
+	BfFieldFlags_SpecialName = 0x80,
+	BfFieldFlags_EnumPayload = 0x100,
+	BfFieldFlags_EnumDiscriminator = 0x200,
+	BfFieldFlags_EnumCase = 0x400
+};
+
 enum BfReflectKind
 {
 	BfReflectKind_None = 0,

+ 190 - 46
IDEHelper/Compiler/CeMachine.cpp

@@ -3376,7 +3376,7 @@ void CeContext::PrepareConstStructEntry(CeConstStructData& constEntry)
 
 bool CeContext::CheckMemory(addr_ce addr, int32 size)
 {
-	if (((addr)-0x10000) + (size) > (mMemory.mSize - 0x10000))
+	if ((addr < 0x10000) || (addr + size > mMemory.mSize))		
 		return false;
 	return true;
 }
@@ -3441,10 +3441,12 @@ bool CeContext::GetStringFromStringView(addr_ce addr, StringImpl& str)
 	addr_ce charsPtr = *(addr_ce*)(mMemory.mVals + addr);
 	int32 len = *(int32*)(mMemory.mVals + addr + ptrSize);
 
-	if (!CheckMemory(charsPtr, len))
-		return false;
-
-	str.Append((const char*)(mMemory.mVals + charsPtr), len);
+	if (len > 0)
+	{
+		if (!CheckMemory(charsPtr, len))
+			return false;
+		str.Append((const char*)(mMemory.mVals + charsPtr), len);
+	}
 
 	return true;
 }
@@ -3595,6 +3597,19 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
 					return false;
 			}
 
+			if (typeInst->IsPayloadEnum())
+			{
+				auto innerType = typeInst->GetUnionInnerType();
+				if (!innerType->IsValuelessType())
+				{
+					auto fieldConstant = module->mBfIRBuilder->GetConstant(aggConstant->mValues[1]);
+					if (fieldConstant == NULL)
+						return false;
+					if (!WriteConstant(module, addr, fieldConstant, innerType))
+						return false;
+				}
+			}
+
 			for (auto& fieldInstance : typeInst->mFieldInstances)
 			{
 				if (fieldInstance.mDataOffset < 0)
@@ -3611,9 +3626,15 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
 	}
 
 	if (constant->mConstType == BfConstType_AggZero)
-	{		
+	{
 		BF_ASSERT(type->IsComposite());
-		memset(mMemory.mVals + addr, 0, type->mSize);		
+		memset(mMemory.mVals + addr, 0, type->mSize);
+		return true;
+	}
+
+	if (constant->mConstType == BfConstType_ArrayZero8)
+	{		
+		memset(mMemory.mVals + addr, 0, constant->mInt32);
 		return true;
 	}
 
@@ -3722,6 +3743,29 @@ bool CeContext::WriteConstant(BfModule* module, addr_ce addr, BfConstant* consta
 		return true;
 	}
 
+	if (constant->mConstType == BfConstType_ExtractValue)
+	{
+		Array<BfConstantExtractValue*> extractStack;
+		auto checkConstant = constant;		
+		while (true)
+		{
+			if (checkConstant == NULL)
+				break;
+
+			if (checkConstant->mConstType == BfConstType_ExtractValue)
+			{
+				auto gepConst = (BfConstantExtractValue*)constant;
+				BfIRValue targetConst(BfIRValueFlags_Const, gepConst->mTarget);
+				checkConstant = module->mBfIRBuilder->GetConstant(targetConst);
+				extractStack.Add(gepConst);
+				continue;
+			}
+
+			if (checkConstant->mConstType == BfConstType_AggCE)
+				return WriteConstant(module, addr, checkConstant, type, isParams);
+		}				
+	}
+
 	return false;
 }
 
@@ -3926,8 +3970,7 @@ BfIRValue CeContext::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType
 
 		if (typeInst->IsInstanceOf(ceModule->mCompiler->mTypeTypeDef))
 		{
-			addr_ce addr = *(addr_ce*)(instData);
-			int typeId = GetTypeIdFromType(addr);
+			int typeId = GetTypeIdFromType(instData - mMemory.mVals);
 			if (typeId <= 0)
 			{
 				Fail("Unable to locate return type type");
@@ -3950,13 +3993,20 @@ BfIRValue CeContext::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType
 				return BfIRValue();
 			fieldVals.Add(result);
 		}				
-
-		if (typeInst->mIsUnion)
+		
+		if (typeInst->IsUnion())
 		{
-			auto unionInnerType = typeInst->GetUnionInnerType();
-			fieldVals.Add(CreateConstant(module, ptr, unionInnerType, outType));						
+			auto innerType = typeInst->GetUnionInnerType();
+			if (!innerType->IsValuelessType())
+			{
+				auto result = CreateConstant(module, instData, innerType);
+				if (!result)
+					return BfIRValue();
+				fieldVals.Add(result);
+			}
 		}
-		else
+
+		if ((!typeInst->IsUnion()) || (typeInst->IsPayloadEnum()))
 		{
 			for (int fieldIdx = 0; fieldIdx < typeInst->mFieldInstances.size(); fieldIdx++)
 			{
@@ -3997,7 +4047,7 @@ BfIRValue CeContext::CreateConstant(BfModule* module, uint8* ptr, BfType* bfType
 				fieldVal = irBuilder->CreateConstArrayZero(0);
 		}
 
-		auto instResult = irBuilder->CreateConstAgg(irBuilder->MapTypeInst(typeInst, BfIRPopulateType_Full), fieldVals);
+		auto instResult = irBuilder->CreateConstAgg(irBuilder->MapTypeInst(typeInst, BfIRPopulateType_Identity), fieldVals);
 		return instResult;
 	}
 
@@ -4156,14 +4206,30 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
 	int thisArgIdx = -1;
 	int appendAllocIdx = -1;
 	bool hasAggData = false;
-	if (methodInstance->mMethodDef->mMethodType == BfMethodType_Ctor)
+	if (!methodInstance->mMethodDef->mIsStatic)
 	{	
 		if (!methodInstance->GetOwner()->IsValuelessType())
 		{
 			thisArgIdx = 0;
-			auto constant = module->mBfIRBuilder->GetConstant(args[0]);
-			if ((constant != NULL) && (constant->mConstType == BfConstType_AggCE))
-				hasAggData = true;
+			auto checkConstant = module->mBfIRBuilder->GetConstant(args[0]);
+			while (checkConstant != NULL)
+			{
+				if ((checkConstant != NULL) && (checkConstant->mConstType == BfConstType_AggCE))
+				{
+					hasAggData = true;
+					break;
+				}
+
+				if (checkConstant->mConstType == BfConstType_ExtractValue)
+				{					
+					auto gepConst = (BfConstantExtractValue*)checkConstant;
+					BfIRValue targetConst(BfIRValueFlags_Const, gepConst->mTarget);
+					checkConstant = module->mBfIRBuilder->GetConstant(targetConst);
+					continue;
+				}
+
+				break;
+			}
 		}
 
 		if ((methodInstance->GetParamCount() >= 1) && (methodInstance->GetParamKind(0) == BfParamKind_AppendIdx))
@@ -4181,14 +4247,12 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
 			paramType = methodInstance->GetParamType(paramIdx);
 			if (paramType->IsTypedPrimitive())
 				paramType = paramType->GetUnderlyingType();
-			if (!paramType->IsValuelessType())
+			if ((!paramType->IsValuelessType()) && (!paramType->IsVar()))
 				break;
 		}
-		if (paramType->IsComposite())
-		{			
-			paramCompositeSize += paramType->mSize;
-		}
-
+		
+		BfType* compositeType = paramType->IsComposite() ? paramType : NULL;		
+		
 		auto arg = args[argIdx];
 		bool isConst = arg.IsConst();
 		if (isConst)
@@ -4203,6 +4267,17 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
 // 				else
 // 					isConst = false;
 			}
+			else if (((constant->mConstType == BfConstType_AggZero) || (constant->mConstType == BfConstType_Agg)) &&
+				((paramType->IsPointer()) || (paramType->IsRef())))
+				compositeType = paramType->GetUnderlyingType();
+		}
+
+		if (compositeType != NULL)
+		{
+			if ((paramType->IsPointer()) || (paramType->IsRef()))
+				paramCompositeSize += paramType->GetUnderlyingType()->mSize;
+			else
+				paramCompositeSize += paramType->mSize;
 		}
 
 		if (!isConst)
@@ -4252,6 +4327,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
 	BfTypeInstance* thisType = methodInstance->GetOwner();
 	addr_ce allocThisInstAddr = 0;
 	addr_ce allocThisAddr = 0;
+	addr_ce thisAddr = 0;
 	int allocThisSize = -1;
 
 	if ((thisArgIdx != -1) && (!hasAggData))
@@ -4294,6 +4370,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
 
 		allocThisInstAddr = allocThisPtr - memStart;
 		allocThisAddr = allocThisInstAddr;
+		thisAddr = allocThisAddr;
 	}
 
 	addr_ce allocAppendIdxAddr = 0;
@@ -4327,7 +4404,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
 			paramType = methodInstance->GetParamType(paramIdx);
 			if (paramType->IsTypedPrimitive())
 				paramType = paramType->GetUnderlyingType();
-			if (!paramType->IsValuelessType())
+			if ((!paramType->IsValuelessType()) && (!paramType->IsVar()))
 				break;
 		}
 
@@ -4357,10 +4434,14 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
 		}
 
 		auto constant = module->mBfIRBuilder->GetConstant(arg);
-		if (paramType->IsComposite())
+		BfType* compositeType = paramType->IsComposite() ? paramType : NULL;		
+		if (((constant->mConstType == BfConstType_AggZero) || (constant->mConstType == BfConstType_Agg)) &&
+			((paramType->IsPointer()) || (paramType->IsRef())))
+			compositeType = paramType->GetUnderlyingType();
+		if (compositeType != NULL)
 		{			
-			useCompositeAddr -= paramType->mSize;
-			if (!WriteConstant(module, useCompositeAddr, constant, paramType, isParams))
+			useCompositeAddr -= compositeType->mSize;
+			if (!WriteConstant(module, useCompositeAddr, constant, compositeType, isParams))
 			{
 				Fail(StrFormat("Failed to process argument for param '%s'", methodInstance->GetParamName(paramIdx).c_str()));
 				return BfTypedValue();
@@ -4369,17 +4450,47 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
 
 			stackPtr -= ceModule->mSystem->mPtrSize;
 			int64 addr64 = useCompositeAddr;
+			if (argIdx == thisArgIdx)
+				thisAddr = addr64;
 			memcpy(stackPtr, &addr64, ceModule->mSystem->mPtrSize);
-		}
+		}				
 		else
-		{
+		{			
 			stackPtr -= paramType->mSize;
-			if (!WriteConstant(module, stackPtr - memStart, constant, paramType, isParams))
+			auto useCompositeAddr = stackPtr - memStart;
+			if (!WriteConstant(module, useCompositeAddr, constant, paramType, isParams))
 			{
 				Fail(StrFormat("Failed to process argument for param '%s'", methodInstance->GetParamName(paramIdx).c_str()));
 				return BfTypedValue();
 			}
 			_FixVariables();
+
+			if (argIdx == thisArgIdx)
+			{
+				auto checkConstant = constant;
+				while (checkConstant != NULL)
+				{
+					if ((checkConstant != NULL) && (checkConstant->mConstType == BfConstType_AggCE))
+					{
+						auto constAggData = (BfConstantAggCE*)checkConstant;
+						if (paramType->IsPointer())
+							thisAddr = constAggData->mCEAddr;
+						else
+							thisAddr = useCompositeAddr;
+						break;
+					}
+
+					if (checkConstant->mConstType == BfConstType_ExtractValue)
+					{
+						auto gepConst = (BfConstantExtractValue*)checkConstant;
+						BfIRValue targetConst(BfIRValueFlags_Const, gepConst->mTarget);
+						checkConstant = module->mBfIRBuilder->GetConstant(targetConst);
+						continue;
+					}
+
+					break;
+				}
+			}
 		}
 	}
 
@@ -4399,16 +4510,18 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
 
 	addr_ce retInstAddr = retAddr;
 
-	if (returnType->IsInstanceOf(mCeMachine->mCompiler->mTypeTypeDef))
-	{
-		// Allow
-	}
-	else if ((returnType->IsObject()) || (returnType->IsPointer()))
+	if ((returnType->IsObject()) || (returnType->IsPointer()))
 	{
 		// Or pointer?
 		retInstAddr = *(addr_ce*)(memStart + retAddr);
 	}
 
+	if ((flags & CeEvalFlags_ForceReturnThis) != 0)
+	{
+		returnType = thisType;
+		retInstAddr = thisAddr;
+	}
+
 	BfTypedValue returnValue;
 
 	if (success)
@@ -4452,7 +4565,7 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
 		}
 		else if (returnType->IsComposite())
 		{
-			returnValue = BfTypedValue(module->mBfIRBuilder->CreateConstArrayZero(module->mBfIRBuilder->MapType(returnType)), returnType);
+			returnValue = BfTypedValue(module->mBfIRBuilder->CreateConstAggZero(module->mBfIRBuilder->MapType(returnType, BfIRPopulateType_Identity)), returnType);
 		}
 		else if (returnType->IsValuelessType())
 		{
@@ -4462,6 +4575,8 @@ BfTypedValue CeContext::Call(BfAstNode* targetSrc, BfModule* module, BfMethodIns
 
 	mCallStack.Clear();
 
+	moduleCurMethodInstance.Restore();
+	moduleCurTypeInstance.Restore();
 	module->AddDependency(methodInstance->GetOwner(), module->mCurTypeInstance, BfDependencyMap::DependencyFlag_ConstEval);
 
 	return returnValue;
@@ -5014,6 +5129,20 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
 				*(int16*)(stackPtr + 4) = 0; // Flags
 				CeSetAddrVal(stackPtr + 4+2, stringAddr, ptrSize);								
 			}
+			else if (checkFunction->mFunctionKind == CeFunctionKind_Field_GetName)
+			{				
+				int64 fieldHandle = *(int64*)((uint8*)stackPtr + ptrSize);
+				
+				auto fieldInstance = mCeMachine->GetFieldInstance(fieldHandle);
+				if (fieldInstance == NULL)
+				{
+					_Fail("Invalid field instance");
+					return false;
+				}
+				
+				CeSetAddrVal(stackPtr + 0, GetString(fieldInstance->GetFieldDef()->mName), ptrSize);
+				_FixVariables();
+			}
 			else if (checkFunction->mFunctionKind == CeFunctionKind_EmitTypeBody)
 			{
 				int32 typeId = *(int32*)((uint8*)stackPtr);
@@ -7506,6 +7635,12 @@ void CeMachine::DerefMethodInfo(CeFunctionInfo* ceFunctionInfo)
 	delete ceFunctionInfo;
 }
 
+void CeMachine::RemoveFunc(CeFunction* ceFunction)
+{
+	mFunctionIdMap.Remove(ceFunction->mId);
+	ceFunction->mId = -1;	
+}
+
 void CeMachine::RemoveMethod(BfMethodInstance* methodInstance)
 {
 	BfLogSys(methodInstance->GetOwner()->mModule->mSystem, "CeMachine::RemoveMethod %p\n", methodInstance);
@@ -7527,13 +7662,9 @@ void CeMachine::RemoveMethod(BfMethodInstance* methodInstance)
 			}
 			if (ceFunction->mId != -1)
 			{
-				mFunctionIdMap.Remove(ceFunction->mId);
-				ceFunction->mId = -1;
+				RemoveFunc(ceFunction);
 				for (auto innerFunction : ceFunction->mInnerFunctions)
-				{
-					mFunctionIdMap.Remove(innerFunction->mId);
-					innerFunction->mId = -1;
-				}
+					RemoveFunc(innerFunction);
 			}
 
 			delete ceFunction;
@@ -7555,6 +7686,7 @@ void CeMachine::RemoveMethod(BfMethodInstance* methodInstance)
 
 		mFunctions.Remove(itr);
 	}
+	methodInstance->mInCEMachine = false;
 }
 
 CeErrorKind CeMachine::WriteConstant(CeConstStructData& data, BeConstant* constVal, CeContext* ceContext)
@@ -7865,6 +7997,10 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction)
 				{
 					ceFunction->mFunctionKind = CeFunctionKind_Method_GetParamInfo;
 				}
+				else if (methodDef->mName == "Comptime_Field_GetName")
+				{
+					ceFunction->mFunctionKind = CeFunctionKind_Field_GetName;
+				}
 			}
 			else if (owner->IsInstanceOf(mCeModule->mCompiler->mCompilerTypeDef))
 			{
@@ -8208,7 +8344,7 @@ 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;		
 		MapFunctionId(ceFunction);
@@ -8283,6 +8419,14 @@ BfMethodInstance* CeMachine::GetMethodInstance(int64 methodHandle)
 	return methodInstance;
 }
 
+BfFieldInstance* CeMachine::GetFieldInstance(int64 fieldHandle)
+{
+	BfFieldInstance* fieldInstance = (BfFieldInstance*)(intptr)fieldHandle;
+	if (!mFieldInstanceSet.Contains(fieldInstance))
+		return NULL;
+	return fieldInstance;
+}
+
 CeFunction* CeMachine::QueueMethod(BfMethodInstance* methodInstance, BfIRValue func)
 {
 	if (mPreparingFunction != NULL)
@@ -8369,7 +8513,7 @@ void CeMachine::ReleaseContext(CeContext* ceContext)
 BfTypedValue CeMachine::Call(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* methodInstance, const BfSizedArray<BfIRValue>& args, CeEvalFlags flags, BfType* expectingType)
 {	
 	auto ceContext = AllocContext();
-	auto result = ceContext->Call(targetSrc, module, methodInstance, args, flags, expectingType);
+	auto result = ceContext->Call(targetSrc, module, methodInstance, args, flags, expectingType);	
 	ReleaseContext(ceContext);	
 	return result;
 }

+ 12 - 6
IDEHelper/Compiler/CeMachine.h

@@ -332,6 +332,7 @@ enum CeFunctionKind
 	CeFunctionKind_Method_GetName,
 	CeFunctionKind_Method_GetInfo,
 	CeFunctionKind_Method_GetParamInfo,
+	CeFunctionKind_Field_GetName,
 	
 	CeFunctionKind_EmitTypeBody,
 	CeFunctionKind_EmitAddInterface,
@@ -516,7 +517,7 @@ public:
 	String mGenError;
 	int mFrameSize;	
 	int mMaxReturnSize;
-	int mId;
+	int mId;	
 
 public:
 	CeFunction()
@@ -544,7 +545,8 @@ enum CeEvalFlags
 	CeEvalFlags_Cascade = 1,
 	CeEvalFlags_PersistantError = 2,
 	CeEvalFlags_DeferIfNotOnlyError = 4,
-	CeEvalFlags_NoRebuild = 8
+	CeEvalFlags_NoRebuild = 8,
+	CeEvalFlags_ForceReturnThis = 0x10
 };
 
 enum CeOperandKind
@@ -689,8 +691,8 @@ public:
 	Dictionary<BeConstant*, int> mConstDataMap;
 	Dictionary<BeFunction*, int> mInnerFunctionMap;
 	Dictionary<BeGlobalVariable*, int> mStaticFieldMap;
-	Dictionary<String, BfFieldInstance*> mStaticFieldInstanceMap;
-	
+	Dictionary<String, BfFieldInstance*> mStaticFieldInstanceMap;		
+
 public:
 	CeBuilder()
 	{
@@ -927,7 +929,9 @@ public:
 	Dictionary<int, CeFunction*> mFunctionIdMap; // Only used for 32-bit			
 	Dictionary<BfType*, CeTypeInfo> mTypeInfoMap;
 	HashSet<BfMethodInstance*> mMethodInstanceSet;
-	
+	HashSet<BfFieldInstance*> mFieldInstanceSet;
+	Array<BeFunction*> mFunctionList;
+		
 	Array<CeContext*> mContextList;
 
 	BfCompiler* mCompiler;
@@ -937,7 +941,7 @@ public:
 	int mRevisionExecuteTime;	
 	int mCurFunctionId;	
 	int mExecuteId;
-	CeAppendAllocInfo* mAppendAllocInfo;
+	CeAppendAllocInfo* mAppendAllocInfo;	
 	
 	CeContext* mCurContext;
 	CeEmitContext* mCurEmitContext;
@@ -957,6 +961,7 @@ public:
 	BeModule* GetBeModule();
 
 	void DerefMethodInfo(CeFunctionInfo* ceFunctionInfo);
+	void RemoveFunc(CeFunction* ceFunction);
 	void RemoveMethod(BfMethodInstance* methodInstance);					
 	void CreateFunction(BfMethodInstance* methodInstance, CeFunction* ceFunction);			
 	CeErrorKind WriteConstant(CeConstStructData& data, BeConstant* constVal, CeContext* ceContext);	
@@ -970,6 +975,7 @@ public:
 	CeFunction* GetPreparedFunction(BfMethodInstance* methodInstance);
 	CeTypeInfo* GetTypeInfo(BfType* type);
 	BfMethodInstance* GetMethodInstance(int64 methodHandle);
+	BfFieldInstance* GetFieldInstance(int64 fieldHandle);
 
 public:
 	void CompileStarted();