diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index e199e01a..dd3ca123 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -624,7 +624,7 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio paramDef->mTypeRef = paramDecl->mTypeRef; paramDef->mMethodGenericParamIdx = mSystem->GetGenericParamIdx(methodDef->mGenericParams, paramDef->mTypeRef); if (paramDecl->mModToken == NULL) - paramDef->mParamKind = BfParamKind_Normal; + paramDef->mParamKind = BfParamKind_Normal; else if (paramDecl->mModToken->mToken == BfToken_Params) paramDef->mParamKind = BfParamKind_Params; else if ((paramDecl->mModToken->mToken == BfToken_ReadOnly) && (isAutoCtor)) @@ -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); } } @@ -1068,13 +1072,13 @@ void BfDefBuilder::Visit(BfPropertyDeclaration* propertyDeclaration) if (BfNodeDynCast(methodDeclaration->mBody) != NULL) methodDef->mIsMutating = true; // Don't require "set mut;", just "set;" - auto paramDef = new BfParameterDef(); + auto paramDef = new BfParameterDef(); paramDef->mName = "value"; if (auto refTypeRef = BfNodeDynCast(propertyDeclaration->mTypeRef)) paramDef->mTypeRef = refTypeRef->mElementType; else paramDef->mTypeRef = propertyDeclaration->mTypeRef; - methodDef->mParams.push_back(paramDef); + methodDef->mParams.Insert(0, paramDef); propertyDef->mMethods.Add(methodDef); } else diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 38fa1548..aa42a5f2 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -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) @@ -17200,7 +17209,7 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp mResult = mModule->GetDefaultTypedValue(methodInstance.mMethodInstance->mReturnType); } else - { + { SizedArray args; if (!matchedMethod->mIsStatic) { @@ -17225,66 +17234,11 @@ 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()); - } + mModule->EmitObjectAccessCheck(mPropTarget); + } + + 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 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 prevFlags(mBfEvalExprFlags, (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_NoLookupError), pass == 0); + SetAndRestoreValue 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; } diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 1b3558af..6eafe68d 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -22354,7 +22354,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool mCurMethodInstance->mDefaultValues.Add(defaultValue); } } - } + } if ((paramDef != NULL) && (paramDef->mParamKind == BfParamKind_Params)) { @@ -22444,10 +22444,10 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool methodParam.mResolvedType = resolvedParamType; methodParam.mParamDefIdx = paramDefIdx; mCurMethodInstance->mParams.push_back(methodParam); - } + } if (paramDefIdx < (int)methodDef->mParams.size() - 1) - { + { Fail("Only the last parameter can specify 'params'", paramDef->mParamDeclaration->mModToken); } } diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index b1d08992..e306457b 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -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 }; diff --git a/IDEHelper/Tests/src/Indexers.bf b/IDEHelper/Tests/src/Indexers.bf index ae4fd683..978867d3 100644 --- a/IDEHelper/Tests/src/Indexers.bf +++ b/IDEHelper/Tests/src/Indexers.bf @@ -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); } } }