1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 03:28:20 +02:00

Expanding support for params in delegates, params tuple support

This commit is contained in:
Brian Fiete 2025-02-16 11:36:14 -08:00
parent 4b660b2314
commit 421cace017
11 changed files with 203 additions and 59 deletions

View file

@ -0,0 +1,5 @@
namespace System;
struct Tuple
{
}

View file

@ -551,10 +551,12 @@ protected:
if ((mAllocSizeAndFlags & AttrFlags) == StrPtrFlag)
{
// It's a reference
char* newPtr = AllocPtr(this->mLength);
memcpy(newPtr, this->mPtr, this->mLength + 1);
int allocSize = (int)BF_MAX(GetAllocSize(), this->mLength + 1);
char* newPtr = AllocPtr(allocSize);
memcpy(newPtr, this->mPtr, this->mLength);
newPtr[this->mLength] = 0;
this->mPtr = newPtr;
mAllocSizeAndFlags = this->mLength | DynAllocFlag | StrPtrFlag;
mAllocSizeAndFlags = allocSize | DynAllocFlag | StrPtrFlag;
}
}

View file

@ -213,6 +213,11 @@ namespace System
public static extern bool Equals<T>(T val1, T val2);
}
struct Tuple
{
}
struct Function : int
{

View file

@ -478,6 +478,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
mTypeTypeDef = NULL;
mUnboundAttributeTypeDef = NULL;
mValueTypeTypeDef = NULL;
mTupleTypeDef = NULL;
mResultTypeDef = NULL;
mObsoleteAttributeTypeDef = NULL;
mErrorAttributeTypeDef = NULL;
@ -7334,6 +7335,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
mTypeTypeDef = _GetRequiredType("System.Type");
mUnboundAttributeTypeDef = _GetRequiredType("System.UnboundAttribute");
mValueTypeTypeDef = _GetRequiredType("System.ValueType");
mTupleTypeDef = _GetRequiredType("System.Tuple");
mObsoleteAttributeTypeDef = _GetRequiredType("System.ObsoleteAttribute");
mErrorAttributeTypeDef = _GetRequiredType("System.ErrorAttribute");
mWarnAttributeTypeDef = _GetRequiredType("System.WarnAttribute");

View file

@ -379,6 +379,7 @@ public:
BfTypeDef* mTypeTypeDeclDef;
BfTypeDef* mTypeTypeDef;
BfTypeDef* mValueTypeTypeDef;
BfTypeDef* mTupleTypeDef;
BfTypeDef* mResultTypeDef;
BfTypeDef* mGCTypeDef;
BfTypeDef* mGenericIEnumerableTypeDef;

View file

@ -14741,30 +14741,19 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam
if (invokeMethodInstance != NULL)
{
for (int paramIdx = 0; paramIdx < (int)invokeMethodInstance->mMethodDef->mParams.size(); paramIdx++)
for (int paramIdx = 0; paramIdx < (int)invokeMethodInstance->GetParamCount(); paramIdx++)
{
auto invokeParamDef = invokeMethodInstance->mMethodDef->mParams[paramIdx];
BfParameterDef* paramDef = new BfParameterDef();
paramDef->mParamDeclaration = tempParamDecls.Alloc();
BfAstNode::Zero(paramDef->mParamDeclaration);
BfLocalVariable* localVar = new BfLocalVariable();
if (paramIdx < (int)lambdaBindExpr->mParams.size())
{
localVar->mName = lambdaBindExpr->mParams[paramIdx]->ToString();
localVar->mNameNode = lambdaBindExpr->mParams[paramIdx];
paramDef->mParamDeclaration->mNameNode = lambdaBindExpr->mParams[paramIdx];
}
else
{
mModule->AssertErrorState();
localVar->mName = invokeParamDef->mName;
paramDef->mParamDeclaration->mNameNode = NULL;
localVar->mName = invokeMethodInstance->GetParamName(paramIdx);
}
paramDef->mName = localVar->mName;
methodDef->mParams.push_back(paramDef);
localVar->mResolvedType = invokeMethodInstance->GetParamType(paramIdx);
mModule->PopulateType(localVar->mResolvedType);
localVar->mAssignedKind = BfLocalVarAssignKind_Unconditional;
@ -14775,13 +14764,39 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam
mModule->DoAddLocalVariable(localVar);
if (autoComplete != NULL)
autoComplete->CheckLocalDef(BfNodeDynCast<BfIdentifierNode>(paramDef->mParamDeclaration->mNameNode), methodState.mLocals.back());
auto resolvePassData = mModule->mCompiler->mResolvePassData;
if (resolvePassData != NULL)
resolvePassData->HandleLocalReference(BfNodeDynCast<BfIdentifierNode>(paramDef->mParamDeclaration->mNameNode), mModule->mCurTypeInstance->mTypeDef,
resolvePassData->HandleLocalReference(BfNodeDynCast<BfIdentifierNode>(localVar->mNameNode), mModule->mCurTypeInstance->mTypeDef,
mModule->mCurMethodInstance->mMethodDef, localVar->mLocalVarId);
}
for (int paramIdx = 0; paramIdx < (int)invokeMethodInstance->mMethodDef->mParams.size(); paramIdx++)
{
auto invokeParamDef = invokeMethodInstance->mMethodDef->mParams[paramIdx];
BfParameterDef* paramDef = new BfParameterDef();
paramDef->mParamDeclaration = tempParamDecls.Alloc();
BfAstNode::Zero(paramDef->mParamDeclaration);
paramDef->mTypeRef = invokeParamDef->mTypeRef;
paramDef->mParamKind = invokeParamDef->mParamKind;
if ((paramIdx < (int)lambdaBindExpr->mParams.size()) && (invokeMethodInstance->GetParamKind(paramIdx) != BfParamKind_DelegateParam))
{
//TODO: Not always correct if we have a 'params'
paramDef->mParamDeclaration->mNameNode = lambdaBindExpr->mParams[paramIdx];
paramDef->mName = paramDef->mParamDeclaration->mNameNode->ToString();
}
else
{
paramDef->mParamDeclaration->mNameNode = NULL;
paramDef->mName = invokeParamDef->mName;
}
methodDef->mParams.push_back(paramDef);
if (autoComplete != NULL)
autoComplete->CheckLocalDef(BfNodeDynCast<BfIdentifierNode>(paramDef->mParamDeclaration->mNameNode), methodState.mLocals.back());
}
}
bool isAutocomplete = mModule->mCompiler->IsAutocomplete();
@ -24091,12 +24106,17 @@ void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExp
rightTypedValueExpr.mRefNode = opToken;
auto valueTypeEmpty = mModule->mBfIRBuilder->CreateConstAgg(mModule->mBfIRBuilder->MapType(indexType->mBaseType->mBaseType), {});
SizedArray<BfIRValue, 8> tupleEmptyMembers;
tupleEmptyMembers.Add(valueTypeEmpty);
auto tupleTypeEmpty = mModule->mBfIRBuilder->CreateConstAgg(mModule->mBfIRBuilder->MapType(mModule->ResolveTypeDef(mModule->mCompiler->mTupleTypeDef)), tupleEmptyMembers);
SizedArray<BfIRValue, 8> enumMembers;
enumMembers.Add(valueTypeEmpty);
auto enumValue = mModule->mBfIRBuilder->CreateConstAgg(mModule->mBfIRBuilder->MapType(indexType->mBaseType), enumMembers);
SizedArray<BfIRValue, 8> tupleMembers;
tupleMembers.Add(valueTypeEmpty);
tupleMembers.Add(tupleTypeEmpty);
tupleMembers.Add(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 1));
auto tupleValue = mModule->mBfIRBuilder->CreateConstAgg(mModule->mBfIRBuilder->MapType(indexType->mFieldInstances[0].mResolvedType), tupleMembers);

View file

@ -3617,25 +3617,22 @@ void BfModule::FatalError(const StringImpl& error, const char* file, int line, i
BfpSystem_FatalError(fullError.c_str(), "FATAL MODULE ERROR");
}
void BfModule::FatalError(const StringImpl& error, BfAstNode* refNode)
void BfModule::FatalError(const StringImpl& error, BfFailHandleKind failHandleKind)
{
if (refNode != NULL)
{
auto parser = refNode->GetParserData();
if (parser != NULL)
{
int line = -1;
int lineChar = -1;
parser->GetLineCharAtIdx(refNode->mSrcStart, line, lineChar);
if (line != -1)
FatalError(error, parser->mFileName.c_str(), line, lineChar);
}
}
if (failHandleKind == BfFailHandleKind_Normal)
FatalError(error);
else if (failHandleKind == BfFailHandleKind_Soft)
InternalError(error);
}
void BfModule::InternalError(const StringImpl& error, BfAstNode* refNode, const char* file, int line)
{
static bool isInside = false;
if (isInside)
return;
isInside = true;
String fullError = error;
if (file != NULL)
@ -3652,6 +3649,8 @@ void BfModule::InternalError(const StringImpl& error, BfAstNode* refNode, const
fullError += StrFormat("\nSource Location: %s:%d", mCurFilePosition.mFileInstance->mParser->mFileName.c_str(), mCurFilePosition.mCurLine + 1);
Fail(String("INTERNAL ERROR: ") + fullError, refNode);
isInside = false;
}
void BfModule::NotImpl(BfAstNode* astNode)
@ -16018,6 +16017,8 @@ BfIRValue BfModule::AllocLocalVariable(BfType* type, const StringImpl& name, boo
void BfModule::DoAddLocalVariable(BfLocalVariable* localVar)
{
BF_ASSERT(localVar->mResolvedType != NULL);
while (localVar->mName.StartsWith('@'))
{
localVar->mNamePrefixCount++;
@ -17064,7 +17065,7 @@ void BfModule::AssertErrorState()
if (mCompiler->mPassInstance->HasFailed())
return;
InternalError("Compiler in invalid state but AssertErrorState failed to prior error");
InternalError("Compiler in invalid state but AssertErrorState failed to detect prior error");
}
void BfModule::AssertParseErrorState()
@ -20008,14 +20009,17 @@ void BfModule::ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfTyp
{
if (compositeVariableIdx == -1)
{
compositeVariableIdx = (int)mCurMethodState->mLocals.size();
BfLocalVariable* localVar = new BfLocalVariable();
auto paramInst = &methodInstance->mParams[paramIdx];
auto paramDef = methodDef->mParams[paramInst->mParamDefIdx];
compositeVariableIdx = (int)mCurMethodState->mLocals.size();
BfLocalVariable* localVar = new BfLocalVariable();
localVar->mName = paramDef->mName;
localVar->mNamePrefixCount = paramDef->mNamePrefixCount;
if (paramDef->mTypeRef != NULL)
localVar->mResolvedType = ResolveTypeRef(paramDef->mTypeRef, BfPopulateType_Declaration, BfResolveTypeRefFlag_NoResolveGenericParam);
if (localVar->mResolvedType == NULL)
localVar->mResolvedType = GetPrimitiveType(BfTypeCode_None);
localVar->mCompositeCount = 0;
DoAddLocalVariable(localVar);
}
@ -20064,9 +20068,9 @@ void BfModule::ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfTyp
if (genericParamInstance->mTypeConstraint != NULL)
{
auto typeInstConstraint = genericParamInstance->mTypeConstraint->ToTypeInstance();
if ((genericParamInstance->mTypeConstraint->IsDelegate()) || (genericParamInstance->mTypeConstraint->IsFunction()) ||
if ((genericParamInstance->mTypeConstraint->IsDelegate()) || (genericParamInstance->mTypeConstraint->IsFunction()) || (genericParamInstance->mTypeConstraint->IsTuple()) ||
((typeInstConstraint != NULL) &&
((typeInstConstraint->IsInstanceOf(mCompiler->mDelegateTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mFunctionTypeDef)))))
((typeInstConstraint->IsInstanceOf(mCompiler->mDelegateTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mFunctionTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mTupleTypeDef)))))
{
BfLocalVariable* localVar = new BfLocalVariable();
localVar->mName = paramDef->mName;
@ -24965,10 +24969,43 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
isValid = true;
addParams = false;
}
else if (resolvedParamType->IsTuple())
{
auto tupleType = (BfTupleType*)resolvedParamType;
PopulateType(tupleType);
hadDelegateParams = true;
// This means we copy the params from a delegate
BfMethodParam methodParam;
methodParam.mResolvedType = resolvedParamType;
methodParam.mParamDefIdx = paramDefIdx;
methodParam.mDelegateParamIdx = 0;
auto invokeMethodInstance = methodParam.GetDelegateParamInvoke();
for (int delegateParamIdx = 0; delegateParamIdx < tupleType->mFieldInstances.mSize; delegateParamIdx++)
{
auto& fieldInstance = tupleType->mFieldInstances[delegateParamIdx];
methodParam.mDelegateParamIdx = delegateParamIdx;
mCurMethodInstance->mParams.Add(methodParam);
if (!methodInstance->IsSpecializedGenericMethod())
AddDependency(fieldInstance.mResolvedType, mCurTypeInstance, BfDependencyMap::DependencyFlag_ParamOrReturnValue);
}
isValid = true;
addParams = false;
}
else if (resolvedParamType->IsGenericParam())
{
auto genericParamInstance = GetGenericParamInstance((BfGenericParamType*)resolvedParamType);
if (genericParamInstance->mTypeConstraint != NULL)
auto genericParamInstance = GetGenericParamInstance((BfGenericParamType*)resolvedParamType, false, BfFailHandleKind_Ignore);
if (genericParamInstance == NULL)
{
// Delegate case with a 'params T'?
mCurMethodInstance->mHadGenericDelegateParams = true;
isValid = true;
addParams = false;
}
else if (genericParamInstance->mTypeConstraint != NULL)
{
auto typeInstConstraint = genericParamInstance->mTypeConstraint->ToTypeInstance();
if ((genericParamInstance->mTypeConstraint->IsArray()) || (genericParamInstance->mTypeConstraint->IsSizedArray()))
@ -24979,9 +25016,9 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
mCurMethodInstance->mParams.Add(methodParam);
isValid = true;
}
else if ((genericParamInstance->mTypeConstraint->IsDelegate()) || (genericParamInstance->mTypeConstraint->IsFunction()) ||
else if ((genericParamInstance->mTypeConstraint->IsDelegate()) || (genericParamInstance->mTypeConstraint->IsFunction()) || (genericParamInstance->mTypeConstraint->IsTuple()) ||
((genericParamInstance != NULL) && (typeInstConstraint != NULL) &&
((typeInstConstraint->IsInstanceOf(mCompiler->mDelegateTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mFunctionTypeDef)))))
((typeInstConstraint->IsInstanceOf(mCompiler->mDelegateTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mFunctionTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mTupleTypeDef)))))
{
mCurMethodInstance->mHadGenericDelegateParams = true;
isValid = true;
@ -25055,13 +25092,25 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
{
if (usedParamDefIdx[methodParam.mParamDefIdx] > 1)
methodParam.mDelegateParamNameCombine = true;
if (methodParam.mResolvedType->IsTuple())
{
auto tupleType = (BfTupleType*)methodParam.mResolvedType;
auto& fieldInstance = tupleType->mFieldInstances[methodParam.mDelegateParamIdx];
auto paramName = fieldInstance.GetFieldDef()->mName;
if (!usedNames.Add(paramName))
methodParam.mDelegateParamNameCombine = true;
}
else
{
BfMethodInstance* invokeMethodInstance = methodParam.GetDelegateParamInvoke();
String paramName = invokeMethodInstance->GetParamName(methodParam.mDelegateParamIdx);
if (usedNames.Contains(paramName))
if (!usedNames.Add(paramName))
methodParam.mDelegateParamNameCombine = true;
}
}
}
}
int argIdx = 0;
resolveModule->PopulateType(methodInstance->mReturnType, BfPopulateType_Data);

View file

@ -1617,6 +1617,7 @@ public:
public:
void FatalError(const StringImpl& error, const char* file = NULL, int line = -1, int column = -1);
void FatalError(const StringImpl& error, BfAstNode* refNode);
void FatalError(const StringImpl& error, BfFailHandleKind failHandleKind);
void InternalError(const StringImpl& error, BfAstNode* refNode = NULL, const char* file = NULL, int line = -1);
void NotImpl(BfAstNode* astNode);
void AddMethodReference(const BfMethodRef& methodRef, BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_None);
@ -1959,7 +1960,7 @@ public:
BfType* ResolveGenericType(BfType* unspecializedType, BfTypeVector* typeGenericArguments, BfTypeVector* methodGenericArguments, BfType* selfType, bool allowFail = false);
BfType* ResolveSelfType(BfType* type, BfType* selfType);
bool IsUnboundGeneric(BfType* type);
BfGenericParamInstance* GetGenericTypeParamInstance(int paramIdx);
BfGenericParamInstance* GetGenericTypeParamInstance(int paramIdx, BfFailHandleKind failHandleKind = BfFailHandleKind_Normal);
BfGenericParamInstance* GetGenericParamInstance(BfGenericParamType* type, bool checkMixinBind = false, BfFailHandleKind failHandleKind = BfFailHandleKind_Normal);
void GetActiveTypeGenericParamInstances(SizedArray<BfGenericParamInstance*, 4>& genericParamInstance);
BfGenericParamInstance* GetMergedGenericParamData(BfType* type, BfGenericParamFlags& outFlags, BfType*& outTypeConstraint);

View file

@ -4209,6 +4209,10 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
{
baseType = ResolveTypeDef(mCompiler->mPointerTTypeDef, BfPopulateType_Data);
}
else if (resolvedTypeRef->IsTuple())
{
baseType = ResolveTypeDef(mCompiler->mTupleTypeDef, BfPopulateType_Data);
}
else if ((resolvedTypeRef->IsValueType()) && (typeDef != mCompiler->mValueTypeTypeDef))
{
baseType = ResolveTypeDef(mCompiler->mValueTypeTypeDef, BfPopulateType_Data)->ToTypeInstance();
@ -9565,7 +9569,7 @@ bool BfModule::IsUnboundGeneric(BfType* type)
return (genericParamInst->mGenericParamFlags & BfGenericParamFlag_Var) != 0;
}
BfGenericParamInstance* BfModule::GetGenericTypeParamInstance(int genericParamIdx)
BfGenericParamInstance* BfModule::GetGenericTypeParamInstance(int genericParamIdx, BfFailHandleKind failHandleKind)
{
// When we're evaluating a method, make sure the params refer back to that method context
auto curTypeInstance = mCurTypeInstance;
@ -9577,7 +9581,7 @@ BfGenericParamInstance* BfModule::GetGenericTypeParamInstance(int genericParamId
if (genericTypeInst == NULL)
{
FatalError("Invalid mCurTypeInstance for GetGenericTypeParamInstance");
FatalError("Invalid mCurTypeInstance for GetGenericTypeParamInstance", failHandleKind);
return NULL;
}
@ -9756,7 +9760,7 @@ BfGenericParamInstance* BfModule::GetGenericParamInstance(BfGenericParamType* ty
return curGenericMethodInstance->mMethodInfoEx->mGenericParams[type->mGenericParamIdx];
}
return GetGenericTypeParamInstance(type->mGenericParamIdx);
return GetGenericTypeParamInstance(type->mGenericParamIdx, failHandleKind);
}
bool BfModule::ResolveTypeResult_Validate(BfAstNode* typeRef, BfType* resolvedTypeRef)

View file

@ -698,7 +698,8 @@ BfMethodInstance* BfMethodParam::GetDelegateParamInvoke()
auto methodRefType = (BfMethodRefType*)mResolvedType;
return methodRefType->mMethodRef;
}
else if (mResolvedType->IsTuple())
return NULL;
BF_ASSERT(mResolvedType->IsDelegate() || mResolvedType->IsFunction());
auto bfModule = BfModule::GetModuleFor(mResolvedType);
BfMethodInstance* invokeMethodInstance = bfModule->GetRawMethodInstanceAtIdx(mResolvedType->ToTypeInstance(), 0, "Invoke");
@ -1166,6 +1167,23 @@ void BfMethodInstance::GetParamName(int paramIdx, StringImpl& name, int& namePre
BfParameterDef* paramDef = mMethodDef->mParams[methodParam->mParamDefIdx];
if (methodParam->mDelegateParamIdx != -1)
{
if (methodParam->mResolvedType->IsTuple())
{
auto tupleType = (BfTupleType*)methodParam->mResolvedType;
auto& fieldInstance = tupleType->mFieldInstances[methodParam->mDelegateParamIdx];
if (methodParam->mDelegateParamNameCombine)
name = paramDef->mName + "__" + fieldInstance.GetFieldDef()->mName;
else
name = fieldInstance.GetFieldDef()->mName;
if (name == "p__a__a")
{
NOP;
}
return;
}
BfMethodInstance* invokeMethodInstance = methodParam->GetDelegateParamInvoke();
if (methodParam->mDelegateParamNameCombine)
name = paramDef->mName + "__" + invokeMethodInstance->GetParamName(methodParam->mDelegateParamIdx);
@ -1213,6 +1231,12 @@ BfType* BfMethodInstance::GetParamType(int paramIdx, bool returnUnderlyingParams
BfMethodParam* methodParam = &mParams[paramIdx];
if (methodParam->mDelegateParamIdx != -1)
{
if (methodParam->mResolvedType->IsTuple())
{
auto tupleType = (BfTupleType*)methodParam->mResolvedType;
return tupleType->mFieldInstances[methodParam->mDelegateParamIdx].mResolvedType;
}
BfMethodInstance* invokeMethodInstance = methodParam->GetDelegateParamInvoke();
return invokeMethodInstance->GetParamType(methodParam->mDelegateParamIdx, true);
}
@ -1247,6 +1271,8 @@ bool BfMethodInstance::GetParamIsSplat(int paramIdx)
if (methodParam->mDelegateParamIdx != -1)
{
BfMethodInstance* invokeMethodInstance = methodParam->GetDelegateParamInvoke();
if (invokeMethodInstance == NULL)
return false;
return invokeMethodInstance->GetParamIsSplat(methodParam->mDelegateParamIdx);
}
return methodParam->mIsSplat;

View file

@ -0,0 +1,29 @@
using System;
namespace Tests;
class Params
{
class ClassA<T> where T : Tuple
{
public static int Test(delegate int(char8 a, params T) dlg, params T par)
{
return dlg('A', params par);
}
}
class ClassB : ClassA<(int a, float b)>
{
}
[Test]
public static void TestBasics()
{
int val = ClassB.Test(scope (a, __a, b) =>
{
return (.)a + (.)__a + (.)b;
}, 10, 2.3f);
Test.Assert(val == 65+10+2);
}
}