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

Allow comptime attempts on generic interface dispatches

This commit is contained in:
Brian Fiete 2021-07-20 11:10:10 -07:00
parent 4b8983a013
commit f1d9964ba1
3 changed files with 45 additions and 25 deletions

View file

@ -5214,7 +5214,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, bool isTailCall) BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl<BfIRValue>& irArgs, BfTypedValue* sret, BfCreateCallFlags callFlags)
{ {
// static int sCallIdx = 0; // static int sCallIdx = 0;
// if (!mModule->mCompiler->mIsResolveOnly) // if (!mModule->mCompiler->mIsResolveOnly)
@ -5457,6 +5457,11 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
{ {
doConstReturn = true; doConstReturn = true;
} }
else if (((callFlags & BfCreateCallFlags_GenericParamThis) != 0) && (methodInstance->GetOwner()->IsInterface()))
{
mModule->Warn(0, "Concrete method may fail to comptime during specialization", targetSrc);
doConstReturn = true;
}
else else
{ {
CeEvalFlags evalFlags = CeEvalFlags_None; CeEvalFlags evalFlags = CeEvalFlags_None;
@ -5502,7 +5507,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
{ {
if (returnType->IsInstanceOf(mModule->mCompiler->mSpanTypeDef)) if (returnType->IsInstanceOf(mModule->mCompiler->mSpanTypeDef))
{ {
if (mExpectingType->IsUndefSizedArray()) if ((mExpectingType != NULL) && (mExpectingType->IsUndefSizedArray()))
{ {
if (returnType->GetUnderlyingType() == mExpectingType->GetUnderlyingType()) if (returnType->GetUnderlyingType() == mExpectingType->GetUnderlyingType())
return mModule->GetDefaultTypedValue(mExpectingType, true, BfDefaultValueKind_Undef); return mModule->GetDefaultTypedValue(mExpectingType, true, BfDefaultValueKind_Undef);
@ -5922,7 +5927,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance*
//argIdx++; //argIdx++;
} }
if (isTailCall) if ((callFlags & BfCreateCallFlags_TailCall) != 0)
mModule->mBfIRBuilder->SetTailCall(callInst); mModule->mBfIRBuilder->SetTailCall(callInst);
if (methodDef->mIsNoReturn) if (methodDef->mIsNoReturn)
@ -6001,9 +6006,9 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodMatcher* methodMatcher, BfTyped
PerformCallChecks(moduleMethodInstance.mMethodInstance, methodMatcher->mTargetSrc); PerformCallChecks(moduleMethodInstance.mMethodInstance, methodMatcher->mTargetSrc);
BfCreateFallFlags callFlags = BfCreateFallFlags_None; BfCreateCallFlags callFlags = BfCreateCallFlags_None;
if (methodMatcher->mAllowImplicitRef) if (methodMatcher->mAllowImplicitRef)
callFlags = (BfCreateFallFlags)(callFlags | BfCreateFallFlags_AllowImplicitRef); callFlags = (BfCreateCallFlags)(callFlags | BfCreateCallFlags_AllowImplicitRef);
return CreateCall(methodMatcher->mTargetSrc, target, BfTypedValue(), methodMatcher->mBestMethodDef, moduleMethodInstance, callFlags, methodMatcher->mArguments); return CreateCall(methodMatcher->mTargetSrc, target, BfTypedValue(), methodMatcher->mBestMethodDef, moduleMethodInstance, callFlags, methodMatcher->mArguments);
} }
@ -6335,10 +6340,10 @@ 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, BfCreateFallFlags 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)
{ {
bool bypassVirtual = (callFlags & BfCreateFallFlags_BypassVirtual) != 0; bool bypassVirtual = (callFlags & BfCreateCallFlags_BypassVirtual) != 0;
bool skipThis = (callFlags & BfCreateFallFlags_SkipThis) != 0;; bool skipThis = (callFlags & BfCreateCallFlags_SkipThis) != 0;;
static int sCallIdx = 0; static int sCallIdx = 0;
if (!mModule->mCompiler->mIsResolveOnly) if (!mModule->mCompiler->mIsResolveOnly)
@ -7050,7 +7055,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
refNode = targetSrc; refNode = targetSrc;
if ((wantType->IsRef()) && (!argValue.mType->IsRef()) && if ((wantType->IsRef()) && (!argValue.mType->IsRef()) &&
(((callFlags & BfCreateFallFlags_AllowImplicitRef) != 0) || (wantType->IsIn()))) (((callFlags & BfCreateCallFlags_AllowImplicitRef) != 0) || (wantType->IsIn())))
argValue = mModule->ToRef(argValue, (BfRefType*)wantType); argValue = mModule->ToRef(argValue, (BfRefType*)wantType);
if (mModule->mCurMethodState != NULL) if (mModule->mCurMethodState != NULL)
@ -7277,8 +7282,12 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
return BfTypedValue(); return BfTypedValue();
} }
BfCreateCallFlags physCallFlags = BfCreateCallFlags_None;
if ((origTarget.mType != NULL) && (origTarget.mType->IsGenericParam()))
physCallFlags = (BfCreateCallFlags)(physCallFlags | BfCreateCallFlags_GenericParamThis);
auto func = moduleMethodInstance.mFunc; auto func = moduleMethodInstance.mFunc;
BfTypedValue callResult = CreateCall(targetSrc, methodInstance, func, bypassVirtual, irArgs); BfTypedValue callResult = CreateCall(targetSrc, methodInstance, func, bypassVirtual, irArgs, NULL, physCallFlags);
// This gets triggered for non-sret (ie: comptime) composite returns so they aren't considered readonly // This gets triggered for non-sret (ie: comptime) composite returns so they aren't considered readonly
if ((callResult.mKind == BfTypedValueKind_Value) && (!callResult.mValue.IsConst()) && if ((callResult.mKind == BfTypedValueKind_Value) && (!callResult.mValue.IsConst()) &&
@ -7480,7 +7489,7 @@ BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBou
if (isFailurePass) if (isFailurePass)
mModule->Fail(StrFormat("'%s' is inaccessible due to its protection level", mModule->MethodToString(moduleMethodInstance.mMethodInstance).c_str()), targetSrc); mModule->Fail(StrFormat("'%s' is inaccessible due to its protection level", mModule->MethodToString(moduleMethodInstance.mMethodInstance).c_str()), targetSrc);
prevBindResult.Restore(); prevBindResult.Restore();
return CreateCall(methodMatcher.mTargetSrc, target, BfTypedValue(), methodMatcher.mBestMethodDef, moduleMethodInstance, BfCreateFallFlags_None, methodMatcher.mArguments); return CreateCall(methodMatcher.mTargetSrc, target, BfTypedValue(), methodMatcher.mBestMethodDef, moduleMethodInstance, BfCreateCallFlags_None, methodMatcher.mArguments);
} }
static int sInvocationIdx = 0; static int sInvocationIdx = 0;
@ -9155,11 +9164,11 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
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); 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);
} }
BfCreateFallFlags subCallFlags = BfCreateFallFlags_None; BfCreateCallFlags subCallFlags = BfCreateCallFlags_None;
if (bypassVirtual) if (bypassVirtual)
subCallFlags = (BfCreateFallFlags)(subCallFlags | BfCreateFallFlags_BypassVirtual); subCallFlags = (BfCreateCallFlags)(subCallFlags | BfCreateCallFlags_BypassVirtual);
if (skipThis) if (skipThis)
subCallFlags = (BfCreateFallFlags)(subCallFlags | BfCreateFallFlags_SkipThis); subCallFlags = (BfCreateCallFlags)(subCallFlags | BfCreateCallFlags_SkipThis);
result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, subCallFlags, argValues.mResolvedArgs, &argCascade); result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, subCallFlags, argValues.mResolvedArgs, &argCascade);
} }
@ -9720,13 +9729,19 @@ void BfExprEvaluator::LookupQualifiedStaticField(BfAstNode* nameNode, BfIdentifi
{ {
mResult = LookupField(nameRight, BfTypedValue(genericParamInstance->mTypeConstraint), findName); mResult = LookupField(nameRight, BfTypedValue(genericParamInstance->mTypeConstraint), findName);
if ((mResult) || (mPropDef != NULL)) if ((mResult) || (mPropDef != NULL))
{
mOrigPropTarget = lookupType;
return; return;
}
} }
for (auto constraint : genericParamInstance->mInterfaceConstraints) for (auto constraint : genericParamInstance->mInterfaceConstraints)
{ {
mResult = LookupField(nameRight, BfTypedValue(constraint), findName); mResult = LookupField(nameRight, BfTypedValue(constraint), findName);
if ((mResult) || (mPropDef != NULL)) if ((mResult) || (mPropDef != NULL))
{
mOrigPropTarget = lookupType;
return; return;
}
} }
} }
@ -17059,7 +17074,10 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp
} }
} }
else else
mResult = CreateCall(mPropSrc, methodInstance.mMethodInstance, methodInstance.mFunc, mPropDefBypassVirtual, args); {
BfCreateCallFlags callFlags = mOrigPropTarget.mType->IsGenericParam() ? BfCreateCallFlags_GenericParamThis : BfCreateCallFlags_None;
mResult = CreateCall(mPropSrc, methodInstance.mMethodInstance, methodInstance.mFunc, mPropDefBypassVirtual, args, NULL, callFlags);
}
if (mResult.mType != NULL) if (mResult.mType != NULL)
{ {
if ((mResult.mType->IsVar()) && (mModule->mCompiler->mIsResolveOnly)) if ((mResult.mType->IsVar()) && (mModule->mCompiler->mIsResolveOnly))
@ -21817,7 +21835,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
argValues.push_back(resolvedArg); argValues.push_back(resolvedArg);
resolvedArg.mTypedValue = rightValue; resolvedArg.mTypedValue = rightValue;
argValues.push_back(resolvedArg); argValues.push_back(resolvedArg);
mResult = CreateCall(opToken, BfTypedValue(), BfTypedValue(), moduleMethodInstance.mMethodInstance->mMethodDef, moduleMethodInstance, BfCreateFallFlags_None, argValues); mResult = CreateCall(opToken, BfTypedValue(), BfTypedValue(), moduleMethodInstance.mMethodInstance->mMethodDef, moduleMethodInstance, BfCreateCallFlags_None, argValues);
if ((mResult) && if ((mResult) &&
((binaryOp == BfBinaryOp_InEquality) || (binaryOp == BfBinaryOp_StrictInEquality))) ((binaryOp == BfBinaryOp_InEquality) || (binaryOp == BfBinaryOp_StrictInEquality)))
mResult.mValue = mModule->mBfIRBuilder->CreateNot(mResult.mValue); mResult.mValue = mModule->mBfIRBuilder->CreateNot(mResult.mValue);

View file

@ -41,12 +41,14 @@ enum BfResolveArgFlags
BfResolveArgFlag_FromGenericParam = 2 BfResolveArgFlag_FromGenericParam = 2
}; };
enum BfCreateFallFlags enum BfCreateCallFlags
{ {
BfCreateFallFlags_None, BfCreateCallFlags_None,
BfCreateFallFlags_BypassVirtual = 1, BfCreateCallFlags_BypassVirtual = 1,
BfCreateFallFlags_SkipThis = 2, BfCreateCallFlags_SkipThis = 2,
BfCreateFallFlags_AllowImplicitRef = 4 BfCreateCallFlags_AllowImplicitRef = 4,
BfCreateCallFlags_TailCall = 8,
BfCreateCallFlags_GenericParamThis = 0x10
}; };
class BfResolvedArg class BfResolvedArg
@ -444,8 +446,8 @@ 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, bool isTailCall = false); BfTypedValue CreateCall(BfAstNode* targetSrc, BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl<BfIRValue>& irArgs, BfTypedValue* sret = NULL, BfCreateCallFlags callFlags = BfCreateCallFlags_None);
BfTypedValue CreateCall(BfAstNode* targetSrc, const BfTypedValue& target, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance methodInstance, BfCreateFallFlags 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);
void SplatArgs(BfTypedValue value, SizedArrayImpl<BfIRValue>& irArgs); void SplatArgs(BfTypedValue value, SizedArrayImpl<BfIRValue>& irArgs);

