mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-14 14:24:10 +02:00
Fixed extension method and methodRef infererence issues
This commit is contained in:
parent
efa44caee0
commit
3b9558a508
3 changed files with 122 additions and 48 deletions
|
@ -311,10 +311,10 @@ bool BfGenericInferContext::InferGenericArgument(BfMethodInstance* methodInstanc
|
||||||
checkArgType = checkTypeInst->mBaseType;
|
checkArgType = checkTypeInst->mBaseType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(*mCheckMethodGenericArguments)[wantGenericParam->mGenericParamIdx] = argType;
|
|
||||||
}
|
}
|
||||||
|
if ((*mCheckMethodGenericArguments)[wantGenericParam->mGenericParamIdx] == NULL)
|
||||||
|
mInferredCount++;
|
||||||
(*mCheckMethodGenericArguments)[wantGenericParam->mGenericParamIdx] = argType;
|
(*mCheckMethodGenericArguments)[wantGenericParam->mGenericParamIdx] = argType;
|
||||||
mPrevArgValues[wantGenericParam->mGenericParamIdx] = argValue;
|
mPrevArgValues[wantGenericParam->mGenericParamIdx] = argValue;
|
||||||
};
|
};
|
||||||
|
@ -590,9 +590,9 @@ int BfMethodMatcher::GetMostSpecificType(BfType* lhs, BfType* rhs)
|
||||||
if (rhs->IsGenericParam())
|
if (rhs->IsGenericParam())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (lhs->IsUnspecializedType())
|
if ((lhs->IsUnspecializedType()) && (lhs->IsGenericTypeInstance()))
|
||||||
{
|
{
|
||||||
if (!rhs->IsUnspecializedType())
|
if ((!rhs->IsUnspecializedType()) || (!rhs->IsGenericTypeInstance()))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
auto lhsTypeInst = lhs->ToTypeInstance();
|
auto lhsTypeInst = lhs->ToTypeInstance();
|
||||||
|
@ -603,7 +603,7 @@ int BfMethodMatcher::GetMostSpecificType(BfType* lhs, BfType* rhs)
|
||||||
|
|
||||||
bool hadLHSMoreSpecific = false;
|
bool hadLHSMoreSpecific = false;
|
||||||
bool hadRHSMoreSpecific = false;
|
bool hadRHSMoreSpecific = false;
|
||||||
|
|
||||||
for (int generigArgIdx = 0; generigArgIdx < (int)lhsTypeInst->mGenericTypeInfo->mTypeGenericArguments.size(); generigArgIdx++)
|
for (int generigArgIdx = 0; generigArgIdx < (int)lhsTypeInst->mGenericTypeInfo->mTypeGenericArguments.size(); generigArgIdx++)
|
||||||
{
|
{
|
||||||
int argMoreSpecific = GetMostSpecificType(lhsTypeInst->mGenericTypeInfo->mTypeGenericArguments[generigArgIdx],
|
int argMoreSpecific = GetMostSpecificType(lhsTypeInst->mGenericTypeInfo->mTypeGenericArguments[generigArgIdx],
|
||||||
|
@ -1485,25 +1485,35 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
||||||
|
|
||||||
int paramOfs = methodInstance->GetImplicitParamCount();
|
int paramOfs = methodInstance->GetImplicitParamCount();
|
||||||
int paramCount = methodInstance->GetParamCount();
|
int paramCount = methodInstance->GetParamCount();
|
||||||
|
SizedArray<int, 8> deferredArgs;
|
||||||
|
|
||||||
int argIdx = 0;
|
int argIdx = 0;
|
||||||
int paramIdx = 0;
|
int paramIdx = 0;
|
||||||
|
|
||||||
if (checkMethod->mHasAppend)
|
if (checkMethod->mHasAppend)
|
||||||
paramIdx++;
|
paramIdx++;
|
||||||
|
|
||||||
if (checkMethod->mMethodType == BfMethodType_Extension)
|
if (checkMethod->mMethodType == BfMethodType_Extension)
|
||||||
{
|
{
|
||||||
argIdx--;
|
argIdx--;
|
||||||
}
|
}
|
||||||
paramIdx += paramOfs;
|
paramIdx += paramOfs;
|
||||||
|
|
||||||
for ( ; argIdx < (int)mArguments.size(); argIdx++)
|
bool hadInferFailure = false;
|
||||||
|
int inferParamOffset = paramOfs - argIdx;
|
||||||
|
|
||||||
|
enum ResultKind
|
||||||
{
|
{
|
||||||
if (paramIdx >= paramCount)
|
ResultKind_Ok,
|
||||||
break; // Possible for delegate 'params' type methods
|
ResultKind_Failed,
|
||||||
|
ResultKind_Deferred,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto _CheckArg = [&](int argIdx)
|
||||||
|
{
|
||||||
|
paramIdx = argIdx + inferParamOffset;
|
||||||
auto wantType = methodInstance->GetParamType(paramIdx);
|
auto wantType = methodInstance->GetParamType(paramIdx);
|
||||||
|
|
||||||
auto checkType = wantType;
|
auto checkType = wantType;
|
||||||
auto origCheckType = checkType;
|
auto origCheckType = checkType;
|
||||||
|
|
||||||
|
@ -1514,19 +1524,24 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
||||||
checkType = NULL;
|
checkType = NULL;
|
||||||
|
|
||||||
if (genericParamType->mGenericParamKind == BfGenericParamKind_Method)
|
if (genericParamType->mGenericParamKind == BfGenericParamKind_Method)
|
||||||
{
|
{
|
||||||
if ((genericArgumentsSubstitute != NULL) && (genericParamType->mGenericParamIdx < (int)genericArgumentsSubstitute->size()))
|
if ((genericArgumentsSubstitute != NULL) && (genericParamType->mGenericParamIdx < (int)genericArgumentsSubstitute->size()))
|
||||||
checkType = (*genericArgumentsSubstitute)[genericParamType->mGenericParamIdx];
|
checkType = (*genericArgumentsSubstitute)[genericParamType->mGenericParamIdx];
|
||||||
genericParamInstance = methodInstance->mMethodInfoEx->mGenericParams[genericParamType->mGenericParamIdx];
|
genericParamInstance = methodInstance->mMethodInfoEx->mGenericParams[genericParamType->mGenericParamIdx];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
genericParamInstance = mModule->GetGenericParamInstance(genericParamType);
|
genericParamInstance = mModule->GetGenericParamInstance(genericParamType);
|
||||||
if (checkType == NULL)
|
if (checkType == NULL)
|
||||||
|
{
|
||||||
checkType = genericParamInstance->mTypeConstraint;
|
checkType = genericParamInstance->mTypeConstraint;
|
||||||
|
origCheckType = checkType; // We can do "ResolveGenericType" on this type
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool attemptedGenericResolve = false;
|
||||||
if ((checkType != NULL) && (genericArgumentsSubstitute != NULL) && (checkType->IsUnspecializedType()))
|
if ((checkType != NULL) && (genericArgumentsSubstitute != NULL) && (checkType->IsUnspecializedType()))
|
||||||
{
|
{
|
||||||
|
attemptedGenericResolve = true;
|
||||||
checkType = mModule->ResolveGenericType(origCheckType, NULL, genericArgumentsSubstitute);
|
checkType = mModule->ResolveGenericType(origCheckType, NULL, genericArgumentsSubstitute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1541,18 +1556,53 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
||||||
{
|
{
|
||||||
auto type = argTypedValue.mType;
|
auto type = argTypedValue.mType;
|
||||||
if (!argTypedValue)
|
if (!argTypedValue)
|
||||||
goto NoMatch;
|
{
|
||||||
|
if ((checkType == NULL) && (attemptedGenericResolve) && (genericInferContext.GetUnresolvedCount() >= 2))
|
||||||
|
{
|
||||||
|
deferredArgs.Add(argIdx);
|
||||||
|
return ResultKind_Deferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultKind_Failed;
|
||||||
|
}
|
||||||
|
|
||||||
if (type->IsVar())
|
if (type->IsVar())
|
||||||
mHasVarArguments = true;
|
mHasVarArguments = true;
|
||||||
|
|
||||||
genericInferContext.mCheckedTypeSet.Clear();
|
genericInferContext.mCheckedTypeSet.Clear();
|
||||||
if (!genericInferContext.InferGenericArgument(methodInstance, type, wantType, argTypedValue.mValue))
|
if (!genericInferContext.InferGenericArgument(methodInstance, type, wantType, argTypedValue.mValue))
|
||||||
goto NoMatch;
|
return ResultKind_Failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ResultKind_Ok;
|
||||||
|
};
|
||||||
|
|
||||||
paramIdx++;
|
for (; argIdx < (int)mArguments.size(); argIdx++)
|
||||||
|
{
|
||||||
|
paramIdx = argIdx + inferParamOffset;
|
||||||
|
if (paramIdx >= paramCount)
|
||||||
|
break; // Possible for delegate 'params' type methods
|
||||||
|
|
||||||
|
auto resultKind = _CheckArg(argIdx);
|
||||||
|
if (resultKind == ResultKind_Failed)
|
||||||
|
goto NoMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!deferredArgs.IsEmpty())
|
||||||
|
{
|
||||||
|
int prevDeferredSize = (int)deferredArgs.size();
|
||||||
|
for (int i = 0; i < prevDeferredSize; i++)
|
||||||
|
{
|
||||||
|
auto resultKind = _CheckArg(deferredArgs[i]);
|
||||||
|
if (resultKind == ResultKind_Failed)
|
||||||
|
goto NoMatch;
|
||||||
|
}
|
||||||
|
deferredArgs.RemoveRange(0, prevDeferredSize);
|
||||||
|
if (prevDeferredSize == deferredArgs.size())
|
||||||
|
{
|
||||||
|
// No progress
|
||||||
|
goto NoMatch;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -5619,6 +5669,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
int argExprIdx = argIdx;
|
||||||
|
if (methodDef->mMethodType == BfMethodType_Extension)
|
||||||
|
argExprIdx--;
|
||||||
|
|
||||||
bool isThis = (paramIdx == -1) || ((methodDef->mHasExplicitThis) && (paramIdx == 0));
|
bool isThis = (paramIdx == -1) || ((methodDef->mHasExplicitThis) && (paramIdx == 0));
|
||||||
bool isDirectPass = false;
|
bool isDirectPass = false;
|
||||||
|
|
||||||
|
@ -5626,22 +5680,22 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
{
|
{
|
||||||
if (methodInstance->IsVarArgs())
|
if (methodInstance->IsVarArgs())
|
||||||
{
|
{
|
||||||
if (argIdx >= (int)argValues.size())
|
if (argExprIdx >= (int)argValues.size())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
BfTypedValue argValue = ResolveArgValue(argValues[argIdx], NULL);
|
BfTypedValue argValue = ResolveArgValue(argValues[argExprIdx], NULL);
|
||||||
if (argValue)
|
if (argValue)
|
||||||
{
|
{
|
||||||
auto typeInst = argValue.mType->ToTypeInstance();
|
auto typeInst = argValue.mType->ToTypeInstance();
|
||||||
|
|
||||||
if (argValue.mType == mModule->GetPrimitiveType(BfTypeCode_Float))
|
if (argValue.mType == mModule->GetPrimitiveType(BfTypeCode_Float))
|
||||||
argValue = mModule->Cast(argValues[argIdx].mExpression, argValue, mModule->GetPrimitiveType(BfTypeCode_Double));
|
argValue = mModule->Cast(argValues[argExprIdx].mExpression, argValue, mModule->GetPrimitiveType(BfTypeCode_Double));
|
||||||
|
|
||||||
if ((typeInst != NULL) && (typeInst->mTypeDef == mModule->mCompiler->mStringTypeDef))
|
if ((typeInst != NULL) && (typeInst->mTypeDef == mModule->mCompiler->mStringTypeDef))
|
||||||
{
|
{
|
||||||
BfType* charType = mModule->GetPrimitiveType(BfTypeCode_Char8);
|
BfType* charType = mModule->GetPrimitiveType(BfTypeCode_Char8);
|
||||||
BfType* charPtrType = mModule->CreatePointerType(charType);
|
BfType* charPtrType = mModule->CreatePointerType(charType);
|
||||||
argValue = mModule->Cast(argValues[argIdx].mExpression, argValue, charPtrType);
|
argValue = mModule->Cast(argValues[argExprIdx].mExpression, argValue, charPtrType);
|
||||||
}
|
}
|
||||||
PushArg(argValue, irArgs, true, false);
|
PushArg(argValue, irArgs, true, false);
|
||||||
}
|
}
|
||||||
|
@ -5649,9 +5703,9 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argIdx < (int)argValues.size())
|
if (argExprIdx < (int)argValues.size())
|
||||||
{
|
{
|
||||||
BfAstNode* errorRef = argValues[argIdx].mExpression;
|
BfAstNode* errorRef = argValues[argExprIdx].mExpression;
|
||||||
if (errorRef == NULL)
|
if (errorRef == NULL)
|
||||||
errorRef = targetSrc;
|
errorRef = targetSrc;
|
||||||
|
|
||||||
|
@ -5659,7 +5713,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
if ((prevBindResult.mPrevVal != NULL) && (prevBindResult.mPrevVal->mBindType != NULL))
|
if ((prevBindResult.mPrevVal != NULL) && (prevBindResult.mPrevVal->mBindType != NULL))
|
||||||
error = mModule->Fail(StrFormat("Method '%s' has too many parameters to bind to '%s'.", mModule->MethodToString(methodInstance).c_str(), mModule->TypeToString(prevBindResult.mPrevVal->mBindType).c_str()), errorRef);
|
error = mModule->Fail(StrFormat("Method '%s' has too many parameters to bind to '%s'.", mModule->MethodToString(methodInstance).c_str(), mModule->TypeToString(prevBindResult.mPrevVal->mBindType).c_str()), errorRef);
|
||||||
else
|
else
|
||||||
error = mModule->Fail(StrFormat("Too many arguments, expected %d fewer.", (int)argValues.size() - argIdx), errorRef);
|
error = mModule->Fail(StrFormat("Too many arguments, expected %d fewer.", (int)argValues.size() - argExprIdx), errorRef);
|
||||||
if ((error != NULL) && (methodInstance->mMethodDef->mMethodDeclaration != NULL))
|
if ((error != NULL) && (methodInstance->mMethodDef->mMethodDeclaration != NULL))
|
||||||
mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("See method declaration"), methodInstance->mMethodDef->GetRefNode());
|
mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("See method declaration"), methodInstance->mMethodDef->GetRefNode());
|
||||||
failed = true;
|
failed = true;
|
||||||
|
@ -5795,15 +5849,9 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
}
|
}
|
||||||
|
|
||||||
BfAstNode* arg = NULL;
|
BfAstNode* arg = NULL;
|
||||||
bool hadMissingArg = false;
|
bool hadMissingArg = false;
|
||||||
|
if (argExprIdx == -1)
|
||||||
int argExprIdx = argIdx;
|
arg = targetSrc;
|
||||||
if (methodDef->mMethodType == BfMethodType_Extension)
|
|
||||||
{
|
|
||||||
argExprIdx--;
|
|
||||||
if (argExprIdx == -1)
|
|
||||||
arg = targetSrc;
|
|
||||||
}
|
|
||||||
if (argExprIdx >= 0)
|
if (argExprIdx >= 0)
|
||||||
{
|
{
|
||||||
if (argExprIdx < (int)argValues.size())
|
if (argExprIdx < (int)argValues.size())
|
||||||
|
@ -6038,7 +6086,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
|
|
||||||
if (wantType->IsMethodRef())
|
if (wantType->IsMethodRef())
|
||||||
{
|
{
|
||||||
auto expr = argValues[argIdx].mExpression;
|
auto expr = argValues[argExprIdx].mExpression;
|
||||||
if (expr != NULL)
|
if (expr != NULL)
|
||||||
SetMethodElementType(expr);
|
SetMethodElementType(expr);
|
||||||
|
|
||||||
|
@ -13249,7 +13297,7 @@ BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfAstNode* targetSrc,
|
||||||
if ((genericParam->mTypeConstraint != NULL) && (genericParam->mTypeConstraint->IsDelegate()))
|
if ((genericParam->mTypeConstraint != NULL) && (genericParam->mTypeConstraint->IsDelegate()))
|
||||||
{
|
{
|
||||||
// The only other option was to bind to a MethodRef
|
// The only other option was to bind to a MethodRef
|
||||||
genericArg = genericParam->mTypeConstraint;
|
genericArg = mModule->ResolveGenericType(genericParam->mTypeConstraint, NULL, &methodMatcher.mBestMethodGenericArguments);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -13275,18 +13323,19 @@ BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfAstNode* targetSrc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (genericArg == NULL)
|
|
||||||
{
|
|
||||||
failed = true;
|
|
||||||
mModule->Fail(StrFormat("Unable to determine generic argument '%s'", methodDef->mGenericParams[checkGenericIdx]->mName.c_str()).c_str(), targetSrc);
|
|
||||||
if ((genericParam->mTypeConstraint != NULL) && (!genericParam->mTypeConstraint->IsUnspecializedType()))
|
|
||||||
genericArg = genericParam->mTypeConstraint;
|
|
||||||
else
|
|
||||||
genericArg = mModule->mContext->mBfObjectType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (genericArg == NULL)
|
||||||
|
{
|
||||||
|
failed = true;
|
||||||
|
mModule->Fail(StrFormat("Unable to determine generic argument '%s'", methodDef->mGenericParams[checkGenericIdx]->mName.c_str()).c_str(), targetSrc);
|
||||||
|
if ((genericParam->mTypeConstraint != NULL) && (!genericParam->mTypeConstraint->IsUnspecializedType()))
|
||||||
|
genericArg = genericParam->mTypeConstraint;
|
||||||
|
else
|
||||||
|
genericArg = mModule->mContext->mBfObjectType;
|
||||||
|
}
|
||||||
|
|
||||||
resolvedGenericArguments.push_back(genericArg);
|
resolvedGenericArguments.push_back(genericArg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -109,9 +109,19 @@ public:
|
||||||
BfModule* mModule;
|
BfModule* mModule;
|
||||||
BfTypeVector* mCheckMethodGenericArguments;
|
BfTypeVector* mCheckMethodGenericArguments;
|
||||||
SizedArray<BfIRValue, 4> mPrevArgValues;
|
SizedArray<BfIRValue, 4> mPrevArgValues;
|
||||||
|
int mInferredCount;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
BfGenericInferContext()
|
||||||
|
{
|
||||||
|
mModule = NULL;
|
||||||
|
mInferredCount = 0;
|
||||||
|
}
|
||||||
bool InferGenericArgument(BfMethodInstance* methodInstance, BfType* argType, BfType* wantType, BfIRValue argValue);
|
bool InferGenericArgument(BfMethodInstance* methodInstance, BfType* argType, BfType* wantType, BfIRValue argValue);
|
||||||
|
int GetUnresolvedCount()
|
||||||
|
{
|
||||||
|
return (int)mCheckMethodGenericArguments->size() - mInferredCount;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class BfMethodMatcher
|
class BfMethodMatcher
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
namespace Tests
|
namespace Tests
|
||||||
{
|
{
|
||||||
|
@ -46,6 +47,16 @@ namespace Tests
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static T DoOnListA<T, TDlg>(List<T> val, TDlg dlg) where TDlg : delegate T(T a)
|
||||||
|
{
|
||||||
|
return dlg(val[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static T DoOnListB<T, TDlg>(TDlg dlg, List<T> val) where TDlg : delegate T(T a)
|
||||||
|
{
|
||||||
|
return dlg(val[0]);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public static void TestBasics()
|
public static void TestBasics()
|
||||||
{
|
{
|
||||||
|
@ -63,6 +74,10 @@ namespace Tests
|
||||||
|
|
||||||
float val4 = Do10f(=> FuncA, 0.34f);
|
float val4 = Do10f(=> FuncA, 0.34f);
|
||||||
Test.Assert(val4 == -34);
|
Test.Assert(val4 == -34);
|
||||||
|
|
||||||
|
List<float> fList = scope .() { 1.2f, 2.3f };
|
||||||
|
Test.Assert(DoOnListA(fList, (val) => val + 100) == 101.2f);
|
||||||
|
Test.Assert(DoOnListB((val) => val + 200, fList) == 201.2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MethodRefHolder<T> where T : delegate int(int num)
|
struct MethodRefHolder<T> where T : delegate int(int num)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue