mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-09 12:02:21 +02:00
Added improved invocation rules with extension methods / fields / props
This commit is contained in:
parent
f04da6d826
commit
10d4047d01
1 changed files with 165 additions and 147 deletions
|
@ -1329,7 +1329,6 @@ BfTypedValue BfMethodMatcher::ResolveArgTypedValue(BfResolvedArg& resolvedArg, B
|
||||||
|
|
||||||
auto prevBlock = mModule->mBfIRBuilder->GetInsertBlock();
|
auto prevBlock = mModule->mBfIRBuilder->GetInsertBlock();
|
||||||
|
|
||||||
|
|
||||||
BfExprEvaluator exprEvaluator(mModule);
|
BfExprEvaluator exprEvaluator(mModule);
|
||||||
exprEvaluator.mBfEvalExprFlags = (BfEvalExprFlags)(exprEvaluator.mBfEvalExprFlags | BfEvalExprFlags_AllowIntUnknown | BfEvalExprFlags_NoAutoComplete);
|
exprEvaluator.mBfEvalExprFlags = (BfEvalExprFlags)(exprEvaluator.mBfEvalExprFlags | BfEvalExprFlags_AllowIntUnknown | BfEvalExprFlags_NoAutoComplete);
|
||||||
if ((resolvedArg.mArgFlags & BfArgFlag_ParamsExpr) != 0)
|
if ((resolvedArg.mArgFlags & BfArgFlag_ParamsExpr) != 0)
|
||||||
|
@ -1599,7 +1598,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Being in autocomplete mode is the only excuse for not having the virtual method table slotted
|
// Being in autocomplete mode is the only excuse for not having the virtual method table slotted
|
||||||
if ((!mModule->mCompiler->IsAutocomplete()) && (!targetTypeInstance->mTypeFailed))
|
if ((!mModule->mCompiler->IsAutocomplete()) && (!targetTypeInstance->mTypeFailed) && (!targetTypeInstance->IsUnspecializedTypeVariation()))
|
||||||
{
|
{
|
||||||
mModule->AssertErrorState();
|
mModule->AssertErrorState();
|
||||||
}
|
}
|
||||||
|
@ -8113,6 +8112,9 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
||||||
|
|
||||||
bool skipThis = false;
|
bool skipThis = false;
|
||||||
|
|
||||||
|
BfTypedValue fieldVal;
|
||||||
|
bool hasFieldVal = false;
|
||||||
|
|
||||||
// Fail, check for delegate field invocation
|
// Fail, check for delegate field invocation
|
||||||
if ((methodDef == NULL) && ((methodGenericArguments == NULL) || (methodGenericArguments->size() == 0)))
|
if ((methodDef == NULL) && ((methodGenericArguments == NULL) || (methodGenericArguments->size() == 0)))
|
||||||
{
|
{
|
||||||
|
@ -8146,7 +8148,6 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
||||||
return enumResult;
|
return enumResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
BfTypedValue fieldVal;
|
|
||||||
if (allowImplicitThis)
|
if (allowImplicitThis)
|
||||||
{
|
{
|
||||||
auto identifierNode = BfNodeDynCast<BfIdentifierNode>(targetSrc);
|
auto identifierNode = BfNodeDynCast<BfIdentifierNode>(targetSrc);
|
||||||
|
@ -8159,147 +8160,22 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
||||||
fieldVal = LookupField(targetSrc, target, methodName);
|
fieldVal = LookupField(targetSrc, target, methodName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPropDef != NULL)
|
|
||||||
fieldVal = GetResult();
|
|
||||||
|
|
||||||
if (fieldVal)
|
if (fieldVal)
|
||||||
{
|
{
|
||||||
if (fieldVal.mType->IsGenericParam())
|
hasFieldVal = true;
|
||||||
|
wantsExtensionCheck = !fieldVal.mType->IsDelegate() && !fieldVal.mType->IsFunction();
|
||||||
|
}
|
||||||
|
else if (mPropDef != NULL)
|
||||||
{
|
{
|
||||||
bool delegateFailed = true;
|
hasFieldVal = true;
|
||||||
auto genericParamInstance = mModule->GetGenericParamInstance((BfGenericParamType*)fieldVal.mType);
|
|
||||||
BfTypeInstance* typeInstConstraint = NULL;
|
|
||||||
if (genericParamInstance->mTypeConstraint != NULL)
|
|
||||||
typeInstConstraint = genericParamInstance->mTypeConstraint->ToTypeInstance();
|
|
||||||
if ((typeInstConstraint != NULL) &&
|
|
||||||
((typeInstConstraint->mTypeDef == mModule->mCompiler->mDelegateTypeDef) || (typeInstConstraint->mTypeDef == mModule->mCompiler->mFunctionTypeDef)))
|
|
||||||
{
|
|
||||||
MarkResultUsed();
|
|
||||||
|
|
||||||
// if (argValues.mResolvedArgs.size() > 0)
|
BfMethodDef* matchedMethod = GetPropertyMethodDef(mPropDef, BfMethodType_PropertyGetter, mPropCheckedKind, mPropTarget);
|
||||||
// {
|
if (matchedMethod != NULL)
|
||||||
// if ((argValues.mResolvedArgs[0].mArgFlags & BfArgFlag_FromParamComposite) != 0)
|
|
||||||
// delegateFailed = false;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
|
|
||||||
if (argValues.mArguments->size() == 1)
|
|
||||||
{
|
{
|
||||||
BfExprEvaluator exprEvaluator(mModule);
|
auto getMethodInstance = mModule->GetRawMethodInstance(mPropTarget.mType->ToTypeInstance(), matchedMethod);
|
||||||
exprEvaluator.mBfEvalExprFlags = BfEvalExprFlags_AllowParamsExpr;
|
if ((getMethodInstance != NULL) &&
|
||||||
exprEvaluator.Evaluate((*argValues.mArguments)[0]);
|
((getMethodInstance->mReturnType->IsDelegate()) || (getMethodInstance->mReturnType->IsFunction())))
|
||||||
if ((mModule->mCurMethodState != NULL) && (exprEvaluator.mResultLocalVar != NULL) && (exprEvaluator.mResultLocalVarRefNode != NULL))
|
wantsExtensionCheck = false;
|
||||||
{
|
|
||||||
/*if (exprEvaluator.mResult.mKind != BfTypedValueKind_Params)
|
|
||||||
mModule->Warn(0, "'params' token expected", (*argValues.mArguments)[0]);*/
|
|
||||||
|
|
||||||
auto localVar = exprEvaluator.mResultLocalVar;
|
|
||||||
if ((localVar->mCompositeCount >= 0) && (localVar->mResolvedType == fieldVal.mType))
|
|
||||||
{
|
|
||||||
delegateFailed = false;
|
|
||||||
if (mModule->mCurMethodInstance->mIsUnspecialized)
|
|
||||||
{
|
|
||||||
auto retTypeType = mModule->CreateModifiedTypeType(fieldVal.mType, BfToken_RetType);
|
|
||||||
return mModule->GetFakeTypedValue(retTypeType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delegateFailed)
|
|
||||||
{
|
|
||||||
mModule->Fail(StrFormat("Generic delegates can only be invoked with 'params %s' composite parameters", mModule->TypeToString(fieldVal.mType).c_str()), targetSrc);
|
|
||||||
return BfTypedValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fieldVal.mType->IsTypeInstance())
|
|
||||||
{
|
|
||||||
prevBindResult.Restore();
|
|
||||||
auto fieldTypeInst = fieldVal.mType->ToTypeInstance();
|
|
||||||
MarkResultUsed();
|
|
||||||
return MatchMethod(targetSrc, NULL, fieldVal, false, false, "Invoke", argValues, methodGenericArguments, checkedKind);
|
|
||||||
}
|
|
||||||
if (fieldVal.mType->IsVar())
|
|
||||||
return BfTypedValue(mModule->GetDefaultValue(fieldVal.mType), fieldVal.mType);
|
|
||||||
if (fieldVal.mType->IsGenericParam())
|
|
||||||
{
|
|
||||||
auto genericParam = mModule->GetGenericParamInstance((BfGenericParamType*)fieldVal.mType);
|
|
||||||
BfType* typeConstraint = genericParam->mTypeConstraint;
|
|
||||||
|
|
||||||
if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized) && (mModule->mCurMethodInstance->mMethodInfoEx != NULL))
|
|
||||||
{
|
|
||||||
for (int genericParamIdx = (int)mModule->mCurMethodInstance->mMethodInfoEx->mMethodGenericArguments.size();
|
|
||||||
genericParamIdx < mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++)
|
|
||||||
{
|
|
||||||
auto genericParam = mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx];
|
|
||||||
if ((genericParam->mExternType == fieldVal.mType) && (genericParam->mTypeConstraint != NULL))
|
|
||||||
typeConstraint = genericParam->mTypeConstraint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((typeConstraint != NULL) &&
|
|
||||||
((typeConstraint->IsDelegate()) || (typeConstraint->IsFunction())))
|
|
||||||
{
|
|
||||||
BfMethodInstance* invokeMethodInstance = mModule->GetRawMethodInstanceAtIdx(typeConstraint->ToTypeInstance(), 0, "Invoke");
|
|
||||||
|
|
||||||
methodDef = invokeMethodInstance->mMethodDef;
|
|
||||||
methodMatcher.mBestMethodInstance = invokeMethodInstance;
|
|
||||||
methodMatcher.mBestMethodTypeInstance = invokeMethodInstance->GetOwner();
|
|
||||||
methodMatcher.mBestMethodDef = invokeMethodInstance->mMethodDef;
|
|
||||||
target = mModule->GetDefaultTypedValue(methodMatcher.mBestMethodTypeInstance);
|
|
||||||
isFailurePass = false;
|
|
||||||
isIndirectMethodCall = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (fieldVal.mType->IsMethodRef())
|
|
||||||
{
|
|
||||||
auto functionBindResults = prevBindResult.mPrevVal;
|
|
||||||
if (functionBindResults != NULL)
|
|
||||||
{
|
|
||||||
functionBindResults->mOrigTarget = fieldVal;
|
|
||||||
}
|
|
||||||
origTarget = fieldVal;
|
|
||||||
|
|
||||||
auto methodRefType = (BfMethodRefType*)fieldVal.mType;
|
|
||||||
BfMethodInstance* methodInstance = methodRefType->mMethodRef;
|
|
||||||
methodDef = methodInstance->mMethodDef;
|
|
||||||
if (methodDef->mIsLocalMethod)
|
|
||||||
{
|
|
||||||
methodMatcher.mBestMethodInstance = mModule->ReferenceExternalMethodInstance(methodInstance);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BfTypeVector methodGenericArguments;
|
|
||||||
if (methodInstance->mMethodInfoEx != NULL)
|
|
||||||
methodGenericArguments = methodInstance->mMethodInfoEx->mMethodGenericArguments;
|
|
||||||
methodMatcher.mBestMethodInstance = mModule->GetMethodInstance(methodInstance->GetOwner(), methodInstance->mMethodDef, methodGenericArguments);
|
|
||||||
}
|
|
||||||
methodMatcher.mBestMethodTypeInstance = methodInstance->GetOwner();
|
|
||||||
if (methodInstance->HasThis())
|
|
||||||
{
|
|
||||||
bool failed = false;
|
|
||||||
target = DoImplicitArgCapture(targetSrc, methodInstance, -1, failed, BfImplicitParamKind_General, origTarget);
|
|
||||||
}
|
|
||||||
else if (!methodDef->mIsStatic)
|
|
||||||
{
|
|
||||||
auto thisType = methodInstance->GetParamType(-1);
|
|
||||||
BF_ASSERT(thisType->IsValuelessType());
|
|
||||||
target = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), methodMatcher.mBestMethodTypeInstance);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
target = BfTypedValue(methodMatcher.mBestMethodTypeInstance);
|
|
||||||
methodMatcher.mBypassVirtual = true;
|
|
||||||
bypassVirtual = true;
|
|
||||||
isFailurePass = false;
|
|
||||||
isIndirectMethodCall = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (methodDef == NULL)
|
|
||||||
{
|
|
||||||
mModule->Fail(StrFormat("Cannot perform invocation on type '%s'", mModule->TypeToString(fieldVal.mType).c_str()), targetSrc);
|
|
||||||
return BfTypedValue();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8488,6 +8364,143 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((methodDef == NULL) && (hasFieldVal))
|
||||||
|
{
|
||||||
|
if (mPropDef != NULL)
|
||||||
|
fieldVal = GetResult();
|
||||||
|
|
||||||
|
if (fieldVal)
|
||||||
|
{
|
||||||
|
if (fieldVal.mType->IsGenericParam())
|
||||||
|
{
|
||||||
|
bool delegateFailed = true;
|
||||||
|
auto genericParamInstance = mModule->GetGenericParamInstance((BfGenericParamType*)fieldVal.mType);
|
||||||
|
BfTypeInstance* typeInstConstraint = NULL;
|
||||||
|
if (genericParamInstance->mTypeConstraint != NULL)
|
||||||
|
typeInstConstraint = genericParamInstance->mTypeConstraint->ToTypeInstance();
|
||||||
|
if ((typeInstConstraint != NULL) &&
|
||||||
|
((typeInstConstraint->mTypeDef == mModule->mCompiler->mDelegateTypeDef) || (typeInstConstraint->mTypeDef == mModule->mCompiler->mFunctionTypeDef)))
|
||||||
|
{
|
||||||
|
MarkResultUsed();
|
||||||
|
|
||||||
|
if (argValues.mArguments->size() == 1)
|
||||||
|
{
|
||||||
|
BfExprEvaluator exprEvaluator(mModule);
|
||||||
|
exprEvaluator.mBfEvalExprFlags = BfEvalExprFlags_AllowParamsExpr;
|
||||||
|
exprEvaluator.Evaluate((*argValues.mArguments)[0]);
|
||||||
|
if ((mModule->mCurMethodState != NULL) && (exprEvaluator.mResultLocalVar != NULL) && (exprEvaluator.mResultLocalVarRefNode != NULL))
|
||||||
|
{
|
||||||
|
auto localVar = exprEvaluator.mResultLocalVar;
|
||||||
|
if ((localVar->mCompositeCount >= 0) && (localVar->mResolvedType == fieldVal.mType))
|
||||||
|
{
|
||||||
|
delegateFailed = false;
|
||||||
|
if (mModule->mCurMethodInstance->mIsUnspecialized)
|
||||||
|
{
|
||||||
|
auto retTypeType = mModule->CreateModifiedTypeType(fieldVal.mType, BfToken_RetType);
|
||||||
|
return mModule->GetFakeTypedValue(retTypeType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delegateFailed)
|
||||||
|
{
|
||||||
|
mModule->Fail(StrFormat("Generic delegates can only be invoked with 'params %s' composite parameters", mModule->TypeToString(fieldVal.mType).c_str()), targetSrc);
|
||||||
|
return BfTypedValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldVal.mType->IsTypeInstance())
|
||||||
|
{
|
||||||
|
prevBindResult.Restore();
|
||||||
|
auto fieldTypeInst = fieldVal.mType->ToTypeInstance();
|
||||||
|
MarkResultUsed();
|
||||||
|
return MatchMethod(targetSrc, NULL, fieldVal, false, false, "Invoke", argValues, methodGenericArguments, checkedKind);
|
||||||
|
}
|
||||||
|
if (fieldVal.mType->IsVar())
|
||||||
|
return BfTypedValue(mModule->GetDefaultValue(fieldVal.mType), fieldVal.mType);
|
||||||
|
if (fieldVal.mType->IsGenericParam())
|
||||||
|
{
|
||||||
|
auto genericParam = mModule->GetGenericParamInstance((BfGenericParamType*)fieldVal.mType);
|
||||||
|
BfType* typeConstraint = genericParam->mTypeConstraint;
|
||||||
|
|
||||||
|
if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized) && (mModule->mCurMethodInstance->mMethodInfoEx != NULL))
|
||||||
|
{
|
||||||
|
for (int genericParamIdx = (int)mModule->mCurMethodInstance->mMethodInfoEx->mMethodGenericArguments.size();
|
||||||
|
genericParamIdx < mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++)
|
||||||
|
{
|
||||||
|
auto genericParam = mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx];
|
||||||
|
if ((genericParam->mExternType == fieldVal.mType) && (genericParam->mTypeConstraint != NULL))
|
||||||
|
typeConstraint = genericParam->mTypeConstraint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((typeConstraint != NULL) &&
|
||||||
|
((typeConstraint->IsDelegate()) || (typeConstraint->IsFunction())))
|
||||||
|
{
|
||||||
|
BfMethodInstance* invokeMethodInstance = mModule->GetRawMethodInstanceAtIdx(typeConstraint->ToTypeInstance(), 0, "Invoke");
|
||||||
|
|
||||||
|
methodDef = invokeMethodInstance->mMethodDef;
|
||||||
|
methodMatcher.mBestMethodInstance = invokeMethodInstance;
|
||||||
|
methodMatcher.mBestMethodTypeInstance = invokeMethodInstance->GetOwner();
|
||||||
|
methodMatcher.mBestMethodDef = invokeMethodInstance->mMethodDef;
|
||||||
|
target = mModule->GetDefaultTypedValue(methodMatcher.mBestMethodTypeInstance);
|
||||||
|
isFailurePass = false;
|
||||||
|
isIndirectMethodCall = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (fieldVal.mType->IsMethodRef())
|
||||||
|
{
|
||||||
|
auto functionBindResults = prevBindResult.mPrevVal;
|
||||||
|
if (functionBindResults != NULL)
|
||||||
|
{
|
||||||
|
functionBindResults->mOrigTarget = fieldVal;
|
||||||
|
}
|
||||||
|
origTarget = fieldVal;
|
||||||
|
|
||||||
|
auto methodRefType = (BfMethodRefType*)fieldVal.mType;
|
||||||
|
BfMethodInstance* methodInstance = methodRefType->mMethodRef;
|
||||||
|
methodDef = methodInstance->mMethodDef;
|
||||||
|
if (methodDef->mIsLocalMethod)
|
||||||
|
{
|
||||||
|
methodMatcher.mBestMethodInstance = mModule->ReferenceExternalMethodInstance(methodInstance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BfTypeVector methodGenericArguments;
|
||||||
|
if (methodInstance->mMethodInfoEx != NULL)
|
||||||
|
methodGenericArguments = methodInstance->mMethodInfoEx->mMethodGenericArguments;
|
||||||
|
methodMatcher.mBestMethodInstance = mModule->GetMethodInstance(methodInstance->GetOwner(), methodInstance->mMethodDef, methodGenericArguments);
|
||||||
|
}
|
||||||
|
methodMatcher.mBestMethodTypeInstance = methodInstance->GetOwner();
|
||||||
|
if (methodInstance->HasThis())
|
||||||
|
{
|
||||||
|
bool failed = false;
|
||||||
|
target = DoImplicitArgCapture(targetSrc, methodInstance, -1, failed, BfImplicitParamKind_General, origTarget);
|
||||||
|
}
|
||||||
|
else if (!methodDef->mIsStatic)
|
||||||
|
{
|
||||||
|
auto thisType = methodInstance->GetParamType(-1);
|
||||||
|
BF_ASSERT(thisType->IsValuelessType());
|
||||||
|
target = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), methodMatcher.mBestMethodTypeInstance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
target = BfTypedValue(methodMatcher.mBestMethodTypeInstance);
|
||||||
|
methodMatcher.mBypassVirtual = true;
|
||||||
|
bypassVirtual = true;
|
||||||
|
isFailurePass = false;
|
||||||
|
isIndirectMethodCall = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (methodDef == NULL)
|
||||||
|
{
|
||||||
|
mModule->Fail(StrFormat("Cannot perform invocation on type '%s'", mModule->TypeToString(fieldVal.mType).c_str()), targetSrc);
|
||||||
|
return BfTypedValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This will flush out any new ambiguity errors from extension methods
|
// This will flush out any new ambiguity errors from extension methods
|
||||||
methodMatcher.FlushAmbiguityError();
|
methodMatcher.FlushAmbiguityError();
|
||||||
|
|
||||||
|
@ -10473,10 +10486,15 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if ((!targetType->IsInterface()) && (!mModule->TypeIsSubTypeOf(targetTypeInstance, srcTypeInstance)))
|
else if ((!targetType->IsInterface()) && (!mModule->TypeIsSubTypeOf(targetTypeInstance, srcTypeInstance)))
|
||||||
|
{
|
||||||
|
if (!mModule->IsInSpecializedSection())
|
||||||
{
|
{
|
||||||
mModule->Fail(StrFormat("Cannot convert type '%s' to '%s' via any conversion",
|
mModule->Fail(StrFormat("Cannot convert type '%s' to '%s' via any conversion",
|
||||||
mModule->TypeToString(targetValue.mType).c_str(), mModule->TypeToString(targetTypeInstance).c_str()), dynCastExpr->mAsToken);
|
mModule->TypeToString(targetValue.mType).c_str(), mModule->TypeToString(targetTypeInstance).c_str()), dynCastExpr->mAsToken);
|
||||||
}
|
}
|
||||||
|
mResult = mModule->GetDefaultTypedValue(targetType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (autoComplete != NULL)
|
if (autoComplete != NULL)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue