1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +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;
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()))

View file

@ -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;

View file

@ -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<BfFilePosition> prevFilePos(module->mCurFilePosition);
SetAndRestoreValue<BfMethodInstance*> 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))

View file

@ -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);

View file

@ -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<BfDotTypeReference>(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<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);
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))
{

View file

@ -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<BfDelegateBindExpression>());
auto delegateBindExpr = BfNodeDynCast<BfDelegateBindExpression>(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<BfExpression*, 4> 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<bool> 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<bool> prevForceAllowNonStatic(autoComplete->mForceAllowNonStatic, methodInstance->mMethodDef->mHasExplicitThis);
GetAutoComplete()->CheckNode(delegateBindExpr->mTarget);
}
if ((!delegateBindExpr->mTarget->IsA<BfIdentifierNode>()) &&
(!delegateBindExpr->mTarget->IsA<BfMemberReferenceExpression>()))
@ -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;

View file

@ -169,7 +169,7 @@ public:
Array<BfAmbiguousEntry> 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);

View file

@ -311,14 +311,9 @@ void BfGNUMangler::MangleTypeInst(MangleContext& mangleContext, StringImpl& name
else
name += "N8functionI";
SizedArray<BfType*, 8> typeVec;
typeVec.push_back(BfNodeDynCast<BfDirectTypeReference>(methodDef->mReturnTypeRef)->mType);
if (delegateInfo->mFunctionThisType != NULL)
{
name += "_";
name += "this";
typeVec.push_back(delegateInfo->mFunctionThisType);
}
typeVec.push_back(BfNodeDynCast<BfDirectTypeReference>(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<BfType*, 8> typeVec;
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++)
{
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)
{
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++;

View file

@ -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);

View file

@ -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<BfType*> 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<BfDirectTypeReference>();
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<BfDirectTypeReference>();
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<bool> ignoreErrors(mIgnoreErrors, true);
if (CastToValue(srcNode, typedVal, toType, (BfCastFlags)(BfCastFlags_Explicit | BfCastFlags_SilentFail)))
{
{
bool doWrap = false;
if (auto unaryOpExpr = BfNodeDynCast<BfUnaryOperatorExpression>(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())
{

View file

@ -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;
}

View file

@ -416,15 +416,15 @@ class BfDelegateInfo
{
public:
Array<BfAstNode*> mDirectAllocNodes;
BfType* mReturnType;
BfType* mFunctionThisType;
BfType* mReturnType;
Array<BfType*> 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);

View file

@ -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;

View file

@ -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<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]
@ -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
});
}
}
}