diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index 0ae5007e..264eae3a 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -676,6 +676,9 @@ const char* BfAutoComplete::GetTypeName(BfType* type) void BfAutoComplete::AddInnerTypes(BfTypeInstance* typeInst, const StringImpl& filter, bool allowProtected, bool allowPrivate) { + if (typeInst->IsEnum()) + AddEntry(AutoCompleteEntry("valuetype", "UnderlyingType"), filter); + for (auto innerType : typeInst->mTypeDef->mNestedTypes) { if (CheckProtection(innerType->mProtection, innerType, allowProtected, allowPrivate)) @@ -847,7 +850,7 @@ void BfAutoComplete::AddTypeMembers(BfTypeInstance* typeInst, bool addStatic, bo if ((addStatic) && (mModule->mCurMethodInstance == NULL) && (typeInst->IsEnum())) { - AddEntry(AutoCompleteEntry("valuetype", "_"), filter); + AddEntry(AutoCompleteEntry("value", "_"), filter); } #define CHECK_STATIC(staticVal) ((staticVal && addStatic) || (!staticVal && addNonStatic)) @@ -1847,6 +1850,17 @@ bool BfAutoComplete::CheckMemberReference(BfAstNode* target, BfAstNode* dotToken checkType = genericParamInstance->mTypeConstraint; else checkType = mModule->mContext->mBfObjectType; + + if ((genericParamInstance->IsEnum())) + { + if (isStatic) + AddEntry(AutoCompleteEntry("valuetype", "UnderlyingType"), filter); + else + { + AddEntry(AutoCompleteEntry("value", "Underlying"), filter); + AddEntry(AutoCompleteEntry("value", "UnderlyingRef"), filter); + } + } }; _HandleGenericParamInstance(genericParamInstance); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index ce32e1b2..f35cff5b 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -9757,7 +9757,16 @@ void BfExprEvaluator::LookupQualifiedName(BfAstNode* nameNode, BfIdentifierNode* prevDef = mPropDef; prevTarget = mPropTarget; } - } + } + + if ((mPropDef == NULL) && (genericParamInst->IsEnum())) + { + if ((fieldName == "Underlying") || (fieldName == "UnderlyingRef")) + { + mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Var)); + return; + } + } } if (mPropDef != NULL) @@ -10467,6 +10476,25 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie _Int32Result((typeInstance != NULL) ? typeInstance->mInstAlign : type->mSize); else if (memberName == "InstanceStride") _Int32Result((typeInstance != NULL) ? typeInstance->GetInstStride() : type->GetStride()); + else if (memberName == "UnderlyingType") + { + auto typeType = mModule->ResolveTypeDef(mModule->mCompiler->mTypeTypeDef); + if (type->IsGenericParam()) + { + auto genericParamInstance = mModule->GetGenericParamInstance((BfGenericParamType*)type); + if (genericParamInstance->IsEnum()) + mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->MapType(typeType)), typeType); + } + else if (type->IsEnum()) + { + auto underlyingType = type->GetUnderlyingType(); + if (underlyingType != NULL) + { + mModule->AddDependency(underlyingType, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_ExprTypeReference); + mResult = BfTypedValue(mModule->CreateTypeDataRef(underlyingType), typeType); + } + } + } else if ((memberName == "MinValue") || (memberName == "MaxValue")) { bool isMin = memberName == "MinValue"; diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index ea12d5e9..60547e7c 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -7284,6 +7284,13 @@ BfType* BfModule::ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopu } if (nestedTypeDef != NULL) break; + + if ((outerTypeInstance->IsEnum()) && (findName == "UnderlyingType")) + { + auto underlyingType = outerTypeInstance->GetUnderlyingType(); + if (underlyingType != NULL) + return underlyingType; + } } } } @@ -9949,6 +9956,12 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula auto genericParam = GetGenericParamInstance((BfGenericParamType*)leftType); if ((genericParam->mGenericParamFlags & BfGenericParamFlag_Var) != 0) return ResolveTypeResult(typeRef, GetPrimitiveType(BfTypeCode_Var), populateType, resolveFlags); + if ((genericParam->IsEnum()) && (qualifiedTypeRef->mRight != NULL)) + { + StringView findNameRight = qualifiedTypeRef->mRight->ToStringView(); + if (findNameRight == "UnderlyingType") + return ResolveTypeResult(typeRef, GetPrimitiveType(BfTypeCode_Var), populateType, resolveFlags); + } } auto resolvedType = ResolveInnerType(leftType, qualifiedTypeRef->mRight, populateType, false, numGenericArgs); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 51ae78c7..c8a4f1fe 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -64,6 +64,22 @@ bool BfTypedValue::CanModify() const ////////////////////////////////////////////////////////////////////////// +bool BfGenericParamInstance::IsEnum() +{ + if ((mGenericParamFlags & BfGenericParamFlag_Enum) != 0) + return true; + if (mTypeConstraint != NULL) + { + auto module = mTypeConstraint->GetModule(); + if ((module != NULL) && (mTypeConstraint->IsInstanceOf(module->mCompiler->mEnumTypeDef))) + return true; + } + return true; + return false; +} + +////////////////////////////////////////////////////////////////////////// + bool BfDependencyMap::AddUsedBy(BfType* dependentType, BfDependencyMap::DependencyFlags flags) { BF_ASSERT(dependentType != NULL); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 7106280a..195dbb8a 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -1162,6 +1162,7 @@ public: virtual BfGenericParamDef* GetGenericParamDef() = 0; virtual BfExternalConstraintDef* GetExternConstraintDef() = 0; virtual String GetName() = 0; + bool IsEnum(); }; class BfGenericTypeParamInstance : public BfGenericParamInstance