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

Reworked functions with explicit 'this'

This commit is contained in:
Brian Fiete 2020-09-11 10:33:16 -07:00
parent 9fde8a3c89
commit 3627f8c40f
15 changed files with 556 additions and 199 deletions

View file

@ -138,6 +138,7 @@ BfAutoComplete::BfAutoComplete(BfResolveType resolveType)
mIgnoreFixits = false; mIgnoreFixits = false;
mHasFriendSet = false; mHasFriendSet = false;
mUncertain = false; mUncertain = false;
mForceAllowNonStatic = false;
mMethodMatchInfo = NULL; mMethodMatchInfo = NULL;
mIsGetDefinition = mIsGetDefinition =
(resolveType == BfResolveType_GetSymbolInfo) || (resolveType == BfResolveType_GetSymbolInfo) ||
@ -588,6 +589,9 @@ void BfAutoComplete::AddTypeMembers(BfTypeInstance* typeInst, bool addStatic, bo
{ {
bool isInterface = false; bool isInterface = false;
if (mForceAllowNonStatic)
addNonStatic = true;
auto activeTypeDef = mModule->GetActiveTypeDef(); auto activeTypeDef = mModule->GetActiveTypeDef();
if ((addStatic) && (mModule->mCurMethodInstance == NULL) && (typeInst->IsEnum())) if ((addStatic) && (mModule->mCurMethodInstance == NULL) && (typeInst->IsEnum()))

View file

@ -179,6 +179,7 @@ public:
bool mIgnoreFixits; bool mIgnoreFixits;
bool mHasFriendSet; bool mHasFriendSet;
bool mUncertain; // May be an unknown identifier, do not aggressively autocomplete bool mUncertain; // May be an unknown identifier, do not aggressively autocomplete
bool mForceAllowNonStatic;
int mCursorLineStart; int mCursorLineStart;
int mCursorLineEnd; int mCursorLineEnd;

View file

@ -4272,11 +4272,16 @@ void BfCompiler::ProcessAutocompleteTempType()
methodInstance->GetMethodInfoEx()->mGenericParams.push_back(genericParamInstance); methodInstance->GetMethodInfoEx()->mGenericParams.push_back(genericParamInstance);
} }
bool wantsProcess = !actualTypeDef->mIsFunction;
SetAndRestoreValue<BfFilePosition> prevFilePos(module->mCurFilePosition); SetAndRestoreValue<BfFilePosition> prevFilePos(module->mCurFilePosition);
SetAndRestoreValue<BfMethodInstance*> prevMethodInst(module->mCurMethodInstance, methodInstance); SetAndRestoreValue<BfMethodInstance*> prevMethodInst(module->mCurMethodInstance, methodInstance);
module->DoMethodDeclaration(methodDeclaration, true); module->DoMethodDeclaration(methodDeclaration, true, wantsProcess);
if (wantsProcess)
{
module->mIncompleteMethodCount++; module->mIncompleteMethodCount++;
module->ProcessMethod(methodInstance); module->ProcessMethod(methodInstance);
}
if (methodInstance->mIRFunction) if (methodInstance->mIRFunction)
{ {
@ -7420,7 +7425,7 @@ void BfCompiler::GenerateAutocompleteInfo()
int dispParamIdx = 0; int dispParamIdx = 0;
StringT<64> paramName; 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); auto paramKind = methodInstance->GetParamKind(paramIdx);
if ((paramKind == BfParamKind_ImplicitCapture) || (paramKind == BfParamKind_AppendIdx)) if ((paramKind == BfParamKind_ImplicitCapture) || (paramKind == BfParamKind_AppendIdx))

View file

@ -621,6 +621,12 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
else // else //
paramDef->mParamKind = BfParamKind_Params; paramDef->mParamKind = BfParamKind_Params;
if ((mCurTypeDef->mIsFunction) && (paramIdx == 0) && (paramDef->mName == "this"))
{
paramDef->mParamKind = BfParamKind_ExplicitThis;
methodDef->mIsStatic = false;
}
if (auto dotTypeRef = BfNodeDynCast<BfDotTypeReference>(paramDef->mTypeRef)) if (auto dotTypeRef = BfNodeDynCast<BfDotTypeReference>(paramDef->mTypeRef))
{ {
if (dotTypeRef->mDotToken->mToken == BfToken_DotDotDot) if (dotTypeRef->mDotToken->mToken == BfToken_DotDotDot)
@ -658,6 +664,22 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
methodDef->mParams.push_back(paramDef); 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<BfRefTypeRef>(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); ParseAttributes(methodDeclaration->mAttributes, methodDef);
return 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)) if ((mCurTypeDef->mTypeCode == BfTypeCode_Object) && (!mCurTypeDef->mIsStatic))
{ {
auto methodDef = AddMethod(mCurTypeDef, BfMethodType_CtorClear, BfProtection_Private, false, ""); auto methodDef = AddMethod(mCurTypeDef, BfMethodType_CtorClear, BfProtection_Private, false, "");
@ -1934,12 +1966,6 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
} }
bool makeCtorPrivate = hasCtor; 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) if (mCurTypeDef->mTypeCode == BfTypeCode_TypeAlias)
needsDefaultCtor = false; needsDefaultCtor = false;
@ -1962,7 +1988,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
isAutocomplete = true; isAutocomplete = true;
//TODO: Don't do this for the autocomplete pass //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)) (!mCurTypeDef->mIsStatic) && (!isAutocomplete) && (!isAlias))
{ {
AddDynamicCastMethods(mCurTypeDef); AddDynamicCastMethods(mCurTypeDef);
@ -2012,12 +2038,6 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
if (hasToStringMethod) if (hasToStringMethod)
wantsToString = false; wantsToString = false;
if (mCurTypeDef->mIsFunction)
{
wantsToString = false;
needsEqualsMethod = false;
}
if ((mCurTypeDef->mTypeCode == BfTypeCode_Enum) && (!isPayloadEnum)) if ((mCurTypeDef->mTypeCode == BfTypeCode_Enum) && (!isPayloadEnum))
{ {
auto methodDef = new BfMethodDef(); auto methodDef = new BfMethodDef();

View file

@ -542,6 +542,27 @@ bool BfGenericInferContext::InferGenericArgument(BfMethodInstance* methodInstanc
InferGenericArgument(methodInstance, argInvokeMethod->GetParamType(argIdx), wantInvokeMethod->GetParamType(argIdx), BfIRValue()); 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; return true;
@ -1021,7 +1042,7 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
RETURN_RESULTS; 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; BfTypedValue argTypedValue = resolvedArg.mTypedValue;
if ((resolvedArg.mArgFlags & BfArgFlag_DelegateBindAttempt) != 0) if ((resolvedArg.mArgFlags & BfArgFlag_DelegateBindAttempt) != 0)
@ -1032,7 +1053,7 @@ BfTypedValue BfMethodMatcher::ResolveArgTypedValue(BfResolvedArg& resolvedArg, B
BF_ASSERT(resolvedArg.mExpression->IsA<BfDelegateBindExpression>()); BF_ASSERT(resolvedArg.mExpression->IsA<BfDelegateBindExpression>());
auto delegateBindExpr = BfNodeDynCast<BfDelegateBindExpression>(resolvedArg.mExpression); auto delegateBindExpr = BfNodeDynCast<BfDelegateBindExpression>(resolvedArg.mExpression);
BfMethodInstance* boundMethodInstance = NULL; BfMethodInstance* boundMethodInstance = NULL;
if (exprEvaluator.CanBindDelegate(delegateBindExpr, &boundMethodInstance)) if (exprEvaluator.CanBindDelegate(delegateBindExpr, &boundMethodInstance, origCheckType, genericArgumentsSubstitute))
{ {
if (delegateBindExpr->mNewToken == NULL) if (delegateBindExpr->mNewToken == NULL)
{ {
@ -1509,7 +1530,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
if (argIdx == -1) if (argIdx == -1)
argTypedValue = mTarget; argTypedValue = mTarget;
else else
argTypedValue = ResolveArgTypedValue(mArguments[argIdx], checkType, genericArgumentsSubstitute); argTypedValue = ResolveArgTypedValue(mArguments[argIdx], checkType, genericArgumentsSubstitute, origCheckType);
if (!argTypedValue.IsUntypedValue()) if (!argTypedValue.IsUntypedValue())
{ {
auto type = argTypedValue.mType; auto type = argTypedValue.mType;
@ -2615,6 +2636,16 @@ void BfExprEvaluator::Visit(BfAttributedExpression* attribExpr)
} }
VisitChild(attribExpr->mExpression); VisitChild(attribExpr->mExpression);
attributeState.mUsed = true; 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 else
{ {
@ -4896,6 +4927,9 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
bool doingThis = !methodDef->mIsStatic; bool doingThis = !methodDef->mIsStatic;
int argIdx = 0; int argIdx = 0;
if (methodDef->mHasExplicitThis)
paramIdx++;
int paramCount = methodInstance->GetParamCount(); int paramCount = methodInstance->GetParamCount();
for ( ; argIdx < callIRArgCount ; ) for ( ; argIdx < callIRArgCount ; )
@ -4986,13 +5020,14 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
BfType* paramType = NULL; BfType* paramType = NULL;
if (doingThis) if (doingThis)
{ {
paramType = methodInstance->GetOwner(); int thisIdx = methodInstance->GetThisIdx();
paramType = methodInstance->GetThisType();
if (paramType->IsValuelessType()) if (paramType->IsValuelessType())
{ {
doingThis = false; doingThis = false;
continue; continue;
} }
bool isSplatted = methodInstance->GetParamIsSplat(-1); // (resolvedTypeRef->IsSplattable()) && (!methodDef->mIsMutating); bool isSplatted = methodInstance->GetParamIsSplat(thisIdx); // (resolvedTypeRef->IsSplattable()) && (!methodDef->mIsMutating);
if (isSplatted) if (isSplatted)
{ {
BfTypeUtils::SplatIterate(_HandleParamType, paramType); BfTypeUtils::SplatIterate(_HandleParamType, paramType);
@ -5357,7 +5392,7 @@ void BfExprEvaluator::PushThis(BfAstNode* targetSrc, BfTypedValue argVal, BfMeth
return; return;
} }
auto thisType = methodInstance->GetParamType(-1); auto thisType = methodInstance->GetThisType();
PushArg(argVal, irArgs, !methodInstance->AllowsThisSplatting(), thisType->IsPointer()); PushArg(argVal, irArgs, !methodInstance->AllowsThisSplatting(), thisType->IsPointer());
} }
@ -5452,12 +5487,23 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
{ {
auto bindResult = prevBindResult.mPrevVal; auto bindResult = prevBindResult.mPrevVal;
if (bindResult->mBindType != NULL) if (bindResult->mBindType != NULL)
{
auto delegateInfo = bindResult->mBindType->GetDelegateInfo();
if ((delegateInfo != NULL) && (delegateInfo->mFunctionThisType != NULL))
{ {
// Allow binding a function to a 'this' type even if no target is specified // Allow binding a function to a 'this' type even if no target is specified
target = mModule->GetDefaultTypedValue(delegateInfo->mFunctionThisType, false, BfDefaultValueKind_Addr); auto delegateInfo = bindResult->mBindType->GetDelegateInfo();
if (delegateInfo != NULL)
{
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)) if ((boxScopeData == NULL) && (mModule->mCurMethodState != NULL))
boxScopeData = mModule->mCurMethodState->mCurScope; boxScopeData = mModule->mCurMethodState->mCurScope;
if (methodInstance->HasExplicitThis())
paramIdx = -1;
bool failed = false; bool failed = false;
while (true) while (true)
{ {
bool isThis = (paramIdx == -1) || ((methodDef->mHasExplicitThis) && (paramIdx == 0));
bool isDirectPass = false; bool isDirectPass = false;
if (paramIdx >= (int)methodInstance->GetParamCount()) if (paramIdx >= (int)methodInstance->GetParamCount())
@ -6021,7 +6065,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
if (argValue) if (argValue)
{ {
if ((paramIdx == -1) && (argValue.mType->IsRef())) if ((isThis) && (argValue.mType->IsRef()))
{ {
// Convert a 'ref this' to a 'this*' // Convert a 'ref this' to a 'this*'
argValue.mType = mModule->CreatePointerType(argValue.mType->GetUnderlyingType()); argValue.mType = mModule->CreatePointerType(argValue.mType->GetUnderlyingType());
@ -6107,7 +6151,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
if (argValue) if (argValue)
{ {
if (paramIdx == -1) if (isThis)
PushThis(targetSrc, argValue, methodInstance, irArgs); PushThis(targetSrc, argValue, methodInstance, irArgs);
else if (wantsSplat) else if (wantsSplat)
SplatArgs(argValue, irArgs); SplatArgs(argValue, irArgs);
@ -9485,7 +9529,11 @@ bool BfExprEvaluator::IsExactMethodMatch(BfMethodInstance* methodA, BfMethodInst
return false; return false;
int implicitParamCountA = methodA->GetImplicitParamCount(); int implicitParamCountA = methodA->GetImplicitParamCount();
if (methodA->HasExplicitThis())
implicitParamCountA++;
int implicitParamCountB = methodB->GetImplicitParamCount(); int implicitParamCountB = methodB->GetImplicitParamCount();
if (methodB->HasExplicitThis())
implicitParamCountB++;
if (methodA->GetParamCount() - implicitParamCountA != methodB->GetParamCount() - implicitParamCountB) if (methodA->GetParamCount() - implicitParamCountA != methodB->GetParamCount() - implicitParamCountB)
return false; return false;
@ -9517,15 +9565,21 @@ BfTypeInstance* BfExprEvaluator::VerifyBaseDelegateType(BfTypeInstance* baseDele
return baseDelegateType; 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; return false;
} }
auto typeInstance = mExpectingType->ToTypeInstance(); bool isGenericMatch = mExpectingType == NULL;
if ((typeInstance == NULL) || (!typeInstance->mTypeDef->mIsDelegate)) auto expectingType = mExpectingType;
if (expectingType == NULL)
expectingType = origMethodExpectingType;
auto typeInstance = expectingType->ToTypeInstance();
if ((typeInstance == NULL) ||
((!typeInstance->mTypeDef->mIsDelegate) && (!typeInstance->mTypeDef->mIsFunction)))
return false; return false;
mModule->PopulateType(typeInstance, BfPopulateType_DataAndMethods); mModule->PopulateType(typeInstance, BfPopulateType_DataAndMethods);
@ -9547,11 +9601,28 @@ bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr
SizedArray<BfExpression*, 4> args; SizedArray<BfExpression*, 4> args;
args.resize(methodInstance->GetParamCount()); 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++) for (int i = 0; i < (int) methodInstance->GetParamCount(); i++)
{ {
auto typedValueExpr = &typedValueExprs[i]; auto typedValueExpr = &typedValueExprs[i];
typedValueExpr->mTypedValue.mValue = BfIRValue(BfIRValueFlags_Value, -1); typedValueExpr->mTypedValue.mValue = BfIRValue(BfIRValueFlags_Value, -1);
typedValueExpr->mTypedValue.mType = methodInstance->GetParamType(i); typedValueExpr->mTypedValue.mType = _FixType(methodInstance->GetParamType(i));
typedValueExpr->mRefNode = NULL; typedValueExpr->mRefNode = NULL;
args[i] = typedValueExpr; args[i] = typedValueExpr;
} }
@ -9562,6 +9633,7 @@ bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr
BfFunctionBindResult bindResult; BfFunctionBindResult bindResult;
bindResult.mSkipMutCheck = true; // Allow operating on copies bindResult.mSkipMutCheck = true; // Allow operating on copies
bindResult.mBindType = expectingType;
mFunctionBindResult = &bindResult; mFunctionBindResult = &bindResult;
SetAndRestoreValue<bool> ignoreError(mModule->mIgnoreErrors, true); SetAndRestoreValue<bool> ignoreError(mModule->mIgnoreErrors, true);
DoInvocation(delegateBindExpr->mTarget, delegateBindExpr, args, methodGenericArguments); DoInvocation(delegateBindExpr->mTarget, delegateBindExpr, args, methodGenericArguments);
@ -9570,7 +9642,25 @@ bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr
return false; return false;
if (boundMethod != NULL) if (boundMethod != NULL)
*boundMethod = bindResult.mMethodInstance; *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) BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfIdentifierNode* identifierNode, int shadowIdx)
@ -9928,14 +10018,15 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
} }
} }
typedValueExprs.resize(methodInstance->GetParamCount()); int paramOffset = methodInstance->HasExplicitThis() ? 1 : 0;
args.resize(methodInstance->GetParamCount()); typedValueExprs.resize(methodInstance->GetParamCount() - paramOffset);
args.resize(methodInstance->GetParamCount() - paramOffset);
for (int i = 0; i < (int)methodInstance->GetParamCount(); i++) for (int i = 0; i < (int)methodInstance->GetParamCount() - paramOffset; i++)
{ {
auto typedValueExpr = &typedValueExprs[i]; auto typedValueExpr = &typedValueExprs[i];
typedValueExpr->mTypedValue.mValue = BfIRValue(BfIRValueFlags_Value, -1); typedValueExpr->mTypedValue.mValue = BfIRValue(BfIRValueFlags_Value, -1);
typedValueExpr->mTypedValue.mType = methodInstance->GetParamType(i); typedValueExpr->mTypedValue.mType = methodInstance->GetParamType(i + paramOffset);
typedValueExpr->mRefNode = NULL; typedValueExpr->mRefNode = NULL;
args[i] = typedValueExpr; args[i] = typedValueExpr;
} }
@ -9950,8 +10041,12 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
return; return;
} }
if (GetAutoComplete() != NULL) auto autoComplete = GetAutoComplete();
if (autoComplete != NULL)
{
SetAndRestoreValue<bool> prevForceAllowNonStatic(autoComplete->mForceAllowNonStatic, methodInstance->mMethodDef->mHasExplicitThis);
GetAutoComplete()->CheckNode(delegateBindExpr->mTarget); GetAutoComplete()->CheckNode(delegateBindExpr->mTarget);
}
if ((!delegateBindExpr->mTarget->IsA<BfIdentifierNode>()) && if ((!delegateBindExpr->mTarget->IsA<BfIdentifierNode>()) &&
(!delegateBindExpr->mTarget->IsA<BfMemberReferenceExpression>())) (!delegateBindExpr->mTarget->IsA<BfMemberReferenceExpression>()))
@ -19533,13 +19628,14 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
} }
else else
{ {
auto convertedValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox); auto convertedValue = mModule->Cast(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox);
if (!convertedValue) if (!convertedValue)
return; return;
convertedValue = mModule->LoadValue(convertedValue);
if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality)) 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 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; return;

View file

@ -169,7 +169,7 @@ public:
Array<BfAmbiguousEntry> mAmbiguousEntries; Array<BfAmbiguousEntry> mAmbiguousEntries;
public: 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); bool InferFromGenericConstraints(BfGenericParamInstance* genericParamInst, BfTypeVector* methodGenericArgs);
void CompareMethods(BfMethodInstance* prevMethodInstance, BfTypeVector* prevGenericArgumentsSubstitute, void CompareMethods(BfMethodInstance* prevMethodInstance, BfTypeVector* prevGenericArgumentsSubstitute,
BfMethodInstance* newMethodInstance, BfTypeVector* genericArgumentsSubstitute, BfMethodInstance* newMethodInstance, BfTypeVector* genericArgumentsSubstitute,
@ -401,7 +401,7 @@ public:
void SetMethodElementType(BfAstNode* target); void SetMethodElementType(BfAstNode* target);
BfTypedValue DoImplicitArgCapture(BfAstNode* refNode, BfIdentifierNode* identifierNode, int shadowIdx); 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()); 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); bool IsExactMethodMatch(BfMethodInstance* methodA, BfMethodInstance* methodB, bool ignoreImplicitParams = false);
BfTypeInstance* VerifyBaseDelegateType(BfTypeInstance* delegateType); BfTypeInstance* VerifyBaseDelegateType(BfTypeInstance* delegateType);
void ConstResolve(BfExpression* expr); void ConstResolve(BfExpression* expr);

View file

@ -312,13 +312,8 @@ void BfGNUMangler::MangleTypeInst(MangleContext& mangleContext, StringImpl& name
name += "N8functionI"; name += "N8functionI";
SizedArray<BfType*, 8> typeVec; SizedArray<BfType*, 8> typeVec;
typeVec.push_back(BfNodeDynCast<BfDirectTypeReference>(methodDef->mReturnTypeRef)->mType); typeVec.push_back(BfNodeDynCast<BfDirectTypeReference>(methodDef->mReturnTypeRef)->mType);
if (delegateInfo->mFunctionThisType != NULL) if (methodDef->mIsMutating)
{ name += "_mut_";
name += "_";
name += "this";
typeVec.push_back(delegateInfo->mFunctionThisType);
}
for (int paramIdx = 0; paramIdx < (int)methodDef->mParams.size(); paramIdx++) for (int paramIdx = 0; paramIdx < (int)methodDef->mParams.size(); paramIdx++)
{ {
name += "_"; name += "_";
@ -1175,18 +1170,11 @@ bool BfMSMangler::FindOrCreateNameSub(MangleContext& mangleContext, StringImpl&
name += "?$delegate"; name += "?$delegate";
else else
name += "?$function"; name += "?$function";
if (methodDef->mIsMutating)
name += "_mut_";
SizedArray<BfType*, 8> typeVec; SizedArray<BfType*, 8> typeVec;
typeVec.push_back(BfNodeDynCast<BfDirectTypeReference>(methodDef->mReturnTypeRef)->mType); typeVec.push_back(BfNodeDynCast<BfDirectTypeReference>(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++) for (int paramIdx = 0; paramIdx < (int)methodDef->mParams.size(); paramIdx++)
{ {
name += "_"; name += "_";

View file

@ -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) BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPersistent)
{ {
BP_ZONE("BfModule::Fail"); BP_ZONE("BfModule::Fail");
@ -3074,7 +3083,14 @@ void BfModule::AddDependency(BfType* usedType, BfType* userType, BfDependencyMap
return; return;
if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsAutocompleteMethod)) if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsAutocompleteMethod))
{
if (userType->IsMethodRef())
{
// We cannot short-circuit dependencies because of method group ref counting
}
else
return; return;
}
if (usedType->IsSpecializedByAutoCompleteMethod()) if (usedType->IsSpecializedByAutoCompleteMethod())
return; return;
@ -14790,7 +14806,7 @@ BfIRCallingConv BfModule::GetIRCallingConvention(BfMethodInstance* methodInstanc
auto methodDef = methodInstance->mMethodDef; auto methodDef = methodInstance->mMethodDef;
BfTypeInstance* owner = NULL; BfTypeInstance* owner = NULL;
if (!methodDef->mIsStatic) if (!methodDef->mIsStatic)
owner = methodInstance->GetParamType(-1)->ToTypeInstance(); owner = methodInstance->GetThisType()->ToTypeInstance();
if (owner == NULL) if (owner == NULL)
owner = methodInstance->GetOwner(); owner = methodInstance->GetOwner();
@ -14842,10 +14858,8 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func
int argIdx = 0; int argIdx = 0;
int paramIdx = 0; int paramIdx = 0;
if (methodInstance->HasThis()) if ((methodInstance->HasThis()) && (!methodDef->mHasExplicitThis))
{
paramIdx = -1; paramIdx = -1;
}
int argCount = methodInstance->GetIRFunctionParamCount(this); int argCount = methodInstance->GetIRFunctionParamCount(this);
@ -14859,7 +14873,8 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func
continue; continue;
} }
while ((paramIdx != -1) && (methodInstance->IsParamSkipped(paramIdx))) bool isThis = (paramIdx == -1) || ((methodDef->mHasExplicitThis) && (paramIdx == 0));
while ((!isThis) && (methodInstance->IsParamSkipped(paramIdx)))
paramIdx++; paramIdx++;
BfType* resolvedTypeRef = NULL; BfType* resolvedTypeRef = NULL;
@ -14867,14 +14882,13 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func
String paramName; String paramName;
bool isSplattable = false; bool isSplattable = false;
bool tryLowering = true; bool tryLowering = true;
bool isThis = paramIdx == -1;
if (isThis) if (isThis)
{ {
paramName = "this"; paramName = "this";
if (methodInstance->mIsClosure) if (methodInstance->mIsClosure)
resolvedTypeRef = mCurMethodState->mClosureState->mClosureType; resolvedTypeRef = mCurMethodState->mClosureState->mClosureType;
else else
resolvedTypeRef = methodInstance->GetOwner(); resolvedTypeRef = methodInstance->GetThisType();
isSplattable = (resolvedTypeRef->IsSplattable()) && (methodInstance->AllowsThisSplatting()); isSplattable = (resolvedTypeRef->IsSplattable()) && (methodInstance->AllowsThisSplatting());
tryLowering = methodInstance->AllowsThisSplatting(); tryLowering = methodInstance->AllowsThisSplatting();
} }
@ -14933,7 +14947,7 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func
} }
if ((resolvedTypeRef->IsComposite()) && (!resolvedTypeRef->IsTypedPrimitive())) if ((resolvedTypeRef->IsComposite()) && (!resolvedTypeRef->IsTypedPrimitive()))
{ {
if (paramIdx == -1) if (isThis)
{ {
mBfIRBuilder->Func_AddAttribute(func, argIdx + 1, BfIRAttribute_NoCapture); mBfIRBuilder->Func_AddAttribute(func, argIdx + 1, BfIRAttribute_NoCapture);
PopulateType(resolvedTypeRef, BfPopulateType_Data); PopulateType(resolvedTypeRef, BfPopulateType_Data);
@ -16965,6 +16979,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
} }
if (methodInstance->mIsIntrinsic) if (methodInstance->mIsIntrinsic)
return; return;
if (mCurTypeInstance->IsFunction())
return;
auto prevActiveFunction = mBfIRBuilder->GetActiveFunction(); auto prevActiveFunction = mBfIRBuilder->GetActiveFunction();
mBfIRBuilder->SetActiveFunction(mCurMethodInstance->mIRFunction); mBfIRBuilder->SetActiveFunction(mCurMethodInstance->mIRFunction);
@ -20319,6 +20335,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
methodInstance->mMethodDef->mParams.Reserve((int)methodDef->mParams.size()); methodInstance->mMethodDef->mParams.Reserve((int)methodDef->mParams.size());
bool hadDelegateParams = false; bool hadDelegateParams = false;
bool hadParams = false; bool hadParams = false;
for (int paramIdx = 0; paramIdx < (int)methodDef->mParams.size() + implicitParamCount; paramIdx++) for (int paramIdx = 0; paramIdx < (int)methodDef->mParams.size() + implicitParamCount; paramIdx++)
@ -20380,8 +20397,12 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
bool wasGenericParam = false; bool wasGenericParam = false;
if (resolvedParamType == NULL) if (resolvedParamType == NULL)
{ {
resolvedParamType = ResolveTypeRef(paramDef->mTypeRef, BfPopulateType_Declaration, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowRef | BfResolveTypeRefFlag_AllowRefGeneric | BfResolveTypeRefFlag_AllowGenericMethodParamConstValue);
(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) if (resolvedParamType == NULL)
{ {
@ -20616,11 +20637,12 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
int argIdx = 0; int argIdx = 0;
PopulateType(methodInstance->mReturnType, BfPopulateType_Data); PopulateType(methodInstance->mReturnType, BfPopulateType_Data);
if (!methodDef->mIsStatic) if ((!methodDef->mIsStatic) && (!methodDef->mHasExplicitThis))
{ {
int thisIdx = methodDef->mHasExplicitThis ? 0 : -1;
auto thisType = methodInstance->GetOwner(); auto thisType = methodInstance->GetOwner();
if (methodInstance->GetParamIsSplat(-1)) if (methodInstance->GetParamIsSplat(thisIdx))
argIdx += methodInstance->GetParamType(-1)->GetSplatCount(); argIdx += methodInstance->GetParamType(thisIdx)->GetSplatCount();
else if (!thisType->IsValuelessType()) else if (!thisType->IsValuelessType())
{ {
BfTypeCode loweredTypeCode = BfTypeCode_None; BfTypeCode loweredTypeCode = BfTypeCode_None;
@ -20636,25 +20658,44 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
if (methodInstance->GetStructRetIdx() != -1) if (methodInstance->GetStructRetIdx() != -1)
argIdx++; 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; methodParam.mIsSplat = true;
} }
else if ((methodParam.mResolvedType->IsComposite()) && (methodInstance->AllowsSplatting())) else if ((checkType->IsComposite()) && (methodInstance->AllowsSplatting()))
{ {
PopulateType(methodParam.mResolvedType, BfPopulateType_Data); PopulateType(checkType, BfPopulateType_Data);
if (methodParam.mResolvedType->IsSplattable()) if (checkType->IsSplattable())
{ {
int splatCount = methodParam.mResolvedType->GetSplatCount(); int splatCount = checkType->GetSplatCount();
if (argIdx + splatCount <= mCompiler->mOptions.mMaxSplatRegs) if (checkArgIdx + splatCount <= mCompiler->mOptions.mMaxSplatRegs)
{ {
methodParam.mIsSplat = true; methodParam.mIsSplat = true;
argIdx += splatCount; argIdx += splatCount;
continue; 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++; argIdx++;

View file

@ -1420,6 +1420,7 @@ public:
void GetAccessAllowed(BfTypeInstance* checkType, bool& allowProtected, bool& allowPrivate); void GetAccessAllowed(BfTypeInstance* checkType, bool& allowProtected, bool& allowPrivate);
bool CheckProtection(BfProtectionCheckFlags& flags, BfTypeInstance* memberOwner, BfProject* memberProject, BfProtection memberProtection, BfTypeInstance* lookupStartType); bool CheckProtection(BfProtectionCheckFlags& flags, BfTypeInstance* memberOwner, BfProject* memberProject, BfProtection memberProtection, BfTypeInstance* lookupStartType);
void SetElementType(BfAstNode* astNode, BfSourceElementType elementType); void SetElementType(BfAstNode* astNode, BfSourceElementType elementType);
void SetFail();
BfError* Fail(const StringImpl& error, BfAstNode* refNode = NULL, bool isPersistent = false); BfError* Fail(const StringImpl& error, BfAstNode* refNode = NULL, bool isPersistent = false);
BfError* FailInternal(const StringImpl& error, BfAstNode* refNode = NULL); BfError* FailInternal(const StringImpl& error, BfAstNode* refNode = NULL);
BfError* FailAfter(const StringImpl& error, BfAstNode* refNode); BfError* FailAfter(const StringImpl& error, BfAstNode* refNode);

View file

@ -6331,6 +6331,7 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty
bool hasTypeGenerics = false; bool hasTypeGenerics = false;
auto returnType = ResolveGenericType(unspecializedDelegateInfo->mReturnType, typeGenericArguments, methodGenericArguments, allowFail); auto returnType = ResolveGenericType(unspecializedDelegateInfo->mReturnType, typeGenericArguments, methodGenericArguments, allowFail);
if (returnType == NULL) if (returnType == NULL)
return NULL; return NULL;
if (returnType->IsVar()) if (returnType->IsVar())
@ -6338,6 +6339,7 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty
_CheckType(returnType); _CheckType(returnType);
if (returnType->IsGenericParam()) if (returnType->IsGenericParam())
hasTypeGenerics |= ((BfGenericParamType*)returnType)->mGenericParamKind == BfGenericParamKind_Type; hasTypeGenerics |= ((BfGenericParamType*)returnType)->mGenericParamKind == BfGenericParamKind_Type;
Array<BfType*> paramTypes; Array<BfType*> paramTypes;
for (auto param : unspecializedDelegateInfo->mParams) for (auto param : unspecializedDelegateInfo->mParams)
{ {
@ -6420,12 +6422,15 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty
typeDef->mIsDelegate = unspecializedDelegateType->mTypeDef->mIsDelegate; typeDef->mIsDelegate = unspecializedDelegateType->mTypeDef->mIsDelegate;
typeDef->mIsFunction = unspecializedDelegateType->mTypeDef->mIsFunction; typeDef->mIsFunction = unspecializedDelegateType->mTypeDef->mIsFunction;
BfMethodDef* unspecializedInvokeMethodDef = unspecializedDelegateType->mTypeDef->GetMethodByName("Invoke");
BfMethodDef* methodDef = new BfMethodDef(); BfMethodDef* methodDef = new BfMethodDef();
methodDef->mDeclaringType = typeDef; methodDef->mDeclaringType = typeDef;
methodDef->mName = "Invoke"; methodDef->mName = "Invoke";
methodDef->mProtection = BfProtection_Public; methodDef->mProtection = BfProtection_Public;
methodDef->mIdx = 0; methodDef->mIdx = 0;
methodDef->mIsStatic = !typeDef->mIsDelegate; methodDef->mIsStatic = !typeDef->mIsDelegate && !unspecializedDelegateInfo->mHasExplicitThis;
methodDef->mHasExplicitThis = unspecializedDelegateInfo->mHasExplicitThis;
auto directTypeRef = BfAstNode::ZeroedAlloc<BfDirectTypeReference>(); auto directTypeRef = BfAstNode::ZeroedAlloc<BfDirectTypeReference>();
delegateInfo->mDirectAllocNodes.push_back(directTypeRef); delegateInfo->mDirectAllocNodes.push_back(directTypeRef);
@ -6440,8 +6445,7 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty
directTypeRef->Init(returnType); directTypeRef->Init(returnType);
methodDef->mReturnTypeRef = directTypeRef; methodDef->mReturnTypeRef = directTypeRef;
delegateInfo->mReturnType = returnType; delegateInfo->mReturnType = returnType;
delegateInfo->mHasExplicitThis = unspecializedDelegateInfo->mHasExplicitThis;
BfMethodDef* unspecializedInvokeMethodDef = unspecializedDelegateType->mTypeDef->GetMethodByName("Invoke");
int paramIdx = 0; int paramIdx = 0;
for (int paramIdx = 0; paramIdx < (int)paramTypes.size(); paramIdx++) 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); 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) if (typeDef->mIsDelegate)
{
BfDefBuilder::AddMethod(typeDef, BfMethodType_Ctor, BfProtection_Public, false, "");
BfDefBuilder::AddDynamicCastMethods(typeDef); BfDefBuilder::AddDynamicCastMethods(typeDef);
}
delegateType->mContext = mContext; delegateType->mContext = mContext;
delegateType->mTypeDef = typeDef; delegateType->mTypeDef = typeDef;
@ -6904,8 +6917,8 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy
else if (resolvedTypeRef->IsDelegateFromTypeRef() || resolvedTypeRef->IsFunctionFromTypeRef()) else if (resolvedTypeRef->IsDelegateFromTypeRef() || resolvedTypeRef->IsFunctionFromTypeRef())
{ {
auto delegateInfo = resolvedTypeRef->GetDelegateInfo(); auto delegateInfo = resolvedTypeRef->GetDelegateInfo();
if (delegateInfo->mFunctionThisType != NULL) // if (delegateInfo->mFunctionThisType != NULL)
AddDependency(delegateInfo->mFunctionThisType, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference); // AddDependency(delegateInfo->mFunctionThisType, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference);
AddDependency(delegateInfo->mReturnType, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference); AddDependency(delegateInfo->mReturnType, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference);
for (auto& param : delegateInfo->mParams) for (auto& param : delegateInfo->mParams)
AddDependency(param, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference); AddDependency(param, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference);
@ -8905,6 +8918,8 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
hasMutSpecifier = true; hasMutSpecifier = true;
functionThisType = refType->mElementType; functionThisType = refType->mElementType;
} }
paramTypes.Add(functionThisType);
_CheckType(functionThisType);
} }
else else
{ {
@ -8981,10 +8996,13 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
methodDef->mProtection = BfProtection_Public; methodDef->mProtection = BfProtection_Public;
methodDef->mIdx = 0; methodDef->mIdx = 0;
methodDef->mIsStatic = !typeDef->mIsDelegate && (functionThisType == NULL); methodDef->mIsStatic = !typeDef->mIsDelegate && (functionThisType == NULL);
methodDef->mIsMutating = true; methodDef->mHasExplicitThis = functionThisType != NULL;
if ((functionThisType != NULL) && (functionThisType->IsValueType()) && (!hasMutSpecifier)) if ((functionThisType != NULL) && (hasMutSpecifier))
methodDef->mIsMutating = false; {
if ((functionThisType->IsValueType()) || (functionThisType->IsGenericParam()))
methodDef->mIsMutating = true;
}
auto directTypeRef = BfAstNode::ZeroedAlloc<BfDirectTypeReference>(); auto directTypeRef = BfAstNode::ZeroedAlloc<BfDirectTypeReference>();
delegateInfo->mDirectAllocNodes.push_back(directTypeRef); delegateInfo->mDirectAllocNodes.push_back(directTypeRef);
@ -8999,11 +9017,12 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
directTypeRef->Init(returnType); directTypeRef->Init(returnType);
methodDef->mReturnTypeRef = directTypeRef; methodDef->mReturnTypeRef = directTypeRef;
delegateInfo->mReturnType = returnType; delegateInfo->mReturnType = returnType;
delegateInfo->mFunctionThisType = functionThisType; delegateInfo->mHasExplicitThis = functionThisType != NULL;
auto hashVal = mContext->mResolvedTypes.Hash(typeRef, &lookupCtx); 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++) for (int paramIdx = 0; paramIdx < (int)paramTypes.size(); paramIdx++)
{ {
auto param = delegateTypeRef->mParams[paramIdx + paramSrcOfs]; auto param = delegateTypeRef->mParams[paramIdx + paramSrcOfs];
@ -9026,6 +9045,8 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
paramDef->mTypeRef = directTypeRef; paramDef->mTypeRef = directTypeRef;
paramDef->mName = paramName; paramDef->mName = paramName;
if ((paramIdx == 0) && (functionThisType != NULL))
paramDef->mParamKind = BfParamKind_ExplicitThis;
methodDef->mParams.push_back(paramDef); methodDef->mParams.push_back(paramDef);
delegateInfo->mParams.Add(paramType); delegateInfo->mParams.Add(paramType);
@ -9042,9 +9063,11 @@ 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); BfDefBuilder::AddDynamicCastMethods(typeDef);
}
delegateType->mContext = mContext; delegateType->mContext = mContext;
delegateType->mTypeDef = typeDef; delegateType->mTypeDef = typeDef;
@ -9052,8 +9075,8 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
resolvedEntry->mValue = delegateType; resolvedEntry->mValue = delegateType;
AddDependency(directTypeRef->mType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue); AddDependency(directTypeRef->mType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue);
if (delegateInfo->mFunctionThisType != NULL) // if (delegateInfo->mFunctionThisType != NULL)
AddDependency(delegateInfo->mFunctionThisType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue); // AddDependency(delegateInfo->mFunctionThisType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue);
for (auto paramType : paramTypes) for (auto paramType : paramTypes)
AddDependency(paramType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue); AddDependency(paramType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue);
@ -9377,13 +9400,12 @@ BfIRValue BfModule::CastToFunction(BfAstNode* srcNode, BfMethodInstance* methodI
else if (invokeMethodInstance->IsExactMatch(methodInstance, false, false)) else if (invokeMethodInstance->IsExactMatch(methodInstance, false, false))
{ {
bool handled = false; bool handled = false;
if (methodInstance->HasThis())
auto thisType = methodInstance->GetParamType(-1);
if (thisType != NULL)
{ {
auto thisType = methodInstance->GetThisType();
if (invokeMethodInstance->HasExplicitThis()) if (invokeMethodInstance->HasExplicitThis())
{ {
auto invokeThisType = invokeMethodInstance->GetParamType(-1); auto invokeThisType = invokeMethodInstance->GetThisType();
bool thisWasPtr = false; bool thisWasPtr = false;
if (thisType->IsPointer()) if (thisType->IsPointer())
@ -9416,6 +9438,7 @@ BfIRValue BfModule::CastToFunction(BfAstNode* srcNode, BfMethodInstance* methodI
if ((!methodInstance->mMethodDef->mIsStatic) && (!invokeMethodInstance->HasExplicitThis())) if ((!methodInstance->mMethodDef->mIsStatic) && (!invokeMethodInstance->HasExplicitThis()))
{ {
handled = true; 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); 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);
} }
@ -9433,6 +9456,7 @@ BfIRValue BfModule::CastToFunction(BfAstNode* srcNode, BfMethodInstance* methodI
BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags, BfCastResultFlags* resultFlags) 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 explicitCast = (castFlags & BfCastFlags_Explicit) != 0;
bool ignoreErrors = mIgnoreErrors || ((castFlags & BfCastFlags_SilentFail) != 0); bool ignoreErrors = mIgnoreErrors || ((castFlags & BfCastFlags_SilentFail) != 0);
bool ignoreWrites = mBfIRBuilder->mIgnoreWrites; bool ignoreWrites = mBfIRBuilder->mIgnoreWrites;
@ -9547,9 +9571,12 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
// void* -> intptr // void* -> intptr
if ((typedVal.mType->IsPointer()) && (toType->IsIntPtr())) if ((typedVal.mType->IsPointer()) && (toType->IsIntPtr()))
{ {
if ((!ignoreErrors) && (!typedVal.mType->GetUnderlyingType()->IsVoid()) && ((castFlags & BfCastFlags_FromCompiler) == 0)) 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); 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; auto toPrimitive = (BfPrimitiveType*)toType;
@ -9559,9 +9586,12 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
// intptr -> void* // intptr -> void*
if ((typedVal.mType->IsIntPtr()) && (toType->IsPointer())) if ((typedVal.mType->IsIntPtr()) && (toType->IsPointer()))
{ {
if ((!ignoreErrors) && (!toType->GetUnderlyingType()->IsVoid()) && ((castFlags & BfCastFlags_FromCompiler) == 0)) if ((!toType->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); 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)); return mBfIRBuilder->CreateIntToPtr(typedVal.mValue, mBfIRBuilder->MapType(toType));
@ -10093,6 +10123,8 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
VariantToString(valStr, variantVal); 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); 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,9 +10585,14 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
{ {
if (mayBeBox) if (mayBeBox)
{ {
if ((!ignoreErrors) && (Fail("Ambiguous cast, may be conversion operator or may be boxing request", srcNode) != NULL)) 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()); mCompiler->mPassInstance->MoreInfo("See conversion operator", opMethodInstance->mMethodDef->GetRefNode());
} }
else if (!silentFail)
SetFail();
}
BfMethodInstance* methodInstance = GetRawMethodInstance(opMethodInstance->GetOwner(), opMethodInstance->mMethodDef); 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'"; 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); Fail(StrFormat(errStr, TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode);
} }
else if (!silentFail)
SetFail();
return BfIRValue(); return BfIRValue();
} }
@ -10816,6 +10855,8 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
} }
} }
} }
else if (!silentFail)
SetFail();
return BfIRValue(); return BfIRValue();
} }
@ -10986,6 +11027,7 @@ BfTypedValue BfModule::Cast(BfAstNode* srcNode, const BfTypedValue& typedVal, Bf
if ((fromMethodInst != NULL) && (toMethodInst != NULL) && if ((fromMethodInst != NULL) && (toMethodInst != NULL) &&
(fromMethodInst->mMethodDef->mCallingConvention == toMethodInst->mMethodDef->mCallingConvention) && (fromMethodInst->mMethodDef->mCallingConvention == toMethodInst->mMethodDef->mCallingConvention) &&
(fromMethodInst->mMethodDef->mIsMutating == toMethodInst->mMethodDef->mIsMutating) &&
(fromMethodInst->mReturnType == toMethodInst->mReturnType) && (fromMethodInst->mReturnType == toMethodInst->mReturnType) &&
(fromMethodInst->GetParamCount() == toMethodInst->GetParamCount())) (fromMethodInst->GetParamCount() == toMethodInst->GetParamCount()))
{ {
@ -11000,7 +11042,7 @@ BfTypedValue BfModule::Cast(BfAstNode* srcNode, const BfTypedValue& typedVal, Bf
} }
else 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; bool nameMatches = true;
@ -11550,16 +11592,7 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF
DoTypeToString(str, delegateInfo->mReturnType, typeNameFlags, genericMethodNameOverrides); DoTypeToString(str, delegateInfo->mReturnType, typeNameFlags, genericMethodNameOverrides);
str += "("; str += "(";
bool isFirstParam = true; 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;
}
for (int paramIdx = 0; paramIdx < methodDef->mParams.size(); paramIdx++) for (int paramIdx = 0; paramIdx < methodDef->mParams.size(); paramIdx++)
{ {
if (!isFirstParam) if (!isFirstParam)
@ -11567,7 +11600,14 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF
auto paramDef = methodDef->mParams[paramIdx]; auto paramDef = methodDef->mParams[paramIdx];
BfTypeNameFlags innerFlags = (BfTypeNameFlags)(typeNameFlags & ~(BfTypeNameFlag_OmitNamespace | BfTypeNameFlag_OmitOuterType)); 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()) if (!paramDef->mName.IsEmpty())
{ {

View file

@ -768,6 +768,29 @@ bool BfMethodInstance::HasThis()
return (!mMethodInstanceGroup->mOwner->IsValuelessType()); 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() bool BfMethodInstance::HasExplicitThis()
{ {
if (mMethodDef->mIsStatic) if (mMethodDef->mIsStatic)
@ -834,10 +857,11 @@ BfType* BfMethodInstance::GetParamType(int paramIdx, bool useResolvedType)
return mMethodInfoEx->mClosureInstanceInfo->mThisOverride; return mMethodInfoEx->mClosureInstanceInfo->mThisOverride;
BF_ASSERT(!mMethodDef->mIsStatic); BF_ASSERT(!mMethodDef->mIsStatic);
auto owner = mMethodInstanceGroup->mOwner; auto owner = mMethodInstanceGroup->mOwner;
auto delegateInfo = owner->GetDelegateInfo();
BfType* thisType = owner; BfType* thisType = owner;
if ((delegateInfo != NULL) && (delegateInfo->mFunctionThisType != NULL)) if (owner->IsFunction())
thisType = delegateInfo->mFunctionThisType; {
BF_FATAL("Wrong 'this' index");
}
if ((thisType->IsValueType()) && ((mMethodDef->mIsMutating) || (!AllowsSplatting())) && (!thisType->GetLoweredType(BfTypeUsage_Parameter))) if ((thisType->IsValueType()) && ((mMethodDef->mIsMutating) || (!AllowsSplatting())) && (!thisType->GetLoweredType(BfTypeUsage_Parameter)))
return owner->mModule->CreatePointerType(thisType); return owner->mModule->CreatePointerType(thisType);
return thisType; return thisType;
@ -1034,6 +1058,8 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType,
returnType = module->mBfIRBuilder->MapType(mReturnType); returnType = module->mBfIRBuilder->MapType(mReturnType);
} }
for (int paramIdx = -1; paramIdx < GetParamCount(); paramIdx++) for (int paramIdx = -1; paramIdx < GetParamCount(); paramIdx++)
{ {
BfType* checkType = NULL; BfType* checkType = NULL;
@ -1048,7 +1074,7 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType,
else else
{ {
if (HasExplicitThis()) if (HasExplicitThis())
checkType = GetParamType(-1); checkType = GetParamType(0);
else else
checkType = GetOwner(); checkType = GetOwner();
} }
@ -1102,14 +1128,14 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType,
} }
} }
if ((paramIdx == 0) && (GetParamName(0) == "this") && (checkType->IsPointer())) // if ((paramIdx == 0) && (GetParamName(0) == "this") && (checkType->IsPointer()))
{ // {
// We don't actually pass a this pointer for mut methods in valueless structs // // We don't actually pass a this pointer for mut methods in valueless structs
auto underlyingType = checkType->GetUnderlyingType(); // auto underlyingType = checkType->GetUnderlyingType();
module->PopulateType(underlyingType, BfPopulateType_Data); // module->PopulateType(underlyingType, BfPopulateType_Data);
if (underlyingType->IsValuelessType()) // if (underlyingType->IsValuelessType())
continue; // continue;
} // }
if (checkType->CanBeValuelessType()) if (checkType->CanBeValuelessType())
module->PopulateType(checkType, BfPopulateType_Data); module->PopulateType(checkType, BfPopulateType_Data);
@ -1159,6 +1185,9 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType,
if (checkType2 != NULL) if (checkType2 != NULL)
_AddType(checkType2); _AddType(checkType2);
if ((paramIdx == -1) && (mMethodDef->mHasExplicitThis))
paramIdx++; // Skip over the explicit 'this'
} }
if (GetStructRetIdx(forceStatic) == 1) if (GetStructRetIdx(forceStatic) == 1)
@ -1227,13 +1256,18 @@ bool BfMethodInstance::IsExactMatch(BfMethodInstance* other, bool ignoreImplicit
if (!mMethodDef->mIsStatic) if (!mMethodDef->mIsStatic)
{ {
if (GetParamType(-1) != other->GetParamType(-1)) if (GetThisType() != other->GetThisType())
{ {
return false; return false;
} }
} }
} }
if (mMethodDef->mHasExplicitThis)
implicitParamCountA++;
if (other->mMethodDef->mHasExplicitThis)
implicitParamCountB++;
if (GetParamCount() - implicitParamCountA != other->GetParamCount() - implicitParamCountB) if (GetParamCount() - implicitParamCountA != other->GetParamCount() - implicitParamCountB)
return false; return false;
for (int i = 0; i < (int)GetParamCount() - implicitParamCountA; i++) 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(methodDef->mName == "Invoke");
BF_ASSERT(delegateInfo->mParams.size() == methodDef->mParams.size()); 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++) for (int paramIdx = 0; paramIdx < delegateInfo->mParams.size(); paramIdx++)
{ {
// Parse attributes? // Parse attributes?
@ -3300,6 +3326,10 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx)
auto lhsMethodDef = lhsInst->mTypeDef->mMethods[0]; auto lhsMethodDef = lhsInst->mTypeDef->mMethods[0];
auto rhsMethodDef = rhsInst->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) if (lhsDelegateInfo->mReturnType != rhsDelegateInfo->mReturnType)
return false; return false;
if (lhsDelegateInfo->mParams.size() != rhsDelegateInfo->mParams.size()) if (lhsDelegateInfo->mParams.size() != rhsDelegateInfo->mParams.size())
@ -3701,44 +3731,42 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfTypeReference* rhs, LookupContext*
auto param0 = rhsDelegateType->mParams[0]; auto param0 = rhsDelegateType->mParams[0];
if ((param0->mNameNode != NULL) && (param0->mNameNode->Equals("this"))) if ((param0->mNameNode != NULL) && (param0->mNameNode->Equals("this")))
{ {
if (!lhsDelegateInfo->mHasExplicitThis)
return false;
bool handled = 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)); auto rhsThisType = ctx->mModule->ResolveTypeRef(param0->mTypeRef, BfPopulateType_Identity, (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoWarnOnMut | BfResolveTypeRefFlag_AllowRef));
bool wantsMutating = false;
if (rhsThisType->IsRef()) if (rhsThisType->IsRef())
{ {
if (lhsThisType != rhsThisType->GetUnderlyingType()) if (lhsThisType != rhsThisType->GetUnderlyingType())
return false; return false;
if (!invokeMethodDef->mIsMutating) wantsMutating = (lhsThisType->IsValueType()) || (lhsThisType->IsGenericParam());
return false;
} }
else else
{ {
if (lhsThisType != rhsThisType) if (lhsThisType != rhsThisType)
return false; return false;
if ((invokeMethodDef->mIsMutating) && (lhsThisType->IsValueType()))
return false;
} }
if (invokeMethodDef->mIsMutating != wantsMutating)
return false;
paramRefOfs = 1; paramRefOfs = 1;
} }
} }
if (!rhsIsDelegate) if (lhsDelegateInfo->mParams.size() != (int)rhsDelegateType->mParams.size())
{
if ((lhsDelegateInfo->mFunctionThisType == NULL) != (paramRefOfs == 0))
return false; return false;
} for (int paramIdx = paramRefOfs; paramIdx < lhsDelegateInfo->mParams.size(); paramIdx++)
if (lhsDelegateInfo->mParams.size() != (int)rhsDelegateType->mParams.size() - paramRefOfs)
return false;
for (int paramIdx = 0; 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; return false;
StringView rhsParamName; StringView rhsParamName;
if (rhsDelegateType->mParams[paramIdx + paramRefOfs]->mNameNode != NULL) if (rhsDelegateType->mParams[paramIdx]->mNameNode != NULL)
rhsParamName = rhsDelegateType->mParams[paramIdx + paramRefOfs]->mNameNode->ToStringView(); rhsParamName = rhsDelegateType->mParams[paramIdx]->mNameNode->ToStringView();
if (invokeMethodDef->mParams[paramIdx]->mName != rhsParamName) if (invokeMethodDef->mParams[paramIdx]->mName != rhsParamName)
return false; return false;
} }

View file

@ -417,14 +417,14 @@ class BfDelegateInfo
public: public:
Array<BfAstNode*> mDirectAllocNodes; Array<BfAstNode*> mDirectAllocNodes;
BfType* mReturnType; BfType* mReturnType;
BfType* mFunctionThisType;
Array<BfType*> mParams; Array<BfType*> mParams;
bool mHasExplicitThis;
public: public:
BfDelegateInfo() BfDelegateInfo()
{ {
mReturnType = NULL; mReturnType = NULL;
mFunctionThisType = NULL; mHasExplicitThis = false;
} }
~BfDelegateInfo() ~BfDelegateInfo()
@ -870,6 +870,8 @@ public:
bool IsSpecializedByAutoCompleteMethod(); bool IsSpecializedByAutoCompleteMethod();
bool HasExternConstraints(); bool HasExternConstraints();
bool HasThis(); bool HasThis();
BfType* GetThisType();
int GetThisIdx();
bool HasExplicitThis(); bool HasExplicitThis();
bool HasParamsArray(); bool HasParamsArray();
int GetStructRetIdx(bool forceStatic = false); int GetStructRetIdx(bool forceStatic = false);

View file

@ -459,6 +459,7 @@ struct BfCodeGenOptions
enum BfParamKind : uint8 enum BfParamKind : uint8
{ {
BfParamKind_Normal, BfParamKind_Normal,
BfParamKind_ExplicitThis,
BfParamKind_Params, BfParamKind_Params,
BfParamKind_DelegateParam, BfParamKind_DelegateParam,
BfParamKind_ImplicitCapture, BfParamKind_ImplicitCapture,
@ -725,6 +726,7 @@ public:
bool mIsOperator; bool mIsOperator;
bool mIsExtern; bool mIsExtern;
bool mIsNoDiscard; bool mIsNoDiscard;
bool mHasExplicitThis;
BfCommutableKind mCommutableKind; BfCommutableKind mCommutableKind;
BfCheckedKind mCheckedKind; BfCheckedKind mCheckedKind;
BfImportKind mImportKind; BfImportKind mImportKind;
@ -751,6 +753,7 @@ public:
mIsOperator = false; mIsOperator = false;
mIsExtern = false; mIsExtern = false;
mIsNoDiscard = false; mIsNoDiscard = false;
mHasExplicitThis = false;
mBody = NULL; mBody = NULL;
mExplicitInterface = NULL; mExplicitInterface = NULL;
mReturnTypeRef = NULL; mReturnTypeRef = NULL;

View file

@ -26,6 +26,17 @@ namespace Tests
int mA = 123; int mA = 123;
int mB = 234; int mB = 234;
public this()
{
}
public this(int a, int b)
{
mA = a;
mB = b;
}
public int GetA(float f) public int GetA(float f)
{ {
return mA + mB*100 + (int)f; return mA + mB*100 + (int)f;
@ -35,6 +46,98 @@ namespace Tests
{ {
return mA + mB*100 + (int)f; 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<T>(function int (T this, float f) func, T a, float b)
{
return func(a, b);
}
public static int UseFunc1<T>(function int (mut T this, float f) func, mut T a, float b)
{
return func(a, b);
} }
[Test] [Test]
@ -42,6 +145,7 @@ namespace Tests
{ {
ClassA ca = scope .(); ClassA ca = scope .();
StructA sa = .(); StructA sa = .();
StructB sb = .();
function int (ClassA this, float f) func0 = => ca.GetA; function int (ClassA this, float f) func0 = => ca.GetA;
function int (ClassA this, float) func0b = func0; function int (ClassA this, float) func0b = func0;
@ -50,10 +154,34 @@ namespace Tests
Test.Assert(func0(ca, 100.0f) == 223); Test.Assert(func0(ca, 100.0f) == 223);
function int (StructA this, float f) func1 = => sa.GetA; function int (StructA this, float f) func1 = => sa.GetA;
var func1b = func1;
Test.Assert(func1(sa, 100.0f) == 23623); 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; 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
});
} }
} }
} }