1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Support System.Compiler values in comptime, SetReturnType, Enum helpers

This commit is contained in:
Brian Fiete 2022-06-23 11:53:21 -07:00
parent 0e86b5c49d
commit 2a55b5c7bb
14 changed files with 341 additions and 63 deletions

View file

@ -259,6 +259,9 @@ namespace System
[LinkName("#CallerExpression")] [LinkName("#CallerExpression")]
public static extern String[0x00FFFFFF] CallerExpression; public static extern String[0x00FFFFFF] CallerExpression;
[LinkName("#OrigCalleeType")]
public static extern Type OrigCalleeType;
[LinkName("#ProjectName")] [LinkName("#ProjectName")]
public static extern String ProjectName; public static extern String ProjectName;
@ -287,6 +290,7 @@ namespace System
Runtime.FatalError("Assert failed"); 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_MethodBuilder_EmitStr(void* native, StringView str);
static extern void* Comptime_CreateMethod(int32 typeId, StringView methodName, Type returnType, MethodFlags methodFlags); static extern void* Comptime_CreateMethod(int32 typeId, StringView methodName, Type returnType, MethodFlags methodFlags);
static extern void Comptime_EmitTypeBody(int32 typeId, StringView text); static extern void Comptime_EmitTypeBody(int32 typeId, StringView text);
@ -309,6 +313,12 @@ namespace System
Comptime_EmitTypeBody((.)owner.TypeId, text); Comptime_EmitTypeBody((.)owner.TypeId, text);
} }
[Comptime(OnlyFromComptime=true)]
public static void SetReturnType(Type type)
{
Comptime_SetReturnType((.)type.TypeId);
}
[Comptime(OnlyFromComptime=true)] [Comptime(OnlyFromComptime=true)]
public static void EmitAddInterface(Type owner, Type iface) public static void EmitAddInterface(Type owner, Type iface)
{ {

View file

@ -5,6 +5,67 @@ namespace System
{ {
struct Enum 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) public static void EnumToString(Type type, String strBuffer, int64 iVal)
{ {
for (var field in type.GetFields()) for (var field in type.GetFields())

View file

@ -24,6 +24,7 @@ namespace System.Reflection
public int32 MemberOffset => (int32)mFieldData.mData; public int32 MemberOffset => (int32)mFieldData.mData;
public Type FieldType => Type.[Friend]GetType(mFieldData.mFieldTypeId); public Type FieldType => Type.[Friend]GetType(mFieldData.mFieldTypeId);
public bool IsConst => mFieldData.mFlags.HasFlag(.Const); public bool IsConst => mFieldData.mFlags.HasFlag(.Const);
public bool IsEnumCase => mFieldData.mFlags.HasFlag(.EnumCase);
public bool IsReadOnly => mFieldData.mFlags.HasFlag(.ReadOnly); public bool IsReadOnly => mFieldData.mFlags.HasFlag(.ReadOnly);
public bool IsStatic => mFieldData.mFlags.HasFlag(.Static); public bool IsStatic => mFieldData.mFlags.HasFlag(.Static);
public bool IsPublic => (mFieldData.mFlags & .FieldAccessMask) == .Public; public bool IsPublic => (mFieldData.mFlags & .FieldAccessMask) == .Public;

View file

@ -4691,7 +4691,13 @@ void BfCompiler::ProcessAutocompleteTempType()
auto propDeclaration = BfNodeDynCast<BfPropertyDeclaration>(fieldDecl); auto propDeclaration = BfNodeDynCast<BfPropertyDeclaration>(fieldDecl);
if (propDeclaration != NULL) if (propDeclaration != NULL)
autoComplete->CheckProperty(propDeclaration); autoComplete->CheckProperty(propDeclaration);
module->ResolveTypeRef(propDef->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowRef);
if (BfNodeIsA<BfVarTypeReference>(propDef->mTypeRef))
{
// This is only valid for ConstEval properties
}
else
module->ResolveTypeRef(propDef->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowRef);
if (auto indexerDeclaration = BfNodeDynCast<BfIndexerDeclaration>(propDef->mFieldDeclaration)) if (auto indexerDeclaration = BfNodeDynCast<BfIndexerDeclaration>(propDef->mFieldDeclaration))
{ {

View file

@ -1,12 +1,20 @@
#include "BfDeferEvalChecker.h" #include "BfDeferEvalChecker.h"
#include "BfUtil.h"
USING_NS_BF; USING_NS_BF;
BfDeferEvalChecker::BfDeferEvalChecker() BfDeferEvalChecker::BfDeferEvalChecker()
{ {
mRootNode = NULL;
mNeedsDeferEval = false; mNeedsDeferEval = false;
mDeferLiterals = true; mDeferLiterals = true;
mDeferDelegateBind = true; mDeferDelegateBind = true;
}
void BfDeferEvalChecker::Check(BfAstNode* node)
{
SetAndRestoreValue<BfAstNode*> rootNode(mRootNode, node);
node->Accept(this);
} }
void BfDeferEvalChecker::Visit(BfAstNode* attribExpr) void BfDeferEvalChecker::Visit(BfAstNode* attribExpr)
@ -174,3 +182,9 @@ void BfDeferEvalChecker::Visit(BfDefaultExpression* defaultExpr)
mNeedsDeferEval = true; mNeedsDeferEval = true;
} }
void BfDeferEvalChecker::Visit(BfVariableDeclaration* varDecl)
{
if (varDecl != mRootNode)
mNeedsDeferEval = true;
}

View file

@ -8,6 +8,7 @@ NS_BF_BEGIN
class BfDeferEvalChecker : public BfStructuralVisitor class BfDeferEvalChecker : public BfStructuralVisitor
{ {
public: public:
BfAstNode* mRootNode;
bool mNeedsDeferEval; bool mNeedsDeferEval;
bool mDeferDelegateBind; bool mDeferDelegateBind;
bool mDeferLiterals; bool mDeferLiterals;
@ -15,6 +16,8 @@ public:
public: public:
BfDeferEvalChecker(); BfDeferEvalChecker();
void Check(BfAstNode* node);
virtual void Visit(BfAstNode* node) override; virtual void Visit(BfAstNode* node) override;
virtual void Visit(BfInitializerExpression* collectionInitExpr); virtual void Visit(BfInitializerExpression* collectionInitExpr);
@ -29,8 +32,9 @@ public:
virtual void Visit(BfConditionalExpression* condExpr) override; virtual void Visit(BfConditionalExpression* condExpr) override;
virtual void Visit(BfUnaryOperatorExpression* unaryOpExpr) override; virtual void Visit(BfUnaryOperatorExpression* unaryOpExpr) override;
virtual void Visit(BfObjectCreateExpression* objCreateExpr) 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(BfDefaultExpression* defaultExpr) override;
virtual void Visit(BfVariableDeclaration* varDecl) override;
}; };

View file

@ -4630,7 +4630,7 @@ BfTypedValue BfExprEvaluator::LoadProperty(BfAstNode* targetSrc, BfTypedValue ta
bool isBaseLookup = (target.mType) && (typeInstance != target.mType); bool isBaseLookup = (target.mType) && (typeInstance != target.mType);
if ((isBaseLookup) && (target.mType->IsWrappableType())) if ((isBaseLookup) && (target.mType->IsWrappableType()))
isBaseLookup = false; isBaseLookup = false;
if (prop->mIsStatic) if (prop->mIsStatic)
mPropTarget = BfTypedValue(typeInstance); mPropTarget = BfTypedValue(typeInstance);
else if (isBaseLookup) else if (isBaseLookup)
@ -4655,6 +4655,8 @@ BfTypedValue BfExprEvaluator::LoadProperty(BfAstNode* targetSrc, BfTypedValue ta
} }
mOrigPropTarget = mPropTarget; mOrigPropTarget = mPropTarget;
if (prop->mIsStatic)
mOrigPropTarget = target;
if ((flags & BfLookupFieldFlag_IsAnonymous) == 0) if ((flags & BfLookupFieldFlag_IsAnonymous) == 0)
{ {
@ -4742,7 +4744,7 @@ BfTypedValue BfExprEvaluator::LoadProperty(BfAstNode* targetSrc, BfTypedValue ta
mPropDef = NULL; mPropDef = NULL;
mPropSrc = NULL; mPropSrc = NULL;
mOrigPropTarget = NULL; mOrigPropTarget = BfTypedValue();
return result; return result;
} }
} }
@ -5780,7 +5782,7 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr
{ {
BfDeferEvalChecker deferEvalChecker; BfDeferEvalChecker deferEvalChecker;
deferEvalChecker.mDeferDelegateBind = false; deferEvalChecker.mDeferDelegateBind = false;
argExpr->Accept(&deferEvalChecker); deferEvalChecker.Check(argExpr);
deferParamEval = deferEvalChecker.mNeedsDeferEval; deferParamEval = deferEvalChecker.mNeedsDeferEval;
} }
} }
@ -5938,7 +5940,7 @@ void BfExprEvaluator::PerformCallChecks(BfMethodInstance* methodInstance, BfAstN
mModule->CheckErrorAttributes(methodInstance->GetOwner(), methodInstance, customAttributes, targetSrc); mModule->CheckErrorAttributes(methodInstance->GetOwner(), methodInstance, customAttributes, targetSrc);
} }
BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl<BfIRValue>& irArgs, BfTypedValue* sret, BfCreateCallFlags callFlags) BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl<BfIRValue>& irArgs, BfTypedValue* sret, BfCreateCallFlags callFlags, BfType* origTargetType)
{ {
// static int sCallIdx = 0; // static int sCallIdx = 0;
// if (!mModule->mCompiler->mIsResolveOnly) // if (!mModule->mCompiler->mIsResolveOnly)
@ -6218,8 +6220,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
} }
} }
else 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) if (constRet)
{ {
auto constant = mModule->mBfIRBuilder->GetConstant(constRet.mValue); auto constant = mModule->mBfIRBuilder->GetConstant(constRet.mValue);
@ -7131,6 +7135,31 @@ void BfExprEvaluator::AddCallDependencies(BfMethodInstance* methodInstance)
//TODO: delete argumentsZ //TODO: delete argumentsZ
BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValue& inTarget, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance moduleMethodInstance, BfCreateCallFlags callFlags, SizedArrayImpl<BfResolvedArg>& argValues, BfTypedValue* argCascade) BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValue& inTarget, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance moduleMethodInstance, BfCreateCallFlags callFlags, SizedArrayImpl<BfResolvedArg>& argValues, BfTypedValue* argCascade)
{ {
SetAndRestoreValue<BfEvalExprFlags> 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 bypassVirtual = (callFlags & BfCreateCallFlags_BypassVirtual) != 0;
bool skipThis = (callFlags & BfCreateCallFlags_SkipThis) != 0;; bool skipThis = (callFlags & BfCreateCallFlags_SkipThis) != 0;;
@ -8194,7 +8223,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
physCallFlags = (BfCreateCallFlags)(physCallFlags | BfCreateCallFlags_GenericParamThis); physCallFlags = (BfCreateCallFlags)(physCallFlags | BfCreateCallFlags_GenericParamThis);
auto func = moduleMethodInstance.mFunc; 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) && if ((methodInstance->mMethodDef->mIsNoReturn) && ((mBfEvalExprFlags & BfEvalExprFlags_IsExpressionBody) != 0) &&
(mExpectingType != NULL) && (callResult.mType != mExpectingType)) (mExpectingType != NULL) && (callResult.mType != mExpectingType))
@ -10129,41 +10158,13 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
BfTypedValue result; BfTypedValue result;
BfTypedValue argCascade; BfTypedValue argCascade;
//
{
SetAndRestoreValue<BfEvalExprFlags> prevEvalExprFlag(mBfEvalExprFlags);
if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL) && (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mConstEvalAttributeTypeDef))) BfCreateCallFlags subCallFlags = BfCreateCallFlags_None;
{ if (bypassVirtual)
mModule->mAttributeState->mUsed = true; subCallFlags = (BfCreateCallFlags)(subCallFlags | BfCreateCallFlags_BypassVirtual);
mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_Comptime); if (skipThis)
} subCallFlags = (BfCreateCallFlags)(subCallFlags | BfCreateCallFlags_SkipThis);
else if ((moduleMethodInstance.mMethodInstance->mComptimeFlags & BfComptimeFlag_ConstEval) != 0) result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, subCallFlags, argValues.mResolvedArgs, &argCascade);
{
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);
}
if (overrideReturnType != NULL) if (overrideReturnType != NULL)
{ {
@ -18409,10 +18410,13 @@ BfModuleMethodInstance BfExprEvaluator::GetPropertyMethodInstance(BfMethodDef* m
((!mOrigPropTarget.mType->IsGenericParam()) && (mPropTarget.mType->IsInterface()))) ((!mOrigPropTarget.mType->IsGenericParam()) && (mPropTarget.mType->IsInterface())))
{ {
auto checkType = mOrigPropTarget.mType; auto checkType = mOrigPropTarget.mType;
if ((checkType->IsNullable()) && (!mPropTarget.mType->IsNullable()))
checkType = checkType->GetUnderlyingType();
if (checkType->IsPointer()) if (checkType->IsPointer())
checkType = ((BfPointerType*)checkType)->mElementType; checkType = ((BfPointerType*)checkType)->mElementType;
if (checkType->IsWrappableType()) if (checkType->IsWrappableType())
checkType = mModule->GetWrappedStructType(checkType); checkType = mModule->GetWrappedStructType(checkType);
if ((checkType != NULL) && (checkType->IsTypeInstance())) if ((checkType != NULL) && (checkType->IsTypeInstance()))
{ {
auto activeTypeDef = mModule->GetActiveTypeDef(); auto activeTypeDef = mModule->GetActiveTypeDef();
@ -23707,6 +23711,24 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
} }
auto underlyingType = resultType->GetUnderlyingType(); 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; BfIRValue convResultValue;
if (resultTypedValue->mType == resultType) if (resultTypedValue->mType == resultType)
@ -23728,7 +23750,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
else else
PerformBinaryOperation(underlyingType, convOtherValue, convResultValue, binaryOp, opToken); PerformBinaryOperation(underlyingType, convOtherValue, convResultValue, binaryOp, opToken);
if (mResult.mType == underlyingType) if (mResult.mType == underlyingType)
mResult.mType = resultType; mResult.mType = resultType;
return; return;
} }

View file

@ -476,7 +476,7 @@ public:
BfTypedValue LookupIdentifier(BfIdentifierNode* identifierNode, bool ignoreInitialError = false, bool* hadError = NULL); BfTypedValue LookupIdentifier(BfIdentifierNode* identifierNode, bool ignoreInitialError = false, bool* hadError = NULL);
void AddCallDependencies(BfMethodInstance* methodInstance); void AddCallDependencies(BfMethodInstance* methodInstance);
void PerformCallChecks(BfMethodInstance* methodInstance, BfAstNode* targetSrc); void PerformCallChecks(BfMethodInstance* methodInstance, BfAstNode* targetSrc);
BfTypedValue CreateCall(BfAstNode* targetSrc, BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl<BfIRValue>& irArgs, BfTypedValue* sret = NULL, BfCreateCallFlags callFlags = BfCreateCallFlags_None); BfTypedValue CreateCall(BfAstNode* targetSrc, BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl<BfIRValue>& 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<BfResolvedArg>& argValues, BfTypedValue* argCascade = NULL); BfTypedValue CreateCall(BfAstNode* targetSrc, const BfTypedValue& target, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance methodInstance, BfCreateCallFlags callFlags, SizedArrayImpl<BfResolvedArg>& argValues, BfTypedValue* argCascade = NULL);
BfTypedValue CreateCall(BfMethodMatcher* methodMatcher, BfTypedValue target); BfTypedValue CreateCall(BfMethodMatcher* methodMatcher, BfTypedValue target);
void MakeBaseConcrete(BfTypedValue& typedValue); void MakeBaseConcrete(BfTypedValue& typedValue);

View file

@ -11348,7 +11348,7 @@ BfIRType BfModule::CurrentAddToConstHolder(BfIRType irType)
if (irType.mKind == BfIRTypeData::TypeKind_SizedArray) if (irType.mKind == BfIRTypeData::TypeKind_SizedArray)
{ {
auto sizedArrayType = (BfConstantSizedArrayType*)mBfIRBuilder->GetConstantById(irType.mId); 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; return irType;
@ -12591,7 +12591,9 @@ BfTypedValue BfModule::LoadValue(BfTypedValue typedValue, BfAstNode* refNode, bo
} }
return result; 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; filePath = mCurMethodState->mMixinState->mInjectFilePosition.mFileInstance->mParser->mFileName;
return BfTypedValue(GetStringObjectValue(GetFileDir(filePath)), ResolveTypeDef(mCompiler->mStringTypeDef)); 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") else if (str == "#CallerMemberName")
{ {
String memberName = ""; String memberName = "";
@ -14668,7 +14689,7 @@ BfTypedValue BfModule::GetCompilerFieldValue(const StringImpl& str)
if (project != NULL) if (project != NULL)
return BfTypedValue(GetStringObjectValue(mProject->mName), ResolveTypeDef(mCompiler->mStringTypeDef)); return BfTypedValue(GetStringObjectValue(mProject->mName), ResolveTypeDef(mCompiler->mStringTypeDef));
} }
} }
if (str == "#TimeLocal") if (str == "#TimeLocal")
{ {
@ -15099,6 +15120,9 @@ BfIRValue BfModule::AllocLocalVariable(BfType* type, const StringImpl& name, boo
void BfModule::DoAddLocalVariable(BfLocalVariable* localVar) void BfModule::DoAddLocalVariable(BfLocalVariable* localVar)
{ {
if ((localVar->mName == "maxValue") && (mIsComptimeModule))
BF_ASSERT(!localVar->mAddr.IsFake());
while (localVar->mName.StartsWith('@')) while (localVar->mName.StartsWith('@'))
{ {
localVar->mNamePrefixCount++; localVar->mNamePrefixCount++;

View file

@ -109,7 +109,8 @@ enum BfCastFlags
BfCastFlags_WarnOnBox = 0x800, BfCastFlags_WarnOnBox = 0x800,
BfCastFlags_IsCastCheck = 0x1000, BfCastFlags_IsCastCheck = 0x1000,
BfCastFlags_IsConstraintCheck = 0x2000, BfCastFlags_IsConstraintCheck = 0x2000,
BfCastFlags_WantsConst = 0x4000 BfCastFlags_WantsConst = 0x4000,
BfCastFlags_FromComptimeReturn = 0x8000
}; };
enum BfCastResultFlags : int8 enum BfCastResultFlags : int8

View file

@ -4328,6 +4328,10 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
ValidateGenericConstraints(validateEntry.mTypeRef, validateEntry.mGenericType, false); 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->IsBoxed())
{ {
if ((typeInstance->mCustomAttributes == NULL) && (typeDef->mTypeDeclaration != NULL) && (typeDef->HasCustomAttributes())) if ((typeInstance->mCustomAttributes == NULL) && (typeDef->mTypeDeclaration != NULL) && (typeDef->HasCustomAttributes()))
@ -4696,7 +4700,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
{ {
// Already handled // 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<BfPropertyDeclaration>(fieldDef->mFieldDeclaration)) if (auto propDecl = BfNodeDynCast<BfPropertyDeclaration>(fieldDef->mFieldDeclaration))
{ {
@ -4941,7 +4945,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
if (propDef->IsExpressionBodied()) if (propDef->IsExpressionBodied())
target = (BfAttributeTargets)(target | BfAttributeTargets_Method); 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); auto customAttrs = GetCustomAttributes(propDef->GetFieldDeclaration()->mAttributes, target);
delete customAttrs; delete customAttrs;
@ -5523,7 +5527,13 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
typeState.mCurTypeDef = propDef->mDeclaringType; typeState.mCurTypeDef = propDef->mDeclaringType;
typeState.mType = typeInstance; typeState.mType = typeInstance;
SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState); SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
ResolveTypeRef(propDef->mTypeRef, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowRef);
if (BfNodeIsA<BfVarTypeReference>(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 cast '%s' to '%s'" :
"Unable to implicitly 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); auto error = Fail(errStr, srcNode);
if ((error != NULL) && (srcNode != NULL)) if ((error != NULL) && (srcNode != NULL))
{ {

View file

@ -1024,6 +1024,19 @@ int CeBuilder::GetCallTableIdx(BeFunction* beFunction, CeOperand* outOperand)
callEntry.mFunctionInfo = ceFunctionInfo; callEntry.mFunctionInfo = ceFunctionInfo;
*callIdxPtr = (int)mCeFunction->mCallTable.size(); *callIdxPtr = (int)mCeFunction->mCallTable.size();
mCeFunction->mCallTable.Add(callEntry); 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; return *callIdxPtr;
} }
@ -5148,7 +5161,8 @@ BfTypedValue CeContext::Call(CeCallSource callSource, BfModule* module, BfMethod
mCeMachine->mAppendAllocInfo = NULL; mCeMachine->mAppendAllocInfo = NULL;
BfType* returnType = 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]; memStart = &mMemory[0];
addr_ce retInstAddr = retAddr; addr_ce retInstAddr = retAddr;
@ -5228,6 +5242,13 @@ BfTypedValue CeContext::Call(CeCallSource callSource, BfModule* module, BfMethod
mCallStack = prevCallStack; 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; 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; auto ceModule = mCeMachine->mCeModule;
CeFunction* ceFunction = startFunction; CeFunction* ceFunction = startFunction;
@ -6057,6 +6078,14 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
_FixVariables(); _FixVariables();
CeSetAddrVal(stackPtr + 0, reflectType, ptrSize); 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) else if (checkFunction->mFunctionKind == CeFunctionKind_EmitTypeBody)
{ {
int32 typeId = *(int32*)((uint8*)stackPtr); int32 typeId = *(int32*)((uint8*)stackPtr);
@ -7621,7 +7650,7 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
auto& ceStaticFieldEntry = ceFunction->mStaticFieldTable[tableIdx]; auto& ceStaticFieldEntry = ceFunction->mStaticFieldTable[tableIdx];
if (ceStaticFieldEntry.mBindExecuteId != mExecuteId) if (ceStaticFieldEntry.mBindExecuteId != mExecuteId)
{ {
if (mStaticCtorExecSet.TryAdd(ceStaticFieldEntry.mTypeId, NULL)) if ((mStaticCtorExecSet.TryAdd(ceStaticFieldEntry.mTypeId, NULL)) && (!ceStaticFieldEntry.mName.StartsWith("#")))
{ {
auto bfType = GetBfType(ceStaticFieldEntry.mTypeId); auto bfType = GetBfType(ceStaticFieldEntry.mTypeId);
BfTypeInstance* bfTypeInstance = NULL; BfTypeInstance* bfTypeInstance = NULL;
@ -7667,6 +7696,74 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
if (ceStaticFieldEntry.mSize > 0) if (ceStaticFieldEntry.mSize > 0)
memset(ptr, 0, ceStaticFieldEntry.mSize); memset(ptr, 0, ceStaticFieldEntry.mSize);
staticFieldInfo->mAddr = (addr_ce)(ptr - memStart); 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; ceStaticFieldEntry.mAddr = staticFieldInfo->mAddr;
@ -9199,11 +9296,15 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction)
} }
else if (owner->IsInstanceOf(mCeModule->mCompiler->mCompilerTypeDef)) 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; ceFunction->mFunctionKind = CeFunctionKind_EmitTypeBody;
} }
if (methodDef->mName == "Comptime_EmitAddInterface") else if (methodDef->mName == "Comptime_EmitAddInterface")
{ {
ceFunction->mFunctionKind = CeFunctionKind_EmitAddInterface; ceFunction->mFunctionKind = CeFunctionKind_EmitAddInterface;
} }
@ -9493,7 +9594,7 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f
CeFunctionInfo* ceFunctionInfo = NULL; CeFunctionInfo* ceFunctionInfo = NULL;
CeFunction* ceFunction = NULL; CeFunction* ceFunction = NULL;
if (!mFunctions.TryAdd(methodInstance, NULL, &functionInfoPtr)) if (!mFunctions.TryAdd(methodInstance, NULL, &functionInfoPtr))
{ {
ceFunctionInfo = *functionInfoPtr; ceFunctionInfo = *functionInfoPtr;
BF_ASSERT(ceFunctionInfo->mCeFunction != NULL); BF_ASSERT(ceFunctionInfo->mCeFunction != NULL);
return ceFunctionInfo->mCeFunction; return ceFunctionInfo->mCeFunction;
@ -9524,6 +9625,11 @@ CeFunction* CeMachine::GetFunction(BfMethodInstance* methodInstance, BfIRValue f
else else
{ {
ceFunctionInfo = *namedFunctionInfoPtr; ceFunctionInfo = *namedFunctionInfoPtr;
if ((ceFunctionInfo->mMethodInstance != NULL) && (ceFunctionInfo->mMethodInstance != methodInstance))
{
// This ceFunctionInfo is already taken - probably from a name mangling conflict
ceFunctionInfo = new CeFunctionInfo();
}
} }
} }
else else

View file

@ -329,8 +329,15 @@ public:
mCeFunction = NULL; mCeFunction = NULL;
mRefCount = 0; mRefCount = 0;
} }
~CeFunctionInfo(); ~CeFunctionInfo();
BfTypeInstance* GetOwner()
{
if (mMethodInstance != NULL)
return mMethodInstance->GetOwner();
return mMethodRef.mTypeInstance;
}
}; };
class CeCallEntry class CeCallEntry
@ -440,6 +447,7 @@ enum CeFunctionKind
CeFunctionKind_Method_GetParamInfo, CeFunctionKind_Method_GetParamInfo,
CeFunctionKind_Method_GetGenericArg, CeFunctionKind_Method_GetGenericArg,
CeFunctionKind_SetReturnType,
CeFunctionKind_EmitTypeBody, CeFunctionKind_EmitTypeBody,
CeFunctionKind_EmitAddInterface, CeFunctionKind_EmitAddInterface,
CeFunctionKind_EmitMethodEntry, CeFunctionKind_EmitMethodEntry,
@ -1050,6 +1058,7 @@ public:
Kind mKind; Kind mKind;
BfAstNode* mRefNode; BfAstNode* mRefNode;
BfFieldInstance* mFieldInstance; BfFieldInstance* mFieldInstance;
BfType* mOrigCalleeType;
public: public:
CeCallSource(BfAstNode* refNode) CeCallSource(BfAstNode* refNode)
@ -1057,6 +1066,7 @@ public:
mKind = Kind_Unknown; mKind = Kind_Unknown;
mRefNode = refNode; mRefNode = refNode;
mFieldInstance = NULL; mFieldInstance = NULL;
mOrigCalleeType = NULL;
} }
CeCallSource() CeCallSource()
@ -1064,6 +1074,7 @@ public:
mKind = Kind_Unknown; mKind = Kind_Unknown;
mRefNode = NULL; mRefNode = NULL;
mFieldInstance = NULL; mFieldInstance = NULL;
mOrigCalleeType = NULL;
} }
}; };
@ -1135,7 +1146,7 @@ public:
BfIRValue CreateConstant(BfModule* module, uint8* ptr, BfType* type, BfType** outType = NULL); 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); 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<BfIRValue>& args, CeEvalFlags flags, BfType* expectingType); BfTypedValue Call(CeCallSource callSource, BfModule* module, BfMethodInstance* methodInstance, const BfSizedArray<BfIRValue>& args, CeEvalFlags flags, BfType* expectingType);
}; };

View file

@ -137,6 +137,10 @@ namespace Tests
EnumG eg = .A; EnumG eg = .A;
eg.Set(66); eg.Set(66);
Test.Assert(eg == .B); Test.Assert(eg == .B);
var ea = EnumA.MaxValue;
Test.Assert(ea == .B);
Test.Assert(EnumA.Count == 2);
} }
} }
} }