1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-09 03:52:19 +02:00

Added proper support for explicit 'this' in functions

This commit is contained in:
Brian Fiete 2020-07-10 06:40:24 -07:00
parent 4a08a9702e
commit 7f726ef9ba
8 changed files with 438 additions and 142 deletions

View file

@ -7774,7 +7774,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
if ((resolvedType->IsValueType()) || (resolvedType->IsGenericParam()))
needsRefWrap = true;
if ((InDefinitionSection()) && (!resolvedType->IsGenericParam()))
if ((InDefinitionSection()) && (!resolvedType->IsGenericParam()) && ((resolveFlags & BfResolveTypeRefFlag_NoWarnOnMut) == 0))
{
if (!resolvedType->IsValueType())
Warn(0, StrFormat("Specified 'mut' has no effect on '%s' since reference types are always mutable", TypeToString(resolvedType).c_str()), refTypeRef->mRefToken);
@ -8364,7 +8364,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
return ResolveTypeResult(typeRef, refType, populateType, resolveFlags);
}
else if (auto delegateTypeRef = BfNodeDynCast<BfDelegateTypeRef>(typeRef))
{
{
bool wantGeneric = false;
bool isUnspecialized = false;
auto _CheckType = [&](BfType* type)
@ -8375,19 +8375,56 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
isUnspecialized = true;
};
bool failed = false;
auto returnType = ResolveTypeRef(delegateTypeRef->mReturnType);
if (returnType == NULL)
returnType = GetPrimitiveType(BfTypeCode_Var);
_CheckType(returnType);
BfType* functionThisType = NULL;
bool hasMutSpecifier = false;
bool isFirst = true;
bool isDelegate = delegateTypeRef->mTypeToken->GetToken() == BfToken_Delegate;
Array<BfType*> paramTypes;
for (auto param : delegateTypeRef->mParams)
{
auto paramType = ResolveTypeRef(param->mTypeRef, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowRef);
BfResolveTypeRefFlags resolveTypeFlags = BfResolveTypeRefFlag_AllowRef;
if ((param->mNameNode != NULL) && (param->mNameNode->Equals("this")))
resolveTypeFlags = (BfResolveTypeRefFlags)(resolveTypeFlags | BfResolveTypeRefFlag_NoWarnOnMut);
auto paramType = ResolveTypeRef(param->mTypeRef, BfPopulateType_Declaration, resolveTypeFlags);
if (paramType == NULL)
{
failed = true;
paramType = GetPrimitiveType(BfTypeCode_Var);
paramTypes.Add(paramType);
_CheckType(paramType);
}
if ((!isDelegate) && (isFirst) && (param->mNameNode != NULL) && (param->mNameNode->Equals("this")))
{
functionThisType = paramType;
if (functionThisType->IsRef())
{
auto refType = (BfRefType*)functionThisType;
if (refType->mRefKind != BfRefType::RefKind_Mut)
{
if (auto refTypeRef = BfNodeDynCast<BfRefTypeRef>(param->mTypeRef))
{
failed = true;
Fail("Only 'mut' is allowed here", refTypeRef->mRefToken);
}
}
hasMutSpecifier = true;
functionThisType = refType->mElementType;
}
}
else
{
paramTypes.Add(paramType);
_CheckType(paramType);
}
isFirst = false;
}
if ((mCurTypeInstance == NULL) || (!mCurTypeInstance->IsGenericTypeInstance()))
@ -8414,25 +8451,6 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
CheckUnspecializedGenericType(genericTypeInst, populateType);
// for (auto paramType : paramTypes)
// {
// if (paramType->IsUnspecializedType())
// genericTypeInst->mGenericTypeInfo->mIsUnspecialized = true;
// if (paramType->IsUnspecializedTypeVariation())
// genericTypeInst->mGenericTypeInfo->mIsUnspecializedVariation = true;
// if (paramType->IsGenericParam())
// {
// BfGenericParamType* genericParamType = new BfGenericParamType();
// if (genericParamType->mGenericParamKind == BfGenericParamKind_Method)
// {
// if (genericParamType->mGenericParamIdx >= genericTypeInst->mGenericTypeInfo->mGenericParams.size())
// genericTypeInst->mGenericTypeInfo->mIsUnspecializedVariation = true;
// }
// else
// genericTypeInst->mGenericTypeInfo->mIsUnspecializedVariation = true;
// }
// }
// We don't ever need to do an actual pass over generic delegate methods, so it's safe to set the 'unspecialized variation' flag
if (isUnspecialized)
{
@ -8468,13 +8486,17 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
typeDef->mIsFunction = true;
typeDef->mTypeCode = BfTypeCode_Struct;
}
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 && (functionThisType == NULL);
methodDef->mIsMutating = true;
if ((functionThisType != NULL) && (functionThisType->IsValueType()) && (!hasMutSpecifier))
methodDef->mIsMutating = false;
auto directTypeRef = BfAstNode::ZeroedAlloc<BfDirectTypeReference>();
delegateInfo->mDirectAllocNodes.push_back(directTypeRef);
@ -8489,12 +8511,14 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
directTypeRef->Init(returnType);
methodDef->mReturnTypeRef = directTypeRef;
delegateInfo->mReturnType = returnType;
delegateInfo->mFunctionThisType = functionThisType;
auto hashVal = mContext->mResolvedTypes.Hash(typeRef, &lookupCtx);
int paramSrcOfs = (functionThisType != NULL) ? 1 : 0;
for (int paramIdx = 0; paramIdx < (int)paramTypes.size(); paramIdx++)
{
auto param = delegateTypeRef->mParams[paramIdx];
auto param = delegateTypeRef->mParams[paramIdx + paramSrcOfs];
auto paramType = paramTypes[paramIdx];
if (paramType == NULL)
paramType = GetPrimitiveType(BfTypeCode_Var);
@ -8504,8 +8528,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
paramName = param->mNameNode->ToString();
if (!paramType->IsReified())
delegateType->mIsReified = false;
delegateType->mIsReified = false;
auto directTypeRef = BfAstNode::ZeroedAlloc<BfDirectTypeReference>();
delegateInfo->mDirectAllocNodes.push_back(directTypeRef);
@ -8522,6 +8545,13 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
typeDef->mMethods.push_back(methodDef);
if (failed)
{
delete delegateType;
mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags);
}
//
BfDefBuilder::AddMethod(typeDef, BfMethodType_Ctor, BfProtection_Public, false, "");
@ -8531,20 +8561,21 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
delegateType->mContext = mContext;
delegateType->mTypeDef = typeDef;
populateModule->InitType(delegateType, populateType);
resolvedEntry->mValue = delegateType;
resolvedEntry->mValue = delegateType;
AddDependency(directTypeRef->mType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue);
for (auto paramType : paramTypes)
AddDependency(paramType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue);
// #ifdef _DEBUG
// if (BfResolvedTypeSet::Hash(delegateType, &lookupCtx) != resolvedEntry->mHash)
// {
// int refHash = BfResolvedTypeSet::Hash(typeRef, &lookupCtx);
// int typeHash = BfResolvedTypeSet::Hash(delegateType, &lookupCtx);
// BF_ASSERT(refHash == typeHash);
// }
// #endif
#ifdef _DEBUG
if (BfResolvedTypeSet::Hash(delegateType, &lookupCtx) != resolvedEntry->mHash)
{
int refHash = BfResolvedTypeSet::Hash(typeRef, &lookupCtx);
int typeHash = BfResolvedTypeSet::Hash(delegateType, &lookupCtx);
BF_ASSERT(refHash == typeHash);
}
BF_ASSERT(BfResolvedTypeSet::Equals(delegateType, typeRef, &lookupCtx));
#endif
BF_ASSERT(BfResolvedTypeSet::Hash(delegateType, &lookupCtx) == resolvedEntry->mHash);
@ -8847,7 +8878,56 @@ BfIRValue BfModule::CastToFunction(BfAstNode* srcNode, BfMethodInstance* methodI
}
else if (invokeMethodInstance->IsExactMatch(methodInstance, false, false))
{
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(methodInstance->GetParamType(-1)).c_str()), srcNode);
bool handled = false;
auto thisType = methodInstance->GetParamType(-1);
if (thisType != NULL)
{
if (invokeMethodInstance->HasExplicitThis())
{
auto invokeThisType = invokeMethodInstance->GetParamType(-1);
bool thisWasPtr = false;
if (thisType->IsPointer())
{
thisType = thisType->GetUnderlyingType();
thisWasPtr = true;
}
bool invokeThisWasPtr = false;
if (invokeThisType->IsPointer())
{
invokeThisType = invokeThisType->GetUnderlyingType();
invokeThisWasPtr = true;
}
if (invokeThisType == thisType)
{
if (invokeThisWasPtr != thisWasPtr)
{
if (invokeThisWasPtr)
Fail(StrFormat("Non-static method '%s' cannot match '%s', consider removing 'mut' from 'mut %s this' in the function parameters", MethodToString(methodInstance).c_str(), TypeToString(toType).c_str(), TypeToString(thisType).c_str()), srcNode);
else
Fail(StrFormat("Non-static method '%s' cannot match '%s', consider adding 'mut' specifier to '%s this' in the function parameters", MethodToString(methodInstance).c_str(), TypeToString(toType).c_str(), TypeToString(thisType).c_str()), srcNode);
handled = true;
}
}
}
}
if ((!methodInstance->mMethodDef->mIsStatic) && (!invokeMethodInstance->HasExplicitThis()))
{
handled = true;
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);
}
if (!handled)
{
if (invokeMethodInstance->mMethodDef->mIsStatic)
Fail(StrFormat("Static method '%s' cannot match '%s'", MethodToString(methodInstance).c_str(), TypeToString(toType).c_str()).c_str(), srcNode);
else
Fail(StrFormat("Non-static method '%s' cannot match '%s'", MethodToString(methodInstance).c_str(), TypeToString(toType).c_str()).c_str(), srcNode);
}
}
}
return BfIRValue();
@ -10386,34 +10466,41 @@ BfTypedValue BfModule::Cast(BfAstNode* srcNode, const BfTypedValue& typedVal, Bf
(fromMethodInst->mReturnType == toMethodInst->mReturnType) &&
(fromMethodInst->GetParamCount() == toMethodInst->GetParamCount()))
{
bool matched = true;
bool matched = true;
StringT<64> fromParamName;
StringT<64> toParamName;
for (int paramIdx = 0; paramIdx < (int)fromMethodInst->GetParamCount(); paramIdx++)
if (fromMethodInst->HasExplicitThis() != toMethodInst->HasExplicitThis())
{
bool nameMatches = true;
if (!explicitCast)
matched = false;
}
else
{
for (int paramIdx = fromMethodInst->HasExplicitThis() ? -1 : 0; paramIdx < (int)fromMethodInst->GetParamCount(); paramIdx++)
{
fromMethodInst->GetParamName(paramIdx, fromParamName);
toMethodInst->GetParamName(paramIdx, toParamName);
if ((!fromParamName.IsEmpty()) && (!toParamName.IsEmpty()))
nameMatches = fromParamName == toParamName;
bool nameMatches = true;
if (!explicitCast)
{
fromMethodInst->GetParamName(paramIdx, fromParamName);
toMethodInst->GetParamName(paramIdx, toParamName);
if ((!fromParamName.IsEmpty()) && (!toParamName.IsEmpty()))
nameMatches = fromParamName == toParamName;
}
if ((fromMethodInst->GetParamKind(paramIdx) == toMethodInst->GetParamKind(paramIdx)) &&
(fromMethodInst->GetParamType(paramIdx) == toMethodInst->GetParamType(paramIdx)) &&
(nameMatches))
{
// Matched, required for implicit/explicit
}
else
{
matched = false;
break;
}
}
if ((fromMethodInst->GetParamKind(paramIdx) == toMethodInst->GetParamKind(paramIdx)) &&
(fromMethodInst->GetParamType(paramIdx) == toMethodInst->GetParamType(paramIdx)) &&
(nameMatches))
{
// Matched, required for implicit/explicit
}
else
{
matched = false;
break;
}
}
if (matched)
@ -10939,9 +11026,20 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF
str += "function ";
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;
}
for (int paramIdx = 0; paramIdx < methodDef->mParams.size(); paramIdx++)
{
if (paramIdx > 0)
if (!isFirstParam)
str += ", ";
auto paramDef = methodDef->mParams[paramIdx];
BfTypeNameFlags innerFlags = (BfTypeNameFlags)(typeNameFlags & ~(BfTypeNameFlag_OmitNamespace | BfTypeNameFlag_OmitOuterType));
@ -10953,6 +11051,8 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF
str += " ";
str += paramDef->mName;
}
isFirstParam = false;
}
str += ")";