mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-21 01:18:02 +02:00
Added extension methods
This commit is contained in:
parent
c1a2bd79e1
commit
e1c340a711
12 changed files with 507 additions and 225 deletions
|
@ -2810,26 +2810,27 @@ public:
|
||||||
BF_AST_TYPE(BfMethodDeclaration, BfMemberDeclaration);
|
BF_AST_TYPE(BfMethodDeclaration, BfMemberDeclaration);
|
||||||
|
|
||||||
BfCommentNode* mDocumentation;
|
BfCommentNode* mDocumentation;
|
||||||
ASTREF(BfAttributeDirective*) mReturnAttributes;
|
BfAttributeDirective* mReturnAttributes;
|
||||||
ASTREF(BfTokenNode*) mExternSpecifier;
|
BfTokenNode* mExternSpecifier;
|
||||||
ASTREF(BfTokenNode*) mVirtualSpecifier; // either 'virtual', 'override', or 'abstract'
|
BfTokenNode* mVirtualSpecifier; // either 'virtual', 'override', or 'abstract'
|
||||||
ASTREF(BfTokenNode*) mNewSpecifier;
|
BfTokenNode* mNewSpecifier;
|
||||||
ASTREF(BfTokenNode*) mMixinSpecifier;
|
BfTokenNode* mMixinSpecifier;
|
||||||
ASTREF(BfTokenNode*) mPartialSpecifier;
|
BfTokenNode* mPartialSpecifier;
|
||||||
ASTREF(BfTokenNode*) mMutSpecifier;
|
BfTokenNode* mMutSpecifier;
|
||||||
ASTREF(BfTypeReference*) mReturnType;
|
BfTypeReference* mReturnType;
|
||||||
ASTREF(BfTypeReference*) mExplicitInterface;
|
BfTypeReference* mExplicitInterface;
|
||||||
ASTREF(BfTokenNode*) mExplicitInterfaceDotToken;
|
BfTokenNode* mExplicitInterfaceDotToken;
|
||||||
ASTREF(BfIdentifierNode*) mNameNode;
|
BfIdentifierNode* mNameNode;
|
||||||
ASTREF(BfTokenNode*) mOpenParen;
|
BfTokenNode* mOpenParen;
|
||||||
BfSizedArray<ASTREF(BfParameterDeclaration*)> mParams;
|
BfTokenNode* mThisToken;
|
||||||
BfSizedArray<ASTREF(BfTokenNode*)> mCommas;
|
BfSizedArray<BfParameterDeclaration*> mParams;
|
||||||
ASTREF(BfTokenNode*) mCloseParen;
|
BfSizedArray<BfTokenNode*> mCommas;
|
||||||
ASTREF(BfGenericParamsDeclaration*) mGenericParams;
|
BfTokenNode* mCloseParen;
|
||||||
ASTREF(BfGenericConstraintsDeclaration*) mGenericConstraintsDeclaration;
|
BfGenericParamsDeclaration* mGenericParams;
|
||||||
ASTREF(BfAstNode*) mEndSemicolon;
|
BfGenericConstraintsDeclaration* mGenericConstraintsDeclaration;
|
||||||
ASTREF(BfTokenNode*) mFatArrowToken;
|
BfAstNode* mEndSemicolon;
|
||||||
ASTREF(BfAstNode*) mBody; // Either expression or block
|
BfTokenNode* mFatArrowToken;
|
||||||
|
BfAstNode* mBody; // Either expression or block
|
||||||
|
|
||||||
//BfMethodDef* mMethodDef;
|
//BfMethodDef* mMethodDef;
|
||||||
|
|
||||||
|
|
|
@ -910,16 +910,104 @@ void BfAutoComplete::AddEnumTypeMembers(BfTypeInstance* typeInst, const StringIm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// bool BfAutoComplete::IsInExpression(BfAstNode* node)
|
void BfAutoComplete::AddExtensionMethods(BfTypeInstance* targetType, BfTypeInstance* extensionContainer, const StringImpl & filter, bool allowProtected, bool allowPrivate)
|
||||||
// {
|
{
|
||||||
// if (mModule->mCurMethodInstance != NULL)
|
if (!extensionContainer->mTypeDef->mHasExtensionMethods)
|
||||||
// return true;
|
return;
|
||||||
// if (node == NULL)
|
|
||||||
// return false;
|
mModule->PopulateType(extensionContainer, BfPopulateType_Data);
|
||||||
// if ((node->IsA<BfExpression>()) && (!node->IsA<BfIdentifierNode>()) && (!node->IsA<BfBlock>()))
|
|
||||||
// return true;
|
for (auto methodDef : extensionContainer->mTypeDef->mMethods)
|
||||||
// return IsInExpression(node->mParent);
|
{
|
||||||
// }
|
if (methodDef->mMethodType != BfMethodType_Extension)
|
||||||
|
continue;
|
||||||
|
if (methodDef->mIsNoShow)
|
||||||
|
continue;
|
||||||
|
if (methodDef->mName.IsEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool canUseMethod = true;
|
||||||
|
canUseMethod &= CheckProtection(methodDef->mProtection, allowProtected, allowPrivate);
|
||||||
|
|
||||||
|
auto methodInstance = mModule->GetRawMethodInstanceAtIdx(extensionContainer, methodDef->mIdx);
|
||||||
|
if (methodInstance == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Do filter match first- may be cheaper than generic validation
|
||||||
|
if (!DoesFilterMatch(methodDef->mName.c_str(), filter.c_str()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto thisType = methodInstance->GetParamType(0);
|
||||||
|
bool paramValidated = false;
|
||||||
|
if (methodInstance->GetNumGenericParams() > 0)
|
||||||
|
{
|
||||||
|
if ((thisType->IsGenericParam()) && (methodInstance->GetNumGenericParams() == 1))
|
||||||
|
{
|
||||||
|
auto genericParamType = (BfGenericParamType*)thisType;
|
||||||
|
if (genericParamType->mGenericParamKind == BfGenericParamKind_Method)
|
||||||
|
{
|
||||||
|
auto& genericParams = methodInstance->mMethodInfoEx->mGenericParams;
|
||||||
|
if (!mModule->CheckGenericConstraints(BfGenericParamSource(methodInstance), targetType, NULL, genericParams[genericParamType->mGenericParamIdx], NULL, NULL))
|
||||||
|
continue;
|
||||||
|
paramValidated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((thisType->IsUnspecializedTypeVariation()) || (thisType->IsGenericParam())) &&
|
||||||
|
(!paramValidated))
|
||||||
|
{
|
||||||
|
BfTypeVector genericTypeVector;
|
||||||
|
genericTypeVector.resize(methodInstance->GetNumGenericParams());
|
||||||
|
BfGenericInferContext genericInferContext;
|
||||||
|
genericInferContext.mCheckMethodGenericArguments = &genericTypeVector;
|
||||||
|
genericInferContext.mModule = mModule;
|
||||||
|
genericInferContext.mPrevArgValues.resize(methodInstance->GetNumGenericParams());
|
||||||
|
|
||||||
|
if (!genericInferContext.InferGenericArgument(methodInstance, targetType, thisType, BfIRValue()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
thisType = mModule->ResolveGenericType(thisType, NULL, &genericTypeVector, false);
|
||||||
|
if (thisType == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto& genericParams = methodInstance->mMethodInfoEx->mGenericParams;
|
||||||
|
bool validateError = false;
|
||||||
|
for (int genericIdx = 0; genericIdx < (int)genericTypeVector.size(); genericIdx++)
|
||||||
|
{
|
||||||
|
auto genericArg = genericTypeVector[genericIdx];
|
||||||
|
if (genericArg == NULL)
|
||||||
|
continue;
|
||||||
|
if (!mModule->CheckGenericConstraints(BfGenericParamSource(methodInstance), genericArg, NULL, genericParams[genericIdx], &genericTypeVector, NULL))
|
||||||
|
{
|
||||||
|
validateError = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validateError)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!paramValidated)
|
||||||
|
{
|
||||||
|
if (!mModule->CanCast(BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), targetType), thisType))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canUseMethod)
|
||||||
|
{
|
||||||
|
if (auto methodDeclaration = methodDef->GetMethodDeclaration())
|
||||||
|
{
|
||||||
|
String replaceName;
|
||||||
|
AutoCompleteEntry entry("method", methodDef->mName, methodDeclaration->mDocumentation);
|
||||||
|
if ((AddEntry(entry)) && (mIsGetDefinition))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BfAutoComplete::AddTopLevelNamespaces(BfAstNode* identifierNode)
|
void BfAutoComplete::AddTopLevelNamespaces(BfAstNode* identifierNode)
|
||||||
{
|
{
|
||||||
|
@ -988,35 +1076,6 @@ void BfAutoComplete::AddTopLevelTypes(BfAstNode* identifierNode, bool onlyAttrib
|
||||||
}
|
}
|
||||||
|
|
||||||
AddCurrentTypes(mModule->mCurTypeInstance, filter, true, true, onlyAttribute);
|
AddCurrentTypes(mModule->mCurTypeInstance, filter, true, true, onlyAttribute);
|
||||||
|
|
||||||
// Do inners
|
|
||||||
// bool allowInnerPrivate = false;
|
|
||||||
// auto checkTypeInst = mModule->mCurTypeInstance;
|
|
||||||
// while (checkTypeInst != NULL)
|
|
||||||
// {
|
|
||||||
// auto checkTypeDef = checkTypeInst->mTypeDef;
|
|
||||||
// for (auto nestedTypeDef : checkTypeDef->mNestedTypes)
|
|
||||||
// {
|
|
||||||
// if (CheckProtection(nestedTypeDef->mProtection, true, allowInnerPrivate))
|
|
||||||
// AddTypeDef(nestedTypeDef, filter, onlyAttribute);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// checkTypeInst = mModule->GetOuterType(mModule->mCurTypeInstance);
|
|
||||||
// if (checkTypeInst != NULL)
|
|
||||||
// AddInnerTypes(checkTypeInst, filter, true, true);
|
|
||||||
//
|
|
||||||
// AddOuterTypes(checkTypeInst, filter, true, true);
|
|
||||||
//
|
|
||||||
// checkTypeInst = mModule->GetBaseType(checkTypeInst);
|
|
||||||
// allowInnerPrivate = false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// allowInnerPrivate = true;
|
|
||||||
// checkTypeInst = mModule->GetOuterType(mModule->mCurTypeInstance);
|
|
||||||
// if (checkTypeInst != NULL)
|
|
||||||
// AddInnerTypes(checkTypeInst, filter, true, true);
|
|
||||||
//
|
|
||||||
// AddOuterTypes(mModule->mCurTypeInstance, filter, true, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mModule->mCurMethodInstance != NULL)
|
if (mModule->mCurMethodInstance != NULL)
|
||||||
|
@ -1090,29 +1149,6 @@ void BfAutoComplete::AddTopLevelTypes(BfAstNode* identifierNode, bool onlyAttrib
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BfStaticSearch* staticSearch;
|
|
||||||
// if (mModule->mCurTypeInstance->mStaticSearchMap.TryGetValue(activeTypeDef, &staticSearch))
|
|
||||||
// {
|
|
||||||
// for (auto typeInst : staticSearch->mStaticTypes)
|
|
||||||
// {
|
|
||||||
// AddTypeDef(typeInst->mTypeDef, filter, onlyAttribute);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else if (!activeTypeDef->mStaticSearch.IsEmpty())
|
|
||||||
// {
|
|
||||||
// BF_ASSERT(mModule->mCompiler->IsAutocomplete());
|
|
||||||
// for (auto typeRef : activeTypeDef->mStaticSearch)
|
|
||||||
// {
|
|
||||||
// auto type = mModule->ResolveTypeRef(typeRef, NULL, BfPopulateType_Declaration);
|
|
||||||
// if (type != NULL)
|
|
||||||
// {
|
|
||||||
// auto typeInst = type->ToTypeInstance();
|
|
||||||
// if (typeInst != NULL)
|
|
||||||
// AddTypeDef(typeInst->mTypeDef, filter, onlyAttribute);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1567,8 +1603,38 @@ bool BfAutoComplete::CheckMemberReference(BfAstNode* target, BfAstNode* dotToken
|
||||||
AddInnerTypes(typeInst, filter, allowProtected, allowPrivate);
|
AddInnerTypes(typeInst, filter, allowProtected, allowPrivate);
|
||||||
|
|
||||||
if (!onlyShowTypes)
|
if (!onlyShowTypes)
|
||||||
|
{
|
||||||
AddTypeMembers(typeInst, isStatic, !isStatic, filter, typeInst, false, false);
|
AddTypeMembers(typeInst, isStatic, !isStatic, filter, typeInst, false, false);
|
||||||
|
|
||||||
|
if (!isStatic)
|
||||||
|
{
|
||||||
|
auto checkTypeInst = mModule->mCurTypeInstance;
|
||||||
|
while (checkTypeInst != NULL)
|
||||||
|
{
|
||||||
|
AddExtensionMethods(typeInst, checkTypeInst, filter, allowProtected, allowPrivate);
|
||||||
|
checkTypeInst = mModule->GetOuterType(checkTypeInst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mModule->mContext->mCurTypeState != NULL) && (mModule->mContext->mCurTypeState->mTypeInstance != NULL))
|
||||||
|
{
|
||||||
|
BF_ASSERT(mModule->mCurTypeInstance == mModule->mContext->mCurTypeState->mTypeInstance);
|
||||||
|
|
||||||
|
BfGlobalLookup globalLookup;
|
||||||
|
globalLookup.mKind = BfGlobalLookup::Kind_All;
|
||||||
|
mModule->PopulateGlobalContainersList(globalLookup);
|
||||||
|
for (auto& globalContainer : mModule->mContext->mCurTypeState->mGlobalContainers)
|
||||||
|
AddExtensionMethods(typeInst, globalContainer.mTypeInst, filter, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
BfStaticSearch* staticSearch = mModule->GetStaticSearch();
|
||||||
|
if (staticSearch != NULL)
|
||||||
|
{
|
||||||
|
for (auto staticTypeInst : staticSearch->mStaticTypes)
|
||||||
|
AddExtensionMethods(typeInst, staticTypeInst, filter, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (typeInst->IsInterface())
|
if (typeInst->IsInterface())
|
||||||
{
|
{
|
||||||
AddTypeMembers(mModule->mContext->mBfObjectType, isStatic, !isStatic, filter, mModule->mContext->mBfObjectType, true, false);
|
AddTypeMembers(mModule->mContext->mBfObjectType, isStatic, !isStatic, filter, mModule->mContext->mBfObjectType, true, false);
|
||||||
|
|
|
@ -210,6 +210,7 @@ public:
|
||||||
void AddSelfResultTypeMembers(BfTypeInstance* typeInst, BfTypeInstance* selfType, const StringImpl& filter, bool allowPrivate);
|
void AddSelfResultTypeMembers(BfTypeInstance* typeInst, BfTypeInstance* selfType, const StringImpl& filter, bool allowPrivate);
|
||||||
bool InitAutocomplete(BfAstNode* dotNode, BfAstNode* nameNode, String& filter);
|
bool InitAutocomplete(BfAstNode* dotNode, BfAstNode* nameNode, String& filter);
|
||||||
void AddEnumTypeMembers(BfTypeInstance* typeInst, const StringImpl& filter, bool allowProtected, bool allowPrivate);
|
void AddEnumTypeMembers(BfTypeInstance* typeInst, const StringImpl& filter, bool allowProtected, bool allowPrivate);
|
||||||
|
void AddExtensionMethods(BfTypeInstance* targetType, BfTypeInstance* extensionContainer, const StringImpl& filter, bool allowProtected, bool allowPrivate);
|
||||||
void AddTopLevelNamespaces(BfAstNode* identifierNode);
|
void AddTopLevelNamespaces(BfAstNode* identifierNode);
|
||||||
void AddTopLevelTypes(BfAstNode* identifierNode, bool onlyAttribute = false);
|
void AddTopLevelTypes(BfAstNode* identifierNode, bool onlyAttribute = false);
|
||||||
void AddOverrides(const StringImpl& filter);
|
void AddOverrides(const StringImpl& filter);
|
||||||
|
|
|
@ -3666,6 +3666,10 @@ void BfCompiler::ProcessAutocompleteTempType()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetAndRestoreValue<BfMethodState*> prevMethodState(module->mCurMethodState, NULL);
|
||||||
|
SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(module->mCurTypeInstance, NULL);
|
||||||
|
SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(module->mCurMethodInstance, NULL);
|
||||||
|
|
||||||
// >>> VisitExteriorIdentifiers
|
// >>> VisitExteriorIdentifiers
|
||||||
mResolvePassData->mAutoComplete->SetModule(module);
|
mResolvePassData->mAutoComplete->SetModule(module);
|
||||||
{
|
{
|
||||||
|
@ -3705,8 +3709,6 @@ void BfCompiler::ProcessAutocompleteTempType()
|
||||||
BfLogSysM("ProcessAutocompleteTempType - project disabled\n");
|
BfLogSysM("ProcessAutocompleteTempType - project disabled\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetAndRestoreValue<BfMethodState*> prevMethodState(module->mCurMethodState, NULL);
|
|
||||||
|
|
||||||
BfTypeState typeState;
|
BfTypeState typeState;
|
||||||
typeState.mCurTypeDef = tempTypeDef;
|
typeState.mCurTypeDef = tempTypeDef;
|
||||||
|
@ -4096,6 +4098,9 @@ void BfCompiler::ProcessAutocompleteTempType()
|
||||||
methodInstance->mMethodDef = methodDef;
|
methodInstance->mMethodDef = methodDef;
|
||||||
methodInstance->mMethodInstanceGroup = &methodInstanceGroup;
|
methodInstance->mMethodInstanceGroup = &methodInstanceGroup;
|
||||||
methodInstance->mIsAutocompleteMethod = true;
|
methodInstance->mIsAutocompleteMethod = true;
|
||||||
|
|
||||||
|
methodInstanceGroup.mDefault = methodInstance;
|
||||||
|
defer(methodInstanceGroup.mDefault = NULL);
|
||||||
|
|
||||||
for (int genericParamIdx = 0; genericParamIdx < (int)methodDef->mGenericParams.size(); genericParamIdx++)
|
for (int genericParamIdx = 0; genericParamIdx < (int)methodDef->mGenericParams.size(); genericParamIdx++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -409,7 +409,10 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
|
||||||
methodDef->mIsNew = methodDeclaration->mNewSpecifier != NULL;
|
methodDef->mIsNew = methodDeclaration->mNewSpecifier != NULL;
|
||||||
methodDef->mIsMutating = methodDeclaration->mMutSpecifier != NULL;
|
methodDef->mIsMutating = methodDeclaration->mMutSpecifier != NULL;
|
||||||
methodDef->mIsExtern = methodDeclaration->mExternSpecifier != NULL;
|
methodDef->mIsExtern = methodDeclaration->mExternSpecifier != NULL;
|
||||||
methodDef->mBody = methodDeclaration->mBody;
|
methodDef->mBody = methodDeclaration->mBody;
|
||||||
|
|
||||||
|
if (methodDeclaration->mThisToken != NULL)
|
||||||
|
methodDef->mMethodType = BfMethodType_Extension;
|
||||||
|
|
||||||
HashContext signatureHashCtx;
|
HashContext signatureHashCtx;
|
||||||
HashNode(signatureHashCtx, methodDeclaration, methodDef->mBody);
|
HashNode(signatureHashCtx, methodDeclaration, methodDef->mBody);
|
||||||
|
@ -553,15 +556,19 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
|
||||||
{
|
{
|
||||||
if (methodDeclaration->mNameNode != NULL)
|
if (methodDeclaration->mNameNode != NULL)
|
||||||
methodDef->mName = methodDeclaration->mNameNode->ToString();
|
methodDef->mName = methodDeclaration->mNameNode->ToString();
|
||||||
methodDef->mMethodType = BfMethodType_Mixin;
|
methodDef->mMethodType = BfMethodType_Mixin;
|
||||||
/*if (!methodDef->mIsStatic)
|
|
||||||
Fail("Mixin must be declared static", methodDeclaration->mMixinSpecifier);*/
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (methodDeclaration->mNameNode != NULL)
|
if (methodDeclaration->mNameNode != NULL)
|
||||||
methodDef->mName = methodDeclaration->mNameNode->ToString();
|
methodDef->mName = methodDeclaration->mNameNode->ToString();
|
||||||
methodDef->mMethodType = BfMethodType_Normal;
|
methodDef->mMethodType = BfMethodType_Normal;
|
||||||
|
|
||||||
|
if (methodDeclaration->mThisToken != NULL)
|
||||||
|
{
|
||||||
|
methodDef->mMethodType = BfMethodType_Extension;
|
||||||
|
mCurTypeDef->mHasExtensionMethods = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outerMethodDef != NULL)
|
if (outerMethodDef != NULL)
|
||||||
|
|
|
@ -981,6 +981,7 @@ void BfElementVisitor::Visit(BfMethodDeclaration* methodDeclaration)
|
||||||
VisitChild(methodDeclaration->mExplicitInterfaceDotToken);
|
VisitChild(methodDeclaration->mExplicitInterfaceDotToken);
|
||||||
VisitChild(methodDeclaration->mNameNode);
|
VisitChild(methodDeclaration->mNameNode);
|
||||||
VisitChild(methodDeclaration->mOpenParen);
|
VisitChild(methodDeclaration->mOpenParen);
|
||||||
|
VisitChild(methodDeclaration->mThisToken);
|
||||||
for (auto& param : methodDeclaration->mParams)
|
for (auto& param : methodDeclaration->mParams)
|
||||||
VisitChild(param);
|
VisitChild(param);
|
||||||
for (auto& comma : methodDeclaration->mCommas)
|
for (auto& comma : methodDeclaration->mCommas)
|
||||||
|
|
|
@ -171,8 +171,8 @@ void BfMethodMatcher::Init(/*SizedArrayImpl<BfResolvedArg>& arguments, */BfSized
|
||||||
mSkipImplicitParams = false;
|
mSkipImplicitParams = false;
|
||||||
mAllowImplicitThis = false;
|
mAllowImplicitThis = false;
|
||||||
mHadVarConflictingReturnType = false;
|
mHadVarConflictingReturnType = false;
|
||||||
mMethodCheckCount = 0;
|
mAutoFlushAmbiguityErrors = true;
|
||||||
mInferGenericProgressIdx = 0;
|
mMethodCheckCount = 0;
|
||||||
mCheckedKind = BfCheckedKind_NotSet;
|
mCheckedKind = BfCheckedKind_NotSet;
|
||||||
mMatchFailKind = MatchFailKind_None;
|
mMatchFailKind = MatchFailKind_None;
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ bool BfMethodMatcher::IsMemberAccessible(BfTypeInstance* typeInst, BfTypeDef* de
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfType* argType, BfType* wantType, BfIRValue argValue, HashSet<BfType*>& checkedTypeSet)
|
bool BfGenericInferContext::InferGenericArgument(BfMethodInstance* methodInstance, BfType* argType, BfType* wantType, BfIRValue argValue)
|
||||||
{
|
{
|
||||||
if (argType == NULL)
|
if (argType == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
@ -249,7 +249,7 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCheckMethodGenericArguments[wantGenericParam->mGenericParamIdx] != argType)
|
if ((*mCheckMethodGenericArguments)[wantGenericParam->mGenericParamIdx] != argType)
|
||||||
{
|
{
|
||||||
if (methodGenericTypeConstraint != NULL)
|
if (methodGenericTypeConstraint != NULL)
|
||||||
{
|
{
|
||||||
|
@ -266,7 +266,7 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
if (argGenericType->mTypeDef == wantGenericType->mTypeDef)
|
if (argGenericType->mTypeDef == wantGenericType->mTypeDef)
|
||||||
{
|
{
|
||||||
for (int genericArgIdx = 0; genericArgIdx < (int)argGenericType->mTypeGenericArguments.size(); genericArgIdx++)
|
for (int genericArgIdx = 0; genericArgIdx < (int)argGenericType->mTypeGenericArguments.size(); genericArgIdx++)
|
||||||
InferGenericArgument(methodInstance, argGenericType->mTypeGenericArguments[genericArgIdx], wantGenericType->mTypeGenericArguments[genericArgIdx], BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, argGenericType->mTypeGenericArguments[genericArgIdx], wantGenericType->mTypeGenericArguments[genericArgIdx], BfIRValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (checkArgType->IsSizedArray())
|
else if (checkArgType->IsSizedArray())
|
||||||
|
@ -274,10 +274,10 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
auto sizedArrayType = (BfSizedArrayType*)checkArgType;
|
auto sizedArrayType = (BfSizedArrayType*)checkArgType;
|
||||||
if (wantGenericType->mTypeDef == mModule->mCompiler->mSizedArrayTypeDef)
|
if (wantGenericType->mTypeDef == mModule->mCompiler->mSizedArrayTypeDef)
|
||||||
{
|
{
|
||||||
InferGenericArgument(methodInstance, sizedArrayType->mElementType, wantGenericType->mTypeGenericArguments[0], BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, sizedArrayType->mElementType, wantGenericType->mTypeGenericArguments[0], BfIRValue());
|
||||||
auto intType = mModule->GetPrimitiveType(BfTypeCode_IntPtr);
|
auto intType = mModule->GetPrimitiveType(BfTypeCode_IntPtr);
|
||||||
BfTypedValue arraySize = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, (uint64)sizedArrayType->mElementCount), intType);
|
BfTypedValue arraySize = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, (uint64)sizedArrayType->mElementCount), intType);
|
||||||
InferGenericArgument(methodInstance, mModule->CreateConstExprValueType(arraySize), wantGenericType->mTypeGenericArguments[1], BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, mModule->CreateConstExprValueType(arraySize), wantGenericType->mTypeGenericArguments[1], BfIRValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (checkArgType->IsPointer())
|
else if (checkArgType->IsPointer())
|
||||||
|
@ -285,7 +285,7 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
auto pointerType = (BfPointerType*)checkArgType;
|
auto pointerType = (BfPointerType*)checkArgType;
|
||||||
if (wantGenericType->mTypeDef == mModule->mCompiler->mPointerTTypeDef)
|
if (wantGenericType->mTypeDef == mModule->mCompiler->mPointerTTypeDef)
|
||||||
{
|
{
|
||||||
InferGenericArgument(methodInstance, pointerType->mElementType, wantGenericType->mTypeGenericArguments[0], BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, pointerType->mElementType, wantGenericType->mTypeGenericArguments[0], BfIRValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,11 +296,10 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mInferGenericProgressIdx++;
|
(*mCheckMethodGenericArguments)[wantGenericParam->mGenericParamIdx] = argType;
|
||||||
mCheckMethodGenericArguments[wantGenericParam->mGenericParamIdx] = argType;
|
|
||||||
}
|
}
|
||||||
mCheckMethodGenericArguments[wantGenericParam->mGenericParamIdx] = argType;
|
(*mCheckMethodGenericArguments)[wantGenericParam->mGenericParamIdx] = argType;
|
||||||
mPrevArgValues[wantGenericParam->mGenericParamIdx] = argValue;
|
mPrevArgValues[wantGenericParam->mGenericParamIdx] = argValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -334,7 +333,7 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto prevGenericMethodArg = mCheckMethodGenericArguments[wantGenericParam->mGenericParamIdx];
|
auto prevGenericMethodArg = (*mCheckMethodGenericArguments)[wantGenericParam->mGenericParamIdx];
|
||||||
auto prevArgValue = mPrevArgValues[wantGenericParam->mGenericParamIdx];
|
auto prevArgValue = mPrevArgValues[wantGenericParam->mGenericParamIdx];
|
||||||
if (prevGenericMethodArg == NULL)
|
if (prevGenericMethodArg == NULL)
|
||||||
{
|
{
|
||||||
|
@ -382,7 +381,7 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
}
|
}
|
||||||
|
|
||||||
// No implicit conversion, FAIL!
|
// No implicit conversion, FAIL!
|
||||||
mCheckMethodGenericArguments[wantGenericParam->mGenericParamIdx] = NULL;
|
(*mCheckMethodGenericArguments)[wantGenericParam->mGenericParamIdx] = NULL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -396,12 +395,12 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
auto genericParam = mModule->GetGenericParamInstance((BfGenericParamType*)argType);
|
auto genericParam = mModule->GetGenericParamInstance((BfGenericParamType*)argType);
|
||||||
if ((genericParam->mGenericParamFlags & BfGenericParamFlag_Var) != 0)
|
if ((genericParam->mGenericParamFlags & BfGenericParamFlag_Var) != 0)
|
||||||
{
|
{
|
||||||
InferGenericArgument(methodInstance, mModule->GetPrimitiveType(BfTypeCode_Var), wantType, BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, mModule->GetPrimitiveType(BfTypeCode_Var), wantType, BfIRValue());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((genericParam->mTypeConstraint != NULL) && (genericParam->mTypeConstraint->IsGenericTypeInstance()))
|
if ((genericParam->mTypeConstraint != NULL) && (genericParam->mTypeConstraint->IsGenericTypeInstance()))
|
||||||
InferGenericArgument(methodInstance, genericParam->mTypeConstraint, wantType, BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, genericParam->mTypeConstraint, wantType, BfIRValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argType->IsVar())
|
if (argType->IsVar())
|
||||||
|
@ -411,7 +410,7 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
BfType* wantGenericArgument = wantGenericType->mTypeGenericArguments[genericArgIdx];
|
BfType* wantGenericArgument = wantGenericType->mTypeGenericArguments[genericArgIdx];
|
||||||
if (!wantGenericArgument->IsUnspecializedType())
|
if (!wantGenericArgument->IsUnspecializedType())
|
||||||
continue;
|
continue;
|
||||||
InferGenericArgument(methodInstance, mModule->GetPrimitiveType(BfTypeCode_Var), wantGenericArgument, BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, mModule->GetPrimitiveType(BfTypeCode_Var), wantGenericArgument, BfIRValue());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -420,16 +419,16 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
return true;
|
return true;
|
||||||
auto argGenericType = (BfGenericTypeInstance*)argType;
|
auto argGenericType = (BfGenericTypeInstance*)argType;
|
||||||
if (argGenericType->mTypeDef != wantGenericType->mTypeDef)
|
if (argGenericType->mTypeDef != wantGenericType->mTypeDef)
|
||||||
return true;
|
return false;
|
||||||
|
|
||||||
for (int genericArgIdx = 0; genericArgIdx < (int)argGenericType->mTypeGenericArguments.size(); genericArgIdx++)
|
for (int genericArgIdx = 0; genericArgIdx < (int)argGenericType->mTypeGenericArguments.size(); genericArgIdx++)
|
||||||
{
|
{
|
||||||
BfType* wantGenericArgument = wantGenericType->mTypeGenericArguments[genericArgIdx];
|
BfType* wantGenericArgument = wantGenericType->mTypeGenericArguments[genericArgIdx];
|
||||||
if (!wantGenericArgument->IsUnspecializedType())
|
if (!wantGenericArgument->IsUnspecializedType())
|
||||||
continue;
|
continue;
|
||||||
if (!_AddToCheckedSet(argType, checkedTypeSet, alreadyChecked))
|
if (!_AddToCheckedSet(argType, mCheckedTypeSet, alreadyChecked))
|
||||||
return true;
|
return true;
|
||||||
InferGenericArgument(methodInstance, argGenericType->mTypeGenericArguments[genericArgIdx], wantGenericArgument, BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, argGenericType->mTypeGenericArguments[genericArgIdx], wantGenericArgument, BfIRValue());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -440,15 +439,14 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
if (!argType->IsRef())
|
if (!argType->IsRef())
|
||||||
{
|
{
|
||||||
// Match to non-ref
|
// Match to non-ref
|
||||||
InferGenericArgument(methodInstance, argType, wantRefType->mElementType, BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, argType, wantRefType->mElementType, BfIRValue());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
auto argRefType = (BfRefType*)argType;
|
auto argRefType = (BfRefType*)argType;
|
||||||
//TODO: We removed this check so we still infer even if we have the wrong ref kind
|
//TODO: We removed this check so we still infer even if we have the wrong ref kind
|
||||||
//if (wantRefType->mRefKind != argRefType->mRefKind)
|
//if (wantRefType->mRefKind != argRefType->mRefKind)
|
||||||
//return true;
|
//return true;
|
||||||
InferGenericArgument(methodInstance, argRefType->mElementType, wantRefType->mElementType, BfIRValue(), checkedTypeSet);
|
return InferGenericArgument(methodInstance, argRefType->mElementType, wantRefType->mElementType, BfIRValue());
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wantType->IsPointer())
|
if (wantType->IsPointer())
|
||||||
|
@ -457,8 +455,7 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
return true;
|
return true;
|
||||||
auto wantPointerType = (BfPointerType*) wantType;
|
auto wantPointerType = (BfPointerType*) wantType;
|
||||||
auto argPointerType = (BfPointerType*) argType;
|
auto argPointerType = (BfPointerType*) argType;
|
||||||
InferGenericArgument(methodInstance, argPointerType->mElementType, wantPointerType->mElementType, BfIRValue(), checkedTypeSet);
|
return InferGenericArgument(methodInstance, argPointerType->mElementType, wantPointerType->mElementType, BfIRValue());
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wantType->IsUnknownSizedArray())
|
if (wantType->IsUnknownSizedArray())
|
||||||
|
@ -467,14 +464,14 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
if (argType->IsUnknownSizedArray())
|
if (argType->IsUnknownSizedArray())
|
||||||
{
|
{
|
||||||
auto argArrayType = (BfUnknownSizedArrayType*)argType;
|
auto argArrayType = (BfUnknownSizedArrayType*)argType;
|
||||||
InferGenericArgument(methodInstance, argArrayType->mElementCountSource, wantArrayType->mElementCountSource, BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, argArrayType->mElementCountSource, wantArrayType->mElementCountSource, BfIRValue());
|
||||||
}
|
}
|
||||||
else if (argType->IsSizedArray())
|
else if (argType->IsSizedArray())
|
||||||
{
|
{
|
||||||
auto argArrayType = (BfSizedArrayType*)argType;
|
auto argArrayType = (BfSizedArrayType*)argType;
|
||||||
BfTypedValue sizeValue(mModule->GetConstValue(argArrayType->mElementCount), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
|
BfTypedValue sizeValue(mModule->GetConstValue(argArrayType->mElementCount), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
|
||||||
auto sizedType = mModule->CreateConstExprValueType(sizeValue);
|
auto sizedType = mModule->CreateConstExprValueType(sizeValue);
|
||||||
InferGenericArgument(methodInstance, sizedType, wantArrayType->mElementCountSource, BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, sizedType, wantArrayType->mElementCountSource, BfIRValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,7 +481,7 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
{
|
{
|
||||||
auto wantArrayType = (BfSizedArrayType*)wantType;
|
auto wantArrayType = (BfSizedArrayType*)wantType;
|
||||||
auto argArrayType = (BfSizedArrayType*)argType;
|
auto argArrayType = (BfSizedArrayType*)argType;
|
||||||
InferGenericArgument(methodInstance, argArrayType->mElementType, wantArrayType->mElementType, BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, argArrayType->mElementType, wantArrayType->mElementType, BfIRValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,7 +490,7 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
if (((argType->IsDelegate()) || (argType->IsFunction())) &&
|
if (((argType->IsDelegate()) || (argType->IsFunction())) &&
|
||||||
(wantType->IsDelegate() == argType->IsDelegate()))
|
(wantType->IsDelegate() == argType->IsDelegate()))
|
||||||
{
|
{
|
||||||
if (!_AddToCheckedSet(argType, checkedTypeSet, alreadyChecked))
|
if (!_AddToCheckedSet(argType, mCheckedTypeSet, alreadyChecked))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
auto argInvokeMethod = mModule->GetRawMethodByName(argType->ToTypeInstance(), "Invoke");
|
auto argInvokeMethod = mModule->GetRawMethodByName(argType->ToTypeInstance(), "Invoke");
|
||||||
|
@ -501,9 +498,9 @@ bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfT
|
||||||
|
|
||||||
if ((argInvokeMethod != NULL) && (wantInvokeMethod != NULL) && (argInvokeMethod->GetParamCount() == wantInvokeMethod->GetParamCount()))
|
if ((argInvokeMethod != NULL) && (wantInvokeMethod != NULL) && (argInvokeMethod->GetParamCount() == wantInvokeMethod->GetParamCount()))
|
||||||
{
|
{
|
||||||
InferGenericArgument(methodInstance, argInvokeMethod->mReturnType, wantInvokeMethod->mReturnType, BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, argInvokeMethod->mReturnType, wantInvokeMethod->mReturnType, BfIRValue());
|
||||||
for (int argIdx = 0; argIdx < (int)argInvokeMethod->GetParamCount(); argIdx++)
|
for (int argIdx = 0; argIdx < (int)argInvokeMethod->GetParamCount(); argIdx++)
|
||||||
InferGenericArgument(methodInstance, argInvokeMethod->GetParamType(argIdx), wantInvokeMethod->GetParamType(argIdx), BfIRValue(), checkedTypeSet);
|
InferGenericArgument(methodInstance, argInvokeMethod->GetParamType(argIdx), wantInvokeMethod->GetParamType(argIdx), BfIRValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -515,6 +512,13 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
||||||
BfMethodInstance* newMethodInstance, BfTypeVector* genericArgumentsSubstitute,
|
BfMethodInstance* newMethodInstance, BfTypeVector* genericArgumentsSubstitute,
|
||||||
bool* outNewIsBetter, bool* outNewIsWorse, bool allowSpecializeFail)
|
bool* outNewIsBetter, bool* outNewIsWorse, bool allowSpecializeFail)
|
||||||
{
|
{
|
||||||
|
if (prevMethodInstance == newMethodInstance)
|
||||||
|
{
|
||||||
|
*outNewIsBetter = false;
|
||||||
|
*outNewIsWorse = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#define SET_BETTER_OR_WORSE(lhs, rhs) \
|
#define SET_BETTER_OR_WORSE(lhs, rhs) \
|
||||||
if ((!isBetter) && (lhs) && !(rhs)) isBetter = true; \
|
if ((!isBetter) && (lhs) && !(rhs)) isBetter = true; \
|
||||||
if ((!isWorse) && !(lhs) && (rhs)) isWorse = true;
|
if ((!isWorse) && !(lhs) && (rhs)) isWorse = true;
|
||||||
|
@ -551,12 +555,25 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool anyIsExtension = false;
|
||||||
|
|
||||||
int newImplicitParamCount = newMethodInstance->GetImplicitParamCount();
|
int newImplicitParamCount = newMethodInstance->GetImplicitParamCount();
|
||||||
if (newMethodInstance->mMethodDef->mHasAppend)
|
if (newMethodInstance->mMethodDef->mHasAppend)
|
||||||
newImplicitParamCount++;
|
newImplicitParamCount++;
|
||||||
|
if (newMethodInstance->mMethodDef->mMethodType == BfMethodType_Extension)
|
||||||
|
{
|
||||||
|
newImplicitParamCount++;
|
||||||
|
anyIsExtension = true;
|
||||||
|
}
|
||||||
|
|
||||||
int prevImplicitParamCount = prevMethodInstance->GetImplicitParamCount();
|
int prevImplicitParamCount = prevMethodInstance->GetImplicitParamCount();
|
||||||
if (prevMethodInstance->mMethodDef->mHasAppend)
|
if (prevMethodInstance->mMethodDef->mHasAppend)
|
||||||
prevImplicitParamCount++;
|
prevImplicitParamCount++;
|
||||||
|
if (prevMethodInstance->mMethodDef->mMethodType == BfMethodType_Extension)
|
||||||
|
{
|
||||||
|
prevImplicitParamCount++;
|
||||||
|
anyIsExtension = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool hadEnoughArgs = newMethodInstance->GetParamCount() - newImplicitParamCount < (int)mArguments.size();
|
bool hadEnoughArgs = newMethodInstance->GetParamCount() - newImplicitParamCount < (int)mArguments.size();
|
||||||
bool prevHadEnoughArgs = prevMethodInstance->GetParamCount() - prevImplicitParamCount < (int)mArguments.size();
|
bool prevHadEnoughArgs = prevMethodInstance->GetParamCount() - prevImplicitParamCount < (int)mArguments.size();
|
||||||
|
@ -570,22 +587,32 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
||||||
auto activeDef = mModule->GetActiveTypeDef();
|
auto activeDef = mModule->GetActiveTypeDef();
|
||||||
RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType == activeDef, prevMethodDef->mDeclaringType == activeDef);
|
RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType == activeDef, prevMethodDef->mDeclaringType == activeDef);
|
||||||
RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType->IsExtension(), prevMethodDef->mDeclaringType->IsExtension());
|
RETURN_BETTER_OR_WORSE(newMethodDef->mDeclaringType->IsExtension(), prevMethodDef->mDeclaringType->IsExtension());
|
||||||
|
|
||||||
if ((!isBetter) && (!isWorse))
|
if ((!isBetter) && (!isWorse))
|
||||||
{
|
{
|
||||||
bool betterByGenericParam = false;
|
bool betterByGenericParam = false;
|
||||||
bool worseByGenericParam = false;
|
bool worseByGenericParam = false;
|
||||||
|
|
||||||
for (argIdx = 0; argIdx < (int)mArguments.size(); argIdx++)
|
for (argIdx = anyIsExtension ? -1 : 0; argIdx < (int)mArguments.size(); argIdx++)
|
||||||
{
|
{
|
||||||
BfResolvedArg resolvedArg = mArguments[argIdx];;
|
BfTypedValue arg;
|
||||||
BfTypedValue arg = resolvedArg.mTypedValue;
|
BfResolvedArg* resolvedArg = NULL;
|
||||||
|
|
||||||
|
if (argIdx == -1)
|
||||||
|
{
|
||||||
|
arg = mTarget;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resolvedArg = &mArguments[argIdx];
|
||||||
|
arg = resolvedArg->mTypedValue;
|
||||||
|
}
|
||||||
|
|
||||||
int newArgIdx = argIdx + newImplicitParamCount;
|
int newArgIdx = argIdx + newImplicitParamCount;
|
||||||
int prevArgIdx = argIdx + prevImplicitParamCount;
|
int prevArgIdx = argIdx + prevImplicitParamCount;
|
||||||
|
|
||||||
bool wasGenericParam = newMethodInstance->WasGenericParam(newArgIdx);
|
bool wasGenericParam = (newArgIdx >= 0) && newMethodInstance->WasGenericParam(newArgIdx);
|
||||||
bool prevWasGenericParam = prevMethodInstance->WasGenericParam(prevArgIdx);
|
bool prevWasGenericParam = (prevArgIdx >= 0) && prevMethodInstance->WasGenericParam(prevArgIdx);
|
||||||
|
|
||||||
BfType* paramType = newMethodInstance->GetParamType(newArgIdx);
|
BfType* paramType = newMethodInstance->GetParamType(newArgIdx);
|
||||||
BfType* prevParamType = prevMethodInstance->GetParamType(prevArgIdx);
|
BfType* prevParamType = prevMethodInstance->GetParamType(prevArgIdx);
|
||||||
|
@ -637,7 +664,7 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
||||||
{
|
{
|
||||||
// The resolved argument type may actually match for both considered functions. IE:
|
// The resolved argument type may actually match for both considered functions. IE:
|
||||||
// Method(int8 val) and Method(int16 val) called with Method(0) will create arguments that match their param types
|
// Method(int8 val) and Method(int16 val) called with Method(0) will create arguments that match their param types
|
||||||
if ((IsType(arg, paramType)) && (prevParamType != resolvedArg.mBestBoundType))
|
if ((IsType(arg, paramType)) && ((resolvedArg == NULL) || (prevParamType != resolvedArg->mBestBoundType)))
|
||||||
isBetter = true;
|
isBetter = true;
|
||||||
else if ((IsType(arg, prevParamType)) && (!IsType(arg, paramType)))
|
else if ((IsType(arg, prevParamType)) && (!IsType(arg, paramType)))
|
||||||
isWorse = true;
|
isWorse = true;
|
||||||
|
@ -706,9 +733,9 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
||||||
isWorse = true;
|
isWorse = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newMethodInstance->GetParamKind(newArgIdx) == BfParamKind_Params)
|
if ((newArgIdx >= 0) && (newMethodInstance->GetParamKind(newArgIdx) == BfParamKind_Params))
|
||||||
usedExtendedForm = true;
|
usedExtendedForm = true;
|
||||||
if (prevMethodInstance->GetParamKind(prevArgIdx) == BfParamKind_Params)
|
if ((prevArgIdx >= 0) && (prevMethodInstance->GetParamKind(prevArgIdx) == BfParamKind_Params))
|
||||||
prevUsedExtendedForm = true;
|
prevUsedExtendedForm = true;
|
||||||
|
|
||||||
if ((usedExtendedForm) || (prevUsedExtendedForm))
|
if ((usedExtendedForm) || (prevUsedExtendedForm))
|
||||||
|
@ -1236,6 +1263,10 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BfGenericInferContext genericInferContext;
|
||||||
|
genericInferContext.mModule = mModule;
|
||||||
|
genericInferContext.mCheckMethodGenericArguments = &mCheckMethodGenericArguments;
|
||||||
|
|
||||||
HashSet<int> allowEmptyGenericSet;
|
HashSet<int> allowEmptyGenericSet;
|
||||||
BfAutoComplete* autoComplete = NULL;
|
BfAutoComplete* autoComplete = NULL;
|
||||||
if ((mModule->mCompiler->mResolvePassData != NULL) && (!isFailurePass))
|
if ((mModule->mCompiler->mResolvePassData != NULL) && (!isFailurePass))
|
||||||
|
@ -1279,8 +1310,9 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
||||||
for (auto& checkGenericArgRef : mCheckMethodGenericArguments)
|
for (auto& checkGenericArgRef : mCheckMethodGenericArguments)
|
||||||
checkGenericArgRef = NULL;
|
checkGenericArgRef = NULL;
|
||||||
|
|
||||||
mCheckMethodGenericArguments.resize(checkMethod->mGenericParams.size());
|
mCheckMethodGenericArguments.resize(checkMethod->mGenericParams.size());
|
||||||
mPrevArgValues.resize(checkMethod->mGenericParams.size());
|
|
||||||
|
//mPrevArgValues.resize(checkMethod->mGenericParams.size());
|
||||||
for (auto& genericArgRef : mCheckMethodGenericArguments)
|
for (auto& genericArgRef : mCheckMethodGenericArguments)
|
||||||
genericArgRef = NULL;
|
genericArgRef = NULL;
|
||||||
|
|
||||||
|
@ -1313,18 +1345,28 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
||||||
|
|
||||||
if (needInferGenericParams)
|
if (needInferGenericParams)
|
||||||
{
|
{
|
||||||
|
genericInferContext.mPrevArgValues.resize(checkMethod->mGenericParams.size());
|
||||||
|
|
||||||
int paramOfs = methodInstance->GetImplicitParamCount();
|
int paramOfs = methodInstance->GetImplicitParamCount();
|
||||||
int paramCount = methodInstance->GetParamCount();
|
int paramCount = methodInstance->GetParamCount();
|
||||||
|
|
||||||
|
int argIdx = 0;
|
||||||
|
int paramIdx = 0;
|
||||||
|
|
||||||
if (checkMethod->mHasAppend)
|
if (checkMethod->mHasAppend)
|
||||||
paramOfs++;
|
paramIdx++;
|
||||||
for (int argIdx = 0; argIdx < (int)mArguments.size(); argIdx++)
|
|
||||||
|
if (checkMethod->mMethodType == BfMethodType_Extension)
|
||||||
|
{
|
||||||
|
argIdx--;
|
||||||
|
paramOfs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; argIdx < (int)mArguments.size(); argIdx++)
|
||||||
{
|
{
|
||||||
if (argIdx >= (int)checkMethod->mParams.size())
|
|
||||||
break;
|
|
||||||
int paramIdx = argIdx + paramOfs;
|
|
||||||
if (paramIdx >= paramCount)
|
if (paramIdx >= paramCount)
|
||||||
break; // Possible for delegate 'params' type methods
|
break; // Possible for delegate 'params' type methods
|
||||||
auto wantType = methodInstance->GetParamType(argIdx + paramOfs);
|
auto wantType = methodInstance->GetParamType(paramIdx);
|
||||||
|
|
||||||
auto checkType = wantType;
|
auto checkType = wantType;
|
||||||
auto origCheckType = checkType;
|
auto origCheckType = checkType;
|
||||||
|
@ -1354,17 +1396,25 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
||||||
|
|
||||||
if (wantType->IsUnspecializedType())
|
if (wantType->IsUnspecializedType())
|
||||||
{
|
{
|
||||||
BfTypedValue argTypedValue = ResolveArgTypedValue(mArguments[argIdx], checkType, genericArgumentsSubstitute);
|
BfTypedValue argTypedValue;
|
||||||
|
if (argIdx == -1)
|
||||||
|
argTypedValue = mTarget;
|
||||||
|
else
|
||||||
|
argTypedValue = ResolveArgTypedValue(mArguments[argIdx], checkType, genericArgumentsSubstitute);
|
||||||
if (!argTypedValue.IsUntypedValue())
|
if (!argTypedValue.IsUntypedValue())
|
||||||
{
|
{
|
||||||
auto type = argTypedValue.mType;
|
auto type = argTypedValue.mType;
|
||||||
if (!argTypedValue)
|
if (!argTypedValue)
|
||||||
goto NoMatch;
|
goto NoMatch;
|
||||||
HashSet<BfType*> checkedTypeSet;
|
//HashSet<BfType*> checkedTypeSet;
|
||||||
if (!InferGenericArgument(methodInstance, type, wantType, argTypedValue.mValue, checkedTypeSet))
|
|
||||||
|
genericInferContext.mCheckedTypeSet.Clear();
|
||||||
|
if (!genericInferContext.InferGenericArgument(methodInstance, type, wantType, argTypedValue.mValue))
|
||||||
goto NoMatch;
|
goto NoMatch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
paramIdx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1414,6 +1464,9 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (checkMethod->mMethodType == BfMethodType_Extension)
|
||||||
|
argIdx--;
|
||||||
|
|
||||||
// Iterate through params
|
// Iterate through params
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -1425,7 +1478,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
||||||
|
|
||||||
bool isDeferredEval = false;
|
bool isDeferredEval = false;
|
||||||
|
|
||||||
if ((methodInstance->GetParamKind(paramIdx) == BfParamKind_Params) && (paramsElementType == NULL))
|
if ((argIdx >= 0) && (methodInstance->GetParamKind(paramIdx) == BfParamKind_Params) && (paramsElementType == NULL))
|
||||||
{
|
{
|
||||||
if (paramIdx >= (int) mArguments.size())
|
if (paramIdx >= (int) mArguments.size())
|
||||||
break; // No params
|
break; // No params
|
||||||
|
@ -1501,12 +1554,17 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
||||||
if (wantType->IsSelf())
|
if (wantType->IsSelf())
|
||||||
wantType = typeInstance;
|
wantType = typeInstance;
|
||||||
|
|
||||||
if ((mArguments[argIdx].mArgFlags & BfArgFlag_ParamsExpr) != 0)
|
if ((argIdx >= 0) && ((mArguments[argIdx].mArgFlags & BfArgFlag_ParamsExpr) != 0))
|
||||||
{
|
{
|
||||||
// We had a 'params' expression but this method didn't have a params slot in this parameter
|
// We had a 'params' expression but this method didn't have a params slot in this parameter
|
||||||
goto NoMatch;
|
goto NoMatch;
|
||||||
}
|
}
|
||||||
BfTypedValue argTypedValue = ResolveArgTypedValue(mArguments[argIdx], wantType, genericArgumentsSubstitute);
|
|
||||||
|
BfTypedValue argTypedValue;
|
||||||
|
if (argIdx == -1)
|
||||||
|
argTypedValue = mTarget;
|
||||||
|
else
|
||||||
|
argTypedValue = ResolveArgTypedValue(mArguments[argIdx], wantType, genericArgumentsSubstitute);
|
||||||
|
|
||||||
if (!argTypedValue.IsUntypedValue())
|
if (!argTypedValue.IsUntypedValue())
|
||||||
{
|
{
|
||||||
|
@ -1775,17 +1833,13 @@ bool BfMethodMatcher::IsType(BfTypedValue& typedVal, BfType* type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method checks all base classes before checking interfaces. Is that correct?
|
// This method checks all base classes before checking interfaces. Is that correct?
|
||||||
bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue target, bool isFailurePass)
|
bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue target, bool isFailurePass, bool forceOuterCheck)
|
||||||
{
|
{
|
||||||
auto curTypeInst = typeInstance;
|
auto curTypeInst = typeInstance;
|
||||||
auto curTypeDef = typeInstance->mTypeDef;
|
auto curTypeDef = typeInstance->mTypeDef;
|
||||||
|
|
||||||
int checkInterfaceIdx = 0;
|
int checkInterfaceIdx = 0;
|
||||||
|
|
||||||
bool allowExplicitInterface = curTypeInst->IsInterface() && mBypassVirtual;
|
|
||||||
auto activeTypeDef = mModule->GetActiveTypeDef();
|
|
||||||
bool isDelegate = typeInstance->IsDelegate();
|
|
||||||
|
|
||||||
bool targetIsBase = target.IsBase();
|
bool targetIsBase = target.IsBase();
|
||||||
bool checkExtensionBase = false;
|
bool checkExtensionBase = false;
|
||||||
if (targetIsBase)
|
if (targetIsBase)
|
||||||
|
@ -1805,16 +1859,26 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe
|
||||||
targetTypeInstance = target.mType->ToTypeInstance();
|
targetTypeInstance = target.mType->ToTypeInstance();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
curTypeDef->PopulateMemberSets();
|
bool doSearch = true;
|
||||||
|
if ((mMethodType == BfMethodType_Extension) && (!curTypeDef->mHasExtensionMethods))
|
||||||
|
doSearch = false;
|
||||||
|
|
||||||
BfMethodDef* nextMethodDef = NULL;
|
BfMethodDef* nextMethodDef = NULL;
|
||||||
BfMemberSetEntry* entry;
|
if (doSearch)
|
||||||
if (curTypeDef->mMethodSet.TryGetWith(mMethodName, &entry))
|
{
|
||||||
nextMethodDef = (BfMethodDef*)entry->mMemberDef;
|
curTypeDef->PopulateMemberSets();
|
||||||
|
BfMemberSetEntry* entry;
|
||||||
|
if (curTypeDef->mMethodSet.TryGetWith(mMethodName, &entry))
|
||||||
|
nextMethodDef = (BfMethodDef*)entry->mMemberDef;
|
||||||
|
}
|
||||||
BfProtectionCheckFlags protectionCheckFlags = BfProtectionCheckFlag_None;
|
BfProtectionCheckFlags protectionCheckFlags = BfProtectionCheckFlag_None;
|
||||||
while (nextMethodDef != NULL)
|
while (nextMethodDef != NULL)
|
||||||
{
|
{
|
||||||
|
bool allowExplicitInterface = curTypeInst->IsInterface() && mBypassVirtual;
|
||||||
|
auto activeTypeDef = mModule->GetActiveTypeDef();
|
||||||
|
bool isDelegate = typeInstance->IsDelegate();
|
||||||
|
|
||||||
auto checkMethod = nextMethodDef;
|
auto checkMethod = nextMethodDef;
|
||||||
nextMethodDef = nextMethodDef->mNextWithSameName;
|
nextMethodDef = nextMethodDef->mNextWithSameName;
|
||||||
|
|
||||||
|
@ -1914,9 +1978,10 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe
|
||||||
mMatchFailKind = matchFailKind;
|
mMatchFailKind = matchFailKind;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mBestMethodDef != NULL)
|
if ((mBestMethodDef != NULL) && (mMethodType != BfMethodType_Extension))
|
||||||
{
|
{
|
||||||
FlushAmbiguityError();
|
if (mAutoFlushAmbiguityErrors)
|
||||||
|
FlushAmbiguityError();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1953,7 +2018,8 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe
|
||||||
mBestMethodDef = mBackupMethodDef;
|
mBestMethodDef = mBackupMethodDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mBestMethodDef == NULL) && (!target) && (mAllowImplicitThis))
|
if (((mBestMethodDef == NULL) && (!target) && (mAllowImplicitThis)) ||
|
||||||
|
(forceOuterCheck))
|
||||||
{
|
{
|
||||||
// No explicit target - maybe this was a static call in the outer type?
|
// No explicit target - maybe this was a static call in the outer type?
|
||||||
auto outerType = mModule->GetOuterType(typeInstance);
|
auto outerType = mModule->GetOuterType(typeInstance);
|
||||||
|
@ -1961,7 +2027,8 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe
|
||||||
CheckOuterTypeStaticMethods(outerType, isFailurePass);
|
CheckOuterTypeStaticMethods(outerType, isFailurePass);
|
||||||
}
|
}
|
||||||
|
|
||||||
FlushAmbiguityError();
|
if (mAutoFlushAmbiguityErrors)
|
||||||
|
FlushAmbiguityError();
|
||||||
|
|
||||||
return mBestMethodDef != NULL;
|
return mBestMethodDef != NULL;
|
||||||
}
|
}
|
||||||
|
@ -1977,11 +2044,6 @@ void BfMethodMatcher::TryDevirtualizeCall(BfTypedValue target, BfTypedValue* ori
|
||||||
if (mModule->mBfIRBuilder->mIgnoreWrites)
|
if (mModule->mBfIRBuilder->mIgnoreWrites)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mBestMethodDef->mName == "Quab")
|
|
||||||
{
|
|
||||||
NOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mBestMethodTypeInstance->IsInterface())
|
if (mBestMethodTypeInstance->IsInterface())
|
||||||
{
|
{
|
||||||
mModule->PopulateType(mBestMethodTypeInstance, BfPopulateType_DataAndMethods);
|
mModule->PopulateType(mBestMethodTypeInstance, BfPopulateType_DataAndMethods);
|
||||||
|
@ -2165,7 +2227,7 @@ void BfMethodMatcher::CheckOuterTypeStaticMethods(BfTypeInstance* typeInstance,
|
||||||
// These can only be invoked when the target itself is the interface
|
// These can only be invoked when the target itself is the interface
|
||||||
if (checkMethod->mExplicitInterface != NULL)
|
if (checkMethod->mExplicitInterface != NULL)
|
||||||
continue;
|
continue;
|
||||||
if ((checkMethod->mMethodType != BfMethodType_Normal) || (!checkMethod->mIsStatic))
|
if ((checkMethod->mMethodType != mMethodType) || (!checkMethod->mIsStatic))
|
||||||
continue;
|
continue;
|
||||||
if (checkMethod->mName != mMethodName)
|
if (checkMethod->mName != mMethodName)
|
||||||
continue;
|
continue;
|
||||||
|
@ -5240,7 +5302,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
skipMutCheck = true;
|
skipMutCheck = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PushThis(targetSrc, target, moduleMethodInstance.mMethodInstance, irArgs, skipMutCheck);
|
if (methodDef->mMethodType == BfMethodType_Extension)
|
||||||
|
PushArg(target, irArgs);
|
||||||
|
else
|
||||||
|
PushThis(targetSrc, target, moduleMethodInstance.mMethodInstance, irArgs, skipMutCheck);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((target) && (target.mType->IsFunction()))
|
else if ((target) && (target.mType->IsFunction()))
|
||||||
|
@ -5251,6 +5316,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
auto funcPtrType = mModule->mBfIRBuilder->GetPointerTo(funcType);
|
auto funcPtrType = mModule->mBfIRBuilder->GetPointerTo(funcType);
|
||||||
moduleMethodInstance.mFunc = mModule->mBfIRBuilder->CreateIntToPtr(target.mValue, funcPtrType);
|
moduleMethodInstance.mFunc = mModule->mBfIRBuilder->CreateIntToPtr(target.mValue, funcPtrType);
|
||||||
}
|
}
|
||||||
|
else if (methodDef->mMethodType == BfMethodType_Extension)
|
||||||
|
{
|
||||||
|
// Handled in args
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mModule->CheckStaticAccess(methodInstance->mMethodInstanceGroup->mOwner);
|
mModule->CheckStaticAccess(methodInstance->mMethodInstanceGroup->mOwner);
|
||||||
|
@ -5463,14 +5532,25 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
|
|
||||||
BfAstNode* arg = NULL;
|
BfAstNode* arg = NULL;
|
||||||
bool hadMissingArg = false;
|
bool hadMissingArg = false;
|
||||||
if (argIdx < (int)argValues.size())
|
|
||||||
|
int argExprIdx = argIdx;
|
||||||
|
if ((methodDef->mMethodType == BfMethodType_Extension))
|
||||||
{
|
{
|
||||||
arg = argValues[argIdx].mExpression;
|
argExprIdx--;
|
||||||
if ((arg == NULL) && (argValues[0].mExpression != NULL))
|
if (argExprIdx == -1)
|
||||||
hadMissingArg = true;
|
arg = targetSrc;
|
||||||
|
}
|
||||||
|
if (argExprIdx >= 0)
|
||||||
|
{
|
||||||
|
if (argExprIdx < (int)argValues.size())
|
||||||
|
{
|
||||||
|
arg = argValues[argExprIdx].mExpression;
|
||||||
|
if ((arg == NULL) && (argValues[argExprIdx].mExpression != NULL))
|
||||||
|
hadMissingArg = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hadMissingArg = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
hadMissingArg = true;
|
|
||||||
|
|
||||||
BfTypedValue argValue;
|
BfTypedValue argValue;
|
||||||
|
|
||||||
|
@ -5588,12 +5668,15 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
argValue = argValues[argIdx].mTypedValue;
|
if (argExprIdx == -1)
|
||||||
|
argValue = target;
|
||||||
|
else
|
||||||
|
argValue = argValues[argExprIdx].mTypedValue;
|
||||||
|
|
||||||
if ((argValue.IsParams()) && (!isDirectPass))
|
if ((argValue.IsParams()) && (!isDirectPass))
|
||||||
{
|
{
|
||||||
BfAstNode* refNode = argValues[argIdx].mExpression;
|
BfAstNode* refNode = arg;
|
||||||
if (auto unaryOperatorExpr = BfNodeDynCast<BfUnaryOperatorExpression>(refNode))
|
if (auto unaryOperatorExpr = BfNodeDynCast<BfUnaryOperatorExpression>(refNode))
|
||||||
refNode = unaryOperatorExpr->mOpToken;
|
refNode = unaryOperatorExpr->mOpToken;
|
||||||
mModule->Warn(0, "Unused 'params' expression", refNode);
|
mModule->Warn(0, "Unused 'params' expression", refNode);
|
||||||
|
@ -5606,7 +5689,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
SetMethodElementType(expr);
|
SetMethodElementType(expr);
|
||||||
|
|
||||||
if (!argValue)
|
if (!argValue)
|
||||||
argValue = mModule->CreateValueFromExpression(BfNodeDynCast<BfExpression>(argValues[argIdx].mExpression), wantType, BfEvalExprFlags_NoCast);
|
argValue = mModule->CreateValueFromExpression(BfNodeDynCast<BfExpression>(arg), wantType, BfEvalExprFlags_NoCast);
|
||||||
|
|
||||||
// Add any implicit captures now
|
// Add any implicit captures now
|
||||||
auto methodRefType = (BfMethodRefType*)wantType;
|
auto methodRefType = (BfMethodRefType*)wantType;
|
||||||
|
@ -5615,7 +5698,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
for (int dataIdx = 0; dataIdx < methodRefType->GetCaptureDataCount(); dataIdx++)
|
for (int dataIdx = 0; dataIdx < methodRefType->GetCaptureDataCount(); dataIdx++)
|
||||||
{
|
{
|
||||||
int paramIdx = methodRefType->GetParamIdxFromDataIdx(dataIdx);
|
int paramIdx = methodRefType->GetParamIdxFromDataIdx(dataIdx);
|
||||||
auto lookupVal = DoImplicitArgCapture(argValues[argIdx].mExpression, useMethodInstance, paramIdx, failed, BfImplicitParamKind_General, argValue);
|
auto lookupVal = DoImplicitArgCapture(arg, useMethodInstance, paramIdx, failed, BfImplicitParamKind_General, argValue);
|
||||||
if (lookupVal)
|
if (lookupVal)
|
||||||
{
|
{
|
||||||
if (methodRefType->WantsDataPassedAsSplat(dataIdx))
|
if (methodRefType->WantsDataPassedAsSplat(dataIdx))
|
||||||
|
@ -5633,14 +5716,14 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
argIdx++;
|
argIdx++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else if (argExprIdx >= 0)
|
||||||
{
|
{
|
||||||
BfParamKind paramKind = BfParamKind_Normal;
|
BfParamKind paramKind = BfParamKind_Normal;
|
||||||
if (paramIdx < methodInstance->GetParamCount())
|
if (paramIdx < methodInstance->GetParamCount())
|
||||||
paramKind = methodInstance->GetParamKind(paramIdx);
|
paramKind = methodInstance->GetParamKind(paramIdx);
|
||||||
|
|
||||||
argValues[argIdx].mExpectedType = wantType;
|
argValues[argExprIdx].mExpectedType = wantType;
|
||||||
argValue = ResolveArgValue(argValues[argIdx], wantType, NULL, paramKind);
|
argValue = ResolveArgValue(argValues[argExprIdx], wantType, NULL, paramKind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6449,6 +6532,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
||||||
|
|
||||||
SetAndRestoreValue<bool> prevNoBind(mNoBind, mNoBind || isUnboundCall);
|
SetAndRestoreValue<bool> prevNoBind(mNoBind, mNoBind || isUnboundCall);
|
||||||
|
|
||||||
|
bool wantsExtensionCheck = target;
|
||||||
auto targetType = target.mType;
|
auto targetType = target.mType;
|
||||||
BfTypeDef* curTypeDef = NULL;
|
BfTypeDef* curTypeDef = NULL;
|
||||||
BfTypeInstance* targetTypeInst = NULL;
|
BfTypeInstance* targetTypeInst = NULL;
|
||||||
|
@ -6544,10 +6628,12 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
||||||
BfTypeInstance* curTypeInst = targetTypeInst;
|
BfTypeInstance* curTypeInst = targetTypeInst;
|
||||||
|
|
||||||
BfMethodMatcher methodMatcher(targetSrc, mModule, methodName, argValues.mResolvedArgs, methodGenericArguments);
|
BfMethodMatcher methodMatcher(targetSrc, mModule, methodName, argValues.mResolvedArgs, methodGenericArguments);
|
||||||
|
methodMatcher.mTarget = target;
|
||||||
methodMatcher.mCheckedKind = checkedKind;
|
methodMatcher.mCheckedKind = checkedKind;
|
||||||
methodMatcher.mAllowImplicitThis = allowImplicitThis;
|
methodMatcher.mAllowImplicitThis = allowImplicitThis;
|
||||||
methodMatcher.mAllowStatic = !target.mValue;
|
methodMatcher.mAllowStatic = !target.mValue;
|
||||||
methodMatcher.mAllowNonStatic = !methodMatcher.mAllowStatic;
|
methodMatcher.mAllowNonStatic = !methodMatcher.mAllowStatic;
|
||||||
|
methodMatcher.mAutoFlushAmbiguityErrors = !wantsExtensionCheck;
|
||||||
if (allowImplicitThis)
|
if (allowImplicitThis)
|
||||||
{
|
{
|
||||||
if (mModule->mCurMethodState == NULL)
|
if (mModule->mCurMethodState == NULL)
|
||||||
|
@ -7051,50 +7137,77 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
||||||
|
|
||||||
return structInst;
|
return structInst;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For for extensions in current type
|
||||||
|
if (wantsExtensionCheck)
|
||||||
|
{
|
||||||
|
auto checkTypeInst = mModule->mCurTypeInstance;
|
||||||
|
methodMatcher.mMethodType = BfMethodType_Extension;
|
||||||
|
methodMatcher.CheckType(checkTypeInst, BfTypedValue(), false, true);
|
||||||
|
if (methodMatcher.mBestMethodDef != NULL)
|
||||||
|
{
|
||||||
|
isFailurePass = false;
|
||||||
|
curTypeInst = methodMatcher.mBestMethodTypeInstance;
|
||||||
|
methodDef = methodMatcher.mBestMethodDef;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((methodDef == NULL) && (!target) && (mModule->mContext->mCurTypeState != NULL))
|
// Look in globals. Always check for extension methods.
|
||||||
{
|
if ((methodDef == NULL) || (wantsExtensionCheck))
|
||||||
//BF_ASSERT(mModule->mCurTypeInstance == mModule->mContext->mCurTypeState->mTypeInstance);
|
{
|
||||||
|
if (mModule->mContext->mCurTypeState != NULL)
|
||||||
BfGlobalLookup globalLookup;
|
|
||||||
globalLookup.mKind = BfGlobalLookup::Kind_Method;
|
|
||||||
globalLookup.mName = methodName;
|
|
||||||
mModule->PopulateGlobalContainersList(globalLookup);
|
|
||||||
for (auto& globalContainer : mModule->mContext->mCurTypeState->mGlobalContainers)
|
|
||||||
{
|
{
|
||||||
if (globalContainer.mTypeInst == NULL)
|
BfGlobalLookup globalLookup;
|
||||||
continue;
|
globalLookup.mKind = BfGlobalLookup::Kind_Method;
|
||||||
methodMatcher.CheckType(globalContainer.mTypeInst, BfTypedValue(), false);
|
globalLookup.mName = methodName;
|
||||||
if (methodMatcher.mBestMethodDef != NULL)
|
mModule->PopulateGlobalContainersList(globalLookup);
|
||||||
|
for (auto& globalContainer : mModule->mContext->mCurTypeState->mGlobalContainers)
|
||||||
{
|
{
|
||||||
isFailurePass = false;
|
if (globalContainer.mTypeInst == NULL)
|
||||||
curTypeInst = methodMatcher.mBestMethodTypeInstance;
|
continue;
|
||||||
methodDef = methodMatcher.mBestMethodDef;
|
methodMatcher.mMethodType = wantsExtensionCheck ? BfMethodType_Extension : BfMethodType_Normal;
|
||||||
break;
|
methodMatcher.CheckType(globalContainer.mTypeInst, BfTypedValue(), false);
|
||||||
}
|
|
||||||
}
|
if (methodMatcher.mBestMethodDef != NULL)
|
||||||
|
|
||||||
if (methodDef == NULL)
|
|
||||||
{
|
|
||||||
BfStaticSearch* staticSearch = mModule->GetStaticSearch();
|
|
||||||
if (staticSearch != NULL)
|
|
||||||
{
|
|
||||||
for (auto typeInst : staticSearch->mStaticTypes)
|
|
||||||
{
|
{
|
||||||
methodMatcher.CheckType(typeInst, BfTypedValue(), false);
|
isFailurePass = false;
|
||||||
if (methodMatcher.mBestMethodDef != NULL)
|
curTypeInst = methodMatcher.mBestMethodTypeInstance;
|
||||||
{
|
methodDef = methodMatcher.mBestMethodDef;
|
||||||
isFailurePass = false;
|
// Extension check must check all possible extensions, no early bailout
|
||||||
curTypeInst = methodMatcher.mBestMethodTypeInstance;
|
if (!wantsExtensionCheck)
|
||||||
methodDef = methodMatcher.mBestMethodDef;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look in static search. Always check for extension methods.
|
||||||
|
if ((methodDef == NULL) || (wantsExtensionCheck))
|
||||||
|
{
|
||||||
|
BfStaticSearch* staticSearch = mModule->GetStaticSearch();
|
||||||
|
if (staticSearch != NULL)
|
||||||
|
{
|
||||||
|
for (auto typeInst : staticSearch->mStaticTypes)
|
||||||
|
{
|
||||||
|
methodMatcher.mMethodType = wantsExtensionCheck ? BfMethodType_Extension : BfMethodType_Normal;
|
||||||
|
methodMatcher.CheckType(typeInst, BfTypedValue(), false);
|
||||||
|
if (methodMatcher.mBestMethodDef != NULL)
|
||||||
|
{
|
||||||
|
isFailurePass = false;
|
||||||
|
curTypeInst = methodMatcher.mBestMethodTypeInstance;
|
||||||
|
methodDef = methodMatcher.mBestMethodDef;
|
||||||
|
// Extension check must check all possible extensions, no early bailout
|
||||||
|
if (!wantsExtensionCheck)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This will flush out any new ambiguity errors from extension methods
|
||||||
|
methodMatcher.FlushAmbiguityError();
|
||||||
|
|
||||||
if (methodDef == NULL)
|
if (methodDef == NULL)
|
||||||
{
|
{
|
||||||
FinishDeferredEvals(argValues.mResolvedArgs);
|
FinishDeferredEvals(argValues.mResolvedArgs);
|
||||||
|
@ -7205,6 +7318,14 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
||||||
else
|
else
|
||||||
MakeBaseConcrete(target);
|
MakeBaseConcrete(target);
|
||||||
|
|
||||||
|
if (methodDef->mMethodType == BfMethodType_Extension)
|
||||||
|
{
|
||||||
|
auto thisType = moduleMethodInstance.mMethodInstance->GetParamType(0);
|
||||||
|
curTypeInst = thisType->ToTypeInstance();
|
||||||
|
if (curTypeInst == NULL)
|
||||||
|
curTypeInst = mModule->mContext->mBfObjectType;
|
||||||
|
}
|
||||||
|
|
||||||
BfTypedValue callTarget;
|
BfTypedValue callTarget;
|
||||||
if (isSkipCall)
|
if (isSkipCall)
|
||||||
{
|
{
|
||||||
|
@ -12741,6 +12862,9 @@ void BfExprEvaluator::CheckLocalMethods(BfAstNode* targetSrc, BfTypeInstance* ty
|
||||||
|
|
||||||
void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, bool allowImplicitThis, const StringImpl& name, const BfSizedArray<BfExpression*>& arguments, BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArgs)
|
void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, bool allowImplicitThis, const StringImpl& name, const BfSizedArray<BfExpression*>& arguments, BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArgs)
|
||||||
{
|
{
|
||||||
|
if (mModule->mCurMethodState == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
BfAstNode* origTargetSrc = targetSrc;
|
BfAstNode* origTargetSrc = targetSrc;
|
||||||
BfScopedInvocationTarget* scopedInvocationTarget = NULL;
|
BfScopedInvocationTarget* scopedInvocationTarget = NULL;
|
||||||
|
|
||||||
|
@ -13041,7 +13165,7 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo
|
||||||
//auto prevDebugLoc = mModule->mBfIRBuilder->getCurrentDebugLocation();
|
//auto prevDebugLoc = mModule->mBfIRBuilder->getCurrentDebugLocation();
|
||||||
// This is so when we debug we can hit a steppoint on the inlined "call line"
|
// This is so when we debug we can hit a steppoint on the inlined "call line"
|
||||||
mModule->EmitEnsureInstructionAt();
|
mModule->EmitEnsureInstructionAt();
|
||||||
|
|
||||||
auto rootMethodState = mModule->mCurMethodState->GetRootMethodState();
|
auto rootMethodState = mModule->mCurMethodState->GetRootMethodState();
|
||||||
|
|
||||||
BfMixinState* mixinState = rootMethodState->mMixinStates.Alloc();
|
BfMixinState* mixinState = rootMethodState->mMixinStates.Alloc();
|
||||||
|
|
|
@ -101,6 +101,18 @@ public:
|
||||||
void HandleFixits(BfModule* module);
|
void HandleFixits(BfModule* module);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BfGenericInferContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HashSet<BfType*> mCheckedTypeSet;
|
||||||
|
BfModule* mModule;
|
||||||
|
BfTypeVector* mCheckMethodGenericArguments;
|
||||||
|
SizedArray<BfIRValue, 4> mPrevArgValues;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool InferGenericArgument(BfMethodInstance* methodInstance, BfType* argType, BfType* wantType, BfIRValue argValue);
|
||||||
|
};
|
||||||
|
|
||||||
class BfMethodMatcher
|
class BfMethodMatcher
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -119,9 +131,10 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BfAstNode* mTargetSrc;
|
BfAstNode* mTargetSrc;
|
||||||
|
BfTypedValue mTarget;
|
||||||
BfModule* mModule;
|
BfModule* mModule;
|
||||||
BfTypeDef* mActiveTypeDef;
|
BfTypeDef* mActiveTypeDef;
|
||||||
String mMethodName;
|
String mMethodName;
|
||||||
BfMethodInstance* mInterfaceMethodInstance;
|
BfMethodInstance* mInterfaceMethodInstance;
|
||||||
SizedArrayImpl<BfResolvedArg>& mArguments;
|
SizedArrayImpl<BfResolvedArg>& mArguments;
|
||||||
BfMethodType mMethodType;
|
BfMethodType mMethodType;
|
||||||
|
@ -134,13 +147,12 @@ public:
|
||||||
bool mAllowStatic;
|
bool mAllowStatic;
|
||||||
bool mAllowNonStatic;
|
bool mAllowNonStatic;
|
||||||
bool mSkipImplicitParams;
|
bool mSkipImplicitParams;
|
||||||
int mMethodCheckCount;
|
bool mAutoFlushAmbiguityErrors;
|
||||||
int mInferGenericProgressIdx;
|
int mMethodCheckCount;
|
||||||
BfType* mExplicitInterfaceCheck;
|
BfType* mExplicitInterfaceCheck;
|
||||||
MatchFailKind mMatchFailKind;
|
MatchFailKind mMatchFailKind;
|
||||||
|
|
||||||
BfTypeVector mCheckMethodGenericArguments;
|
BfTypeVector mCheckMethodGenericArguments;
|
||||||
SizedArray<BfIRValue, 4> mPrevArgValues;
|
|
||||||
|
|
||||||
BfType* mSelfType; // Only when matching interfaces when 'Self' needs to refer back to the implementing type
|
BfType* mSelfType; // Only when matching interfaces when 'Self' needs to refer back to the implementing type
|
||||||
BfMethodDef* mBackupMethodDef;
|
BfMethodDef* mBackupMethodDef;
|
||||||
|
@ -153,11 +165,10 @@ public:
|
||||||
BfTypeVector mBestMethodGenericArguments;
|
BfTypeVector mBestMethodGenericArguments;
|
||||||
BfTypeVector mExplicitMethodGenericArguments;
|
BfTypeVector mExplicitMethodGenericArguments;
|
||||||
bool mFakeConcreteTarget;
|
bool mFakeConcreteTarget;
|
||||||
Array<BfAmbiguousEntry> mAmbiguousEntries;
|
Array<BfAmbiguousEntry> mAmbiguousEntries;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BfTypedValue ResolveArgTypedValue(BfResolvedArg& resolvedArg, BfType* checkType, BfTypeVector* genericArgumentsSubstitute);
|
BfTypedValue ResolveArgTypedValue(BfResolvedArg& resolvedArg, BfType* checkType, BfTypeVector* genericArgumentsSubstitute);
|
||||||
bool InferGenericArgument(BfMethodInstance* methodInstance, BfType* argType, BfType* wantType, BfIRValue argValue, HashSet<BfType*>& checkedTypeSet);
|
|
||||||
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,
|
||||||
|
@ -170,7 +181,7 @@ public:
|
||||||
BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* interfaceMethodInstance, SizedArrayImpl<BfResolvedArg>& arguments, BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArguments = NULL);
|
BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* interfaceMethodInstance, SizedArrayImpl<BfResolvedArg>& arguments, BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArguments = NULL);
|
||||||
void Init(/*SizedArrayImpl<BfResolvedArg>& arguments, */BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArguments);
|
void Init(/*SizedArrayImpl<BfResolvedArg>& arguments, */BfSizedArray<ASTREF(BfTypeReference*)>* methodGenericArguments);
|
||||||
bool IsMemberAccessible(BfTypeInstance* typeInst, BfTypeDef* declaringType);
|
bool IsMemberAccessible(BfTypeInstance* typeInst, BfTypeDef* declaringType);
|
||||||
bool CheckType(BfTypeInstance* typeInstance, BfTypedValue target, bool isFailurePass);
|
bool CheckType(BfTypeInstance* typeInstance, BfTypedValue target, bool isFailurePass, bool forceOuterCheck = false);
|
||||||
void CheckOuterTypeStaticMethods(BfTypeInstance* typeInstance, bool isFailurePass);
|
void CheckOuterTypeStaticMethods(BfTypeInstance* typeInstance, bool isFailurePass);
|
||||||
bool WantsCheckMethod(BfProtectionCheckFlags& flags, BfTypeInstance* startTypeInstance, BfTypeInstance* checkTypeInstance, BfMethodDef* methodDef);
|
bool WantsCheckMethod(BfProtectionCheckFlags& flags, BfTypeInstance* startTypeInstance, BfTypeInstance* checkTypeInstance, BfMethodDef* methodDef);
|
||||||
bool CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInstance* typeInstance, BfMethodDef* checkMethod, bool isFailurePass);
|
bool CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInstance* typeInstance, BfMethodDef* checkMethod, bool isFailurePass);
|
||||||
|
|
|
@ -2290,6 +2290,7 @@ void BfPrinter::QueueMethodDeclaration(BfMethodDeclaration* methodDeclaration)
|
||||||
}
|
}
|
||||||
|
|
||||||
QueueVisitChild(methodDeclaration->mOpenParen);
|
QueueVisitChild(methodDeclaration->mOpenParen);
|
||||||
|
QueueVisitChild(methodDeclaration->mThisToken);
|
||||||
for (int i = 0; i < (int) methodDeclaration->mParams.size(); i++)
|
for (int i = 0; i < (int) methodDeclaration->mParams.size(); i++)
|
||||||
{
|
{
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
|
|
|
@ -2618,6 +2618,7 @@ void BfSystem::InjectNewRevision(BfTypeDef* typeDef)
|
||||||
typeDef->mIsStatic = nextTypeDef->mIsStatic;
|
typeDef->mIsStatic = nextTypeDef->mIsStatic;
|
||||||
typeDef->mHasAppendCtor = nextTypeDef->mHasAppendCtor;
|
typeDef->mHasAppendCtor = nextTypeDef->mHasAppendCtor;
|
||||||
typeDef->mHasOverrideMethods = nextTypeDef->mHasOverrideMethods;
|
typeDef->mHasOverrideMethods = nextTypeDef->mHasOverrideMethods;
|
||||||
|
typeDef->mHasExtensionMethods = nextTypeDef->mHasExtensionMethods;
|
||||||
typeDef->mIsOpaque = nextTypeDef->mIsOpaque;
|
typeDef->mIsOpaque = nextTypeDef->mIsOpaque;
|
||||||
|
|
||||||
typeDef->mDupDetectedRevision = nextTypeDef->mDupDetectedRevision;
|
typeDef->mDupDetectedRevision = nextTypeDef->mDupDetectedRevision;
|
||||||
|
@ -2718,6 +2719,7 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co
|
||||||
typeDef->mIsConcrete = partialTypeDef->mIsConcrete;
|
typeDef->mIsConcrete = partialTypeDef->mIsConcrete;
|
||||||
typeDef->mIsStatic = partialTypeDef->mIsStatic;
|
typeDef->mIsStatic = partialTypeDef->mIsStatic;
|
||||||
typeDef->mHasAppendCtor = partialTypeDef->mHasAppendCtor;
|
typeDef->mHasAppendCtor = partialTypeDef->mHasAppendCtor;
|
||||||
|
typeDef->mHasExtensionMethods = partialTypeDef->mHasExtensionMethods;
|
||||||
typeDef->mHasOverrideMethods = partialTypeDef->mHasOverrideMethods;
|
typeDef->mHasOverrideMethods = partialTypeDef->mHasOverrideMethods;
|
||||||
|
|
||||||
for (auto generic : partialTypeDef->mGenericParamDefs)
|
for (auto generic : partialTypeDef->mGenericParamDefs)
|
||||||
|
@ -2750,6 +2752,7 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co
|
||||||
typeDef->mIsConcrete |= partialTypeDef->mIsConcrete;
|
typeDef->mIsConcrete |= partialTypeDef->mIsConcrete;
|
||||||
typeDef->mIsStatic |= partialTypeDef->mIsStatic;
|
typeDef->mIsStatic |= partialTypeDef->mIsStatic;
|
||||||
typeDef->mHasAppendCtor |= partialTypeDef->mHasAppendCtor;
|
typeDef->mHasAppendCtor |= partialTypeDef->mHasAppendCtor;
|
||||||
|
typeDef->mHasExtensionMethods |= partialTypeDef->mHasExtensionMethods;
|
||||||
typeDef->mHasOverrideMethods |= partialTypeDef->mHasOverrideMethods;
|
typeDef->mHasOverrideMethods |= partialTypeDef->mHasOverrideMethods;
|
||||||
typeDef->mProtection = BF_MIN(typeDef->mProtection, partialTypeDef->mProtection);
|
typeDef->mProtection = BF_MIN(typeDef->mProtection, partialTypeDef->mProtection);
|
||||||
|
|
||||||
|
|
|
@ -631,7 +631,8 @@ enum BfMethodType : uint8
|
||||||
BfMethodType_CtorClear,
|
BfMethodType_CtorClear,
|
||||||
BfMethodType_Dtor,
|
BfMethodType_Dtor,
|
||||||
BfMethodType_Operator,
|
BfMethodType_Operator,
|
||||||
BfMethodType_Mixin
|
BfMethodType_Mixin,
|
||||||
|
BfMethodType_Extension
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BfCallingConvention : uint8
|
enum BfCallingConvention : uint8
|
||||||
|
@ -898,7 +899,8 @@ public:
|
||||||
bool mIsConcrete;
|
bool mIsConcrete;
|
||||||
bool mIsStatic;
|
bool mIsStatic;
|
||||||
bool mHasAppendCtor;
|
bool mHasAppendCtor;
|
||||||
bool mHasOverrideMethods;
|
bool mHasExtensionMethods;
|
||||||
|
bool mHasOverrideMethods;
|
||||||
bool mIsOpaque;
|
bool mIsOpaque;
|
||||||
bool mIsNextRevision;
|
bool mIsNextRevision;
|
||||||
|
|
||||||
|
@ -934,6 +936,7 @@ public:
|
||||||
mIsClosure = false;
|
mIsClosure = false;
|
||||||
mIsStatic = false;
|
mIsStatic = false;
|
||||||
mHasAppendCtor = false;
|
mHasAppendCtor = false;
|
||||||
|
mHasExtensionMethods = false;
|
||||||
mHasOverrideMethods = false;
|
mHasOverrideMethods = false;
|
||||||
mIsOpaque = false;
|
mIsOpaque = false;
|
||||||
mPartialUsed = false;
|
mPartialUsed = false;
|
||||||
|
|
59
IDEHelper/Tests/src/ExtensionMethods.bf
Normal file
59
IDEHelper/Tests/src/ExtensionMethods.bf
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
using static Tests.ExtensionMethods.ClassB;
|
||||||
|
|
||||||
|
namespace Tests
|
||||||
|
{
|
||||||
|
class ExtensionMethods
|
||||||
|
{
|
||||||
|
public static int Remove(this String str, float val, float val2)
|
||||||
|
{
|
||||||
|
return 123;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClassA
|
||||||
|
{
|
||||||
|
public static void Test()
|
||||||
|
{
|
||||||
|
Test.Assert("Abc".Remove(1.2f, 2.3f) == 123);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClassB
|
||||||
|
{
|
||||||
|
public static int Flop(this String str, int a)
|
||||||
|
{
|
||||||
|
return a + 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public static void TestBasics()
|
||||||
|
{
|
||||||
|
ClassA.Test();
|
||||||
|
|
||||||
|
Test.Assert("Test".Flop(234) == 1234);
|
||||||
|
|
||||||
|
List<int> iList = scope .();
|
||||||
|
iList.Add(3);
|
||||||
|
iList.Add(20);
|
||||||
|
iList.Add(100);
|
||||||
|
|
||||||
|
Test.Assert(iList.Total() == 123);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
public static T Total<T>(this List<T> list) where T : IOpAddable
|
||||||
|
{
|
||||||
|
T total = default;
|
||||||
|
for (let val in list)
|
||||||
|
total += val;
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue