From f4f10fce99c081dedccf5819a56cd91a263becd6 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sat, 5 Feb 2022 13:47:19 -0500 Subject: [PATCH] Partial explicit generic method arguments with ... or ? --- IDEHelper/Compiler/BfExprEvaluator.cpp | 121 ++++++++++++++++------- IDEHelper/Compiler/BfExprEvaluator.h | 30 ++++-- IDEHelper/Compiler/BfModule.cpp | 14 +-- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 2 +- IDEHelper/Compiler/BfReducer.cpp | 28 +++++- IDEHelper/Compiler/BfReducer.h | 2 +- IDEHelper/Compiler/BfStmtEvaluator.cpp | 16 +-- IDEHelper/Tests/src/Generics.bf | 8 ++ 8 files changed, 155 insertions(+), 66 deletions(-) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 8cf9a7fc..0abe0207 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -137,7 +137,7 @@ BfBaseClassWalker::Entry BfBaseClassWalker::Next() ////////////////////////////////////////////////////////////////////////// -BfMethodMatcher::BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, const StringImpl& methodName, SizedArrayImpl& arguments, BfSizedArray* methodGenericArguments) : +BfMethodMatcher::BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, const StringImpl& methodName, SizedArrayImpl& arguments, const BfMethodGenericArguments& methodGenericArguments) : mArguments(arguments) { mTargetSrc = targetSrc; @@ -146,7 +146,7 @@ BfMethodMatcher::BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, const S Init(/*arguments, */methodGenericArguments); } -BfMethodMatcher::BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* interfaceMethodInstance, SizedArrayImpl& arguments, BfSizedArray* methodGenericArguments) : +BfMethodMatcher::BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* interfaceMethodInstance, SizedArrayImpl& arguments, const BfMethodGenericArguments& methodGenericArguments) : mArguments(arguments) { mTargetSrc = targetSrc; @@ -156,7 +156,7 @@ BfMethodMatcher::BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, BfMetho mMethodName = mInterfaceMethodInstance->mMethodDef->mName; } -void BfMethodMatcher::Init(/*SizedArrayImpl& arguments, */BfSizedArray* methodGenericArguments) +void BfMethodMatcher::Init(const BfMethodGenericArguments& methodGenericArguments) { //mArguments = arguments; mActiveTypeDef = NULL; @@ -170,6 +170,8 @@ void BfMethodMatcher::Init(/*SizedArrayImpl& arguments, */BfSized mMethodType = BfMethodType_Normal; mCheckReturnType = NULL; mHadExplicitGenericArguments = false; + mHadOpenGenericArguments = methodGenericArguments.mIsOpen; + mHadPartialGenericArguments = methodGenericArguments.mIsPartial; mHasVarArguments = false; mInterfaceMethodInstance = NULL; mFakeConcreteTarget = false; @@ -202,16 +204,25 @@ void BfMethodMatcher::Init(/*SizedArrayImpl& arguments, */BfSized } } - if (methodGenericArguments != NULL) + if (methodGenericArguments.mArguments != NULL) { - for (BfAstNode* genericArg : *methodGenericArguments) + for (BfAstNode* genericArg : *(methodGenericArguments.mArguments)) { - auto genericArgType = mModule->ResolveTypeRef(genericArg, NULL, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowImplicitConstExpr); - if ((genericArgType != NULL) && (genericArgType->IsGenericParam())) + BfType* genericArgType = NULL; + if (BfNodeIsA(genericArg)) { - auto genericParamInstance = mModule->GetGenericParamInstance((BfGenericParamType*)genericArgType); - if ((genericParamInstance->mGenericParamFlags & BfGenericParamFlag_Var) != 0) - mHasVarArguments = true; + // Allow a null here + BF_ASSERT(mHadPartialGenericArguments); + } + else + { + genericArgType = mModule->ResolveTypeRef(genericArg, NULL, BfPopulateType_Identity, BfResolveTypeRefFlag_AllowImplicitConstExpr); + if ((genericArgType != NULL) && (genericArgType->IsGenericParam())) + { + auto genericParamInstance = mModule->GetGenericParamInstance((BfGenericParamType*)genericArgType); + if ((genericParamInstance->mGenericParamFlags & BfGenericParamFlag_Var) != 0) + mHasVarArguments = true; + } } mExplicitMethodGenericArguments.push_back(genericArgType); } @@ -1705,7 +1716,8 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst int argIdx = 0; int argMatchCount = 0; - bool needInferGenericParams = (checkMethod->mGenericParams.size() != 0) && (!mHadExplicitGenericArguments); + bool needInferGenericParams = (checkMethod->mGenericParams.size() != 0) && + ((!mHadExplicitGenericArguments) || (mHadPartialGenericArguments)); int paramIdx = 0; BfType* paramsElementType = NULL; if (checkMethod->mHasAppend) @@ -1713,8 +1725,20 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst int uniqueGenericStartIdx = mModule->GetLocalInferrableGenericArgCount(checkMethod); - if ((mHadExplicitGenericArguments) && (checkMethod->mGenericParams.size() != mExplicitMethodGenericArguments.size() + uniqueGenericStartIdx)) - goto NoMatch; + if (mHadExplicitGenericArguments) + { + int genericArgDelta = (int)(checkMethod->mGenericParams.size() - (mExplicitMethodGenericArguments.size() + uniqueGenericStartIdx)); + if (mHadOpenGenericArguments) + { + if (genericArgDelta <= 0) + goto NoMatch; + } + else + { + if (genericArgDelta != 0) + goto NoMatch; + } + } for (auto& checkGenericArgRef : mCheckMethodGenericArguments) checkGenericArgRef = NULL; @@ -1740,7 +1764,14 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst else { genericArgumentsSubstitute = &mExplicitMethodGenericArguments; - } + } + + if ((mHadPartialGenericArguments) && (needInferGenericParams)) + { + genericArgumentsSubstitute = &mCheckMethodGenericArguments; + for (int i = 0; i < (int)mExplicitMethodGenericArguments.mSize; i++) + mCheckMethodGenericArguments[i] = mExplicitMethodGenericArguments[i]; + } } else if (needInferGenericParams) genericArgumentsSubstitute = &mCheckMethodGenericArguments; @@ -3780,7 +3811,7 @@ void BfExprEvaluator::Visit(BfStringInterpolationExpression* stringInterpolation BfSizedArray sizedArgExprs(argExprs); BfResolvedArgs argValues(&sizedArgExprs); ResolveArgValues(argValues, BfResolveArgsFlag_InsideStringInterpolationAlloc); - MatchMethod(stringInterpolationExpression, NULL, newString, false, false, "AppendF", argValues, NULL); + MatchMethod(stringInterpolationExpression, NULL, newString, false, false, "AppendF", argValues, BfMethodGenericArguments()); mResult = newString; return; @@ -7666,7 +7697,7 @@ BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBou static int sCtorCount = 0; sCtorCount++; - BfMethodMatcher methodMatcher(targetSrc, mModule, "", argValues.mResolvedArgs, NULL); + BfMethodMatcher methodMatcher(targetSrc, mModule, "", argValues.mResolvedArgs, BfMethodGenericArguments()); methodMatcher.mBfEvalExprFlags = mBfEvalExprFlags; BfTypeVector typeGenericArguments; @@ -8251,10 +8282,12 @@ bool BfExprEvaluator::CheckGenericCtor(BfGenericParamType* genericParamType, BfR } BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExpression* methodBoundExpr, BfTypedValue target, bool allowImplicitThis, bool bypassVirtual, const StringImpl& methodName, - BfResolvedArgs& argValues, BfSizedArray* methodGenericArguments, BfCheckedKind checkedKind) + BfResolvedArgs& argValues, const BfMethodGenericArguments& methodGenericArgs, BfCheckedKind checkedKind) { BP_ZONE("MatchMethod"); + auto methodGenericArguments = methodGenericArgs.mArguments; + if (bypassVirtual) { // "bypassVirtual" means that we know for sure that the target is EXACTLY the specified target type, @@ -8534,7 +8567,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp BfTypeInstance* curTypeInst = targetTypeInst; - BfMethodMatcher methodMatcher(targetSrc, mModule, methodName, argValues.mResolvedArgs, methodGenericArguments); + BfMethodMatcher methodMatcher(targetSrc, mModule, methodName, argValues.mResolvedArgs, methodGenericArgs); methodMatcher.mOrigTarget = origTarget; methodMatcher.mTarget = target; methodMatcher.mCheckedKind = checkedKind; @@ -9053,7 +9086,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp { mFunctionBindResult->mOrigTarget = BfTypedValue(); } - return MatchMethod(targetSrc, NULL, fieldVal, false, false, "Invoke", argValues, methodGenericArguments, checkedKind); + return MatchMethod(targetSrc, NULL, fieldVal, false, false, "Invoke", argValues, methodGenericArgs, checkedKind); } if (IsVar(fieldVal.mType)) { @@ -9634,7 +9667,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp autoComplete->mIsGetDefinition = false; result = mModule->MakeAddressable(result); BfResolvedArgs resolvedArgs; - MatchMethod(targetSrc, NULL, result, false, false, "ReturnValueDiscarded", resolvedArgs, NULL); + MatchMethod(targetSrc, NULL, result, false, false, "ReturnValueDiscarded", resolvedArgs, BfMethodGenericArguments()); if (wasGetDefinition) autoComplete->mIsGetDefinition = true; } @@ -10534,7 +10567,7 @@ void BfExprEvaluator::Visit(BfInitializerExpression* initExpr) BfSizedArray sizedArgExprs(argExprs); BfResolvedArgs argValues(&sizedArgExprs); exprEvaluator.ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval); - exprEvaluator.MatchMethod(elementExpr, NULL, initValue, false, false, "Add", argValues, NULL); + exprEvaluator.MatchMethod(elementExpr, NULL, initValue, false, false, "Add", argValues, BfMethodGenericArguments()); if (addFunctionBindResult.mMethodInstance != NULL) CreateCall(initExpr, addFunctionBindResult.mMethodInstance, addFunctionBindResult.mFunc, true, addFunctionBindResult.mIRArgs); @@ -11598,16 +11631,16 @@ bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr args[i] = typedValueExpr; } - BfSizedArray* methodGenericArguments = NULL; + BfMethodGenericArguments methodGenericArgs; if (delegateBindExpr->mGenericArgs != NULL) - methodGenericArguments = &delegateBindExpr->mGenericArgs->mGenericArgs; + methodGenericArgs.mArguments = &delegateBindExpr->mGenericArgs->mGenericArgs; BfFunctionBindResult bindResult; bindResult.mSkipMutCheck = true; // Allow operating on copies bindResult.mBindType = expectingType; mFunctionBindResult = &bindResult; SetAndRestoreValue ignoreError(mModule->mIgnoreErrors, true); - DoInvocation(delegateBindExpr->mTarget, delegateBindExpr, args, methodGenericArguments); + DoInvocation(delegateBindExpr->mTarget, delegateBindExpr, args, methodGenericArgs); mFunctionBindResult = NULL; if (bindResult.mMethodInstance == NULL) return false; @@ -12002,9 +12035,9 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) args[i] = typedValueExpr; } - BfSizedArray* methodGenericArguments = NULL; + BfMethodGenericArguments methodGenericArgs; if (delegateBindExpr->mGenericArgs != NULL) - methodGenericArguments = &delegateBindExpr->mGenericArgs->mGenericArgs; + methodGenericArgs.mArguments = &delegateBindExpr->mGenericArgs->mGenericArgs; if (delegateBindExpr->mTarget == NULL) { @@ -12034,7 +12067,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) { SetAndRestoreValue prevExpectingType(mExpectingType, methodInstance->mReturnType); mFunctionBindResult = &bindResult; - DoInvocation(delegateBindExpr->mTarget, delegateBindExpr, args, methodGenericArguments); + DoInvocation(delegateBindExpr->mTarget, delegateBindExpr, args, methodGenericArgs); mFunctionBindResult = NULL; } @@ -15289,7 +15322,7 @@ BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfAstNode* targetSrc, } mModule->Fail(StrFormat("Too many generic arguments, expected %d fewer", genericArgCountDiff), errorNode); } - else if (genericArgCountDiff < 0) + else if ((genericArgCountDiff < 0) && (!methodMatcher.mHadOpenGenericArguments)) { BfAstNode* errorNode = targetSrc; if ((invocationExpr != NULL) && (invocationExpr->mGenericArgs != NULL) && (invocationExpr->mGenericArgs->mCloseChevron != NULL)) @@ -15646,7 +15679,7 @@ void BfExprEvaluator::CheckLocalMethods(BfAstNode* targetSrc, BfTypeInstance* ty } } -void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, bool allowImplicitThis, const StringImpl& name, const BfSizedArray& arguments, BfSizedArray* methodGenericArgs) +void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, bool allowImplicitThis, const StringImpl& name, const BfSizedArray& arguments, const BfMethodGenericArguments& methodGenericArgs) { if (mModule->mCurMethodState == NULL) return; @@ -16512,8 +16545,10 @@ void BfExprEvaluator::SetMethodElementType(BfAstNode* target) mModule->SetElementType(target, BfSourceElementType_Method); } -void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* methodBoundExpr, const BfSizedArray& args, BfSizedArray* methodGenericArguments, BfTypedValue* outCascadeValue) +void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* methodBoundExpr, const BfSizedArray& args, const BfMethodGenericArguments& methodGenericArgs, BfTypedValue* outCascadeValue) { + auto methodGenericArguments = methodGenericArgs.mArguments; + // Just a check mModule->mBfIRBuilder->GetInsertBlock(); @@ -17066,7 +17101,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m if ((targetFunctionName != "") && (targetFunctionName[targetFunctionName.length() - 1] == '!')) { targetFunctionName = targetFunctionName.Substring(0, targetFunctionName.length() - 1); - InjectMixin(methodNodeSrc, thisValue, allowImplicitThis, targetFunctionName, args, methodGenericArguments); + InjectMixin(methodNodeSrc, thisValue, allowImplicitThis, targetFunctionName, args, methodGenericArgs); return; } @@ -17161,7 +17196,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m if (isCascade) mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_InCascade); ResolveArgValues(argValues, resolveArgsFlags); - mResult = MatchMethod(methodNodeSrc, methodBoundExpr, thisValue, allowImplicitThis, bypassVirtual, targetFunctionName, argValues, methodGenericArguments, checkedKind); + mResult = MatchMethod(methodNodeSrc, methodBoundExpr, thisValue, allowImplicitThis, bypassVirtual, targetFunctionName, argValues, methodGenericArgs, checkedKind); argValues.HandleFixits(mModule); if (mModule->mAttributeState == &attributeState) @@ -17253,15 +17288,25 @@ void BfExprEvaluator::Visit(BfInvocationExpression* invocationExpr) autoComplete->CheckInvocation(invocationExpr, invocationExpr->mOpenParen, invocationExpr->mCloseParen, invocationExpr->mCommas); mModule->UpdateExprSrcPos(invocationExpr); - BfSizedArray* methodGenericArguments = NULL; + BfMethodGenericArguments methodGenericArgs; if (invocationExpr->mGenericArgs != NULL) - methodGenericArguments = &invocationExpr->mGenericArgs->mGenericArgs; + { + methodGenericArgs.mArguments = &invocationExpr->mGenericArgs->mGenericArgs; + if ((!invocationExpr->mGenericArgs->mCommas.IsEmpty()) && (invocationExpr->mGenericArgs->mCommas.back()->mToken == BfToken_DotDotDot)) + { + methodGenericArgs.mIsOpen = true; + methodGenericArgs.mIsPartial = true; + } + for (int i = 0; i < (int)methodGenericArgs.mArguments->mSize; i++) + if (BfNodeIsA((*methodGenericArgs.mArguments)[i])) + methodGenericArgs.mIsPartial = true; + } SizedArray copiedArgs; for (BfExpression* arg : invocationExpr->mArguments) copiedArgs.push_back(arg); BfTypedValue cascadeValue; - DoInvocation(invocationExpr->mTarget, invocationExpr, copiedArgs, methodGenericArguments, &cascadeValue); + DoInvocation(invocationExpr->mTarget, invocationExpr, copiedArgs, methodGenericArgs, &cascadeValue); if (autoComplete != NULL) { @@ -19916,7 +19961,7 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr) if (!val.mTypedValue) val.mTypedValue = mModule->GetDefaultTypedValue(mModule->mContext->mBfObjectType); - BfMethodMatcher methodMatcher(indexerExpr->mTarget, mModule, "[]", mIndexerValues, NULL); + BfMethodMatcher methodMatcher(indexerExpr->mTarget, mModule, "[]", mIndexerValues, BfMethodGenericArguments()); methodMatcher.mCheckedKind = checkedKind; //methodMatcher.CheckType(target.mType->ToTypeInstance(), target, false); @@ -20306,7 +20351,7 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal BfResolvedArg resolvedArg; resolvedArg.mTypedValue = inValue; args.push_back(resolvedArg); - BfMethodMatcher methodMatcher(opToken, mModule, "", args, NULL); + BfMethodMatcher methodMatcher(opToken, mModule, "", args, BfMethodGenericArguments()); methodMatcher.mBfEvalExprFlags = BfEvalExprFlags_NoAutoComplete; methodMatcher.mAllowImplicitRef = true; BfBaseClassWalker baseClassWalker(inValue.mType, NULL, mModule); @@ -21947,7 +21992,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod auto checkLeftType = leftValue.mType; auto checkRightType = rightValue.mType; - BfMethodMatcher methodMatcher(opToken, mModule, "", args, NULL); + BfMethodMatcher methodMatcher(opToken, mModule, "", args, BfMethodGenericArguments()); methodMatcher.mAllowImplicitRef = true; methodMatcher.mBfEvalExprFlags = BfEvalExprFlags_NoAutoComplete; BfBaseClassWalker baseClassWalker(checkLeftType, checkRightType, mModule); diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index dc66e38f..d099a30f 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -157,6 +157,20 @@ public: void InferGenericArguments(BfMethodInstance* methodInstance); }; +struct BfMethodGenericArguments +{ + BfSizedArray* mArguments; + bool mIsPartial; + bool mIsOpen; // Ends with ... + + BfMethodGenericArguments() + { + mArguments = NULL; + mIsPartial = false; + mIsOpen = false; + } +}; + class BfMethodMatcher { public: @@ -180,7 +194,7 @@ public: BackupMatchKind_EarlyMismatch, BackupMatchKind_PartialLastArgMatch }; - + public: BfAstNode* mTargetSrc; BfTypedValue mTarget; @@ -194,6 +208,8 @@ public: BfMethodType mMethodType; BfCheckedKind mCheckedKind; bool mHadExplicitGenericArguments; + bool mHadOpenGenericArguments; + bool mHadPartialGenericArguments; bool mHasVarArguments; bool mHadVarConflictingReturnType; bool mBypassVirtual; @@ -236,9 +252,9 @@ public: int GetMostSpecificType(BfType* lhs, BfType* rhs); // 0, 1, or -1 public: - BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, const StringImpl& methodName, SizedArrayImpl& arguments, BfSizedArray* methodGenericArguments); - BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* interfaceMethodInstance, SizedArrayImpl& arguments, BfSizedArray* methodGenericArguments = NULL); - void Init(/*SizedArrayImpl& arguments, */BfSizedArray* methodGenericArguments); + BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, const StringImpl& methodName, SizedArrayImpl& arguments, const BfMethodGenericArguments& methodGenericArguments); + BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* interfaceMethodInstance, SizedArrayImpl& arguments, const BfMethodGenericArguments& methodGenericArguments); + void Init(const BfMethodGenericArguments& methodGenericArguments); bool IsMemberAccessible(BfTypeInstance* typeInst, BfTypeDef* declaringType); bool CheckType(BfTypeInstance* typeInstance, BfTypedValue target, bool isFailurePass, bool forceOuterCheck = false); void CheckOuterTypeStaticMethods(BfTypeInstance* typeInstance, bool isFailurePass); @@ -462,16 +478,16 @@ public: BfResolvedArgs& argValues, bool callCtorBodyOnly, bool allowAppendAlloc, BfTypedValue* appendIndexValue = NULL); BfTypedValue CheckEnumCreation(BfAstNode* targetSrc, BfTypeInstance* enumType, const StringImpl& caseName, BfResolvedArgs& argValues); BfTypedValue MatchMethod(BfAstNode* targetSrc, BfMethodBoundExpression* methodBoundExpr, BfTypedValue target, bool allowImplicitThis, bool bypassVirtual, const StringImpl& name, - BfResolvedArgs& argValue, BfSizedArray* methodGenericArguments, BfCheckedKind checkedKind = BfCheckedKind_NotSet); + BfResolvedArgs& argValue, const BfMethodGenericArguments& methodGenericArguments, BfCheckedKind checkedKind = BfCheckedKind_NotSet); BfTypedValue MakeCallableTarget(BfAstNode* targetSrc, BfTypedValue target); BfModuleMethodInstance GetSelectedMethod(BfAstNode* targetSrc, BfTypeInstance* curTypeInst, BfMethodDef* methodDef, BfMethodMatcher& methodMatcher, BfType** overrideReturnType = NULL); BfModuleMethodInstance GetSelectedMethod(BfMethodMatcher& methodMatcher); bool CheckVariableDeclaration(BfAstNode* checkNode, bool requireSimpleIfExpr, bool exprMustBeTrue, bool silentFail); bool HasVariableDeclaration(BfAstNode* checkNode); - void DoInvocation(BfAstNode* target, BfMethodBoundExpression* methodBoundExpr, const BfSizedArray& args, BfSizedArray* methodGenericArgs, BfTypedValue* outCascadeValue = NULL); + void DoInvocation(BfAstNode* target, BfMethodBoundExpression* methodBoundExpr, const BfSizedArray& args, const BfMethodGenericArguments& methodGenericArgs, BfTypedValue* outCascadeValue = NULL); int GetMixinVariable(); void CheckLocalMethods(BfAstNode* targetSrc, BfTypeInstance* typeInstance, const StringImpl& methodName, BfMethodMatcher& methodMatcher, BfMethodType methodType); - void InjectMixin(BfAstNode* targetSrc, BfTypedValue target, bool allowImplicitThis, const StringImpl& name, const BfSizedArray& arguments, BfSizedArray* methodGenericArgs); + void InjectMixin(BfAstNode* targetSrc, BfTypedValue target, bool allowImplicitThis, const StringImpl& name, const BfSizedArray& arguments, const BfMethodGenericArguments& methodGenericArgs); void SetMethodElementType(BfAstNode* target); BfTypedValue DoImplicitArgCapture(BfAstNode* refNode, BfIdentifierNode* identifierNode, int shadowIdx); BfTypedValue DoImplicitArgCapture(BfAstNode* refNode, BfMethodInstance* methodInstance, int paramIdx, bool& failed, BfImplicitParamKind paramKind = BfImplicitParamKind_General, const BfTypedValue& methodRefTarget = BfTypedValue()); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 7c12b92b..06bbb67f 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -8733,7 +8733,7 @@ BfIRValue BfModule::AllocBytes(BfAstNode* refNode, const BfAllocTarget& allocTar if (allocTarget.mScopedInvocationTarget != NULL) { SizedArray genericArgs; - exprEvaluator.DoInvocation(allocTarget.mScopedInvocationTarget, NULL, argExprs, NULL); + exprEvaluator.DoInvocation(allocTarget.mScopedInvocationTarget, NULL, argExprs, BfMethodGenericArguments()); allocResult = LoadValue(exprEvaluator.mResult); } else if (allocTarget.mCustomAllocator) @@ -8779,7 +8779,7 @@ BfIRValue BfModule::AllocBytes(BfAstNode* refNode, const BfAllocTarget& allocTar BfResolvedArgs argValues(&sizedArgExprs); exprEvaluator.ResolveArgValues(argValues); SetAndRestoreValue prevNoBind(mCurMethodState->mNoBind, true); - allocResult = exprEvaluator.MatchMethod(refNode, NULL, allocTarget.mCustomAllocator, false, false, allocMethodName, argValues, NULL); + allocResult = exprEvaluator.MatchMethod(refNode, NULL, allocTarget.mCustomAllocator, false, false, allocMethodName, argValues, BfMethodGenericArguments()); } } } @@ -8854,7 +8854,7 @@ BfIRValue BfModule::GetMarkFuncPtr(BfType* type) BfResolvedArg resolvedArg; resolvedArg.mTypedValue = BfTypedValue(mBfIRBuilder->GetFakeVal(), type, type->IsComposite()); resolvedArgs.Add(resolvedArg); - BfMethodMatcher methodMatcher(NULL, this, "Mark", resolvedArgs, NULL); + BfMethodMatcher methodMatcher(NULL, this, "Mark", resolvedArgs, BfMethodGenericArguments()); methodMatcher.CheckType(gcType, BfTypedValue(), false); BfModuleMethodInstance moduleMethodInst = exprEvaluator.GetSelectedMethod(NULL, methodMatcher.mBestMethodTypeInstance, methodMatcher.mBestMethodDef, methodMatcher); @@ -9457,7 +9457,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget BfResolvedArgs argValues(&sizedArgExprs); exprEvaluator.ResolveArgValues(argValues); exprEvaluator.mNoBind = true; - BfTypedValue allocResult = exprEvaluator.MatchMethod(allocTarget.mRefNode, NULL, allocTarget.mCustomAllocator, false, false, "AllocObject", argValues, NULL); + BfTypedValue allocResult = exprEvaluator.MatchMethod(allocTarget.mRefNode, NULL, allocTarget.mCustomAllocator, false, false, "AllocObject", argValues, BfMethodGenericArguments()); if (allocResult) { if ((allocResult.mType->IsVoidPtr()) || (allocResult.mType == mContext->mBfObjectType)) @@ -11734,7 +11734,7 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri autoComplete->CheckInvocation(attributesDirective, attributesDirective->mCtorOpenParen, attributesDirective->mCtorCloseParen, attributesDirective->mCommas); } - BfMethodMatcher methodMatcher(attributesDirective, this, "", argValues, NULL); + BfMethodMatcher methodMatcher(attributesDirective, this, "", argValues, BfMethodGenericArguments()); attrTypeDef = attrTypeInst->mTypeDef; bool success = true; @@ -17688,7 +17688,7 @@ void BfModule::EmitTupleToStringBody() { BfExprEvaluator exprEvaluator(this); SizedArray resolvedArgs; - BfMethodMatcher methodMatcher(NULL, this, printModuleMethodInstance.mMethodInstance, resolvedArgs); + BfMethodMatcher methodMatcher(NULL, this, printModuleMethodInstance.mMethodInstance, resolvedArgs, BfMethodGenericArguments()); methodMatcher.mBestMethodDef = printModuleMethodInstance.mMethodInstance->mMethodDef; methodMatcher.mBestMethodTypeInstance = iPrintableType; methodMatcher.TryDevirtualizeCall(fieldValue); @@ -17720,7 +17720,7 @@ void BfModule::EmitTupleToStringBody() BfExprEvaluator exprEvaluator(this); SizedArray resolvedArgs; - BfMethodMatcher methodMatcher(NULL, this, toStringModuleMethodInstance.mMethodInstance, resolvedArgs); + BfMethodMatcher methodMatcher(NULL, this, toStringModuleMethodInstance.mMethodInstance, resolvedArgs, BfMethodGenericArguments()); methodMatcher.mBestMethodDef = toStringModuleMethodInstance.mMethodInstance->mMethodDef; methodMatcher.mBestMethodTypeInstance = mContext->mBfObjectType; methodMatcher.TryDevirtualizeCall(fieldValue); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index ea558406..a45032a9 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -12739,7 +12739,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp resolvedArg.mTypedValue.mKind = BfTypedValueKind_Value; } args.push_back(resolvedArg); - BfMethodMatcher methodMatcher(srcNode, this, "", args, NULL); + BfMethodMatcher methodMatcher(srcNode, this, "", args, BfMethodGenericArguments()); methodMatcher.mCheckReturnType = toType; methodMatcher.mBfEvalExprFlags = (BfEvalExprFlags)(BfEvalExprFlags_NoAutoComplete | BfEvalExprFlags_FromConversionOp); if ((castFlags & BfCastFlags_Explicit) != 0) diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 9226140a..9153a692 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -742,7 +742,7 @@ bool BfReducer::IsTypeReference(BfAstNode* checkNode, BfToken successToken, int* if (auto prevToken = BfNodeDynCast(prevNode)) { // If this is just a 'loose' comma then it can't be part of a nullable - if ((prevToken->GetToken() == BfToken_Comma) || + if (((prevToken->GetToken() == BfToken_Comma) && (chevronDepth == 0)) || (prevToken->GetToken() == BfToken_LParen)) { return false; @@ -936,6 +936,11 @@ bool BfReducer::IsTypeReference(BfAstNode* checkNode, BfToken successToken, int* { if (checkNode->IsExact()) mayBeExprPart = true; + else if (auto tokenNode = BfNodeDynCast(checkNode)) + { + if (tokenNode->mToken == BfToken_Question) + mayBeExprPart = true; + } } if (!mayBeExprPart) @@ -2726,7 +2731,8 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat if (auto outToken = BfNodeDynCast(outNode)) { int endNodeIdx = -1; - if ((outToken->GetToken() == BfToken_LParen) && (IsTypeReference(exprLeft, BfToken_LParen, &endNodeIdx))) + if (((outToken->mToken == BfToken_LParen) && (IsTypeReference(exprLeft, BfToken_LParen, &endNodeIdx))) || + (outToken->mToken == BfToken_DotDotDot)) { exprLeft = CreateInvocationExpression(exprLeft); if (exprLeft == NULL) @@ -7352,7 +7358,7 @@ BfInvocationExpression* BfReducer::CreateInvocationExpression(BfAstNode* target, if (tokenNode->GetToken() == BfToken_LChevron) { - auto genericParamsDecl = CreateGenericArguments(tokenNode); + auto genericParamsDecl = CreateGenericArguments(tokenNode, true); MEMBER_SET_CHECKED(invocationExpr, mGenericArgs, genericParamsDecl); tokenNode = ExpectTokenAfter(invocationExpr, BfToken_LParen); } @@ -9726,7 +9732,7 @@ bool BfReducer::ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayIm return true; } -BfGenericArgumentsNode* BfReducer::CreateGenericArguments(BfTokenNode* tokenNode) +BfGenericArgumentsNode* BfReducer::CreateGenericArguments(BfTokenNode* tokenNode, bool allowPartial) { auto genericArgs = mAlloc->Alloc(); BfDeferredAstSizedArray genericArgsArray(genericArgs->mGenericArgs, mAlloc); @@ -9740,6 +9746,11 @@ BfGenericArgumentsNode* BfReducer::CreateGenericArguments(BfTokenNode* tokenNode auto nextNode = mVisitorPos.GetNext(); if (BfNodeIsA(nextNode)) doAsExpr = true; + else if (auto tokenNode = BfNodeDynCast(nextNode)) + { + if (tokenNode->mToken == BfToken_Question) + doAsExpr = true; + } BfAstNode* genericArg = NULL; if (doAsExpr) @@ -9782,6 +9793,15 @@ BfGenericArgumentsNode* BfReducer::CreateGenericArguments(BfTokenNode* tokenNode if (token == BfToken_RDblChevron) tokenNode = BreakDoubleChevron(tokenNode); + if ((token == BfToken_DotDotDot) && (allowPartial)) + { + commas.push_back(tokenNode); + mVisitorPos.MoveNext(); + nextNode = mVisitorPos.GetNext(); + tokenNode = BfNodeDynCast(nextNode); + token = tokenNode->GetToken(); + } + if (token == BfToken_RChevron) { MoveNode(tokenNode, genericArgs); diff --git a/IDEHelper/Compiler/BfReducer.h b/IDEHelper/Compiler/BfReducer.h index 5a63c622..826a5a1f 100644 --- a/IDEHelper/Compiler/BfReducer.h +++ b/IDEHelper/Compiler/BfReducer.h @@ -226,7 +226,7 @@ public: BfTypeReference* CreateTypeRefAfter(BfAstNode* astNode, CreateTypeRefFlags createTypeRefFlags = CreateTypeRefFlags_None); BfTypeReference* CreateRefTypeRef(BfTypeReference* elementType, BfTokenNode* refToken); bool ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayImpl* params, SizedArrayImpl* commas, bool alwaysIncludeBlock = false); - BfGenericArgumentsNode* CreateGenericArguments(BfTokenNode* tokenNode); + BfGenericArgumentsNode* CreateGenericArguments(BfTokenNode* tokenNode, bool allowPartial = false); BfGenericParamsDeclaration* CreateGenericParamsDeclaration(BfTokenNode* tokenNode); BfGenericConstraintsDeclaration* CreateGenericConstraintsDeclaration(BfTokenNode* tokenNode); BfForEachStatement* CreateForEachStatement(BfAstNode* node, bool hasTypeDecl); diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index 5f79e5b5..00cd1665 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -4079,7 +4079,7 @@ void BfModule::Visit(BfDeleteStatement* deleteStmt) BfResolvedArgs argValues(&sizedArgExprs); exprEvaluator.ResolveArgValues(argValues); exprEvaluator.mNoBind = true; - exprEvaluator.MatchMethod(deleteStmt->mAllocExpr, NULL, customAllocator, false, true, "FreeObject", argValues, NULL); + exprEvaluator.MatchMethod(deleteStmt->mAllocExpr, NULL, customAllocator, false, true, "FreeObject", argValues, BfMethodGenericArguments()); customAllocator = BfTypedValue(); } } @@ -4137,7 +4137,7 @@ void BfModule::Visit(BfDeleteStatement* deleteStmt) BfResolvedArgs argValues(&sizedArgExprs); exprEvaluator.ResolveArgValues(argValues); exprEvaluator.mNoBind = true; - exprEvaluator.MatchMethod(deleteStmt->mAllocExpr, NULL, customAllocator, false, false, "Free", argValues, NULL); + exprEvaluator.MatchMethod(deleteStmt->mAllocExpr, NULL, customAllocator, false, false, "Free", argValues, BfMethodGenericArguments()); } mBfIRBuilder->CreateBr(endBB); @@ -5444,7 +5444,7 @@ void BfModule::Visit(BfUsingStatement* usingStmt) exprEvaluator.mFunctionBindResult = &functionBindResult; SizedArray resolvedArgs; - BfMethodMatcher methodMatcher(usingStmt->mVariableDeclaration, this, dispMethod.mMethodInstance, resolvedArgs); + BfMethodMatcher methodMatcher(usingStmt->mVariableDeclaration, this, dispMethod.mMethodInstance, resolvedArgs, BfMethodGenericArguments()); methodMatcher.CheckType(iDisposableType, embeddedValue, false); methodMatcher.TryDevirtualizeCall(embeddedValue); auto retVal = exprEvaluator.CreateCall(&methodMatcher, embeddedValue); @@ -6528,7 +6528,7 @@ void BfModule::Visit(BfForEachStatement* forEachStmt) SetAndRestoreValue prevIgnoreErrors(mIgnoreErrors, true); BfResolvedArgs resolvedArgs; exprEvaluator.mBfEvalExprFlags = (BfEvalExprFlags)(exprEvaluator.mBfEvalExprFlags | BfEvalExprFlags_NoAutoComplete); - exprEvaluator.MatchMethod(forEachStmt->mCollectionExpression, NULL, itr, false, false, "Dispose", resolvedArgs, NULL); + exprEvaluator.MatchMethod(forEachStmt->mCollectionExpression, NULL, itr, false, false, "Dispose", resolvedArgs, BfMethodGenericArguments()); if (functionBindResult.mMethodInstance != NULL) { BfModuleMethodInstance moduleMethodInstance; @@ -6624,7 +6624,7 @@ void BfModule::Visit(BfForEachStatement* forEachStmt) BfExprEvaluator exprEvaluator(this); auto itrTypeInstance = itr.mType->ToTypeInstance(); SizedArray resolvedArgs; - BfMethodMatcher methodMatcher(forEachStmt->mCollectionExpression, this, getNextMethodInst.mMethodInstance, resolvedArgs); + BfMethodMatcher methodMatcher(forEachStmt->mCollectionExpression, this, getNextMethodInst.mMethodInstance, resolvedArgs, BfMethodGenericArguments()); if (isRefExpression) methodMatcher.CheckType(refItrInterface, itr, false); else @@ -6704,7 +6704,7 @@ void BfModule::Visit(BfForEachStatement* forEachStmt) if (typeOptions != NULL) boundsCheck = typeOptions->Apply(boundsCheck, BfOptionFlags_RuntimeChecks); - BfMethodMatcher methodMatcher(forEachStmt->mVariableName, this, "get__", argValues.mResolvedArgs, NULL); + BfMethodMatcher methodMatcher(forEachStmt->mVariableName, this, "get__", argValues.mResolvedArgs, BfMethodGenericArguments()); methodMatcher.mMethodType = BfMethodType_PropertyGetter; methodMatcher.CheckType(target.mType->ToTypeInstance(), target, false); if (methodMatcher.mBestMethodDef == NULL) @@ -6957,7 +6957,7 @@ void BfModule::Visit(BfDeferStatement* deferStmt) exprEvaluator.ResolveArgValues(argValues); exprEvaluator.mNoBind = true; exprEvaluator.mFunctionBindResult = &functionBindResult; - exprEvaluator.MatchMethod(deleteStmt->mAllocExpr, NULL, customAllocator, false, false, "FreeObject", argValues, NULL); + exprEvaluator.MatchMethod(deleteStmt->mAllocExpr, NULL, customAllocator, false, false, "FreeObject", argValues, BfMethodGenericArguments()); } else { @@ -6973,7 +6973,7 @@ void BfModule::Visit(BfDeferStatement* deferStmt) exprEvaluator.ResolveArgValues(argValues); exprEvaluator.mNoBind = true; exprEvaluator.mFunctionBindResult = &functionBindResult; - exprEvaluator.MatchMethod(deleteStmt->mAllocExpr, NULL, customAllocator, false, false, "Free", argValues, NULL); + exprEvaluator.MatchMethod(deleteStmt->mAllocExpr, NULL, customAllocator, false, false, "Free", argValues, BfMethodGenericArguments()); } if (functionBindResult.mMethodInstance != NULL) diff --git a/IDEHelper/Tests/src/Generics.bf b/IDEHelper/Tests/src/Generics.bf index 3717754f..513ba9c7 100644 --- a/IDEHelper/Tests/src/Generics.bf +++ b/IDEHelper/Tests/src/Generics.bf @@ -326,6 +326,11 @@ namespace Tests TestGen(a); } + public static TOut Conv(TIn val) where TOut : operator explicit TIn + { + return (TOut)val; + } + [Test] public static void TestBasics() { @@ -396,6 +401,9 @@ namespace Tests true } == false); MethodG(); + + Test.Assert(Conv(12.34f) == 12); + Test.Assert(Conv(12.34f) == 12); } }