1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 04:22:20 +02:00

Support for 'params' in indexer

This commit is contained in:
Brian Fiete 2021-11-15 15:01:48 -08:00
parent 7dbd5294d7
commit f58362343b
5 changed files with 87 additions and 122 deletions

View file

@ -1034,6 +1034,10 @@ void BfDefBuilder::Visit(BfPropertyDeclaration* propertyDeclaration)
paramDef->mName = paramDecl->mNameNode->ToString();
paramDef->mTypeRef = paramDecl->mTypeRef;
paramDef->mMethodGenericParamIdx = mSystem->GetGenericParamIdx(methodDef->mGenericParams, paramDef->mTypeRef);
if (paramDecl->mModToken == NULL)
paramDef->mParamKind = BfParamKind_Normal;
else if (paramDecl->mModToken->mToken == BfToken_Params)
paramDef->mParamKind = BfParamKind_Params;
methodDef->mParams.push_back(paramDef);
}
}
@ -1074,7 +1078,7 @@ void BfDefBuilder::Visit(BfPropertyDeclaration* propertyDeclaration)
paramDef->mTypeRef = refTypeRef->mElementType;
else
paramDef->mTypeRef = propertyDeclaration->mTypeRef;
methodDef->mParams.push_back(paramDef);
methodDef->mParams.Insert(0, paramDef);
propertyDef->mMethods.Add(methodDef);
}
else

View file