View file

@ -19587,14 +19587,14 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
mBfIRBuilder->PopulateType(methodInstance->mReturnType); mBfIRBuilder->PopulateType(methodInstance->mReturnType);
auto returnType = BfTypedValue(mBfIRBuilder->GetArgument(methodInstance->GetStructRetIdx()), methodInstance->mReturnType, true); auto returnType = BfTypedValue(mBfIRBuilder->GetArgument(methodInstance->GetStructRetIdx()), methodInstance->mReturnType, true);
exprEvaluator.mReceivingValue = &returnType; exprEvaluator.mReceivingValue = &returnType;
auto retVal = exprEvaluator.CreateCall(NULL, innerMethodInstance.mMethodInstance, innerMethodInstance.mFunc, true, innerParams, NULL, true); auto retVal = exprEvaluator.CreateCall(NULL, innerMethodInstance.mMethodInstance, innerMethodInstance.mFunc, true, innerParams, NULL, BfCreateCallFlags_TailCall);
BF_ASSERT(exprEvaluator.mReceivingValue == NULL); // Ensure it was actually used BF_ASSERT(exprEvaluator.mReceivingValue == NULL); // Ensure it was actually used
mBfIRBuilder->CreateRetVoid(); mBfIRBuilder->CreateRetVoid();
} }
else else
{ {
mBfIRBuilder->PopulateType(methodInstance->mReturnType); mBfIRBuilder->PopulateType(methodInstance->mReturnType);
auto retVal = exprEvaluator.CreateCall(NULL, innerMethodInstance.mMethodInstance, innerMethodInstance.mFunc, true, innerParams, NULL, true); auto retVal = exprEvaluator.CreateCall(NULL, innerMethodInstance.mMethodInstance, innerMethodInstance.mFunc, true, innerParams, NULL, BfCreateCallFlags_TailCall);
if (mCurMethodInstance->mReturnType->IsValueType()) if (mCurMethodInstance->mReturnType->IsValueType())
retVal = LoadValue(retVal); retVal = LoadValue(retVal);
CreateReturn(retVal.mValue); CreateReturn(retVal.mValue);