From 3627f8c40f2c3871b86c3c7588881c0b223ded8b Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Fri, 11 Sep 2020 10:33:16 -0700 Subject: [PATCH] Reworked functions with explicit 'this' --- IDEHelper/Compiler/BfAutoComplete.cpp | 4 + IDEHelper/Compiler/BfAutoComplete.h | 1 + IDEHelper/Compiler/BfCompiler.cpp | 17 ++- IDEHelper/Compiler/BfContext.cpp | 2 +- IDEHelper/Compiler/BfDefBuilder.cpp | 48 +++++-- IDEHelper/Compiler/BfExprEvaluator.cpp | 160 ++++++++++++++++----- IDEHelper/Compiler/BfExprEvaluator.h | 4 +- IDEHelper/Compiler/BfMangler.cpp | 24 +--- IDEHelper/Compiler/BfModule.cpp | 97 +++++++++---- IDEHelper/Compiler/BfModule.h | 1 + IDEHelper/Compiler/BfModuleTypeUtils.cpp | 144 ++++++++++++------- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 110 ++++++++------ IDEHelper/Compiler/BfResolvedTypeUtils.h | 8 +- IDEHelper/Compiler/BfSystem.h | 5 +- IDEHelper/Tests/src/Functions.bf | 130 ++++++++++++++++- 15 files changed, 556 insertions(+), 199 deletions(-) diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index 68e248a2..9d8b8657 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -138,6 +138,7 @@ BfAutoComplete::BfAutoComplete(BfResolveType resolveType) mIgnoreFixits = false; mHasFriendSet = false; mUncertain = false; + mForceAllowNonStatic = false; mMethodMatchInfo = NULL; mIsGetDefinition = (resolveType == BfResolveType_GetSymbolInfo) || @@ -588,6 +589,9 @@ void BfAutoComplete::AddTypeMembers(BfTypeInstance* typeInst, bool addStatic, bo { bool isInterface = false; + if (mForceAllowNonStatic) + addNonStatic = true; + auto activeTypeDef = mModule->GetActiveTypeDef(); if ((addStatic) && (mModule->mCurMethodInstance == NULL) && (typeInst->IsEnum())) diff --git a/IDEHelper/Compiler/BfAutoComplete.h b/IDEHelper/Compiler/BfAutoComplete.h index 9572e16f..29a826cc 100644 --- a/IDEHelper/Compiler/BfAutoComplete.h +++ b/IDEHelper/Compiler/BfAutoComplete.h @@ -179,6 +179,7 @@ public: bool mIgnoreFixits; bool mHasFriendSet; bool mUncertain; // May be an unknown identifier, do not aggressively autocomplete + bool mForceAllowNonStatic; int mCursorLineStart; int mCursorLineEnd; diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 21de1e78..1fd1a860 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -2135,7 +2135,7 @@ void BfCompiler::UpdateDependencyMap(bool deleteUnusued, bool& didWork) { auto depType = type->ToDependedType(); auto typeInst = type->ToTypeInstance(); - + if (depType != NULL) { extern BfModule* gLastCreatedModule; @@ -4272,11 +4272,16 @@ void BfCompiler::ProcessAutocompleteTempType() methodInstance->GetMethodInfoEx()->mGenericParams.push_back(genericParamInstance); } + bool wantsProcess = !actualTypeDef->mIsFunction; + SetAndRestoreValue prevFilePos(module->mCurFilePosition); SetAndRestoreValue prevMethodInst(module->mCurMethodInstance, methodInstance); - module->DoMethodDeclaration(methodDeclaration, true); - module->mIncompleteMethodCount++; - module->ProcessMethod(methodInstance); + module->DoMethodDeclaration(methodDeclaration, true, wantsProcess); + if (wantsProcess) + { + module->mIncompleteMethodCount++; + module->ProcessMethod(methodInstance); + } if (methodInstance->mIRFunction) { @@ -4830,7 +4835,7 @@ void BfCompiler::GetSymbolReferences() CheckSymbolReferenceTypeRef(module, externConstraintDef.mTypeRef); rebuildModule->ResolveGenericParamConstraints(&genericParamInstance, rebuildMethodInstance->mIsUnspecialized); } - + rebuildModule->ProcessMethod(rebuildMethodInstance); } } @@ -7420,7 +7425,7 @@ void BfCompiler::GenerateAutocompleteInfo() int dispParamIdx = 0; StringT<64> paramName; - for (int paramIdx = methodInstance->HasExplicitThis() ? -1 : 0; paramIdx < (int)methodInstance->GetParamCount(); paramIdx++) + for (int paramIdx = 0; paramIdx < (int)methodInstance->GetParamCount(); paramIdx++) { auto paramKind = methodInstance->GetParamKind(paramIdx); if ((paramKind == BfParamKind_ImplicitCapture) || (paramKind == BfParamKind_AppendIdx)) diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index 08aceee3..0e814b6f 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -849,7 +849,7 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild return; } - + // We need to verify lookups before we rebuild the type, because a type lookup change needs to count as a TypeDataChanged VerifyTypeLookups(typeInst); diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index 2fc75970..71757c58 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -541,7 +541,7 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio methodDef->mMethodType = BfMethodType_Normal; methodDef->mProtection = BfProtection_Public; methodDef->mIsStatic = mCurTypeDef->mIsFunction; - + auto attributes = mCurTypeDef->mTypeDeclaration->mAttributes; while (attributes != NULL) { @@ -621,6 +621,12 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio else // paramDef->mParamKind = BfParamKind_Params; + if ((mCurTypeDef->mIsFunction) && (paramIdx == 0) && (paramDef->mName == "this")) + { + paramDef->mParamKind = BfParamKind_ExplicitThis; + methodDef->mIsStatic = false; + } + if (auto dotTypeRef = BfNodeDynCast(paramDef->mTypeRef)) { if (dotTypeRef->mDotToken->mToken == BfToken_DotDotDot) @@ -658,6 +664,22 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio methodDef->mParams.push_back(paramDef); } + if ((mCurTypeDef->mIsFunction) && (!methodDef->mParams.IsEmpty()) && (methodDef->mParams[0]->mName == "this")) + { + methodDef->mIsStatic = false; + methodDef->mHasExplicitThis = true; + methodDef->mParams[0]->mParamKind = BfParamKind_ExplicitThis; + + if (auto refTypeRef = BfNodeDynCast(methodDef->mParams[0]->mTypeRef)) + { + if (refTypeRef->mRefToken->mToken != BfToken_Mut) + { + Fail("Only 'mut' is allowed here", refTypeRef->mRefToken); + } + methodDef->mIsMutating = true; + } + } + ParseAttributes(methodDeclaration->mAttributes, methodDef); return methodDef; } @@ -1911,6 +1933,16 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) } } + bool needsDynamicCastMethod = !hasDynamicCastMethod; + + if (mCurTypeDef->mIsFunction) + { + wantsToString = false; + needsEqualsMethod = false; + needsDefaultCtor = false; + needsDynamicCastMethod = false; + } + if ((mCurTypeDef->mTypeCode == BfTypeCode_Object) && (!mCurTypeDef->mIsStatic)) { auto methodDef = AddMethod(mCurTypeDef, BfMethodType_CtorClear, BfProtection_Private, false, ""); @@ -1934,12 +1966,6 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) } bool makeCtorPrivate = hasCtor; -// if ((!mCurTypeDef->IsExtension()) && (mCurTypeDef->mMethods.empty())) -// { -// // This is a bit of a hack to ensure we actually generate debug info in the module -// needsDefaultCtor = true; -// makeCtorPrivate = true; -// } if (mCurTypeDef->mTypeCode == BfTypeCode_TypeAlias) needsDefaultCtor = false; @@ -1962,7 +1988,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) isAutocomplete = true; //TODO: Don't do this for the autocomplete pass - if ((!hasDynamicCastMethod) && (mCurTypeDef->mTypeCode != BfTypeCode_Interface) && (mCurTypeDef->mTypeCode != BfTypeCode_Extension) && + if ((needsDynamicCastMethod) && (mCurTypeDef->mTypeCode != BfTypeCode_Interface) && (mCurTypeDef->mTypeCode != BfTypeCode_Extension) && (!mCurTypeDef->mIsStatic) && (!isAutocomplete) && (!isAlias)) { AddDynamicCastMethods(mCurTypeDef); @@ -2011,12 +2037,6 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) if (hasToStringMethod) wantsToString = false; - - if (mCurTypeDef->mIsFunction) - { - wantsToString = false; - needsEqualsMethod = false; - } if ((mCurTypeDef->mTypeCode == BfTypeCode_Enum) && (!isPayloadEnum)) { diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 75afc29c..05e19934 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -542,6 +542,27 @@ bool BfGenericInferContext::InferGenericArgument(BfMethodInstance* methodInstanc InferGenericArgument(methodInstance, argInvokeMethod->GetParamType(argIdx), wantInvokeMethod->GetParamType(argIdx), BfIRValue()); } } + else if (argType->IsMethodRef()) + { + auto methodTypeRef = (BfMethodRefType*)argType; + if (!_AddToCheckedSet(argType, mCheckedTypeSet, alreadyChecked)) + return true; + + auto argInvokeMethod = methodTypeRef->mMethodRef; + auto delegateInfo = wantType->GetDelegateInfo(); + auto wantInvokeMethod = mModule->GetRawMethodByName(wantType->ToTypeInstance(), "Invoke"); + + if ((delegateInfo->mHasExplicitThis) && (argInvokeMethod->HasThis())) + InferGenericArgument(methodInstance, argInvokeMethod->GetParamType(-1), delegateInfo->mParams[0], BfIRValue()); + + int wantInvokeOffset = delegateInfo->mHasExplicitThis ? 1 : 0; + if ((argInvokeMethod != NULL) && (wantInvokeMethod != NULL) && (argInvokeMethod->GetParamCount() == wantInvokeMethod->GetParamCount() - wantInvokeOffset)) + { + InferGenericArgument(methodInstance, argInvokeMethod->mReturnType, wantInvokeMethod->mReturnType, BfIRValue()); + for (int argIdx = 0; argIdx < (int)argInvokeMethod->GetParamCount(); argIdx++) + InferGenericArgument(methodInstance, argInvokeMethod->GetParamType(argIdx), wantInvokeMethod->GetParamType(argIdx + wantInvokeOffset), BfIRValue()); + } + } } return true; @@ -1021,7 +1042,7 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp RETURN_RESULTS; } -BfTypedValue BfMethodMatcher::ResolveArgTypedValue(BfResolvedArg& resolvedArg, BfType* checkType, BfTypeVector* genericArgumentsSubstitute) +BfTypedValue BfMethodMatcher::ResolveArgTypedValue(BfResolvedArg& resolvedArg, BfType* checkType, BfTypeVector* genericArgumentsSubstitute, BfType *origCheckType) { BfTypedValue argTypedValue = resolvedArg.mTypedValue; if ((resolvedArg.mArgFlags & BfArgFlag_DelegateBindAttempt) != 0) @@ -1032,13 +1053,13 @@ BfTypedValue BfMethodMatcher::ResolveArgTypedValue(BfResolvedArg& resolvedArg, B BF_ASSERT(resolvedArg.mExpression->IsA()); auto delegateBindExpr = BfNodeDynCast(resolvedArg.mExpression); BfMethodInstance* boundMethodInstance = NULL; - if (exprEvaluator.CanBindDelegate(delegateBindExpr, &boundMethodInstance)) + if (exprEvaluator.CanBindDelegate(delegateBindExpr, &boundMethodInstance, origCheckType, genericArgumentsSubstitute)) { if (delegateBindExpr->mNewToken == NULL) { resolvedArg.mExpectedType = checkType; auto methodRefType = mModule->CreateMethodRefType(boundMethodInstance); - mModule->AddDependency(methodRefType, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_Calls); + mModule->AddDependency(methodRefType, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_Calls); mModule->AddCallDependency(boundMethodInstance); argTypedValue = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), methodRefType); } @@ -1509,7 +1530,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst if (argIdx == -1) argTypedValue = mTarget; else - argTypedValue = ResolveArgTypedValue(mArguments[argIdx], checkType, genericArgumentsSubstitute); + argTypedValue = ResolveArgTypedValue(mArguments[argIdx], checkType, genericArgumentsSubstitute, origCheckType); if (!argTypedValue.IsUntypedValue()) { auto type = argTypedValue.mType; @@ -2615,6 +2636,16 @@ void BfExprEvaluator::Visit(BfAttributedExpression* attribExpr) } VisitChild(attribExpr->mExpression); attributeState.mUsed = true; + + if ((!mResult) || + ((mResult) && (mResult.mType->IsVar()))) + { + if (!mResult) + mModule->Fail("Expression did not result in a value", attribExpr->mExpression); + + // Make empty or 'var' resolve as 'false' because var is only valid if we threw errors + mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Boolean)); + } } else { @@ -4894,7 +4925,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV bool hadAttrs = false; int paramIdx = 0; bool doingThis = !methodDef->mIsStatic; - int argIdx = 0; + int argIdx = 0; + + if (methodDef->mHasExplicitThis) + paramIdx++; int paramCount = methodInstance->GetParamCount(); @@ -4986,13 +5020,14 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV BfType* paramType = NULL; if (doingThis) { - paramType = methodInstance->GetOwner(); + int thisIdx = methodInstance->GetThisIdx(); + paramType = methodInstance->GetThisType(); if (paramType->IsValuelessType()) { doingThis = false; continue; } - bool isSplatted = methodInstance->GetParamIsSplat(-1); // (resolvedTypeRef->IsSplattable()) && (!methodDef->mIsMutating); + bool isSplatted = methodInstance->GetParamIsSplat(thisIdx); // (resolvedTypeRef->IsSplattable()) && (!methodDef->mIsMutating); if (isSplatted) { BfTypeUtils::SplatIterate(_HandleParamType, paramType); @@ -5357,7 +5392,7 @@ void BfExprEvaluator::PushThis(BfAstNode* targetSrc, BfTypedValue argVal, BfMeth return; } - auto thisType = methodInstance->GetParamType(-1); + auto thisType = methodInstance->GetThisType(); PushArg(argVal, irArgs, !methodInstance->AllowsThisSplatting(), thisType->IsPointer()); } @@ -5453,11 +5488,22 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu auto bindResult = prevBindResult.mPrevVal; if (bindResult->mBindType != NULL) { + // Allow binding a function to a 'this' type even if no target is specified auto delegateInfo = bindResult->mBindType->GetDelegateInfo(); - if ((delegateInfo != NULL) && (delegateInfo->mFunctionThisType != NULL)) + if (delegateInfo != NULL) { - // Allow binding a function to a 'this' type even if no target is specified - target = mModule->GetDefaultTypedValue(delegateInfo->mFunctionThisType, false, BfDefaultValueKind_Addr); + if (delegateInfo->mHasExplicitThis) + { + target = mModule->GetDefaultTypedValue(delegateInfo->mParams[0], false, BfDefaultValueKind_Addr); + } + } + else if (bindResult->mBindType->IsFunction()) + { + BfMethodInstance* invokeMethodInstance = mModule->GetRawMethodInstanceAtIdx(bindResult->mBindType->ToTypeInstance(), 0, "Invoke"); + if (!invokeMethodInstance->mMethodDef->mIsStatic) + { + target = mModule->GetDefaultTypedValue(invokeMethodInstance->GetThisType(), false, BfDefaultValueKind_Addr); + } } } } @@ -5555,12 +5601,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu if ((boxScopeData == NULL) && (mModule->mCurMethodState != NULL)) boxScopeData = mModule->mCurMethodState->mCurScope; - if (methodInstance->HasExplicitThis()) - paramIdx = -1; - bool failed = false; while (true) { + bool isThis = (paramIdx == -1) || ((methodDef->mHasExplicitThis) && (paramIdx == 0)); bool isDirectPass = false; if (paramIdx >= (int)methodInstance->GetParamCount()) @@ -6021,7 +6065,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu if (argValue) { - if ((paramIdx == -1) && (argValue.mType->IsRef())) + if ((isThis) && (argValue.mType->IsRef())) { // Convert a 'ref this' to a 'this*' argValue.mType = mModule->CreatePointerType(argValue.mType->GetUnderlyingType()); @@ -6107,7 +6151,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu if (argValue) { - if (paramIdx == -1) + if (isThis) PushThis(targetSrc, argValue, methodInstance, irArgs); else if (wantsSplat) SplatArgs(argValue, irArgs); @@ -9485,7 +9529,11 @@ bool BfExprEvaluator::IsExactMethodMatch(BfMethodInstance* methodA, BfMethodInst return false; int implicitParamCountA = methodA->GetImplicitParamCount(); + if (methodA->HasExplicitThis()) + implicitParamCountA++; int implicitParamCountB = methodB->GetImplicitParamCount(); + if (methodB->HasExplicitThis()) + implicitParamCountB++; if (methodA->GetParamCount() - implicitParamCountA != methodB->GetParamCount() - implicitParamCountB) return false; @@ -9517,15 +9565,21 @@ BfTypeInstance* BfExprEvaluator::VerifyBaseDelegateType(BfTypeInstance* baseDele return baseDelegateType; } -bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr, BfMethodInstance** boundMethod) +bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr, BfMethodInstance** boundMethod, BfType* origMethodExpectingType, BfTypeVector* methodGenericArgumentsSubstitute) { - if (mExpectingType == NULL) + if ((mExpectingType == NULL) && (origMethodExpectingType == NULL)) { return false; } - auto typeInstance = mExpectingType->ToTypeInstance(); - if ((typeInstance == NULL) || (!typeInstance->mTypeDef->mIsDelegate)) + bool isGenericMatch = mExpectingType == NULL; + auto expectingType = mExpectingType; + if (expectingType == NULL) + expectingType = origMethodExpectingType; + + auto typeInstance = expectingType->ToTypeInstance(); + if ((typeInstance == NULL) || + ((!typeInstance->mTypeDef->mIsDelegate) && (!typeInstance->mTypeDef->mIsFunction))) return false; mModule->PopulateType(typeInstance, BfPopulateType_DataAndMethods); @@ -9547,11 +9601,28 @@ bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr SizedArray args; args.resize(methodInstance->GetParamCount()); + auto _FixType = [&](BfType* type) + { + if (!isGenericMatch) + return type; + auto fixedType = mModule->ResolveGenericType(type, NULL, methodGenericArgumentsSubstitute); + if (fixedType != NULL) + return fixedType; + return (BfType*)mModule->GetPrimitiveType(BfTypeCode_Var); + }; + + auto _TypeMatches = [&](BfType* lhs, BfType* rhs) + { + if (lhs == rhs) + return true; + return lhs->IsVar(); + }; + for (int i = 0; i < (int) methodInstance->GetParamCount(); i++) { auto typedValueExpr = &typedValueExprs[i]; - typedValueExpr->mTypedValue.mValue = BfIRValue(BfIRValueFlags_Value, -1); - typedValueExpr->mTypedValue.mType = methodInstance->GetParamType(i); + typedValueExpr->mTypedValue.mValue = BfIRValue(BfIRValueFlags_Value, -1); + typedValueExpr->mTypedValue.mType = _FixType(methodInstance->GetParamType(i)); typedValueExpr->mRefNode = NULL; args[i] = typedValueExpr; } @@ -9562,6 +9633,7 @@ bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr 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); @@ -9570,7 +9642,25 @@ bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr return false; if (boundMethod != NULL) *boundMethod = bindResult.mMethodInstance; - return IsExactMethodMatch(methodInstance, bindResult.mMethodInstance, true); + + auto matchedMethod = bindResult.mMethodInstance; + + if (!_TypeMatches(_FixType(methodInstance->mReturnType), matchedMethod->mReturnType)) + return false; + + int implicitParamCountA = methodInstance->GetImplicitParamCount(); + int implicitParamCountB = matchedMethod->GetImplicitParamCount(); + + if (methodInstance->GetParamCount() - implicitParamCountA != matchedMethod->GetParamCount() - implicitParamCountB) + return false; + for (int i = 0; i < (int)methodInstance->GetParamCount() - implicitParamCountA; i++) + { + auto paramA = _FixType(methodInstance->GetParamType(i + implicitParamCountA)); + auto paramB = _FixType(matchedMethod->GetParamType(i + implicitParamCountB)); + if (!_TypeMatches(paramA, paramB)) + return false; + } + return true; } BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfIdentifierNode* identifierNode, int shadowIdx) @@ -9928,14 +10018,15 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) } } - typedValueExprs.resize(methodInstance->GetParamCount()); - args.resize(methodInstance->GetParamCount()); - - for (int i = 0; i < (int)methodInstance->GetParamCount(); i++) + int paramOffset = methodInstance->HasExplicitThis() ? 1 : 0; + typedValueExprs.resize(methodInstance->GetParamCount() - paramOffset); + args.resize(methodInstance->GetParamCount() - paramOffset); + + for (int i = 0; i < (int)methodInstance->GetParamCount() - paramOffset; i++) { auto typedValueExpr = &typedValueExprs[i]; typedValueExpr->mTypedValue.mValue = BfIRValue(BfIRValueFlags_Value, -1); - typedValueExpr->mTypedValue.mType = methodInstance->GetParamType(i); + typedValueExpr->mTypedValue.mType = methodInstance->GetParamType(i + paramOffset); typedValueExpr->mRefNode = NULL; args[i] = typedValueExpr; } @@ -9950,8 +10041,12 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) return; } - if (GetAutoComplete() != NULL) + auto autoComplete = GetAutoComplete(); + if (autoComplete != NULL) + { + SetAndRestoreValue prevForceAllowNonStatic(autoComplete->mForceAllowNonStatic, methodInstance->mMethodDef->mHasExplicitThis); GetAutoComplete()->CheckNode(delegateBindExpr->mTarget); + } if ((!delegateBindExpr->mTarget->IsA()) && (!delegateBindExpr->mTarget->IsA())) @@ -19533,13 +19628,14 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod } else { - auto convertedValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox); + auto convertedValue = mModule->Cast(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox); if (!convertedValue) return; + convertedValue = mModule->LoadValue(convertedValue); if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) - mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); + mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(resultTypedValue->mValue, convertedValue.mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); else - mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); + mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(resultTypedValue->mValue, convertedValue.mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean)); } return; diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index c38d76dd..f5c49b0a 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -169,7 +169,7 @@ public: Array mAmbiguousEntries; public: - BfTypedValue ResolveArgTypedValue(BfResolvedArg& resolvedArg, BfType* checkType, BfTypeVector* genericArgumentsSubstitute); + BfTypedValue ResolveArgTypedValue(BfResolvedArg& resolvedArg, BfType* checkType, BfTypeVector* genericArgumentsSubstitute, BfType *origCheckType = NULL); bool InferFromGenericConstraints(BfGenericParamInstance* genericParamInst, BfTypeVector* methodGenericArgs); void CompareMethods(BfMethodInstance* prevMethodInstance, BfTypeVector* prevGenericArgumentsSubstitute, BfMethodInstance* newMethodInstance, BfTypeVector* genericArgumentsSubstitute, @@ -401,7 +401,7 @@ public: 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()); - bool CanBindDelegate(BfDelegateBindExpression* delegateBindExpr, BfMethodInstance** boundMethod = NULL); + bool CanBindDelegate(BfDelegateBindExpression* delegateBindExpr, BfMethodInstance** boundMethod = NULL, BfType* origMethodExpectingType = NULL, BfTypeVector* methodGenericArgumentsSubstitute = NULL); bool IsExactMethodMatch(BfMethodInstance* methodA, BfMethodInstance* methodB, bool ignoreImplicitParams = false); BfTypeInstance* VerifyBaseDelegateType(BfTypeInstance* delegateType); void ConstResolve(BfExpression* expr); diff --git a/IDEHelper/Compiler/BfMangler.cpp b/IDEHelper/Compiler/BfMangler.cpp index 12f8f926..04bc8c09 100644 --- a/IDEHelper/Compiler/BfMangler.cpp +++ b/IDEHelper/Compiler/BfMangler.cpp @@ -311,14 +311,9 @@ void BfGNUMangler::MangleTypeInst(MangleContext& mangleContext, StringImpl& name else name += "N8functionI"; SizedArray typeVec; - typeVec.push_back(BfNodeDynCast(methodDef->mReturnTypeRef)->mType); - if (delegateInfo->mFunctionThisType != NULL) - { - name += "_"; - name += "this"; - typeVec.push_back(delegateInfo->mFunctionThisType); - } - + typeVec.push_back(BfNodeDynCast(methodDef->mReturnTypeRef)->mType); + if (methodDef->mIsMutating) + name += "_mut_"; for (int paramIdx = 0; paramIdx < (int)methodDef->mParams.size(); paramIdx++) { name += "_"; @@ -1175,18 +1170,11 @@ bool BfMSMangler::FindOrCreateNameSub(MangleContext& mangleContext, StringImpl& name += "?$delegate"; else name += "?$function"; + if (methodDef->mIsMutating) + name += "_mut_"; SizedArray typeVec; typeVec.push_back(BfNodeDynCast(methodDef->mReturnTypeRef)->mType); - - if (delegateInfo->mFunctionThisType != NULL) - { - name += "_"; - name += "this"; - typeVec.push_back(delegateInfo->mFunctionThisType); - if ((delegateInfo->mFunctionThisType->IsValueType()) && (methodDef->mIsMutating)) - name += "_mut"; - } - + for (int paramIdx = 0; paramIdx < (int)methodDef->mParams.size(); paramIdx++) { name += "_"; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 7f4d48ca..89a3d588 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -2610,6 +2610,15 @@ void BfModule::SetElementType(BfAstNode* astNode, BfSourceElementType elementTyp } } +void BfModule::SetFail() +{ + if (mIgnoreErrors) + { + if (mAttributeState != NULL) + mAttributeState->mFlags = (BfAttributeState::Flags)(mAttributeState->mFlags | BfAttributeState::Flag_HadError); + } +} + BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPersistent) { BP_ZONE("BfModule::Fail"); @@ -3074,10 +3083,17 @@ void BfModule::AddDependency(BfType* usedType, BfType* userType, BfDependencyMap return; if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsAutocompleteMethod)) - return; + { + if (userType->IsMethodRef()) + { + // We cannot short-circuit dependencies because of method group ref counting + } + else + return; + } if (usedType->IsSpecializedByAutoCompleteMethod()) - return; + return; // if (usedType->IsBoxed()) // { @@ -14790,7 +14806,7 @@ BfIRCallingConv BfModule::GetIRCallingConvention(BfMethodInstance* methodInstanc auto methodDef = methodInstance->mMethodDef; BfTypeInstance* owner = NULL; if (!methodDef->mIsStatic) - owner = methodInstance->GetParamType(-1)->ToTypeInstance(); + owner = methodInstance->GetThisType()->ToTypeInstance(); if (owner == NULL) owner = methodInstance->GetOwner(); @@ -14842,13 +14858,11 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func int argIdx = 0; int paramIdx = 0; - if (methodInstance->HasThis()) - { - paramIdx = -1; - } + if ((methodInstance->HasThis()) && (!methodDef->mHasExplicitThis)) + paramIdx = -1; int argCount = methodInstance->GetIRFunctionParamCount(this); - + while (argIdx < argCount) { if (argIdx == methodInstance->GetStructRetIdx()) @@ -14859,22 +14873,22 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func continue; } - while ((paramIdx != -1) && (methodInstance->IsParamSkipped(paramIdx))) + bool isThis = (paramIdx == -1) || ((methodDef->mHasExplicitThis) && (paramIdx == 0)); + while ((!isThis) && (methodInstance->IsParamSkipped(paramIdx))) paramIdx++; BfType* resolvedTypeRef = NULL; BfType* resolvedTypeRef2 = NULL; String paramName; bool isSplattable = false; - bool tryLowering = true; - bool isThis = paramIdx == -1; + bool tryLowering = true; if (isThis) { paramName = "this"; if (methodInstance->mIsClosure) resolvedTypeRef = mCurMethodState->mClosureState->mClosureType; else - resolvedTypeRef = methodInstance->GetOwner(); + resolvedTypeRef = methodInstance->GetThisType(); isSplattable = (resolvedTypeRef->IsSplattable()) && (methodInstance->AllowsThisSplatting()); tryLowering = methodInstance->AllowsThisSplatting(); } @@ -14933,7 +14947,7 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func } if ((resolvedTypeRef->IsComposite()) && (!resolvedTypeRef->IsTypedPrimitive())) { - if (paramIdx == -1) + if (isThis) { mBfIRBuilder->Func_AddAttribute(func, argIdx + 1, BfIRAttribute_NoCapture); PopulateType(resolvedTypeRef, BfPopulateType_Data); @@ -16965,6 +16979,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) } if (methodInstance->mIsIntrinsic) return; + if (mCurTypeInstance->IsFunction()) + return; auto prevActiveFunction = mBfIRBuilder->GetActiveFunction(); mBfIRBuilder->SetActiveFunction(mCurMethodInstance->mIRFunction); @@ -20318,7 +20334,8 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool implicitParamCount = (int)methodInstance->mMethodInfoEx->mClosureInstanceInfo->mCaptureEntries.size(); methodInstance->mMethodDef->mParams.Reserve((int)methodDef->mParams.size()); - + + bool hadDelegateParams = false; bool hadParams = false; for (int paramIdx = 0; paramIdx < (int)methodDef->mParams.size() + implicitParamCount; paramIdx++) @@ -20379,9 +20396,13 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool BfType* unresolvedParamType = resolvedParamType; bool wasGenericParam = false; if (resolvedParamType == NULL) - { - resolvedParamType = ResolveTypeRef(paramDef->mTypeRef, BfPopulateType_Declaration, - (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowRef | BfResolveTypeRefFlag_AllowRefGeneric | BfResolveTypeRefFlag_AllowGenericMethodParamConstValue)); + { + BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowRef | BfResolveTypeRefFlag_AllowRefGeneric | BfResolveTypeRefFlag_AllowGenericMethodParamConstValue); + if (paramDef->mParamKind == BfParamKind_ExplicitThis) + resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_NoWarnOnMut); + resolvedParamType = ResolveTypeRef(paramDef->mTypeRef, BfPopulateType_Declaration, resolveFlags); + if ((paramDef->mParamKind == BfParamKind_ExplicitThis) && (resolvedParamType != NULL) && (resolvedParamType->IsRef())) + resolvedParamType = resolvedParamType->GetUnderlyingType(); } if (resolvedParamType == NULL) { @@ -20578,7 +20599,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool methodParam.mResolvedType = resolvedParamType; methodParam.mParamDefIdx = paramDefIdx; mCurMethodInstance->mParams.Add(methodParam); - } + } } if (hadDelegateParams) @@ -20616,11 +20637,12 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool int argIdx = 0; PopulateType(methodInstance->mReturnType, BfPopulateType_Data); - if (!methodDef->mIsStatic) + if ((!methodDef->mIsStatic) && (!methodDef->mHasExplicitThis)) { + int thisIdx = methodDef->mHasExplicitThis ? 0 : -1; auto thisType = methodInstance->GetOwner(); - if (methodInstance->GetParamIsSplat(-1)) - argIdx += methodInstance->GetParamType(-1)->GetSplatCount(); + if (methodInstance->GetParamIsSplat(thisIdx)) + argIdx += methodInstance->GetParamType(thisIdx)->GetSplatCount(); else if (!thisType->IsValuelessType()) { BfTypeCode loweredTypeCode = BfTypeCode_None; @@ -20636,25 +20658,44 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool if (methodInstance->GetStructRetIdx() != -1) argIdx++; - for (auto& methodParam : mCurMethodInstance->mParams) + for (int paramIdx = 0; paramIdx < mCurMethodInstance->mParams.size(); paramIdx++) { - if (methodParam.mResolvedType->IsMethodRef()) + auto& methodParam = mCurMethodInstance->mParams[paramIdx]; + + BfType* checkType = methodParam.mResolvedType; + int checkArgIdx = argIdx; + if ((paramIdx == 0) && (methodDef->mHasExplicitThis)) + { + checkArgIdx = 0; + checkType = methodInstance->GetThisType(); + } + + if (checkType->IsMethodRef()) { methodParam.mIsSplat = true; } - else if ((methodParam.mResolvedType->IsComposite()) && (methodInstance->AllowsSplatting())) + else if ((checkType->IsComposite()) && (methodInstance->AllowsSplatting())) { - PopulateType(methodParam.mResolvedType, BfPopulateType_Data); - if (methodParam.mResolvedType->IsSplattable()) + PopulateType(checkType, BfPopulateType_Data); + if (checkType->IsSplattable()) { - int splatCount = methodParam.mResolvedType->GetSplatCount(); - if (argIdx + splatCount <= mCompiler->mOptions.mMaxSplatRegs) + int splatCount = checkType->GetSplatCount(); + if (checkArgIdx + splatCount <= mCompiler->mOptions.mMaxSplatRegs) { methodParam.mIsSplat = true; argIdx += splatCount; continue; } } + else if (!checkType->IsValuelessType()) + { + BfTypeCode loweredTypeCode = BfTypeCode_None; + BfTypeCode loweredTypeCode2 = BfTypeCode_None; + checkType->GetLoweredType(BfTypeUsage_Parameter, &loweredTypeCode, &loweredTypeCode2); + argIdx++; + if (loweredTypeCode2 != BfTypeCode_None) + argIdx++; + } } argIdx++; diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 8e87f3aa..6ec7c04d 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1420,6 +1420,7 @@ public: void GetAccessAllowed(BfTypeInstance* checkType, bool& allowProtected, bool& allowPrivate); bool CheckProtection(BfProtectionCheckFlags& flags, BfTypeInstance* memberOwner, BfProject* memberProject, BfProtection memberProtection, BfTypeInstance* lookupStartType); void SetElementType(BfAstNode* astNode, BfSourceElementType elementType); + void SetFail(); BfError* Fail(const StringImpl& error, BfAstNode* refNode = NULL, bool isPersistent = false); BfError* FailInternal(const StringImpl& error, BfAstNode* refNode = NULL); BfError* FailAfter(const StringImpl& error, BfAstNode* refNode); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 0bcef30e..8e9d3fc4 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -6331,6 +6331,7 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty bool hasTypeGenerics = false; auto returnType = ResolveGenericType(unspecializedDelegateInfo->mReturnType, typeGenericArguments, methodGenericArguments, allowFail); + if (returnType == NULL) return NULL; if (returnType->IsVar()) @@ -6338,6 +6339,7 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty _CheckType(returnType); if (returnType->IsGenericParam()) hasTypeGenerics |= ((BfGenericParamType*)returnType)->mGenericParamKind == BfGenericParamKind_Type; + Array paramTypes; for (auto param : unspecializedDelegateInfo->mParams) { @@ -6420,13 +6422,16 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty typeDef->mIsDelegate = unspecializedDelegateType->mTypeDef->mIsDelegate; typeDef->mIsFunction = unspecializedDelegateType->mTypeDef->mIsFunction; + BfMethodDef* unspecializedInvokeMethodDef = unspecializedDelegateType->mTypeDef->GetMethodByName("Invoke"); + BfMethodDef* methodDef = new BfMethodDef(); methodDef->mDeclaringType = typeDef; methodDef->mName = "Invoke"; methodDef->mProtection = BfProtection_Public; methodDef->mIdx = 0; - methodDef->mIsStatic = !typeDef->mIsDelegate; - + methodDef->mIsStatic = !typeDef->mIsDelegate && !unspecializedDelegateInfo->mHasExplicitThis; + methodDef->mHasExplicitThis = unspecializedDelegateInfo->mHasExplicitThis; + auto directTypeRef = BfAstNode::ZeroedAlloc(); delegateInfo->mDirectAllocNodes.push_back(directTypeRef); if (typeDef->mIsDelegate) @@ -6440,8 +6445,7 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty directTypeRef->Init(returnType); methodDef->mReturnTypeRef = directTypeRef; delegateInfo->mReturnType = returnType; - - BfMethodDef* unspecializedInvokeMethodDef = unspecializedDelegateType->mTypeDef->GetMethodByName("Invoke"); + delegateInfo->mHasExplicitThis = unspecializedDelegateInfo->mHasExplicitThis; int paramIdx = 0; for (int paramIdx = 0; paramIdx < (int)paramTypes.size(); paramIdx++) @@ -6469,11 +6473,20 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty typeDef->mMethods.push_back(methodDef); - // + if (unspecializedInvokeMethodDef->mIsMutating) + { + if ((delegateInfo->mParams[0]->IsValueType()) || (delegateInfo->mParams[0]->IsGenericParam())) + methodDef->mIsMutating = unspecializedInvokeMethodDef->mIsMutating; + } - BfDefBuilder::AddMethod(typeDef, BfMethodType_Ctor, BfProtection_Public, false, ""); + + // + if (typeDef->mIsDelegate) + { + BfDefBuilder::AddMethod(typeDef, BfMethodType_Ctor, BfProtection_Public, false, ""); BfDefBuilder::AddDynamicCastMethods(typeDef); + } delegateType->mContext = mContext; delegateType->mTypeDef = typeDef; @@ -6904,8 +6917,8 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy else if (resolvedTypeRef->IsDelegateFromTypeRef() || resolvedTypeRef->IsFunctionFromTypeRef()) { auto delegateInfo = resolvedTypeRef->GetDelegateInfo(); - if (delegateInfo->mFunctionThisType != NULL) - AddDependency(delegateInfo->mFunctionThisType, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference); +// if (delegateInfo->mFunctionThisType != NULL) +// AddDependency(delegateInfo->mFunctionThisType, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference); AddDependency(delegateInfo->mReturnType, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference); for (auto& param : delegateInfo->mParams) AddDependency(param, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference); @@ -8903,8 +8916,10 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula } } hasMutSpecifier = true; - functionThisType = refType->mElementType; + functionThisType = refType->mElementType; } + paramTypes.Add(functionThisType); + _CheckType(functionThisType); } else { @@ -8980,11 +8995,14 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula methodDef->mName = "Invoke"; methodDef->mProtection = BfProtection_Public; methodDef->mIdx = 0; - methodDef->mIsStatic = !typeDef->mIsDelegate && (functionThisType == NULL); - methodDef->mIsMutating = true; + methodDef->mIsStatic = !typeDef->mIsDelegate && (functionThisType == NULL); + methodDef->mHasExplicitThis = functionThisType != NULL; - if ((functionThisType != NULL) && (functionThisType->IsValueType()) && (!hasMutSpecifier)) - methodDef->mIsMutating = false; + if ((functionThisType != NULL) && (hasMutSpecifier)) + { + if ((functionThisType->IsValueType()) || (functionThisType->IsGenericParam())) + methodDef->mIsMutating = true; + } auto directTypeRef = BfAstNode::ZeroedAlloc(); delegateInfo->mDirectAllocNodes.push_back(directTypeRef); @@ -8999,11 +9017,12 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula directTypeRef->Init(returnType); methodDef->mReturnTypeRef = directTypeRef; delegateInfo->mReturnType = returnType; - delegateInfo->mFunctionThisType = functionThisType; + delegateInfo->mHasExplicitThis = functionThisType != NULL; auto hashVal = mContext->mResolvedTypes.Hash(typeRef, &lookupCtx); - int paramSrcOfs = (functionThisType != NULL) ? 1 : 0; + //int paramSrcOfs = (functionThisType != NULL) ? 1 : 0; + int paramSrcOfs = 0; for (int paramIdx = 0; paramIdx < (int)paramTypes.size(); paramIdx++) { auto param = delegateTypeRef->mParams[paramIdx + paramSrcOfs]; @@ -9026,8 +9045,10 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula paramDef->mTypeRef = directTypeRef; paramDef->mName = paramName; - methodDef->mParams.push_back(paramDef); - + if ((paramIdx == 0) && (functionThisType != NULL)) + paramDef->mParamKind = BfParamKind_ExplicitThis; + methodDef->mParams.push_back(paramDef); + delegateInfo->mParams.Add(paramType); } @@ -9041,10 +9062,12 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula } // - - BfDefBuilder::AddMethod(typeDef, BfMethodType_Ctor, BfProtection_Public, false, ""); - if (typeDef->mIsDelegate) + + if (typeDef->mIsDelegate) + { + BfDefBuilder::AddMethod(typeDef, BfMethodType_Ctor, BfProtection_Public, false, ""); BfDefBuilder::AddDynamicCastMethods(typeDef); + } delegateType->mContext = mContext; delegateType->mTypeDef = typeDef; @@ -9052,8 +9075,8 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula resolvedEntry->mValue = delegateType; AddDependency(directTypeRef->mType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue); - if (delegateInfo->mFunctionThisType != NULL) - AddDependency(delegateInfo->mFunctionThisType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue); +// if (delegateInfo->mFunctionThisType != NULL) +// AddDependency(delegateInfo->mFunctionThisType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue); for (auto paramType : paramTypes) AddDependency(paramType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue); @@ -9376,14 +9399,13 @@ BfIRValue BfModule::CastToFunction(BfAstNode* srcNode, BfMethodInstance* methodI } else if (invokeMethodInstance->IsExactMatch(methodInstance, false, false)) { - bool handled = false; - - auto thisType = methodInstance->GetParamType(-1); - if (thisType != NULL) + bool handled = false; + if (methodInstance->HasThis()) { + auto thisType = methodInstance->GetThisType(); if (invokeMethodInstance->HasExplicitThis()) { - auto invokeThisType = invokeMethodInstance->GetParamType(-1); + auto invokeThisType = invokeMethodInstance->GetThisType(); bool thisWasPtr = false; if (thisType->IsPointer()) @@ -9416,6 +9438,7 @@ BfIRValue BfModule::CastToFunction(BfAstNode* srcNode, BfMethodInstance* methodI if ((!methodInstance->mMethodDef->mIsStatic) && (!invokeMethodInstance->HasExplicitThis())) { handled = true; + auto thisType = methodInstance->GetParamType(-1); Fail(StrFormat("Non-static method '%s' cannot match '%s', consider adding '%s this' to the function parameters", MethodToString(methodInstance).c_str(), TypeToString(toType).c_str(), TypeToString(thisType).c_str()), srcNode); } @@ -9432,9 +9455,10 @@ BfIRValue BfModule::CastToFunction(BfAstNode* srcNode, BfMethodInstance* methodI } BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags, BfCastResultFlags* resultFlags) -{ +{ + bool silentFail = ((castFlags & BfCastFlags_SilentFail) != 0); bool explicitCast = (castFlags & BfCastFlags_Explicit) != 0; - bool ignoreErrors = mIgnoreErrors || ((castFlags & BfCastFlags_SilentFail) != 0); + bool ignoreErrors = mIgnoreErrors || ((castFlags & BfCastFlags_SilentFail) != 0); bool ignoreWrites = mBfIRBuilder->mIgnoreWrites; if (typedVal.mType == toType) @@ -9547,9 +9571,12 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp // void* -> intptr if ((typedVal.mType->IsPointer()) && (toType->IsIntPtr())) { - if ((!ignoreErrors) && (!typedVal.mType->GetUnderlyingType()->IsVoid()) && ((castFlags & BfCastFlags_FromCompiler) == 0)) - { - Fail(StrFormat("Unable to cast directly from '%s' to '%s', consider casting to void* first", TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode); + if ((!typedVal.mType->GetUnderlyingType()->IsVoid()) && ((castFlags & BfCastFlags_FromCompiler) == 0)) + { + if (!ignoreErrors) + Fail(StrFormat("Unable to cast directly from '%s' to '%s', consider casting to void* first", TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode); + else if (!silentFail) + SetFail(); } auto toPrimitive = (BfPrimitiveType*)toType; @@ -9559,9 +9586,12 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp // intptr -> void* if ((typedVal.mType->IsIntPtr()) && (toType->IsPointer())) { - if ((!ignoreErrors) && (!toType->GetUnderlyingType()->IsVoid()) && ((castFlags & BfCastFlags_FromCompiler) == 0)) + if ((!toType->GetUnderlyingType()->IsVoid()) && ((castFlags & BfCastFlags_FromCompiler) == 0)) { - Fail(StrFormat("Unable to cast directly from '%s' to '%s', consider casting to void* first", TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode); + if (!ignoreErrors) + Fail(StrFormat("Unable to cast directly from '%s' to '%s', consider casting to void* first", TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode); + else if (!silentFail) + SetFail(); } return mBfIRBuilder->CreateIntToPtr(typedVal.mValue, mBfIRBuilder->MapType(toType)); @@ -10088,11 +10118,13 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp } if (!ignoreErrors) - { + { String valStr; VariantToString(valStr, variantVal); Fail(StrFormat("Unable to cast '%s %s' to '%s'", TypeToString(typedVal.mType).c_str(), valStr.c_str(), TypeToString(toType).c_str()), srcNode); } + else if (!silentFail) + SetFail(); } } @@ -10553,8 +10585,13 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp { if (mayBeBox) { - if ((!ignoreErrors) && (Fail("Ambiguous cast, may be conversion operator or may be boxing request", srcNode) != NULL)) - mCompiler->mPassInstance->MoreInfo("See conversion operator", opMethodInstance->mMethodDef->GetRefNode()); + if (!ignoreErrors) + { + if (Fail("Ambiguous cast, may be conversion operator or may be boxing request", srcNode) != NULL) + mCompiler->mPassInstance->MoreInfo("See conversion operator", opMethodInstance->mMethodDef->GetRefNode()); + } + else if (!silentFail) + SetFail(); } BfMethodInstance* methodInstance = GetRawMethodInstance(opMethodInstance->GetOwner(), opMethodInstance->mMethodDef); @@ -10620,6 +10657,8 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp const char* errStr = "Ambiguous conversion operators for casting from '%s' to '%s'"; Fail(StrFormat(errStr, TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode); } + else if (!silentFail) + SetFail(); return BfIRValue(); } @@ -10777,7 +10816,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp "Unable to cast '%s' to '%s'" : "Unable to implicitly cast '%s' to '%s'"; - String errStr = StrFormat(errStrF, TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()); + String errStr = StrFormat(errStrF, TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()); auto error = Fail(errStr, srcNode); if ((error != NULL) && (srcNode != NULL)) { @@ -10787,7 +10826,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp SetAndRestoreValue ignoreErrors(mIgnoreErrors, true); if (CastToValue(srcNode, typedVal, toType, (BfCastFlags)(BfCastFlags_Explicit | BfCastFlags_SilentFail))) - { + { bool doWrap = false; if (auto unaryOpExpr = BfNodeDynCast(srcNode)) { @@ -10805,7 +10844,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp if (doWrap) { mCompiler->mResolvePassData->mAutoComplete->AddEntry(AutoCompleteEntry("fixit", - StrFormat("(%s)\tcast|%s|%d|(%s)(|`%d|)", typeName.c_str(), parser->mFileName.c_str(), srcNode->GetSrcStart(), typeName.c_str(), srcNode->GetSrcLength()).c_str())); + StrFormat("(%s)\tcast|%s|%d|(%s)(|`%d|)", typeName.c_str(), parser->mFileName.c_str(), srcNode->GetSrcStart(), typeName.c_str(), srcNode->GetSrcLength()).c_str())); } else { @@ -10816,6 +10855,8 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp } } } + else if (!silentFail) + SetFail(); return BfIRValue(); } @@ -10986,6 +11027,7 @@ BfTypedValue BfModule::Cast(BfAstNode* srcNode, const BfTypedValue& typedVal, Bf if ((fromMethodInst != NULL) && (toMethodInst != NULL) && (fromMethodInst->mMethodDef->mCallingConvention == toMethodInst->mMethodDef->mCallingConvention) && + (fromMethodInst->mMethodDef->mIsMutating == toMethodInst->mMethodDef->mIsMutating) && (fromMethodInst->mReturnType == toMethodInst->mReturnType) && (fromMethodInst->GetParamCount() == toMethodInst->GetParamCount())) { @@ -11000,7 +11042,7 @@ BfTypedValue BfModule::Cast(BfAstNode* srcNode, const BfTypedValue& typedVal, Bf } else { - for (int paramIdx = fromMethodInst->HasExplicitThis() ? -1 : 0; paramIdx < (int)fromMethodInst->GetParamCount(); paramIdx++) + for (int paramIdx = 0; paramIdx < (int)fromMethodInst->GetParamCount(); paramIdx++) { bool nameMatches = true; @@ -11550,16 +11592,7 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF DoTypeToString(str, delegateInfo->mReturnType, typeNameFlags, genericMethodNameOverrides); str += "("; - bool isFirstParam = true; - if (delegateInfo->mFunctionThisType != NULL) - { - if ((methodDef->mIsMutating) && (delegateInfo->mFunctionThisType->IsValueType())) - str += "mut "; - DoTypeToString(str, delegateInfo->mFunctionThisType, typeNameFlags, genericMethodNameOverrides); - str += " this"; - isFirstParam = false; - } - + bool isFirstParam = true;// for (int paramIdx = 0; paramIdx < methodDef->mParams.size(); paramIdx++) { if (!isFirstParam) @@ -11567,7 +11600,14 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF auto paramDef = methodDef->mParams[paramIdx]; BfTypeNameFlags innerFlags = (BfTypeNameFlags)(typeNameFlags & ~(BfTypeNameFlag_OmitNamespace | BfTypeNameFlag_OmitOuterType)); - DoTypeToString(str, delegateInfo->mParams[paramIdx], innerFlags, genericMethodNameOverrides); + auto paramType = delegateInfo->mParams[paramIdx]; + if ((paramIdx == 0) && (delegateInfo->mHasExplicitThis)) + { + if ((methodDef->mIsMutating) && (paramType->IsValueType())) + str += "mut "; + } + + DoTypeToString(str, paramType, innerFlags, genericMethodNameOverrides); if (!paramDef->mName.IsEmpty()) { diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 5aee5c92..4229b63e 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -768,6 +768,29 @@ bool BfMethodInstance::HasThis() return (!mMethodInstanceGroup->mOwner->IsValuelessType()); } +BfType* BfMethodInstance::GetThisType() +{ + BF_ASSERT(!mMethodDef->mIsStatic); + if (mMethodDef->mHasExplicitThis) + { + auto thisType = mParams[0].mResolvedType; + auto owner = GetOwner(); + if ((thisType->IsValueType()) && ((mMethodDef->mIsMutating) || (!AllowsSplatting())) && (!thisType->GetLoweredType(BfTypeUsage_Parameter))) + return owner->mModule->CreatePointerType(thisType); + return thisType; + } + return GetParamType(-1); +} + +int BfMethodInstance::GetThisIdx() +{ + if (mMethodDef->mIsStatic) + return -2; + if (mMethodDef->mHasExplicitThis) + return 0; + return -1; +} + bool BfMethodInstance::HasExplicitThis() { if (mMethodDef->mIsStatic) @@ -827,17 +850,18 @@ String BfMethodInstance::GetParamName(int paramIdx) } BfType* BfMethodInstance::GetParamType(int paramIdx, bool useResolvedType) -{ +{ if (paramIdx == -1) { if ((mMethodInfoEx != NULL) && (mMethodInfoEx->mClosureInstanceInfo != NULL) && (mMethodInfoEx->mClosureInstanceInfo->mThisOverride != NULL)) return mMethodInfoEx->mClosureInstanceInfo->mThisOverride; BF_ASSERT(!mMethodDef->mIsStatic); auto owner = mMethodInstanceGroup->mOwner; - auto delegateInfo = owner->GetDelegateInfo(); BfType* thisType = owner; - if ((delegateInfo != NULL) && (delegateInfo->mFunctionThisType != NULL)) - thisType = delegateInfo->mFunctionThisType; + if (owner->IsFunction()) + { + BF_FATAL("Wrong 'this' index"); + } if ((thisType->IsValueType()) && ((mMethodDef->mIsMutating) || (!AllowsSplatting())) && (!thisType->GetLoweredType(BfTypeUsage_Parameter))) return owner->mModule->CreatePointerType(thisType); return thisType; @@ -1034,8 +1058,10 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, returnType = module->mBfIRBuilder->MapType(mReturnType); } + + for (int paramIdx = -1; paramIdx < GetParamCount(); paramIdx++) - { + { BfType* checkType = NULL; if (paramIdx == -1) { @@ -1048,7 +1074,7 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, else { if (HasExplicitThis()) - checkType = GetParamType(-1); + checkType = GetParamType(0); else checkType = GetOwner(); } @@ -1102,14 +1128,14 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, } } - if ((paramIdx == 0) && (GetParamName(0) == "this") && (checkType->IsPointer())) - { - // We don't actually pass a this pointer for mut methods in valueless structs - auto underlyingType = checkType->GetUnderlyingType(); - module->PopulateType(underlyingType, BfPopulateType_Data); - if (underlyingType->IsValuelessType()) - continue; - } +// if ((paramIdx == 0) && (GetParamName(0) == "this") && (checkType->IsPointer())) +// { +// // We don't actually pass a this pointer for mut methods in valueless structs +// auto underlyingType = checkType->GetUnderlyingType(); +// module->PopulateType(underlyingType, BfPopulateType_Data); +// if (underlyingType->IsValuelessType()) +// continue; +// } if (checkType->CanBeValuelessType()) module->PopulateType(checkType, BfPopulateType_Data); @@ -1159,6 +1185,9 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, if (checkType2 != NULL) _AddType(checkType2); + + if ((paramIdx == -1) && (mMethodDef->mHasExplicitThis)) + paramIdx++; // Skip over the explicit 'this' } if (GetStructRetIdx(forceStatic) == 1) @@ -1200,7 +1229,7 @@ bool BfMethodInstance::IsExactMatch(BfMethodInstance* other, bool ignoreImplicit if (checkThis) { if (other->mMethodDef->mIsStatic != mMethodDef->mIsStatic) - return false; + return false; // { // // If we are static and we have to match a non-static method, allow us to do so if we have an explicitly defined 'this' param that matches @@ -1227,13 +1256,18 @@ bool BfMethodInstance::IsExactMatch(BfMethodInstance* other, bool ignoreImplicit if (!mMethodDef->mIsStatic) { - if (GetParamType(-1) != other->GetParamType(-1)) + if (GetThisType() != other->GetThisType()) { return false; } } } + if (mMethodDef->mHasExplicitThis) + implicitParamCountA++; + if (other->mMethodDef->mHasExplicitThis) + implicitParamCountB++; + if (GetParamCount() - implicitParamCountA != other->GetParamCount() - implicitParamCountB) return false; for (int i = 0; i < (int)GetParamCount() - implicitParamCountA; i++) @@ -2577,14 +2611,6 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef) BF_ASSERT(methodDef->mName == "Invoke"); BF_ASSERT(delegateInfo->mParams.size() == methodDef->mParams.size()); - if (delegateInfo->mFunctionThisType != NULL) - { - hashVal = ((hashVal ^ (Hash(delegateInfo->mFunctionThisType, ctx))) << 5) - hashVal; - String paramName = "this"; - int nameHash = (int)Hash64(paramName.c_str(), (int)paramName.length()); - hashVal = ((hashVal ^ (nameHash)) << 5) - hashVal; - } - for (int paramIdx = 0; paramIdx < delegateInfo->mParams.size(); paramIdx++) { // Parse attributes? @@ -3300,6 +3326,10 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx) auto lhsMethodDef = lhsInst->mTypeDef->mMethods[0]; auto rhsMethodDef = rhsInst->mTypeDef->mMethods[0]; + if (lhsMethodDef->mCallingConvention != rhsMethodDef->mCallingConvention) + return false; + if (lhsMethodDef->mIsMutating != rhsMethodDef->mIsMutating) + return false; if (lhsDelegateInfo->mReturnType != rhsDelegateInfo->mReturnType) return false; if (lhsDelegateInfo->mParams.size() != rhsDelegateInfo->mParams.size()) @@ -3701,44 +3731,42 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfTypeReference* rhs, LookupContext* auto param0 = rhsDelegateType->mParams[0]; if ((param0->mNameNode != NULL) && (param0->mNameNode->Equals("this"))) { + if (!lhsDelegateInfo->mHasExplicitThis) + return false; + bool handled = false; - auto lhsThisType = lhsDelegateInfo->mFunctionThisType; + auto lhsThisType = lhsDelegateInfo->mParams[0]; auto rhsThisType = ctx->mModule->ResolveTypeRef(param0->mTypeRef, BfPopulateType_Identity, (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoWarnOnMut | BfResolveTypeRefFlag_AllowRef)); + bool wantsMutating = false; + if (rhsThisType->IsRef()) { if (lhsThisType != rhsThisType->GetUnderlyingType()) return false; - if (!invokeMethodDef->mIsMutating) - return false; + wantsMutating = (lhsThisType->IsValueType()) || (lhsThisType->IsGenericParam()); } else { if (lhsThisType != rhsThisType) - return false; - if ((invokeMethodDef->mIsMutating) && (lhsThisType->IsValueType())) - return false; + return false; } + if (invokeMethodDef->mIsMutating != wantsMutating) + return false; paramRefOfs = 1; } } - if (!rhsIsDelegate) - { - if ((lhsDelegateInfo->mFunctionThisType == NULL) != (paramRefOfs == 0)) - return false; - } - - if (lhsDelegateInfo->mParams.size() != (int)rhsDelegateType->mParams.size() - paramRefOfs) + if (lhsDelegateInfo->mParams.size() != (int)rhsDelegateType->mParams.size()) return false; - for (int paramIdx = 0; paramIdx < lhsDelegateInfo->mParams.size(); paramIdx++) + for (int paramIdx = paramRefOfs; paramIdx < lhsDelegateInfo->mParams.size(); paramIdx++) { - if (!Equals(lhsDelegateInfo->mParams[paramIdx], rhsDelegateType->mParams[paramIdx + paramRefOfs]->mTypeRef, ctx)) + if (!Equals(lhsDelegateInfo->mParams[paramIdx], rhsDelegateType->mParams[paramIdx]->mTypeRef, ctx)) return false; StringView rhsParamName; - if (rhsDelegateType->mParams[paramIdx + paramRefOfs]->mNameNode != NULL) - rhsParamName = rhsDelegateType->mParams[paramIdx + paramRefOfs]->mNameNode->ToStringView(); + if (rhsDelegateType->mParams[paramIdx]->mNameNode != NULL) + rhsParamName = rhsDelegateType->mParams[paramIdx]->mNameNode->ToStringView(); if (invokeMethodDef->mParams[paramIdx]->mName != rhsParamName) return false; } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index a7eedbf7..856d1305 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -416,15 +416,15 @@ class BfDelegateInfo { public: Array mDirectAllocNodes; - BfType* mReturnType; - BfType* mFunctionThisType; + BfType* mReturnType; Array mParams; + bool mHasExplicitThis; public: BfDelegateInfo() { mReturnType = NULL; - mFunctionThisType = NULL; + mHasExplicitThis = false; } ~BfDelegateInfo() @@ -870,6 +870,8 @@ public: bool IsSpecializedByAutoCompleteMethod(); bool HasExternConstraints(); bool HasThis(); + BfType* GetThisType(); + int GetThisIdx(); bool HasExplicitThis(); bool HasParamsArray(); int GetStructRetIdx(bool forceStatic = false); diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 6650c920..7a097117 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -458,7 +458,8 @@ struct BfCodeGenOptions enum BfParamKind : uint8 { - BfParamKind_Normal, + BfParamKind_Normal, + BfParamKind_ExplicitThis, BfParamKind_Params, BfParamKind_DelegateParam, BfParamKind_ImplicitCapture, @@ -725,6 +726,7 @@ public: bool mIsOperator; bool mIsExtern; bool mIsNoDiscard; + bool mHasExplicitThis; BfCommutableKind mCommutableKind; BfCheckedKind mCheckedKind; BfImportKind mImportKind; @@ -751,6 +753,7 @@ public: mIsOperator = false; mIsExtern = false; mIsNoDiscard = false; + mHasExplicitThis = false; mBody = NULL; mExplicitInterface = NULL; mReturnTypeRef = NULL; diff --git a/IDEHelper/Tests/src/Functions.bf b/IDEHelper/Tests/src/Functions.bf index 5ec24c15..7228b7c3 100644 --- a/IDEHelper/Tests/src/Functions.bf +++ b/IDEHelper/Tests/src/Functions.bf @@ -26,6 +26,17 @@ namespace Tests int mA = 123; int mB = 234; + public this() + { + + } + + public this(int a, int b) + { + mA = a; + mB = b; + } + public int GetA(float f) { return mA + mB*100 + (int)f; @@ -35,6 +46,98 @@ namespace Tests { return mA + mB*100 + (int)f; } + + public StructA GetA3(float f) + { + StructA sa; + sa.mA = mA + 1000; + sa.mB = mB + 2000 + (int)f; + return sa; + } + + public StructA GetA4(float f) mut + { + StructA sa; + sa.mA = mA + 1000; + sa.mB = mB + 2000 + (int)f; + return sa; + } + } + + struct StructB + { + function StructB Func(StructB this, float f); + function StructB FuncMut(mut StructB this, float f); + + int mA = 123; + int mB = 234; + int mC = 345; + + public this() + { + + } + + public this(int a, int b, int c) + { + mA = a; + mB = b; + mC = c; + } + + public int GetA(float f) + { + return mA + mB*100 + (int)f; + } + + public int GetA2(float f) mut + { + return mA + mB*100 + (int)f; + } + + public StructB GetA3(float f) + { + StructB sb; + sb.mA = mA + 1000; + sb.mB = mB + 2000 + (int)f; + sb.mC = mC + 3000; + return sb; + } + + public StructB GetA4(float f) mut + { + StructB sb; + sb.mA = mA + 1000; + sb.mB = mB + 2000 + (int)f; + sb.mC = mC + 3000; + return sb; + } + + public static void Test() + { + StructB sb = .(); + + Func func0 = => GetA3; + Test.Assert(func0(sb, 100.0f) == .(1123, 2334, 3345)); + function StructB (StructB this, float f) func1 = => GetA3; + + Test.Assert(func0 == func1); + func0 = func1; + + FuncMut func2 = => GetA4; + Test.Assert(func2(sb, 100.0f) == .(1123, 2334, 3345)); + function StructB (mut StructB this, float f) func3 = => GetA4; + } + } + + public static int UseFunc0(function int (T this, float f) func, T a, float b) + { + return func(a, b); + } + + public static int UseFunc1(function int (mut T this, float f) func, mut T a, float b) + { + return func(a, b); } [Test] @@ -42,6 +145,7 @@ namespace Tests { ClassA ca = scope .(); StructA sa = .(); + StructB sb = .(); function int (ClassA this, float f) func0 = => ca.GetA; function int (ClassA this, float) func0b = func0; @@ -50,10 +154,34 @@ namespace Tests Test.Assert(func0(ca, 100.0f) == 223); function int (StructA this, float f) func1 = => sa.GetA; + var func1b = func1; Test.Assert(func1(sa, 100.0f) == 23623); + Test.Assert(! + [IgnoreErrors(true)] + { + func1b = => sb.GetA; + true + }); function int (mut StructA this, float f) func2 = => sa.GetA2; - Test.Assert(func2(mut sa, 100.0f) == 23623); + Test.Assert(func2(sa, 100.0f) == 23623); + + function StructA (StructA this, float f) func3 = => sa.GetA3; + Test.Assert(func3(sa, 100.0f) == .(1123, 2334)); + + function StructA (mut StructA this, float f) func4 = => sa.GetA4; + Test.Assert(func4(sa, 100.0f) == .(1123, 2334)); + + StructB.Test(); + + Test.Assert(UseFunc0(func0, ca, 100.0f) == 223); + Test.Assert(UseFunc0(func1, sa, 100.0f) == 23623); + Test.Assert(! + [IgnoreErrors(true)] + { + UseFunc0(func2, sa, 100.0f); + true + }); } } }