@ -9966,6 +9966,9 @@ void BfExprEvaluator::Visit(BfBaseExpression* baseExpr)
return;
}
if ((mBfEvalExprFlags & BfEvalExprFlags_AllowBase) == 0)
mModule->Fail("Use of keyword 'base' is not valid in this context", baseExpr);
auto baseType = mModule->mCurTypeInstance->mBaseType;
if (baseType == NULL)
baseType = mModule->mContext->mBfObjectType;
@ -9976,6 +9979,12 @@ void BfExprEvaluator::Visit(BfBaseExpression* baseExpr)
mModule->PopulateType(baseType, BfPopulateType_Data);
mResult = mModule->Cast(baseExpr, mResult, baseType, BfCastFlags_Explicit);
if (mResult.IsSplat())
mResult.mKind = BfTypedValueKind_BaseSplatHead;
else if (mResult.IsAddr())
mResult.mKind = BfTypedValueKind_BaseAddr;
else if (mResult)
mResult.mKind = BfTypedValueKind_BaseValue;
}
void BfExprEvaluator::Visit(BfMixinExpression* mixinExpr)
@ -17226,65 +17235,10 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp
if ((mPropGetMethodFlags & BfGetMethodInstanceFlag_DisableObjectAccessChecks) == 0)
mModule->EmitObjectAccessCheck(mPropTarget);
PushThis(mPropSrc, mPropTarget, methodInstance.mMethodInstance, args);
}
bool failed = false;
for (int paramIdx = 0; paramIdx < (int)mIndexerValues.size(); paramIdx++)
{
auto refNode = mIndexerValues[paramIdx].mExpression;
auto wantType = methodInstance.mMethodInstance->GetParamType(paramIdx);
auto argValue = ResolveArgValue(mIndexerValues[paramIdx], wantType);
if (refNode == NULL)
refNode = mPropSrc;
BfTypedValue val;
if (argValue)
val = mModule->Cast(refNode, argValue, wantType);
if (!val)
failed = true;
else
PushArg(val, args);
}
if (mPropDefBypassVirtual)
{
auto methodDef = methodInstance.mMethodInstance->mMethodDef;
if ((methodDef->mIsAbstract) && (mPropDefBypassVirtual))
{
mModule->Fail(StrFormat("Abstract base property method '%s' cannot be invoked", mModule->MethodToString(methodInstance.mMethodInstance).c_str()), mPropSrc);
}
}
if (failed)
{
auto returnType = methodInstance.mMethodInstance->mReturnType;
auto methodDef = methodInstance.mMethodInstance->mMethodDef;
if (returnType->IsRef())
{
auto result = mModule->GetDefaultTypedValue(returnType->GetUnderlyingType(), true, BfDefaultValueKind_Addr);
if (methodDef->mIsReadOnly)
result.mKind = BfTypedValueKind_ReadOnlyAddr;
return result;
}
else
{
auto val = mModule->GetDefaultTypedValue(returnType, true, (GetStructRetIdx(methodInstance.mMethodInstance) != -1) ? BfDefaultValueKind_Addr : BfDefaultValueKind_Value);
if (val.mKind == BfTypedValueKind_Addr)
val.mKind = BfTypedValueKind_TempAddr;
return val;
}
}
else
{
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->IsVar()) && (mModule->mCompiler->mIsResolveOnly))
mModule->Fail("Property type reference failed to resolve", mPropSrc);
BF_ASSERT(!mResult.mType->IsRef());
}
auto callFlags = mPropDefBypassVirtual ? BfCreateCallFlags_BypassVirtual : BfCreateCallFlags_None;
mResult = CreateCall(mPropSrc, mPropTarget, mOrigPropTarget, matchedMethod, methodInstance, callFlags, mIndexerValues, NULL);
}
}
@ -18149,7 +18103,7 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
}
else
{
auto wantType = methodInstance.mMethodInstance->GetParamType(methodInstance.mMethodInstance->GetParamCount() - 1);
auto wantType = methodInstance.mMethodInstance->GetParamType(0);
if (rightValue)
{
convVal = mModule->Cast(assignExpr->mRight, rightValue, wantType);
@ -18173,7 +18127,10 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
if (mPropSrc != NULL)
mModule->UpdateExprSrcPos(mPropSrc);
SizedArray<BfIRValue, 4> args;
BfResolvedArg valueArg;
valueArg.mTypedValue = convVal;
mIndexerValues.Insert(0, valueArg);
if (!setMethod->mIsStatic)
{
auto owner = methodInstance.mMethodInstance->GetOwner();
@ -18190,34 +18147,10 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
}
}
}
mModule->EmitObjectAccessCheck(mPropTarget);
PushThis(mPropSrc, mPropTarget, methodInstance.mMethodInstance, args);
}
for (int paramIdx = 0; paramIdx < (int)mIndexerValues.size(); paramIdx++)
{
auto refNode = mIndexerValues[paramIdx].mExpression;
auto wantType = methodInstance.mMethodInstance->GetParamType(paramIdx);
auto argValue = ResolveArgValue(mIndexerValues[paramIdx], wantType);
if (refNode == NULL)
refNode = mPropSrc;
BfTypedValue val;
if (argValue)
val = mModule->Cast(refNode, argValue, wantType);
if (!val)
{
mPropDef = NULL;
return;
}
PushArg(val, args);
}
PushArg(convVal, args);
if (methodInstance)
CreateCall(assignExpr, methodInstance.mMethodInstance, methodInstance.mFunc, mPropDefBypassVirtual, args);
auto callFlags = mPropDefBypassVirtual ? BfCreateCallFlags_BypassVirtual : BfCreateCallFlags_None;
mResult = CreateCall(mPropSrc, mPropTarget, mOrigPropTarget, setMethod, methodInstance, callFlags, mIndexerValues, NULL);
mPropDef = NULL;
mResult = convVal;
return;
@ -19478,7 +19411,7 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
{
///
{
SetAndRestoreValue<BfEvalExprFlags> prevFlags(mBfEvalExprFlags, (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_NoLookupError), pass == 0);
SetAndRestoreValue<BfEvalExprFlags> prevFlags(mBfEvalExprFlags, (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_NoLookupError | BfEvalExprFlags_AllowBase), pass == 0);
VisitChild(indexerExpr->mTarget);
}
ResolveGenericType();
@ -19636,36 +19569,28 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
if (foundProp != NULL)
{
int indexDiff = matchedIndexCount - (int)mIndexerValues.size();
if (indexDiff > 0)
mPropSrc = indexerExpr->mOpenBracket;
mPropDef = foundProp;
if (foundProp->mIsStatic)
{
mModule->Fail(StrFormat("Expected %d more indices", indexDiff), indexerExpr->mTarget);
//mModule->mCompiler->mPassInstance->MoreInfo("See method declaration", methodInstance->mMethodDef->mMethodDeclaration);
}
else if (indexDiff < 0)
{
mModule->Fail(StrFormat("Expected %d fewer indices", -indexDiff), indexerExpr->mTarget);
mPropTarget = BfTypedValue(curCheckType);
}
else
{
mPropSrc = indexerExpr->mOpenBracket;
mPropDef = foundProp;
if (foundProp->mIsStatic)
{
mPropTarget = BfTypedValue(curCheckType);
}
if (target.mType != foundPropTypeInst)
mPropTarget = mModule->Cast(indexerExpr->mTarget, target, foundPropTypeInst);
else
{
if (target.mType != foundPropTypeInst)
mPropTarget = mModule->Cast(indexerExpr->mTarget, target, foundPropTypeInst);
else
mPropTarget = target;
}
mOrigPropTarget = mPropTarget;
if (isInlined)
mPropGetMethodFlags = (BfGetMethodInstanceFlags)(mPropGetMethodFlags | BfGetMethodInstanceFlag_ForceInline);
mPropCheckedKind = checkedKind;
mPropTarget = target;
}
mOrigPropTarget = mPropTarget;
if (isInlined)
mPropGetMethodFlags = (BfGetMethodInstanceFlags)(mPropGetMethodFlags | BfGetMethodInstanceFlag_ForceInline);
mPropCheckedKind = checkedKind;
if ((target.IsBase()) && (mPropDef->IsVirtual()))
mPropDefBypassVirtual = true;
return;
}

View file

@ -78,6 +78,7 @@ enum BfEvalExprFlags
BfEvalExprFlags_InferReturnType = 0x400000,
BfEvalExprFlags_WasMethodRef = 0x800000,
BfEvalExprFlags_DeclType = 0x1000000,
BfEvalExprFlags_AllowBase = 0x2000000,
BfEvalExprFlags_InheritFlags = BfEvalExprFlags_NoAutoComplete | BfEvalExprFlags_Comptime | BfEvalExprFlags_DeclType
};

View file

@ -24,6 +24,14 @@ namespace Tests
return 234;
}
}
public int BaseIndex
{
get
{
return base[2];
}
}
}
class ClassC : ClassB
@ -33,7 +41,7 @@ namespace Tests
struct StructA
{
int mA;
public int mA;
public int this[int index]
{
@ -47,6 +55,25 @@ namespace Tests
return 2;
}
}
public int this[params int[] indices]
{
get mut
{
int total = 0;
for (var i in indices)
total += i;
mA += total;
return total;
}
set mut
{
for (var i in indices)
mA += i;
mA += value * 1000;
}
}
}
[Test]
@ -61,12 +88,20 @@ namespace Tests
Test.Assert(value == 234);
value = ca[0];
Test.Assert(value == 234);
value = cb.BaseIndex;
Test.Assert(value == 123);
StructA sa = default;
let sa2 = sa;
Test.Assert(sa[0] == 2);
Test.Assert(sa2[0] == 1);
sa[3, 4, 5] = 9;
Test.Assert(sa.mA == 9012);
int a = sa[3, 4, 5];
Test.Assert(a == 12);
Test.Assert(sa.mA == 9024);
}
}
}