mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 19:48:20 +02:00
Improvements to interfaces: extensions, better generics, statics
This commit is contained in:
parent
bff1d657cc
commit
6cb2df65a6
12 changed files with 322 additions and 68 deletions
|
@ -1546,8 +1546,10 @@ bool BfAutoComplete::CheckMemberReference(BfAstNode* target, BfAstNode* dotToken
|
|||
|
||||
auto _HandleGenericParamInstance = [&](BfGenericParamInstance* genericParamInstance)
|
||||
{
|
||||
bool showStatics = !targetValue.mValue;
|
||||
|
||||
for (auto interfaceConstraint : genericParamInstance->mInterfaceConstraints)
|
||||
AddTypeMembers(interfaceConstraint, false, true, filter, interfaceConstraint, true, false);
|
||||
AddTypeMembers(interfaceConstraint, showStatics, !showStatics, filter, interfaceConstraint, true, false);
|
||||
|
||||
if (genericParamInstance->mTypeConstraint != NULL)
|
||||
checkType = genericParamInstance->mTypeConstraint;
|
||||
|
@ -1928,9 +1930,13 @@ void BfAutoComplete::CheckNode(BfAstNode* node)
|
|||
|
||||
bool BfAutoComplete::GetMethodInfo(BfMethodInstance* methodInst, StringImpl* showString, StringImpl* insertString, bool isImplementing, bool isExplicitInterface)
|
||||
{
|
||||
SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mModule->mCurMethodInstance, methodInst);
|
||||
|
||||
auto methodDef = methodInst->mMethodDef;
|
||||
bool isInterface = methodInst->GetOwner()->IsInterface();
|
||||
|
||||
BfTypeNameFlags nameFlags = (BfTypeNameFlags)(BfTypeNameFlag_ReduceName | BfTypeNameFlag_ResolveGenericParamNames);
|
||||
|
||||
if (methodDef->mMethodType == BfMethodType_Normal)
|
||||
{
|
||||
StringT<128> methodPrefix;
|
||||
|
@ -1965,15 +1971,33 @@ bool BfAutoComplete::GetMethodInfo(BfMethodInstance* methodInst, StringImpl* sho
|
|||
methodPrefix += methodDeclaration->mProtectionSpecifier->ToString() + " ";
|
||||
if (!isInterface)
|
||||
methodPrefix += "override ";
|
||||
methodPrefix += mModule->TypeToString(methodInst->mReturnType, BfTypeNameFlag_ReduceName);
|
||||
if (methodDef->mIsStatic)
|
||||
methodPrefix += "static ";
|
||||
|
||||
methodPrefix += mModule->TypeToString(methodInst->mReturnType, nameFlags);
|
||||
methodPrefix += " ";
|
||||
if (isExplicitInterface)
|
||||
{
|
||||
methodName += mModule->TypeToString(methodInst->GetOwner(), BfTypeNameFlag_ReduceName);
|
||||
methodName += mModule->TypeToString(methodInst->GetOwner(), nameFlags);
|
||||
methodName += ".";
|
||||
}
|
||||
|
||||
methodName += methodDef->mName;
|
||||
|
||||
if (methodInst->GetNumGenericArguments() > 0)
|
||||
{
|
||||
methodName += "<";
|
||||
for (int genericArgIdx = 0; genericArgIdx < (int)methodInst->mMethodInfoEx->mGenericParams.size(); genericArgIdx++)
|
||||
{
|
||||
if (genericArgIdx > 0)
|
||||
methodName += ", ";
|
||||
|
||||
auto genericParam = methodInst->mMethodInfoEx->mGenericParams[genericArgIdx];
|
||||
methodName += genericParam->GetName();
|
||||
}
|
||||
methodName += ">";
|
||||
}
|
||||
|
||||
methodName += "(";
|
||||
for (int paramIdx = 0; paramIdx < (int)methodInst->GetParamCount(); paramIdx++)
|
||||
{
|
||||
|
@ -1983,7 +2007,7 @@ bool BfAutoComplete::GetMethodInfo(BfMethodInstance* methodInst, StringImpl* sho
|
|||
if (!isAbstract)
|
||||
impString += ", ";
|
||||
}
|
||||
methodName += mModule->TypeToString(methodInst->GetParamType(paramIdx), BfTypeNameFlag_ReduceName);
|
||||
methodName += mModule->TypeToString(methodInst->GetParamType(paramIdx), nameFlags);
|
||||
methodName += " ";
|
||||
methodName += methodDef->mParams[paramIdx]->mName;
|
||||
|
||||
|
@ -1999,6 +2023,33 @@ bool BfAutoComplete::GetMethodInfo(BfMethodInstance* methodInst, StringImpl* sho
|
|||
}
|
||||
methodName += ")";
|
||||
|
||||
if (methodInst->GetNumGenericArguments() > 0)
|
||||
{
|
||||
for (int genericArgIdx = 0; genericArgIdx < (int)methodInst->mMethodInfoEx->mGenericParams.size(); genericArgIdx++)
|
||||
{
|
||||
auto genericParam = methodInst->mMethodInfoEx->mGenericParams[genericArgIdx];
|
||||
|
||||
if (genericParam->mTypeConstraint != NULL)
|
||||
methodName += " where " + genericParam->GetName() + " : " + mModule->TypeToString(genericParam->mTypeConstraint, nameFlags);
|
||||
|
||||
for (auto ifaceConstraint : genericParam->mInterfaceConstraints)
|
||||
methodName += " where " + genericParam->GetName() + " : " + mModule->TypeToString(ifaceConstraint, nameFlags);
|
||||
|
||||
if ((genericParam->mGenericParamFlags & BfGenericParamFlag_Class) != 0)
|
||||
methodName += " where " + genericParam->GetName() + " : class";
|
||||
if ((genericParam->mGenericParamFlags & BfGenericParamFlag_Struct) != 0)
|
||||
methodName += " where " + genericParam->GetName() + " : struct";
|
||||
if ((genericParam->mGenericParamFlags & BfGenericParamFlag_StructPtr) != 0)
|
||||
methodName += " where " + genericParam->GetName() + " : struct*";
|
||||
if ((genericParam->mGenericParamFlags & BfGenericParamFlag_New) != 0)
|
||||
methodName += " where " + genericParam->GetName() + " : new";
|
||||
if ((genericParam->mGenericParamFlags & BfGenericParamFlag_Delete) != 0)
|
||||
methodName += " where " + genericParam->GetName() + " : delete";
|
||||
if ((genericParam->mGenericParamFlags & BfGenericParamFlag_Var) != 0)
|
||||
methodName += " where " + genericParam->GetName() + " : var";
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAbstract)
|
||||
impString += ");";
|
||||
|
||||
|
@ -2037,11 +2088,11 @@ bool BfAutoComplete::GetMethodInfo(BfMethodInstance* methodInst, StringImpl* sho
|
|||
BfType* propType = methodInst->mReturnType;
|
||||
if (methodDef->mMethodType == BfMethodType_PropertySetter)
|
||||
propType = methodInst->GetParamType(0);
|
||||
impl += mModule->TypeToString(propType, BfTypeNameFlag_ReduceName);
|
||||
impl += mModule->TypeToString(propType, nameFlags);
|
||||
impl += " ";
|
||||
if (isExplicitInterface)
|
||||
{
|
||||
impl += mModule->TypeToString(methodInst->GetOwner(), BfTypeNameFlag_ReduceName);
|
||||
impl += mModule->TypeToString(methodInst->GetOwner(), nameFlags);
|
||||
impl += ".";
|
||||
}
|
||||
|
||||
|
@ -2589,9 +2640,6 @@ void BfAutoComplete::CheckInterfaceFixit(BfTypeInstance* typeInstance, BfAstNode
|
|||
if (ifaceMethodInst == NULL)
|
||||
continue;
|
||||
|
||||
// Don't even try to match generics
|
||||
if (!ifaceMethodInst->mMethodDef->mGenericParams.IsEmpty())
|
||||
continue;
|
||||
auto iReturnType = ifaceMethodInst->mReturnType;
|
||||
if (iReturnType->IsSelf())
|
||||
iReturnType = typeInstance;
|
||||
|
|
|
@ -2954,10 +2954,11 @@ void BfCompiler::UpdateRevisedTypes()
|
|||
continue;
|
||||
}
|
||||
|
||||
// Only allow extending structs and objects
|
||||
// Only allow extending structs, objects, and interfaces
|
||||
if ((checkTypeDef->mTypeCode == BfTypeCode_Struct) ||
|
||||
(checkTypeDef->mTypeCode == BfTypeCode_Object) ||
|
||||
(checkTypeDef->mTypeCode == BfTypeCode_Enum))
|
||||
(checkTypeDef->mTypeCode == BfTypeCode_Enum) ||
|
||||
(checkTypeDef->mTypeCode == BfTypeCode_Interface))
|
||||
{
|
||||
rootTypeDef = checkTypeDef;
|
||||
rootTypeDefEntry = checkTypeDefEntry;
|
||||
|
@ -5016,7 +5017,10 @@ void BfCompiler::PopulateReified()
|
|||
BfMethodInstance* implMethod = *implMethodRef;
|
||||
if (implMethod == NULL)
|
||||
continue;
|
||||
if (!implMethod->IsReifiedAndImplemented())
|
||||
|
||||
// Reify any interface methods that could be called dynamically
|
||||
if ((!implMethod->IsReifiedAndImplemented()) && (implMethod->GetNumGenericParams() == 0) && (!implMethod->mMethodDef->mIsStatic) &&
|
||||
(!implMethod->mReturnType->IsConcreteInterfaceType()))
|
||||
{
|
||||
didWork = true;
|
||||
checkType->mModule->GetMethodInstance(implMethod);
|
||||
|
|
|
@ -1527,22 +1527,13 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
|||
goto NoMatch;
|
||||
}
|
||||
|
||||
// if (genericArg->IsPrimitiveType())
|
||||
// {
|
||||
// auto primType = (BfPrimitiveType*) genericArg;
|
||||
// genericArg = mModule->GetPrimitiveStructType(primType->mTypeDef->mTypeCode);
|
||||
// }
|
||||
|
||||
if (genericArg == NULL)
|
||||
goto NoMatch;
|
||||
|
||||
//SetAndRestoreValue<bool> ignoreError(mModule->mIgnoreErrors, true);
|
||||
if (!mModule->CheckGenericConstraints(BfGenericParamSource(methodInstance), genericArg, NULL, genericParams[checkGenericIdx], genericArgumentsSubstitute, NULL))
|
||||
{
|
||||
goto NoMatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method is applicable, check to see which method is better
|
||||
if (mBestMethodDef != NULL)
|
||||
|
@ -1904,6 +1895,11 @@ void BfMethodMatcher::TryDevirtualizeCall(BfTypedValue target, BfTypedValue* ori
|
|||
if (mModule->mBfIRBuilder->mIgnoreWrites)
|
||||
return;
|
||||
|
||||
if (mBestMethodDef->mName == "Quab")
|
||||
{
|
||||
NOP;
|
||||
}
|
||||
|
||||
if (mBestMethodTypeInstance->IsInterface())
|
||||
{
|
||||
mModule->PopulateType(mBestMethodTypeInstance, BfPopulateType_DataAndMethods);
|
||||
|
@ -5680,10 +5676,22 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
|||
{
|
||||
// Allow a base call to be defined
|
||||
}
|
||||
else if ((methodInstance->IsSpecializedGenericMethod()) && (origTarget) && (!origTarget.mType->IsInterface()))
|
||||
{
|
||||
if (!mModule->mBfIRBuilder->mIgnoreWrites)
|
||||
mModule->AssertErrorState();
|
||||
}
|
||||
else if ((!mModule->mCurMethodInstance->mIsUnspecialized))
|
||||
{
|
||||
// Compiler error?
|
||||
mModule->Fail(StrFormat("Unable to dynamically dispatch '%s'", mModule->MethodToString(methodInstance).c_str()), targetSrc);
|
||||
|
||||
String errorString = "Unable to dynamically dispatch '%s'";
|
||||
if (methodInstance->IsSpecializedGenericMethod())
|
||||
errorString = "Unable to dynamically dispatch '%s' because generic methods can only be directly dispatched";
|
||||
if (methodInstance->mReturnType->IsConcreteInterfaceType())
|
||||
errorString = "Unable to dynamically dispatch '%s' because the concrete return type is unknown";
|
||||
|
||||
mModule->Fail(StrFormat(errorString.c_str(), mModule->MethodToString(methodInstance).c_str()), targetSrc);
|
||||
}
|
||||
|
||||
//BF_ASSERT(mModule->mCurMethodInstance->mIsUnspecialized);
|
||||
|
@ -6600,6 +6608,11 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
methodMatcher.CheckType(lookupTypeInst, target, true);
|
||||
}
|
||||
|
||||
if ((methodMatcher.mBestMethodDef != NULL) && (methodMatcher.mBestMethodDef->mName == "Zorf"))
|
||||
{
|
||||
NOP;
|
||||
}
|
||||
|
||||
BfTypedValue staticResult;
|
||||
methodMatcher.TryDevirtualizeCall(target, &origTarget, &staticResult);
|
||||
if (staticResult)
|
||||
|
@ -7055,6 +7068,11 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
else
|
||||
MakeBaseConcrete(target);
|
||||
|
||||
if ((moduleMethodInstance.mMethodInstance->mMethodDef->mName == "GetVal") && (targetTypeInst != NULL) && (mModule->mCurTypeInstance->mTypeDef->mName->ToString() == "ClassD"))
|
||||
{
|
||||
NOP;
|
||||
}
|
||||
|
||||
BfTypedValue callTarget;
|
||||
if (isSkipCall)
|
||||
{
|
||||
|
@ -7070,6 +7088,13 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
}
|
||||
else
|
||||
callTarget = target;
|
||||
|
||||
if ((callTarget) && (moduleMethodInstance.mMethodInstance->GetOwner()->IsInterface()))
|
||||
{
|
||||
auto wantThis = moduleMethodInstance.mMethodInstance->GetParamType(-1);
|
||||
if ((callTarget.mType != wantThis) && (wantThis->IsInterface()))
|
||||
callTarget = mModule->Cast(targetSrc, callTarget, wantThis, BfCastFlags_Explicit);
|
||||
}
|
||||
}
|
||||
else if (target)
|
||||
{
|
||||
|
@ -17776,7 +17801,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
|
|||
// If one of these is a constant that can be converted into a smaller type, then do that
|
||||
if (rightValue.mValue.IsConst())
|
||||
{
|
||||
if (mModule->CanCast(rightValue, leftValue.mType))
|
||||
if (mModule->CanCast(rightValue, leftValue.mType, BfCastFlags_NoBox))
|
||||
{
|
||||
resultType = leftValue.mType;
|
||||
handled = true;
|
||||
|
@ -18392,7 +18417,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
|
|||
}
|
||||
else
|
||||
{
|
||||
auto convertedValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType);
|
||||
auto convertedValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox);
|
||||
if (!convertedValue)
|
||||
return;
|
||||
if (binaryOp == BfBinaryOp_Equality)
|
||||
|
|
|
@ -2542,7 +2542,6 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
|
|||
|
||||
if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsUnspecializedVariation))
|
||||
return NULL; // Ignore errors on unspecialized variations, they are always dups
|
||||
|
||||
if (!mHadBuildError)
|
||||
mHadBuildError = true;
|
||||
if (mParentModule != NULL)
|
||||
|
@ -6862,6 +6861,8 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
|
|||
BfType* convCheckConstraint = genericParamInst->mTypeConstraint;
|
||||
if ((convCheckConstraint->IsUnspecializedType()) && (methodGenericArgs != NULL))
|
||||
convCheckConstraint = ResolveGenericType(convCheckConstraint, NULL, methodGenericArgs);
|
||||
if (convCheckConstraint == NULL)
|
||||
return false;
|
||||
if ((checkArgType->IsMethodRef()) && (convCheckConstraint->IsDelegate()))
|
||||
{
|
||||
auto methodRefType = (BfMethodRefType*)checkArgType;
|
||||
|
@ -6933,6 +6934,8 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
|
|||
BfType* convCheckConstraint = checkConstraint;
|
||||
if (convCheckConstraint->IsUnspecializedType())
|
||||
convCheckConstraint = ResolveGenericType(convCheckConstraint, NULL, methodGenericArgs);
|
||||
if (convCheckConstraint == NULL)
|
||||
return false;
|
||||
|
||||
BfTypeInstance* typeConstraintInst = convCheckConstraint->ToTypeInstance();
|
||||
|
||||
|
@ -11059,6 +11062,17 @@ bool BfModule::CompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstan
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BfModule::StrictCompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstance* methodB)
|
||||
{
|
||||
if (!CompareMethodSignatures(methodA, methodB))
|
||||
return false;
|
||||
if (methodA->mReturnType != methodB->mReturnType)
|
||||
return false;
|
||||
if (methodA->mMethodDef->mIsStatic != methodB->mMethodDef->mIsStatic)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BfModule::IsCompatibleInterfaceMethod(BfMethodInstance* iMethodInst, BfMethodInstance* methodInstance)
|
||||
{
|
||||
if (iMethodInst->mMethodDef->mName != methodInstance->mMethodDef->mName)
|
||||
|
@ -13239,7 +13253,7 @@ void BfModule::EmitDefaultReturn()
|
|||
{
|
||||
if (mCurMethodInstance->mReturnType->IsVoid())
|
||||
mBfIRBuilder->CreateRetVoid();
|
||||
else
|
||||
else if (!mCurMethodInstance->HasStructRet())
|
||||
mBfIRBuilder->CreateRet(GetDefaultValue(mCurMethodInstance->mReturnType));
|
||||
}
|
||||
|
||||
|
@ -17564,8 +17578,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
|
|||
}
|
||||
else
|
||||
{
|
||||
// During autocomplete, the actual type may not have the proper field instance
|
||||
mBfIRBuilder->CreateRet(GetDefaultValue(methodInstance->mReturnType));
|
||||
CreateReturn(GetDefaultValue(mCurMethodInstance->mReturnType));
|
||||
EmitDefaultReturn();
|
||||
}
|
||||
mCurMethodState->SetHadReturn(true);
|
||||
}
|
||||
|
@ -20963,6 +20977,7 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo
|
|||
|
||||
if (storeIFaceMethod)
|
||||
{
|
||||
if (methodInstance->GetNumGenericParams() != 0)
|
||||
_AddVirtualDecl(iMethodInst);
|
||||
*iMethodPtr = methodInstance;
|
||||
}
|
||||
|
|
|
@ -76,13 +76,14 @@ enum BfCastFlags
|
|||
BfCastFlags_Unchecked = 2,
|
||||
BfCastFlags_Internal = 4,
|
||||
BfCastFlags_SilentFail = 8,
|
||||
BfCastFlags_NoBoxDtor = 0x10,
|
||||
BfCastFlags_NoConversionOperator = 0x20,
|
||||
BfCastFlags_FromCompiler = 0x40, // Not user specified
|
||||
BfCastFlags_Force = 0x80,
|
||||
BfCastFlags_PreferAddr = 0x100,
|
||||
BfCastFlags_WarnOnBox = 0x200,
|
||||
BfCastFlags_IsCastCheck = 0x400
|
||||
BfCastFlags_NoBox = 0x10,
|
||||
BfCastFlags_NoBoxDtor = 0x20,
|
||||
BfCastFlags_NoConversionOperator = 0x40,
|
||||
BfCastFlags_FromCompiler = 0x80, // Not user specified
|
||||
BfCastFlags_Force = 0x100,
|
||||
BfCastFlags_PreferAddr = 0x200,
|
||||
BfCastFlags_WarnOnBox = 0x400,
|
||||
BfCastFlags_IsCastCheck = 0x800
|
||||
};
|
||||
|
||||
enum BfCastResultFlags
|
||||
|
@ -1778,7 +1779,8 @@ public:
|
|||
BfModuleMethodInstance GetInternalMethod(const StringImpl& methodName, int paramCount = -1);
|
||||
bool IsMethodImplementedAndReified(BfTypeInstance* typeInstance, const StringImpl& methodName, int paramCount = -1, bool checkBase = false);
|
||||
bool HasMixin(BfTypeInstance* typeInstance, const StringImpl& methodName, int paramCount, bool checkBase = false);
|
||||
bool CompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstance* methodB); // Doesn't compare return types
|
||||
bool CompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstance* methodB); // Doesn't compare return types nor static
|
||||
bool StrictCompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstance* methodB); // Compares return types and static
|
||||
bool IsCompatibleInterfaceMethod(BfMethodInstance* methodA, BfMethodInstance* methodB);
|
||||
void UniqueSlotVirtualMethod(BfMethodInstance* methodInstance);
|
||||
void CompareDeclTypes(BfTypeDef* newDeclType, BfTypeDef* prevDeclType, bool& isBetter, bool& isWorse);
|
||||
|
|
|
@ -4093,10 +4093,6 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
|
|||
if (ifaceMethodInst == NULL)
|
||||
continue;
|
||||
|
||||
// Don't even try to match generics
|
||||
if (!ifaceMethodInst->mMethodDef->mGenericParams.IsEmpty())
|
||||
continue;
|
||||
|
||||
auto iReturnType = ifaceMethodInst->mReturnType;
|
||||
if (iReturnType->IsSelf())
|
||||
iReturnType = typeInstance;
|
||||
|
@ -4117,6 +4113,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
|
|||
|
||||
bool hadMatch = matchedMethod != NULL;
|
||||
bool hadPubFailure = false;
|
||||
bool hadStaticFailure = false;
|
||||
bool hadMutFailure = false;
|
||||
|
||||
if (hadMatch)
|
||||
|
@ -4127,6 +4124,12 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
|
|||
hadPubFailure = true;
|
||||
}
|
||||
|
||||
if (matchedMethod->mMethodDef->mIsStatic != ifaceMethodInst->mMethodDef->mIsStatic)
|
||||
{
|
||||
hadMatch = false;
|
||||
hadStaticFailure = true;
|
||||
}
|
||||
|
||||
if (ifaceMethodInst->mVirtualTableIdx != -1)
|
||||
{
|
||||
if (matchedMethod->mReturnType != iReturnType)
|
||||
|
@ -4207,7 +4210,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
|
|||
|
||||
if (bestMethodInst->mReturnType != ifaceMethodInst->mReturnType)
|
||||
{
|
||||
auto error = Fail(StrFormat("Default interface method '%s' cannot be used does not have the return type '%s'",
|
||||
auto error = Fail(StrFormat("Default interface method '%s' cannot be used because it doesn't have the return type '%s'",
|
||||
MethodToString(bestMethodInst).c_str(), TypeToString(ifaceMethodInst->mReturnType).c_str()), declTypeDef->mTypeDeclaration->mNameNode);
|
||||
if (error != NULL)
|
||||
{
|
||||
|
@ -4217,7 +4220,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
|
|||
}
|
||||
}
|
||||
|
||||
if ((bestMethodInst->mMethodDef->HasBody()) && (bestMethodInst->mMethodDef->mGenericParams.size() == 0) && (matchedMethod == NULL))
|
||||
if ((bestMethodInst->mMethodDef->HasBody()) && (matchedMethod == NULL))
|
||||
{
|
||||
auto methodDef = bestMethodInst->mMethodDef;
|
||||
BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_ForeignMethodDef;
|
||||
|
@ -4251,30 +4254,51 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
|
|||
}
|
||||
else
|
||||
{
|
||||
String methodString;
|
||||
///
|
||||
{
|
||||
SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, ifaceMethodInst);
|
||||
methodString = MethodToString(ifaceMethodInst);
|
||||
}
|
||||
|
||||
BfTypeDeclaration* typeDecl = declTypeDef->mTypeDeclaration;
|
||||
BfError* error = Fail(StrFormat("'%s' does not implement interface member '%s'", TypeToString(typeInstance).c_str(), MethodToString(ifaceMethodInst).c_str()), typeDecl->mNameNode, true);
|
||||
BfError* error = Fail(StrFormat("'%s' does not implement interface member '%s'", TypeToString(typeInstance).c_str(), methodString.c_str()), typeDecl->mNameNode, true);
|
||||
if ((matchedMethod != NULL) && (error != NULL))
|
||||
{
|
||||
if (hadPubFailure)
|
||||
if (hadStaticFailure)
|
||||
{
|
||||
mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' cannot match because because it is not public",
|
||||
MethodToString(matchedMethod).c_str()), matchedMethod->mMethodDef->mReturnTypeRef);
|
||||
auto staticNodeRef = matchedMethod->mMethodDef->GetRefNode();
|
||||
if (auto methodDecl = BfNodeDynCast<BfMethodDeclaration>(matchedMethod->mMethodDef->mMethodDeclaration))
|
||||
if (methodDecl->mStaticSpecifier != NULL)
|
||||
staticNodeRef = methodDecl->mStaticSpecifier;
|
||||
|
||||
if (matchedMethod->mMethodDef->mIsStatic)
|
||||
mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' cannot match because because it's static",
|
||||
methodString.c_str()), staticNodeRef);
|
||||
else
|
||||
mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' cannot match because because it's not static",
|
||||
methodString.c_str()), staticNodeRef);
|
||||
}
|
||||
else if (hadPubFailure)
|
||||
{
|
||||
mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' cannot match because because it's not public",
|
||||
methodString.c_str()), matchedMethod->mMethodDef->mReturnTypeRef);
|
||||
}
|
||||
else if (ifaceMethodInst->mReturnType->IsConcreteInterfaceType())
|
||||
{
|
||||
mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' cannot match because because it does not have a concrete return type that implements '%s'",
|
||||
MethodToString(matchedMethod).c_str(), TypeToString(ifaceMethodInst->mReturnType).c_str()), matchedMethod->mMethodDef->mReturnTypeRef);
|
||||
methodString.c_str(), TypeToString(ifaceMethodInst->mReturnType).c_str()), matchedMethod->mMethodDef->mReturnTypeRef);
|
||||
}
|
||||
else if (hadMutFailure)
|
||||
{
|
||||
mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' cannot match because because it is market as 'mut' but interface method does not allow it",
|
||||
MethodToString(matchedMethod).c_str()), matchedMethod->mMethodDef->GetMutNode());
|
||||
mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' cannot match because because it's market as 'mut' but interface method does not allow it",
|
||||
methodString.c_str()), matchedMethod->mMethodDef->GetMutNode());
|
||||
mCompiler->mPassInstance->MoreInfo(StrFormat("Declare the interface method as 'mut' to allow matching 'mut' implementations"), ifaceMethodInst->mMethodDef->mMethodDeclaration);
|
||||
}
|
||||
else
|
||||
{
|
||||
mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' cannot match because because it does not have the return type '%s'",
|
||||
MethodToString(matchedMethod).c_str(), TypeToString(ifaceMethodInst->mReturnType).c_str()), matchedMethod->mMethodDef->mReturnTypeRef);
|
||||
methodString.c_str(), TypeToString(ifaceMethodInst->mReturnType).c_str()), matchedMethod->mMethodDef->mReturnTypeRef);
|
||||
if ((ifaceMethodInst->mVirtualTableIdx != -1) && (ifaceMethodInst->mReturnType->IsInterface()))
|
||||
mCompiler->mPassInstance->MoreInfo("Declare the interface method as 'concrete' to allow matching concrete return values", ifaceMethodInst->mMethodDef->GetMethodDeclaration()->mVirtualSpecifier);
|
||||
}
|
||||
|
@ -6882,6 +6906,10 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
|
|||
|
||||
BfTypeInstance* contextTypeInstance = mCurTypeInstance;
|
||||
BfMethodInstance* contextMethodInstance = mCurMethodInstance;
|
||||
|
||||
if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsForeignMethodDef))
|
||||
contextTypeInstance = mCurMethodInstance->mMethodInfoEx->mForeignType;
|
||||
|
||||
if ((mCurMethodState != NULL) && (mCurMethodState->mMixinState != NULL))
|
||||
{
|
||||
contextTypeInstance = mCurMethodState->mMixinState->mMixinMethodInstance->GetOwner();
|
||||
|
@ -9698,7 +9726,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
|||
}
|
||||
}
|
||||
|
||||
if (mayBeBox)
|
||||
if ((mayBeBox) && ((castFlags & BfCastFlags_NoBox) == 0))
|
||||
{
|
||||
BfScopeData* scopeData = NULL;
|
||||
if (mCurMethodState != NULL)
|
||||
|
|
|
@ -4660,6 +4660,11 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF
|
|||
|
||||
if (tokenNode->GetToken() == BfToken_RParen)
|
||||
{
|
||||
if ((fieldTypes.size() == 1) && ((createTypeRefFlags & CreateTypeRefFlags_AllowSingleMemberTuple) == 0))
|
||||
{
|
||||
Fail("Tuple types must contain more than one member", tokenNode);
|
||||
}
|
||||
|
||||
MEMBER_SET(tupleTypeRef, mCloseParen, tokenNode);
|
||||
//return tupleTypeRef;
|
||||
firstNode = tupleTypeRef;
|
||||
|
@ -5733,7 +5738,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, int depth)
|
|||
tokenNode = ExpectTokenAfter(enumEntry, BfToken_Comma, BfToken_AssignEquals, BfToken_LParen, BfToken_Semicolon);
|
||||
if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_LParen))
|
||||
{
|
||||
auto typeRef = CreateTypeRef(tokenNode);
|
||||
auto typeRef = CreateTypeRef(tokenNode, CreateTypeRefFlags_AllowSingleMemberTuple);
|
||||
tokenNode = NULL;
|
||||
auto tupleType = BfNodeDynCast<BfTupleTypeRef>(typeRef);
|
||||
if (tupleType != NULL)
|
||||
|
@ -9202,7 +9207,10 @@ BfGenericConstraintsDeclaration* BfReducer::CreateGenericConstraintsDeclaration(
|
|||
if (opConstraint->mOpToken == NULL)
|
||||
{
|
||||
if (opToken == NULL)
|
||||
{
|
||||
Fail("Conversion operators require either 'implicit' or 'explicit' qualifiers", opConstraint->mOperatorToken);
|
||||
break;
|
||||
}
|
||||
MEMBER_SET(opConstraint, mOpToken, opToken);
|
||||
mVisitorPos.MoveNext();
|
||||
}
|
||||
|
|
|
@ -44,7 +44,8 @@ public:
|
|||
{
|
||||
CreateTypeRefFlags_None,
|
||||
CreateTypeRefFlags_NoParseArrayBrackets = 1,
|
||||
CreateTypeRefFlags_SafeGenericParse = 2
|
||||
CreateTypeRefFlags_SafeGenericParse = 2,
|
||||
CreateTypeRefFlags_AllowSingleMemberTuple = 4
|
||||
};
|
||||
|
||||
struct BfVisitorPos
|
||||
|
|
|
@ -202,7 +202,8 @@ BfNonGenericMethodRef& BfNonGenericMethodRef::operator=(BfMethodInstance* method
|
|||
{
|
||||
mTypeInstance = methodInstance->mMethodInstanceGroup->mOwner;
|
||||
mMethodNum = methodInstance->mMethodInstanceGroup->mMethodIdx;
|
||||
BF_ASSERT(methodInstance->GetNumGenericArguments() == 0);
|
||||
BF_ASSERT((methodInstance->GetNumGenericArguments() == 0) ||
|
||||
((methodInstance->mIsUnspecialized) && (!methodInstance->mIsUnspecializedVariation)));
|
||||
mSignatureHash = (int)mTypeInstance->mTypeDef->mSignatureHash;
|
||||
}
|
||||
return *this;
|
||||
|
|
|
@ -1254,11 +1254,11 @@ void BfPassInstance::MessageAt(const StringImpl& msgPrefix, const StringImpl& er
|
|||
|
||||
if (isFullUnderline)
|
||||
{
|
||||
isFullUnderline = true;
|
||||
for (int i = srcIdx; i < srcIdx + srcLen; VisibleAdvance(bfParser->mSrc, bfParser->mSrcLength, i))
|
||||
isFullUnderline = false;
|
||||
for (int i = srcIdx; i <= srcIdx + srcLen; VisibleAdvance(bfParser->mSrc, bfParser->mSrcLength, i))
|
||||
{
|
||||
char c = bfParser->mSrc[i];
|
||||
if (c == '\n')
|
||||
if ((c == '\n') || (c == '\0'))
|
||||
{
|
||||
isFullUnderline = true;
|
||||
break;
|
||||
|
|
|
@ -123,5 +123,115 @@ namespace Tests
|
|||
Test.Assert(UseIA2(cc) == 70);
|
||||
Test.Assert(UseIA2(cca) == 70);
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
interface IFaceD<T>
|
||||
{
|
||||
T GetVal();
|
||||
|
||||
T Add<T2>(T lhs, T2 rhs) where T : operator T + T2
|
||||
{
|
||||
return lhs + rhs;
|
||||
}
|
||||
|
||||
static T SMethod(T val);
|
||||
|
||||
static T SMethod2(T val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
extension IFaceD<T>
|
||||
{
|
||||
T GetVal2()
|
||||
{
|
||||
return GetVal();
|
||||
}
|
||||
}
|
||||
|
||||
class ClassD : IFaceD<int16>
|
||||
{
|
||||
public int16 GetVal()
|
||||
{
|
||||
return 123;
|
||||
}
|
||||
|
||||
public int16 Add<T2>(int16 lhs, T2 rhs) where int16 : operator int16 + T2
|
||||
{
|
||||
return lhs + rhs + 1000;
|
||||
}
|
||||
|
||||
public static int16 SMethod(int16 val)
|
||||
{
|
||||
return val + 2000;
|
||||
}
|
||||
}
|
||||
|
||||
class ClassE : IFaceD<int16>
|
||||
{
|
||||
public int16 GetVal()
|
||||
{
|
||||
return 234;
|
||||
}
|
||||
|
||||
public static int16 SMethod(int16 val)
|
||||
{
|
||||
return val + 3000;
|
||||
}
|
||||
|
||||
public static int16 SMethod2(int16 val)
|
||||
{
|
||||
return val + 4000;
|
||||
}
|
||||
}
|
||||
|
||||
public static int IDAdd<T>(T val) where T : IFaceD<int16>
|
||||
{
|
||||
return val.Add((int16)23, (int8)100);
|
||||
}
|
||||
|
||||
public static T2 SGet<T, T2>(T val) where T : IFaceD<T2>
|
||||
{
|
||||
return T.SMethod(val.GetVal());
|
||||
}
|
||||
|
||||
public static T2 SGet2<T, T2>(T val) where T : IFaceD<T2>
|
||||
{
|
||||
return T.SMethod2(val.GetVal());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void TestDefaults()
|
||||
{
|
||||
ClassD cd = scope .();
|
||||
IFaceD<int16> ifd = cd;
|
||||
|
||||
int v = ifd.GetVal();
|
||||
|
||||
Test.Assert(v == 123);
|
||||
v = ifd.GetVal2();
|
||||
Test.Assert(v == 123);
|
||||
v = IDAdd(cd);
|
||||
Test.Assert(v == 1123);
|
||||
v = SGet<ClassD, int16>(cd);
|
||||
Test.Assert(v == 2123);
|
||||
v = SGet2<ClassD, int16>(cd);
|
||||
Test.Assert(v == 123);
|
||||
|
||||
ClassE ce = scope .();
|
||||
ifd = ce;
|
||||
v = ifd.GetVal();
|
||||
Test.Assert(v == 234);
|
||||
v = ifd.GetVal2();
|
||||
Test.Assert(v == 234);
|
||||
v = IDAdd(ce);
|
||||
Test.Assert(v == 123);
|
||||
v = SGet<ClassE, int16>(ce);
|
||||
Test.Assert(v == 3234);
|
||||
v = SGet2<ClassE, int16>(ce);
|
||||
Test.Assert(v == 4234);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -270,5 +270,17 @@ namespace Tests
|
|||
|
||||
TestDefaults();
|
||||
}
|
||||
|
||||
public static TTo Convert<TFrom, TTo>(TFrom val) where TTo : operator explicit TFrom
|
||||
{
|
||||
return (TTo)val;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void TestConversion()
|
||||
{
|
||||
int a = 123;
|
||||
float f = Convert<int, float>(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue