diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index efa5ae8f..d575d265 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1744,13 +1744,15 @@ 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 foundAttributes); + void HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCustomAttributes* customAttributes, HashSet foundAttributes, bool underlyingTypeDeferred); void CEMixin(BfAstNode* refNode, const StringImpl& src); - void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind); - void DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers); + void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred); + void DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers, bool underlyingTypeDeferred); void DoCEEmit(BfMethodInstance* methodInstance); void DoPopulateType_TypeAlias(BfTypeInstance* typeAlias); - void DoPopulateType_SetGenericDependencies(BfTypeInstance* genericTypeInstance); + void DoPopulateType_SetGenericDependencies(BfTypeInstance* genericTypeInstance); + void DoPopulateType_FinishEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred, HashContext* dataMemberHashCtx, BfType* unionInnerType); + void DoPopulateType_CeCheckEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred); void DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateType = BfPopulateType_Data); static BfModule* GetModuleFor(BfType* type); void DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 73b8459f..7a93ce43 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -2136,7 +2136,7 @@ void BfModule::UpdateCEEmit(CeEmitContext* ceEmitContext, BfTypeInstance* typeIn } } -void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCustomAttributes* customAttributes, HashSet foundAttributes) +void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCustomAttributes* customAttributes, HashSet foundAttributes, bool underlyingTypeDeferred) { BfTypeInstance* iComptimeTypeApply = NULL; for (auto& customAttribute : customAttributes->mAttributes) @@ -2170,6 +2170,7 @@ void BfModule::HandleCEAttributes(CeEmitContext* ceEmitContext, BfTypeInstance* args.Add(attrVal); args.Add(mBfIRBuilder->CreateTypeOf(typeInstance)); + DoPopulateType_CeCheckEnum(typeInstance, underlyingTypeDeferred); auto result = ceContext->Call(customAttribute.mRef, this, methodInstance, args, CeEvalFlags_None, NULL); if (typeInstance->mDefineState == BfTypeDefineState_DefinedAndMethodsSlotted) @@ -2300,18 +2301,18 @@ void BfModule::CEMixin(BfAstNode* refNode, const StringImpl& code) FinishCEParseContext(refNode, mCurTypeInstance, &ceParseContext); } -void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCEOnCompileKind onCompileKind) +void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInstance, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred) { HashSet foundAttributes; if (ceEmitContext != NULL) { if (typeInstance->mCustomAttributes != NULL) - HandleCEAttributes(ceEmitContext, typeInstance, typeInstance->mCustomAttributes, foundAttributes); + HandleCEAttributes(ceEmitContext, typeInstance, typeInstance->mCustomAttributes, foundAttributes, underlyingTypeDeferred); for (auto& fieldInstance : typeInstance->mFieldInstances) { if (fieldInstance.mCustomAttributes != NULL) - HandleCEAttributes(ceEmitContext, typeInstance, fieldInstance.mCustomAttributes, foundAttributes); + HandleCEAttributes(ceEmitContext, typeInstance, fieldInstance.mCustomAttributes, foundAttributes, underlyingTypeDeferred); } } @@ -2353,7 +2354,7 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* if (onCompileAttribute == NULL) continue; - HandleCEAttributes(ceEmitContext, typeInstance, customAttributes, foundAttributes); + HandleCEAttributes(ceEmitContext, typeInstance, customAttributes, foundAttributes, underlyingTypeDeferred); if (onCompileAttribute->mCtorArgs.size() < 1) continue; @@ -2381,6 +2382,7 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* mCompiler->mCEMachine->mCurEmitContext = ceEmitContext; } + DoPopulateType_CeCheckEnum(typeInstance, underlyingTypeDeferred); auto methodInstance = GetRawMethodInstanceAtIdx(typeInstance, methodDef->mIdx); auto result = mCompiler->mCEMachine->Call(methodDef->GetRefNode(), this, methodInstance, {}, (CeEvalFlags)(CeEvalFlags_PersistantError | CeEvalFlags_DeferIfNotOnlyError), NULL); @@ -2449,11 +2451,11 @@ void BfModule::ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* // } } -void BfModule::DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers) +void BfModule::DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers, bool underlyingTypeDeferred) { CeEmitContext ceEmitContext; ceEmitContext.mType = typeInstance; - ExecuteCEOnCompile(&ceEmitContext, typeInstance, BfCEOnCompileKind_TypeInit); + ExecuteCEOnCompile(&ceEmitContext, typeInstance, BfCEOnCompileKind_TypeInit, underlyingTypeDeferred); hadNewMembers = (typeInstance->mTypeDef->mEmitParent != NULL); if (ceEmitContext.mFailed) @@ -2607,7 +2609,7 @@ void BfModule::DoPopulateType_SetGenericDependencies(BfTypeInstance* genericType } void BfModule::DoPopulateType_TypeAlias(BfTypeInstance* typeAlias) -{ +{ SetAndRestoreValue prevTypeInstance(mCurTypeInstance, typeAlias); SetAndRestoreValue prevMethodInstance(mCurMethodInstance, NULL); SetAndRestoreValue prevMethodState(mCurMethodState, NULL); @@ -2683,6 +2685,176 @@ void BfModule::DoPopulateType_TypeAlias(BfTypeInstance* typeAlias) DoPopulateType_SetGenericDependencies(typeAlias); } +void BfModule::DoPopulateType_FinishEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred, HashContext* dataMemberHashCtx, BfType* unionInnerType) +{ + if (typeInstance->IsEnum()) + { + int64 min = 0; + int64 max = 0; + + bool isFirst = true; + + if (typeInstance->mTypeInfoEx == NULL) + typeInstance->mTypeInfoEx = new BfTypeInfoEx(); + + for (auto& fieldInstanceRef : typeInstance->mFieldInstances) + { + auto fieldInstance = &fieldInstanceRef; + auto fieldDef = fieldInstance->GetFieldDef(); + if ((fieldDef != NULL) && (fieldDef->IsEnumCaseEntry())) + { + if (fieldInstance->mConstIdx == -1) + continue; + + auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); + BF_ASSERT((constant->mTypeCode == BfTypeCode_Int64) || (!underlyingTypeDeferred)); + + if (isFirst) + { + min = constant->mInt64; + max = constant->mInt64; + isFirst = false; + } + else + { + min = BF_MIN(constant->mInt64, min); + max = BF_MAX(constant->mInt64, max); + } + } + } + + typeInstance->mTypeInfoEx->mMinValue = min; + typeInstance->mTypeInfoEx->mMaxValue = max; + + if (underlyingTypeDeferred) + { + BfTypeCode typeCode; + + if ((min >= -0x80) && (max <= 0x7F)) + typeCode = BfTypeCode_Int8; + else if ((min >= 0) && (max <= 0xFF)) + typeCode = BfTypeCode_UInt8; + else if ((min >= -0x8000) && (max <= 0x7FFF)) + typeCode = BfTypeCode_Int16; + else if ((min >= 0) && (max <= 0xFFFF)) + typeCode = BfTypeCode_UInt16; + else if ((min >= -0x80000000LL) && (max <= 0x7FFFFFFF)) + typeCode = BfTypeCode_Int32; + else if ((min >= 0) && (max <= 0xFFFFFFFFLL)) + typeCode = BfTypeCode_UInt32; + else + typeCode = BfTypeCode_Int64; + + if (typeCode != BfTypeCode_Int64) + { + for (auto& fieldInstanceRef : typeInstance->mFieldInstances) + { + auto fieldInstance = &fieldInstanceRef; + if (fieldInstance->mConstIdx == -1) + continue; + if (!fieldInstance->GetFieldDef()->IsEnumCaseEntry()) + continue; + auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); + BfIRValue newConstant = typeInstance->mConstHolder->CreateConst(typeCode, constant->mUInt64); + fieldInstance->mConstIdx = newConstant.mId; + } + } + + BfType* underlyingType = GetPrimitiveType(typeCode); + auto fieldInstance = &typeInstance->mFieldInstances.back(); + fieldInstance->mResolvedType = underlyingType; + fieldInstance->mDataSize = underlyingType->mSize; + + typeInstance->mTypeInfoEx->mUnderlyingType = underlyingType; + + typeInstance->mSize = underlyingType->mSize; + typeInstance->mAlign = underlyingType->mAlign; + typeInstance->mInstSize = underlyingType->mSize; + typeInstance->mInstAlign = underlyingType->mAlign; + + typeInstance->mRebuildFlags = (BfTypeRebuildFlags)(typeInstance->mRebuildFlags & ~BfTypeRebuildFlag_UnderlyingTypeDeferred); + } + } + else + { + BF_ASSERT(!underlyingTypeDeferred); + } + + if ((typeInstance->IsPayloadEnum()) && (!typeInstance->IsBoxed())) + { + typeInstance->mAlign = unionInnerType->mAlign; + + int lastTagId = -1; + for (auto& fieldInstanceRef : typeInstance->mFieldInstances) + { + auto fieldInstance = &fieldInstanceRef; + auto fieldDef = fieldInstance->GetFieldDef(); + if ((fieldDef != NULL) && (fieldInstance->mDataIdx < 0)) + { + BF_ASSERT(fieldInstance->mResolvedType->mAlign >= 1); + typeInstance->mAlign = BF_MAX(typeInstance->mAlign, fieldInstance->mResolvedType->mAlign); + lastTagId = -fieldInstance->mDataIdx - 1; + } + } + + auto fieldInstance = &typeInstance->mFieldInstances.back(); + //BF_ASSERT(fieldInstance->mResolvedType == NULL); + BfPrimitiveType* discriminatorType; + if (lastTagId > 0x7FFFFFFF) // HOW? + discriminatorType = GetPrimitiveType(BfTypeCode_Int64); + else if (lastTagId > 0x7FFF) + discriminatorType = GetPrimitiveType(BfTypeCode_Int32); + else if (lastTagId > 0x7F) + discriminatorType = GetPrimitiveType(BfTypeCode_Int16); + else + discriminatorType = GetPrimitiveType(BfTypeCode_Int8); + fieldInstance->mResolvedType = discriminatorType; + + fieldInstance->mDataOffset = unionInnerType->mSize; + fieldInstance->mDataIdx = 2; // 0 = base, 1 = payload, 2 = discriminator + if (!typeInstance->mIsPacked) + { + if ((fieldInstance->mDataOffset % discriminatorType->mAlign) != 0) + { + fieldInstance->mDataOffset = BF_ALIGN(fieldInstance->mDataOffset, discriminatorType->mAlign); + fieldInstance->mDataIdx++; // Add room for explicit padding + } + } + + typeInstance->mAlign = BF_MAX(typeInstance->mAlign, discriminatorType->mAlign); + typeInstance->mSize = fieldInstance->mDataOffset + discriminatorType->mSize; + + typeInstance->mInstSize = typeInstance->mSize; + typeInstance->mInstAlign = typeInstance->mAlign; + + if (dataMemberHashCtx != NULL) + { + dataMemberHashCtx->Mixin(unionInnerType->mTypeId); + dataMemberHashCtx->Mixin(discriminatorType->mTypeId); + } + + typeInstance->mMergedFieldDataCount = 1; // Track it as a single entry + } +} + +void BfModule::DoPopulateType_CeCheckEnum(BfTypeInstance* typeInstance, bool underlyingTypeDeferred) +{ + if (!typeInstance->IsEnum()) + return; + if ((!underlyingTypeDeferred) && (!typeInstance->IsPayloadEnum())) + return; + if ((typeInstance->mCeTypeInfo != NULL) && (typeInstance->mCeTypeInfo->mNext != NULL)) + return; + + BfType* unionInnerType = NULL; + if (typeInstance->mIsUnion) + { + SetAndRestoreValue prevResolveKind(mContext->mCurTypeState->mResolveKind, BfTypeState::ResolveKind_UnionInnerType); + unionInnerType = typeInstance->GetUnionInnerType(); + } + DoPopulateType_FinishEnum(typeInstance, underlyingTypeDeferred, NULL, unionInnerType); +} + void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateType) { if (populateType == BfPopulateType_Identity) @@ -4055,7 +4227,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy typeInstance->mDefineState = BfTypeDefineState_CETypeInit; bool hadNewMembers = false; - DoCEEmit(typeInstance, hadNewMembers); + DoCEEmit(typeInstance, hadNewMembers, underlyingTypeDeferred); if (typeInstance->mDefineState < BfTypeDefineState_CEPostTypeInit) typeInstance->mDefineState = BfTypeDefineState_CEPostTypeInit; @@ -4659,7 +4831,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy typeInstance->mDefineState = BfTypeDefineState_Defined; if (!typeInstance->IsBoxed()) { - ExecuteCEOnCompile(NULL, typeInstance, BfCEOnCompileKind_TypeDone); + ExecuteCEOnCompile(NULL, typeInstance, BfCEOnCompileKind_TypeDone, underlyingTypeDeferred); if (typeInstance->mDefineState == BfTypeDefineState_DefinedAndMethodsSlotted) return; } @@ -4830,151 +5002,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy BfLogSysM("Setting underlying type %p %d\n", typeInstance, underlyingTypeDeferred); } - if (typeInstance->IsEnum()) - { - int64 min = 0; - int64 max = 0; - - bool isFirst = true; - - if (typeInstance->mTypeInfoEx == NULL) - typeInstance->mTypeInfoEx = new BfTypeInfoEx(); - - for (auto& fieldInstanceRef : typeInstance->mFieldInstances) - { - auto fieldInstance = &fieldInstanceRef; - auto fieldDef = fieldInstance->GetFieldDef(); - if ((fieldDef != NULL) && (fieldDef->IsEnumCaseEntry())) - { - if (fieldInstance->mConstIdx == -1) - continue; - - auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); - BF_ASSERT((constant->mTypeCode == BfTypeCode_Int64) || (!underlyingTypeDeferred)); - - if (isFirst) - { - min = constant->mInt64; - max = constant->mInt64; - isFirst = false; - } - else - { - min = BF_MIN(constant->mInt64, min); - max = BF_MAX(constant->mInt64, max); - } - } - } - - typeInstance->mTypeInfoEx->mMinValue = min; - typeInstance->mTypeInfoEx->mMaxValue = max; - - if (underlyingTypeDeferred) - { - BfTypeCode typeCode; - - if ((min >= -0x80) && (max <= 0x7F)) - typeCode = BfTypeCode_Int8; - else if ((min >= 0) && (max <= 0xFF)) - typeCode = BfTypeCode_UInt8; - else if ((min >= -0x8000) && (max <= 0x7FFF)) - typeCode = BfTypeCode_Int16; - else if ((min >= 0) && (max <= 0xFFFF)) - typeCode = BfTypeCode_UInt16; - else if ((min >= -0x80000000LL) && (max <= 0x7FFFFFFF)) - typeCode = BfTypeCode_Int32; - else if ((min >= 0) && (max <= 0xFFFFFFFFLL)) - typeCode = BfTypeCode_UInt32; - else - typeCode = BfTypeCode_Int64; - - if (typeCode != BfTypeCode_Int64) - { - for (auto& fieldInstanceRef : typeInstance->mFieldInstances) - { - auto fieldInstance = &fieldInstanceRef; - if (fieldInstance->mConstIdx == -1) - continue; - if (!fieldInstance->GetFieldDef()->IsEnumCaseEntry()) - continue; - auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); - BfIRValue newConstant = typeInstance->mConstHolder->CreateConst(typeCode, constant->mUInt64); - fieldInstance->mConstIdx = newConstant.mId; - } - } - - underlyingType = GetPrimitiveType(typeCode); - auto fieldInstance = &typeInstance->mFieldInstances.back(); - fieldInstance->mResolvedType = underlyingType; - fieldInstance->mDataSize = underlyingType->mSize; - - typeInstance->mTypeInfoEx->mUnderlyingType = underlyingType; - - typeInstance->mSize = underlyingType->mSize; - typeInstance->mAlign = underlyingType->mAlign; - typeInstance->mInstSize = underlyingType->mSize; - typeInstance->mInstAlign = underlyingType->mAlign; - - typeInstance->mRebuildFlags = (BfTypeRebuildFlags)(typeInstance->mRebuildFlags & ~BfTypeRebuildFlag_UnderlyingTypeDeferred); - } - } - else - { - BF_ASSERT(!underlyingTypeDeferred); - } - - if ((typeInstance->IsPayloadEnum()) && (!typeInstance->IsBoxed())) - { - typeInstance->mAlign = unionInnerType->mAlign; - - int lastTagId = -1; - for (auto& fieldInstanceRef : typeInstance->mFieldInstances) - { - auto fieldInstance = &fieldInstanceRef; - auto fieldDef = fieldInstance->GetFieldDef(); - if ((fieldDef != NULL) && (fieldInstance->mDataIdx < 0)) - { - BF_ASSERT(fieldInstance->mResolvedType->mAlign >= 1); - typeInstance->mAlign = BF_MAX(typeInstance->mAlign, fieldInstance->mResolvedType->mAlign); - lastTagId = -fieldInstance->mDataIdx - 1; - } - } - - auto fieldInstance = &typeInstance->mFieldInstances.back(); - BF_ASSERT(fieldInstance->mResolvedType == NULL); - BfPrimitiveType* discriminatorType; - if (lastTagId > 0x7FFFFFFF) // HOW? - discriminatorType = GetPrimitiveType(BfTypeCode_Int64); - else if (lastTagId > 0x7FFF) - discriminatorType = GetPrimitiveType(BfTypeCode_Int32); - else if (lastTagId > 0x7F) - discriminatorType = GetPrimitiveType(BfTypeCode_Int16); - else - discriminatorType = GetPrimitiveType(BfTypeCode_Int8); - fieldInstance->mResolvedType = discriminatorType; - - fieldInstance->mDataOffset = unionInnerType->mSize; - fieldInstance->mDataIdx = 2; // 0 = base, 1 = payload, 2 = discriminator - if (!isPacked) - { - if ((fieldInstance->mDataOffset % discriminatorType->mAlign) != 0) - { - fieldInstance->mDataOffset = BF_ALIGN(fieldInstance->mDataOffset, discriminatorType->mAlign); - fieldInstance->mDataIdx++; // Add room for explicit padding - } - } - - typeInstance->mAlign = BF_MAX(typeInstance->mAlign, discriminatorType->mAlign); - typeInstance->mSize = fieldInstance->mDataOffset + discriminatorType->mSize; - - typeInstance->mInstSize = typeInstance->mSize; - typeInstance->mInstAlign = typeInstance->mAlign; - - dataMemberHashCtx.Mixin(unionInnerType->mTypeId); - dataMemberHashCtx.Mixin(discriminatorType->mTypeId); - - typeInstance->mMergedFieldDataCount = 1; // Track it as a single entry - } + DoPopulateType_FinishEnum(typeInstance, underlyingTypeDeferred, &dataMemberHashCtx, unionInnerType); if (!typeInstance->IsBoxed()) { diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index 8517ad00..7b1ac835 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -6081,6 +6081,13 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* { if (iface.mInterfaceType == ifaceType) { + if (valueType->mInterfaceMethodTable.IsEmpty()) + ceModule->PopulateType(valueType, BfPopulateType_Full_Force); + if (valueType->mInterfaceMethodTable.IsEmpty()) + { + _Fail("Empty interface table"); + return false; + } methodInstance = valueType->mInterfaceMethodTable[iface.mStartInterfaceTableIdx + methodIdx].mMethodRef; break; } diff --git a/IDEHelper/Tests/src/Comptime.bf b/IDEHelper/Tests/src/Comptime.bf index 7434fe8f..09831d41 100644 --- a/IDEHelper/Tests/src/Comptime.bf +++ b/IDEHelper/Tests/src/Comptime.bf @@ -230,6 +230,38 @@ namespace Tests } } + [CheckEnum] + enum EnumA + { + case A(int64 aa); + case B(float bb); + } + + [AttributeUsage(.All)] + public struct CheckEnumAttribute : Attribute, IComptimeTypeApply + { + public void ApplyToType(Type type) + { + int fieldIdx = 0; + for (var field in type.GetFields()) + { + switch (fieldIdx) + { + case 0: + Test.Assert(field.Name == "$payload"); + Test.Assert(field.MemberOffset == 0); + Test.Assert(field.FieldType == typeof(int64)); + case 1: + Test.Assert(field.Name == "$discriminator"); + Test.Assert(field.MemberOffset == 8); + Test.Assert(field.FieldType == typeof(int8)); + } + fieldIdx++; + } + Test.Assert(fieldIdx == 4); + } + } + const String cTest0 = Compiler.ReadText("Test0.txt"); const String cTest1 = new String('A', 12); const uint8[?] cTest0Binary = Compiler.ReadBinary("Test0.txt");