From 2a55b5c7bbf8ef8c782b0e132c26a5bc18ed9d41 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 23 Jun 2022 11:53:21 -0700 Subject: [PATCH] Support System.Compiler values in comptime, SetReturnType, Enum helpers --- BeefLibs/corlib/src/Compiler.bf | 10 ++ BeefLibs/corlib/src/Enum.bf | 61 ++++++++++ BeefLibs/corlib/src/Reflection/FieldInfo.bf | 1 + IDEHelper/Compiler/BfCompiler.cpp | 8 +- IDEHelper/Compiler/BfDeferEvalChecker.cpp | 16 ++- IDEHelper/Compiler/BfDeferEvalChecker.h | 6 +- IDEHelper/Compiler/BfExprEvaluator.cpp | 108 +++++++++++------- IDEHelper/Compiler/BfExprEvaluator.h | 2 +- IDEHelper/Compiler/BfModule.cpp | 30 ++++- IDEHelper/Compiler/BfModule.h | 3 +- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 22 +++- IDEHelper/Compiler/CeMachine.cpp | 118 +++++++++++++++++++- IDEHelper/Compiler/CeMachine.h | 15 ++- IDEHelper/Tests/src/Enums.bf | 4 + 14 files changed, 341 insertions(+), 63 deletions(-) diff --git a/BeefLibs/corlib/src/Compiler.bf b/BeefLibs/corlib/src/Compiler.bf index 17d7a8bf..7f881fba 100644 --- a/BeefLibs/corlib/src/Compiler.bf +++ b/BeefLibs/corlib/src/Compiler.bf @@ -259,6 +259,9 @@ namespace System [LinkName("#CallerExpression")] public static extern String[0x00FFFFFF] CallerExpression; + [LinkName("#OrigCalleeType")] + public static extern Type OrigCalleeType; + [LinkName("#ProjectName")] public static extern String ProjectName; @@ -287,6 +290,7 @@ namespace System Runtime.FatalError("Assert failed"); } + static extern void Comptime_SetReturnType(int32 typeId); static extern void* Comptime_MethodBuilder_EmitStr(void* native, StringView str); static extern void* Comptime_CreateMethod(int32 typeId, StringView methodName, Type returnType, MethodFlags methodFlags); static extern void Comptime_EmitTypeBody(int32 typeId, StringView text); @@ -309,6 +313,12 @@ namespace System Comptime_EmitTypeBody((.)owner.TypeId, text); } + [Comptime(OnlyFromComptime=true)] + public static void SetReturnType(Type type) + { + Comptime_SetReturnType((.)type.TypeId); + } + [Comptime(OnlyFromComptime=true)] public static void EmitAddInterface(Type owner, Type iface) { diff --git a/BeefLibs/corlib/src/Enum.bf b/BeefLibs/corlib/src/Enum.bf index d334bb17..ff9931a1 100644 --- a/BeefLibs/corlib/src/Enum.bf +++ b/BeefLibs/corlib/src/Enum.bf @@ -5,6 +5,67 @@ namespace System { struct Enum { + public static int Count + { + [Comptime(ConstEval=true)] + get + { + int count = 0; + for (var field in Compiler.OrigCalleeType.GetFields()) + { + if (field.IsEnumCase) + count++; + } + return count; + } + } + + public static var MinValue + { + [Comptime(ConstEval=true)] + get + { + Compiler.SetReturnType(Compiler.OrigCalleeType); + + int? minValue = null; + for (var field in Compiler.OrigCalleeType.GetFields()) + { + if (field.IsEnumCase) + { + if (minValue == null) + minValue = field.[Friend]mFieldData.mData; + else + minValue = Math.Min(minValue.Value, field.[Friend]mFieldData.mData); + } + } + return minValue.ValueOrDefault; + } + } + + public static var MaxValue + { + [Comptime(ConstEval=true)] + get + { + Compiler.SetReturnType(Compiler.OrigCalleeType); + + int? maxValue = null; + for (var field in Compiler.OrigCalleeType.GetFields()) + { + if (field.IsEnumCase) + { + if (maxValue == null) + maxValue = field.[Friend]mFieldData.mData; + else + maxValue = Math.Max(maxValue.Value, field.[Friend]mFieldData.mData); + } + } + if (maxValue == null) + return -1; + return maxValue.ValueOrDefault; + } + } + public static void EnumToString(Type type, String strBuffer, int64 iVal) { for (var field in type.GetFields()) diff --git a/BeefLibs/corlib/src/Reflection/FieldInfo.bf b/BeefLibs/corlib/src/Reflection/FieldInfo.bf index e75d8f57..c08e08f2 100644 --- a/BeefLibs/corlib/src/Reflection/FieldInfo.bf +++ b/BeefLibs/corlib/src/Reflection/FieldInfo.bf @@ -24,6 +24,7 @@ namespace System.Reflection public int32 MemberOffset => (int32)mFieldData.mData; public Type FieldType => Type.[Friend]GetType(mFieldData.mFieldTypeId); public bool IsConst => mFieldData.mFlags.HasFlag(.Const); + public bool IsEnumCase => mFieldData.mFlags.HasFlag(.EnumCase); public bool IsReadOnly => mFieldData.mFlags.HasFlag(.ReadOnly); public bool IsStatic => mFieldData.mFlags.HasFlag(.Static); public bool IsPublic => (mFieldData.mFlags & .FieldAccessMask) == .Public; diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 3d9937d9..0d120bee 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -4691,7 +4691,13 @@ void BfCompiler::ProcessAutocompleteTempType() auto propDeclaration = BfNodeDynCast(fieldDecl); if (propDeclaration != NULL) autoComplete->CheckProperty(propDeclaration); - module->ResolveTypeRef(propDef->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowRef); + + if (BfNodeIsA(propDef->mTypeRef)) + { + // This is only valid for ConstEval properties + } + else + module->ResolveTypeRef(propDef->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowRef); if (auto indexerDeclaration = BfNodeDynCast(propDef->mFieldDeclaration)) { diff --git a/IDEHelper/Compiler/BfDeferEvalChecker.cpp b/IDEHelper/Compiler/BfDeferEvalChecker.cpp index 2aff7225..aa4b6f72 100644 --- a/IDEHelper/Compiler/BfDeferEvalChecker.cpp +++ b/IDEHelper/Compiler/BfDeferEvalChecker.cpp @@ -1,12 +1,20 @@ #include "BfDeferEvalChecker.h" +#include "BfUtil.h" USING_NS_BF; BfDeferEvalChecker::BfDeferEvalChecker() { + mRootNode = NULL; mNeedsDeferEval = false; mDeferLiterals = true; - mDeferDelegateBind = true; + mDeferDelegateBind = true; +} + +void BfDeferEvalChecker::Check(BfAstNode* node) +{ + SetAndRestoreValue rootNode(mRootNode, node); + node->Accept(this); } void BfDeferEvalChecker::Visit(BfAstNode* attribExpr) @@ -174,3 +182,9 @@ void BfDeferEvalChecker::Visit(BfDefaultExpression* defaultExpr) mNeedsDeferEval = true; } +void BfDeferEvalChecker::Visit(BfVariableDeclaration* varDecl) +{ + if (varDecl != mRootNode) + mNeedsDeferEval = true; +} + diff --git a/IDEHelper/Compiler/BfDeferEvalChecker.h b/IDEHelper/Compiler/BfDeferEvalChecker.h index 13e4a6c8..5492ab28 100644 --- a/IDEHelper/Compiler/BfDeferEvalChecker.h +++ b/IDEHelper/Compiler/BfDeferEvalChecker.h @@ -8,6 +8,7 @@ NS_BF_BEGIN class BfDeferEvalChecker : public BfStructuralVisitor { public: + BfAstNode* mRootNode; bool mNeedsDeferEval; bool mDeferDelegateBind; bool mDeferLiterals; @@ -15,6 +16,8 @@ public: public: BfDeferEvalChecker(); + void Check(BfAstNode* node); + virtual void Visit(BfAstNode* node) override; virtual void Visit(BfInitializerExpression* collectionInitExpr); @@ -29,8 +32,9 @@ public: virtual void Visit(BfConditionalExpression* condExpr) override; virtual void Visit(BfUnaryOperatorExpression* unaryOpExpr) override; virtual void Visit(BfObjectCreateExpression* objCreateExpr) override; - virtual void Visit(BfBinaryOperatorExpression* binOpExpr) override; + virtual void Visit(BfBinaryOperatorExpression* binOpExpr) override; virtual void Visit(BfDefaultExpression* defaultExpr) override; + virtual void Visit(BfVariableDeclaration* varDecl) override; }; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index d2b65911..cd2de450 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -4630,7 +4630,7 @@ BfTypedValue BfExprEvaluator::LoadProperty(BfAstNode* targetSrc, BfTypedValue ta bool isBaseLookup = (target.mType) && (typeInstance != target.mType); if ((isBaseLookup) && (target.mType->IsWrappableType())) isBaseLookup = false; - + if (prop->mIsStatic) mPropTarget = BfTypedValue(typeInstance); else if (isBaseLookup) @@ -4655,6 +4655,8 @@ BfTypedValue BfExprEvaluator::LoadProperty(BfAstNode* targetSrc, BfTypedValue ta } mOrigPropTarget = mPropTarget; + if (prop->mIsStatic) + mOrigPropTarget = target; if ((flags & BfLookupFieldFlag_IsAnonymous) == 0) { @@ -4742,7 +4744,7 @@ BfTypedValue BfExprEvaluator::LoadProperty(BfAstNode* targetSrc, BfTypedValue ta mPropDef = NULL; mPropSrc = NULL; - mOrigPropTarget = NULL; + mOrigPropTarget = BfTypedValue(); return result; } } @@ -5780,7 +5782,7 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr { BfDeferEvalChecker deferEvalChecker; deferEvalChecker.mDeferDelegateBind = false; - argExpr->Accept(&deferEvalChecker); + deferEvalChecker.Check(argExpr); deferParamEval = deferEvalChecker.mNeedsDeferEval; } } @@ -5938,7 +5940,7 @@ void BfExprEvaluator::PerformCallChecks(BfMethodInstance* methodInstance, BfAstN mModule->CheckErrorAttributes(methodInstance->GetOwner(), methodInstance, customAttributes, targetSrc); } -BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl& irArgs, BfTypedValue* sret, BfCreateCallFlags callFlags) +BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl& irArgs, BfTypedValue* sret, BfCreateCallFlags callFlags, BfType* origTargetType) { // static int sCallIdx = 0; // if (!mModule->mCompiler->mIsResolveOnly) @@ -6218,8 +6220,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* } } else - { - auto constRet = mModule->mCompiler->mCeMachine->Call(targetSrc, mModule, methodInstance, irArgs, evalFlags, mExpectingType); + { + CeCallSource ceCallSource(targetSrc); + ceCallSource.mOrigCalleeType = origTargetType; + auto constRet = mModule->mCompiler->mCeMachine->Call(ceCallSource, mModule, methodInstance, irArgs, evalFlags, mExpectingType); if (constRet) { auto constant = mModule->mBfIRBuilder->GetConstant(constRet.mValue); @@ -7131,6 +7135,31 @@ void BfExprEvaluator::AddCallDependencies(BfMethodInstance* methodInstance) //TODO: delete argumentsZ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValue& inTarget, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance moduleMethodInstance, BfCreateCallFlags callFlags, SizedArrayImpl& argValues, BfTypedValue* argCascade) { + SetAndRestoreValue prevEvalExprFlag(mBfEvalExprFlags); + + if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL) && (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mConstEvalAttributeTypeDef))) + { + mModule->mAttributeState->mUsed = true; + mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_Comptime); + } + else if ((moduleMethodInstance.mMethodInstance->mComptimeFlags & BfComptimeFlag_ConstEval) != 0) + { + mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_Comptime); + } + else if (((moduleMethodInstance.mMethodInstance->mComptimeFlags & BfComptimeFlag_Comptime) != 0) && (!mModule->mIsComptimeModule)) + { + if ((mModule->mCurMethodInstance == NULL) || (mModule->mCurMethodInstance->mComptimeFlags == BfComptimeFlag_None)) + mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_Comptime); + } + + if (((moduleMethodInstance.mMethodInstance->mComptimeFlags & BfComptimeFlag_OnlyFromComptime) != 0) && + ((mBfEvalExprFlags & BfEvalExprFlags_Comptime) != 0) && + ((mModule->mCurMethodInstance == NULL) || (mModule->mCurMethodInstance->mComptimeFlags == BfComptimeFlag_None)) && + (!mModule->mIsComptimeModule)) + { + mModule->Fail(StrFormat("Method '%s' can only be invoked at comptime. Consider adding [Comptime] to the current method.", mModule->MethodToString(moduleMethodInstance.mMethodInstance).c_str()), targetSrc); + } + bool bypassVirtual = (callFlags & BfCreateCallFlags_BypassVirtual) != 0; bool skipThis = (callFlags & BfCreateCallFlags_SkipThis) != 0;; @@ -8194,7 +8223,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu physCallFlags = (BfCreateCallFlags)(physCallFlags | BfCreateCallFlags_GenericParamThis); auto func = moduleMethodInstance.mFunc; - BfTypedValue callResult = CreateCall(targetSrc, methodInstance, func, bypassVirtual, irArgs, NULL, physCallFlags); + BfTypedValue callResult = CreateCall(targetSrc, methodInstance, func, bypassVirtual, irArgs, NULL, physCallFlags, origTarget.mType); if ((methodInstance->mMethodDef->mIsNoReturn) && ((mBfEvalExprFlags & BfEvalExprFlags_IsExpressionBody) != 0) && (mExpectingType != NULL) && (callResult.mType != mExpectingType)) @@ -10129,41 +10158,13 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp BfTypedValue result; BfTypedValue argCascade; - - // - { - SetAndRestoreValue prevEvalExprFlag(mBfEvalExprFlags); - if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL) && (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mConstEvalAttributeTypeDef))) - { - mModule->mAttributeState->mUsed = true; - mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_Comptime); - } - else if ((moduleMethodInstance.mMethodInstance->mComptimeFlags & BfComptimeFlag_ConstEval) != 0) - { - mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_Comptime); - } - else if (((moduleMethodInstance.mMethodInstance->mComptimeFlags & BfComptimeFlag_Comptime) != 0) && (!mModule->mIsComptimeModule)) - { - if ((mModule->mCurMethodInstance == NULL) || (mModule->mCurMethodInstance->mComptimeFlags == BfComptimeFlag_None)) - mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_Comptime); - } - - if (((moduleMethodInstance.mMethodInstance->mComptimeFlags & BfComptimeFlag_OnlyFromComptime) != 0) && - ((mBfEvalExprFlags & BfEvalExprFlags_Comptime) != 0) && - ((mModule->mCurMethodInstance == NULL) || (mModule->mCurMethodInstance->mComptimeFlags == BfComptimeFlag_None)) && - (!mModule->mIsComptimeModule)) - { - mModule->Fail(StrFormat("Method '%s' can only be invoked at comptime. Consider adding [Comptime] to the current method.", mModule->MethodToString(moduleMethodInstance.mMethodInstance).c_str()), targetSrc); - } - - BfCreateCallFlags subCallFlags = BfCreateCallFlags_None; - if (bypassVirtual) - subCallFlags = (BfCreateCallFlags)(subCallFlags | BfCreateCallFlags_BypassVirtual); - if (skipThis) - subCallFlags = (BfCreateCallFlags)(subCallFlags | BfCreateCallFlags_SkipThis); - result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, subCallFlags, argValues.mResolvedArgs, &argCascade); - } + BfCreateCallFlags subCallFlags = BfCreateCallFlags_None; + if (bypassVirtual) + subCallFlags = (BfCreateCallFlags)(subCallFlags | BfCreateCallFlags_BypassVirtual); + if (skipThis) + subCallFlags = (BfCreateCallFlags)(subCallFlags | BfCreateCallFlags_SkipThis); + result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, subCallFlags, argValues.mResolvedArgs, &argCascade); if (overrideReturnType != NULL) { @@ -18409,10 +18410,13 @@ BfModuleMethodInstance BfExprEvaluator::GetPropertyMethodInstance(BfMethodDef* m ((!mOrigPropTarget.mType->IsGenericParam()) && (mPropTarget.mType->IsInterface()))) { auto checkType = mOrigPropTarget.mType; + + if ((checkType->IsNullable()) && (!mPropTarget.mType->IsNullable())) + checkType = checkType->GetUnderlyingType(); if (checkType->IsPointer()) checkType = ((BfPointerType*)checkType)->mElementType; if (checkType->IsWrappableType()) - checkType = mModule->GetWrappedStructType(checkType); + checkType = mModule->GetWrappedStructType(checkType); if ((checkType != NULL) && (checkType->IsTypeInstance())) { auto activeTypeDef = mModule->GetActiveTypeDef(); @@ -23707,6 +23711,24 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod } auto underlyingType = resultType->GetUnderlyingType(); + + if (binaryOp == BfBinaryOp_Subtract) + { + intptr maxDist = 0; + auto resultTypeInstance = resultType->ToTypeInstance(); + if ((resultTypeInstance != NULL) && (resultTypeInstance->mTypeInfoEx != NULL)) + maxDist = resultTypeInstance->mTypeInfoEx->mMaxValue - resultTypeInstance->mTypeInfoEx->mMinValue; + + if (maxDist >= 0x80000000UL) + resultType = mModule->GetPrimitiveType(BfTypeCode_Int64); + else if (maxDist >= 0x8000) + resultType = mModule->GetPrimitiveType(BfTypeCode_Int32); + else if (maxDist >= 0x80) + resultType = mModule->GetPrimitiveType(BfTypeCode_Int16); + else + resultType = mModule->GetPrimitiveType(BfTypeCode_Int8); + underlyingType = resultType; + } BfIRValue convResultValue; if (resultTypedValue->mType == resultType) @@ -23728,7 +23750,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod else PerformBinaryOperation(underlyingType, convOtherValue, convResultValue, binaryOp, opToken); if (mResult.mType == underlyingType) - mResult.mType = resultType; + mResult.mType = resultType; return; } diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index ee3566d2..4b4bcfc5 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -476,7 +476,7 @@ public: BfTypedValue LookupIdentifier(BfIdentifierNode* identifierNode, bool ignoreInitialError = false, bool* hadError = NULL); void AddCallDependencies(BfMethodInstance* methodInstance); void PerformCallChecks(BfMethodInstance* methodInstance, BfAstNode* targetSrc); - BfTypedValue CreateCall(BfAstNode* targetSrc, BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl& irArgs, BfTypedValue* sret = NULL, BfCreateCallFlags callFlags = BfCreateCallFlags_None); + BfTypedValue CreateCall(BfAstNode* targetSrc, BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl& irArgs, BfTypedValue* sret = NULL, BfCreateCallFlags callFlags = BfCreateCallFlags_None, BfType* origTargetType = NULL); BfTypedValue CreateCall(BfAstNode* targetSrc, const BfTypedValue& target, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance methodInstance, BfCreateCallFlags callFlags, SizedArrayImpl& argValues, BfTypedValue* argCascade = NULL); BfTypedValue CreateCall(BfMethodMatcher* methodMatcher, BfTypedValue target); void MakeBaseConcrete(BfTypedValue& typedValue); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 83798698..b46efa7d 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -11348,7 +11348,7 @@ BfIRType BfModule::CurrentAddToConstHolder(BfIRType irType) if (irType.mKind == BfIRTypeData::TypeKind_SizedArray) { auto sizedArrayType = (BfConstantSizedArrayType*)mBfIRBuilder->GetConstantById(irType.mId); - return mCurTypeInstance->GetOrCreateConstHolder()->GetSizedArrayType(CurrentAddToConstHolder(sizedArrayType->mType), sizedArrayType->mLength); + return mCurTypeInstance->GetOrCreateConstHolder()->GetSizedArrayType(CurrentAddToConstHolder(sizedArrayType->mType), (int)sizedArrayType->mLength); } return irType; @@ -12591,7 +12591,9 @@ BfTypedValue BfModule::LoadValue(BfTypedValue typedValue, BfAstNode* refNode, bo } return result; } - return GetDefaultTypedValue(typedValue.mType); + + if (!mIsComptimeModule) + return GetDefaultTypedValue(typedValue.mType); } } @@ -14654,6 +14656,25 @@ BfTypedValue BfModule::GetCompilerFieldValue(const StringImpl& str) filePath = mCurMethodState->mMixinState->mInjectFilePosition.mFileInstance->mParser->mFileName; return BfTypedValue(GetStringObjectValue(GetFileDir(filePath)), ResolveTypeDef(mCompiler->mStringTypeDef)); } + else if (str == "#CallerTypeName") + { + String typeName = ""; + if (mCurMethodState->mMixinState->mMixinMethodInstance) + typeName = TypeToString(mCurMethodState->mMixinState->mMixinMethodInstance->GetOwner()); + return BfTypedValue(GetStringObjectValue(typeName), ResolveTypeDef(mCompiler->mStringTypeDef)); + } + else if (str == "#CallerType") + { + auto typeType = ResolveTypeDef(mCompiler->mTypeTypeDef); + BfType* type = NULL; + if (mCurMethodState->mMixinState->mMixinMethodInstance) + type = mCurMethodState->mMixinState->mMixinMethodInstance->GetOwner(); + if (type != NULL) + { + AddDependency(type, mCurTypeInstance, BfDependencyMap::DependencyFlag_ExprTypeReference); + return BfTypedValue(CreateTypeDataRef(type), typeType); + } + } else if (str == "#CallerMemberName") { String memberName = ""; @@ -14668,7 +14689,7 @@ BfTypedValue BfModule::GetCompilerFieldValue(const StringImpl& str) if (project != NULL) return BfTypedValue(GetStringObjectValue(mProject->mName), ResolveTypeDef(mCompiler->mStringTypeDef)); } - } + } if (str == "#TimeLocal") { @@ -15099,6 +15120,9 @@ BfIRValue BfModule::AllocLocalVariable(BfType* type, const StringImpl& name, boo void BfModule::DoAddLocalVariable(BfLocalVariable* localVar) { + if ((localVar->mName == "maxValue") && (mIsComptimeModule)) + BF_ASSERT(!localVar->mAddr.IsFake()); + while (localVar->mName.StartsWith('@')) { localVar->mNamePrefixCount++; diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index a0c46233..2c2568fa 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -109,7 +109,8 @@ enum BfCastFlags BfCastFlags_WarnOnBox = 0x800, BfCastFlags_IsCastCheck = 0x1000, BfCastFlags_IsConstraintCheck = 0x2000, - BfCastFlags_WantsConst = 0x4000 + BfCastFlags_WantsConst = 0x4000, + BfCastFlags_FromComptimeReturn = 0x8000 }; enum BfCastResultFlags : int8 diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 39ba8932..49d68b01 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -4328,6 +4328,10 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy ValidateGenericConstraints(validateEntry.mTypeRef, validateEntry.mGenericType, false); } + bool isRootSystemType = typeInstance->IsInstanceOf(mCompiler->mValueTypeTypeDef) || + typeInstance->IsInstanceOf(mCompiler->mAttributeTypeDef) || + typeInstance->IsInstanceOf(mCompiler->mEnumTypeDef); + if (!typeInstance->IsBoxed()) { if ((typeInstance->mCustomAttributes == NULL) && (typeDef->mTypeDeclaration != NULL) && (typeDef->HasCustomAttributes())) @@ -4696,7 +4700,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy { // Already handled } - else if ((fieldDef != NULL) && (fieldDef->GetFieldDeclaration() != NULL) && (fieldDef->GetFieldDeclaration()->mAttributes != NULL) && (!typeInstance->mTypeFailed)) + else if ((fieldDef != NULL) && (fieldDef->GetFieldDeclaration() != NULL) && (fieldDef->GetFieldDeclaration()->mAttributes != NULL) && (!typeInstance->mTypeFailed) && (!isRootSystemType)) { if (auto propDecl = BfNodeDynCast(fieldDef->mFieldDeclaration)) { @@ -4941,7 +4945,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy if (propDef->IsExpressionBodied()) target = (BfAttributeTargets)(target | BfAttributeTargets_Method); - if ((propDef->GetFieldDeclaration()->mAttributes != NULL) && (!typeInstance->mTypeFailed)) + if ((propDef->GetFieldDeclaration()->mAttributes != NULL) && (!typeInstance->mTypeFailed) && (!isRootSystemType)) { auto customAttrs = GetCustomAttributes(propDef->GetFieldDeclaration()->mAttributes, target); delete customAttrs; @@ -5523,7 +5527,13 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy typeState.mCurTypeDef = propDef->mDeclaringType; typeState.mType = typeInstance; SetAndRestoreValue prevTypeState(mContext->mCurTypeState, &typeState); - ResolveTypeRef(propDef->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowRef); + + if (BfNodeIsA(propDef->mTypeRef)) + { + // This is only valid for ConstEval properties + } + else + ResolveTypeRef(propDef->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowRef); } } @@ -14044,7 +14054,11 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp "Unable to cast '%s' to '%s'" : "Unable to implicitly cast '%s' to '%s'"; - String errStr = StrFormat(errStrF, TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()); + if ((castFlags & BfCastFlags_FromComptimeReturn) != 0) + errStrF = "Comptime return unable to cast '%s' to '%s'"; + + String errStr = StrFormat(errStrF, TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()); + auto error = Fail(errStr, srcNode); if ((error != NULL) && (srcNode != NULL)) { diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index 0e54ff3c..60007fb6 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -1024,6 +1024,19 @@ int CeBuilder::GetCallTableIdx(BeFunction* beFunction, CeOperand* outOperand) callEntry.mFunctionInfo = ceFunctionInfo; *callIdxPtr = (int)mCeFunction->mCallTable.size(); mCeFunction->mCallTable.Add(callEntry); + + if (ceFunctionInfo != NULL) + { + auto callerType = mCeFunction->mCeFunctionInfo->GetOwner(); + auto calleeType = ceFunctionInfo->GetOwner(); + + if ((callerType != NULL) && (calleeType != NULL)) + { + // This will generally already be set, but there are some error cases (such as duplicate type names) + // where this will not be set yet + callerType->mModule->AddDependency(calleeType, callerType, BfDependencyMap::DependencyFlag_Calls); + } + } } return *callIdxPtr; } @@ -5148,7 +5161,8 @@ BfTypedValue CeContext::Call(CeCallSource callSource, BfModule* module, BfMethod mCeMachine->mAppendAllocInfo = NULL; BfType* returnType = NULL; - bool success = Execute(ceFunction, stackPtr - ceFunction->mFrameSize, stackPtr, returnType); + BfType* castReturnType = NULL; + bool success = Execute(ceFunction, stackPtr - ceFunction->mFrameSize, stackPtr, returnType, castReturnType); memStart = &mMemory[0]; addr_ce retInstAddr = retAddr; @@ -5228,6 +5242,13 @@ BfTypedValue CeContext::Call(CeCallSource callSource, BfModule* module, BfMethod mCallStack = prevCallStack; } + if ((castReturnType != NULL) && (returnValue)) + { + auto castedReturnValue = module->Cast(callSource.mRefNode, returnValue, castReturnType, (BfCastFlags)(BfCastFlags_Explicit | BfCastFlags_FromComptimeReturn)); + if (castedReturnValue) + return castedReturnValue; + } + return returnValue; } @@ -5486,7 +5507,7 @@ public: } }; -bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr, BfType*& returnType) +bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr, BfType*& returnType, BfType*& castReturnType) { auto ceModule = mCeMachine->mCeModule; CeFunction* ceFunction = startFunction; @@ -6057,6 +6078,14 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* _FixVariables(); CeSetAddrVal(stackPtr + 0, reflectType, ptrSize); } + else if (checkFunction->mFunctionKind == CeFunctionKind_SetReturnType) + { + int32 typeId = *(int32*)((uint8*)stackPtr); + if (returnType->IsVar()) + castReturnType = GetBfType(typeId); + else + _Fail("Comptime return types can only be set on methods declared with a 'var' return type"); + } else if (checkFunction->mFunctionKind == CeFunctionKind_EmitTypeBody) { int32 typeId = *(int32*)((uint8*)stackPtr); @@ -7621,7 +7650,7 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* auto& ceStaticFieldEntry = ceFunction->mStaticFieldTable[tableIdx]; if (ceStaticFieldEntry.mBindExecuteId != mExecuteId) { - if (mStaticCtorExecSet.TryAdd(ceStaticFieldEntry.mTypeId, NULL)) + if ((mStaticCtorExecSet.TryAdd(ceStaticFieldEntry.mTypeId, NULL)) && (!ceStaticFieldEntry.mName.StartsWith("#"))) { auto bfType = GetBfType(ceStaticFieldEntry.mTypeId); BfTypeInstance* bfTypeInstance = NULL; @@ -7667,6 +7696,74 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* if (ceStaticFieldEntry.mSize > 0) memset(ptr, 0, ceStaticFieldEntry.mSize); staticFieldInfo->mAddr = (addr_ce)(ptr - memStart); + + if (ceStaticFieldEntry.mName.StartsWith("#")) + { + addr_ce resultAddr = 0; + + if (ceStaticFieldEntry.mName == "#CallerLineNum") + { + *(int*)ptr = mCurModule->mCurFilePosition.mCurLine; + } + else if (ceStaticFieldEntry.mName == "#CallerFilePath") + { + String filePath; + if (mCurModule->mCurFilePosition.mFileInstance != NULL) + filePath = mCurModule->mCurFilePosition.mFileInstance->mParser->mFileName; + resultAddr = GetString(filePath); + } + else if (ceStaticFieldEntry.mName == "#CallerFileName") + { + String filePath; + if (mCurModule->mCurFilePosition.mFileInstance != NULL) + filePath = mCurModule->mCurFilePosition.mFileInstance->mParser->mFileName; + resultAddr = GetString(GetFileName(filePath)); + } + else if (ceStaticFieldEntry.mName == "#CallerFileDir") + { + String filePath; + if (mCurModule->mCurFilePosition.mFileInstance != NULL) + filePath = mCurModule->mCurFilePosition.mFileInstance->mParser->mFileName; + resultAddr = GetString(GetFileDir(filePath)); + } + else if (ceStaticFieldEntry.mName == "#CallerTypeName") + { + String typeName = ""; + typeName = mCeMachine->mCeModule->TypeToString(mCallerTypeInstance); + resultAddr = GetString(typeName); + } + else if (ceStaticFieldEntry.mName == "#CallerType") + { + addr_ce typeAddr = GetReflectType(mCallerTypeInstance->mTypeId); + resultAddr = typeAddr; + } + else if (ceStaticFieldEntry.mName == "#CallerMemberName") + { + String memberName = mCeMachine->mCeModule->MethodToString(mCallerMethodInstance); + resultAddr = GetString(memberName); + } + else if (ceStaticFieldEntry.mName == "#CallerProject") + { + BfProject* project = NULL; + project = mCallerTypeInstance->mTypeDef->mProject; + if (project != NULL) + resultAddr = GetString(project->mName); + } + else if (ceStaticFieldEntry.mName == "#OrigCalleeType") + { + if (mCurCallSource->mOrigCalleeType != NULL) + { + addr_ce typeAddr = GetReflectType(mCurCallSource->mOrigCalleeType->mTypeId); + resultAddr = typeAddr; + } + } + + if (resultAddr != 0) + { + _FixVariables(); + CeSetAddrVal(memStart + staticFieldInfo->mAddr, resultAddr, ptrSize); + } + } } ceStaticFieldEntry.mAddr = staticFieldInfo->mAddr; @@ -9199,11 +9296,15 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction) } else if (owner->IsInstanceOf(mCeModule->mCompiler->mCompilerTypeDef)) { - if (methodDef->mName == "Comptime_EmitTypeBody") + if (methodDef->mName == "Comptime_SetReturnType") + { + ceFunction->mFunctionKind = CeFunctionKind_SetReturnType; + } + else if (methodDef->mName == "Comptime_EmitTypeBody") { ceFunction->mFunctionKind = CeFunctionKind_EmitTypeBody; } - if (methodDef->mName == "Comptime_EmitAddInterface") + else if (methodDef->mName == "Comptime_EmitAddInterface") { ceFunction->mFunctionKind = CeFunctionKind_EmitAddInterface; } @@ -9493,7 +9594,7 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f CeFunctionInfo* ceFunctionInfo = NULL; CeFunction* ceFunction = NULL; if (!mFunctions.TryAdd(methodInstance, NULL, &functionInfoPtr)) - { + { ceFunctionInfo = *functionInfoPtr; BF_ASSERT(ceFunctionInfo->mCeFunction != NULL); return ceFunctionInfo->mCeFunction; @@ -9524,6 +9625,11 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f else { ceFunctionInfo = *namedFunctionInfoPtr; + if ((ceFunctionInfo->mMethodInstance != NULL) && (ceFunctionInfo->mMethodInstance != methodInstance)) + { + // This ceFunctionInfo is already taken - probably from a name mangling conflict + ceFunctionInfo = new CeFunctionInfo(); + } } } else diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index 77b2ecbc..0453d1de 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/IDEHelper/Compiler/CeMachine.h @@ -329,8 +329,15 @@ public: mCeFunction = NULL; mRefCount = 0; } - + ~CeFunctionInfo(); + + BfTypeInstance* GetOwner() + { + if (mMethodInstance != NULL) + return mMethodInstance->GetOwner(); + return mMethodRef.mTypeInstance; + } }; class CeCallEntry @@ -440,6 +447,7 @@ enum CeFunctionKind CeFunctionKind_Method_GetParamInfo, CeFunctionKind_Method_GetGenericArg, + CeFunctionKind_SetReturnType, CeFunctionKind_EmitTypeBody, CeFunctionKind_EmitAddInterface, CeFunctionKind_EmitMethodEntry, @@ -1050,6 +1058,7 @@ public: Kind mKind; BfAstNode* mRefNode; BfFieldInstance* mFieldInstance; + BfType* mOrigCalleeType; public: CeCallSource(BfAstNode* refNode) @@ -1057,6 +1066,7 @@ public: mKind = Kind_Unknown; mRefNode = refNode; mFieldInstance = NULL; + mOrigCalleeType = NULL; } CeCallSource() @@ -1064,6 +1074,7 @@ public: mKind = Kind_Unknown; mRefNode = NULL; mFieldInstance = NULL; + mOrigCalleeType = NULL; } }; @@ -1135,7 +1146,7 @@ public: BfIRValue CreateConstant(BfModule* module, uint8* ptr, BfType* type, BfType** outType = NULL); BfIRValue CreateAttribute(BfAstNode* targetSrc, BfModule* module, BfIRConstHolder* constHolder, BfCustomAttribute* customAttribute, addr_ce ceAttrAddr = 0); - bool Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr, BfType*& returnType); + bool Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* startFramePtr, BfType*& returnType, BfType*& castReturnType); BfTypedValue Call(CeCallSource callSource, BfModule* module, BfMethodInstance* methodInstance, const BfSizedArray& args, CeEvalFlags flags, BfType* expectingType); }; diff --git a/IDEHelper/Tests/src/Enums.bf b/IDEHelper/Tests/src/Enums.bf index 5e2ba353..2ae3953a 100644 --- a/IDEHelper/Tests/src/Enums.bf +++ b/IDEHelper/Tests/src/Enums.bf @@ -137,6 +137,10 @@ namespace Tests EnumG eg = .A; eg.Set(66); Test.Assert(eg == .B); + + var ea = EnumA.MaxValue; + Test.Assert(ea == .B); + Test.Assert(EnumA.Count == 2); } } }