1
0
Fork 0
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:
Brian Fiete 2020-05-27 09:46:09 -07:00
parent bff1d657cc
commit 6cb2df65a6
12 changed files with 322 additions and 68 deletions

View file

@ -1546,8 +1546,10 @@ bool BfAutoComplete::CheckMemberReference(BfAstNode* target, BfAstNode* dotToken
auto _HandleGenericParamInstance = [&](BfGenericParamInstance* genericParamInstance) auto _HandleGenericParamInstance = [&](BfGenericParamInstance* genericParamInstance)
{ {
bool showStatics = !targetValue.mValue;
for (auto interfaceConstraint : genericParamInstance->mInterfaceConstraints) 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) if (genericParamInstance->mTypeConstraint != NULL)
checkType = genericParamInstance->mTypeConstraint; 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) bool BfAutoComplete::GetMethodInfo(BfMethodInstance* methodInst, StringImpl* showString, StringImpl* insertString, bool isImplementing, bool isExplicitInterface)
{ {
SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mModule->mCurMethodInstance, methodInst);
auto methodDef = methodInst->mMethodDef; auto methodDef = methodInst->mMethodDef;
bool isInterface = methodInst->GetOwner()->IsInterface(); bool isInterface = methodInst->GetOwner()->IsInterface();
BfTypeNameFlags nameFlags = (BfTypeNameFlags)(BfTypeNameFlag_ReduceName | BfTypeNameFlag_ResolveGenericParamNames);
if (methodDef->mMethodType == BfMethodType_Normal) if (methodDef->mMethodType == BfMethodType_Normal)
{ {
StringT<128> methodPrefix; StringT<128> methodPrefix;
@ -1965,15 +1971,33 @@ bool BfAutoComplete::GetMethodInfo(BfMethodInstance* methodInst, StringImpl* sho
methodPrefix += methodDeclaration->mProtectionSpecifier->ToString() + " "; methodPrefix += methodDeclaration->mProtectionSpecifier->ToString() + " ";
if (!isInterface) if (!isInterface)
methodPrefix += "override "; methodPrefix += "override ";
methodPrefix += mModule->TypeToString(methodInst->mReturnType, BfTypeNameFlag_ReduceName); if (methodDef->mIsStatic)
methodPrefix += "static ";
methodPrefix += mModule->TypeToString(methodInst->mReturnType, nameFlags);
methodPrefix += " "; methodPrefix += " ";
if (isExplicitInterface) if (isExplicitInterface)
{ {
methodName += mModule->TypeToString(methodInst->GetOwner(), BfTypeNameFlag_ReduceName); methodName += mModule->TypeToString(methodInst->GetOwner(), nameFlags);
methodName += "."; methodName += ".";
} }
methodName += methodDef->mName; 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 += "("; methodName += "(";
for (int paramIdx = 0; paramIdx < (int)methodInst->GetParamCount(); paramIdx++) for (int paramIdx = 0; paramIdx < (int)methodInst->GetParamCount(); paramIdx++)
{ {
@ -1983,7 +2007,7 @@ bool BfAutoComplete::GetMethodInfo(BfMethodInstance* methodInst, StringImpl* sho
if (!isAbstract) if (!isAbstract)
impString += ", "; impString += ", ";
} }
methodName += mModule->TypeToString(methodInst->GetParamType(paramIdx), BfTypeNameFlag_ReduceName); methodName += mModule->TypeToString(methodInst->GetParamType(paramIdx), nameFlags);
methodName += " "; methodName += " ";
methodName += methodDef->mParams[paramIdx]->mName; methodName += methodDef->mParams[paramIdx]->mName;
@ -1999,6 +2023,33 @@ bool BfAutoComplete::GetMethodInfo(BfMethodInstance* methodInst, StringImpl* sho
} }
methodName += ")"; 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) if (!isAbstract)
impString += ");"; impString += ");";
@ -2037,11 +2088,11 @@ bool BfAutoComplete::GetMethodInfo(BfMethodInstance* methodInst, StringImpl* sho
BfType* propType = methodInst->mReturnType; BfType* propType = methodInst->mReturnType;
if (methodDef->mMethodType == BfMethodType_PropertySetter) if (methodDef->mMethodType == BfMethodType_PropertySetter)
propType = methodInst->GetParamType(0); propType = methodInst->GetParamType(0);
impl += mModule->TypeToString(propType, BfTypeNameFlag_ReduceName); impl += mModule->TypeToString(propType, nameFlags);
impl += " "; impl += " ";
if (isExplicitInterface) if (isExplicitInterface)
{ {
impl += mModule->TypeToString(methodInst->GetOwner(), BfTypeNameFlag_ReduceName); impl += mModule->TypeToString(methodInst->GetOwner(), nameFlags);
impl += "."; impl += ".";
} }
@ -2589,9 +2640,6 @@ void BfAutoComplete::CheckInterfaceFixit(BfTypeInstance* typeInstance, BfAstNode
if (ifaceMethodInst == NULL) if (ifaceMethodInst == NULL)
continue; continue;
// Don't even try to match generics
if (!ifaceMethodInst->mMethodDef->mGenericParams.IsEmpty())
continue;
auto iReturnType = ifaceMethodInst->mReturnType; auto iReturnType = ifaceMethodInst->mReturnType;
if (iReturnType->IsSelf()) if (iReturnType->IsSelf())
iReturnType = typeInstance; iReturnType = typeInstance;

View file

@ -2954,10 +2954,11 @@ void BfCompiler::UpdateRevisedTypes()
continue; continue;
} }
// Only allow extending structs and objects // Only allow extending structs, objects, and interfaces
if ((checkTypeDef->mTypeCode == BfTypeCode_Struct) || if ((checkTypeDef->mTypeCode == BfTypeCode_Struct) ||
(checkTypeDef->mTypeCode == BfTypeCode_Object) || (checkTypeDef->mTypeCode == BfTypeCode_Object) ||
(checkTypeDef->mTypeCode == BfTypeCode_Enum)) (checkTypeDef->mTypeCode == BfTypeCode_Enum) ||
(checkTypeDef->mTypeCode == BfTypeCode_Interface))
{ {
rootTypeDef = checkTypeDef; rootTypeDef = checkTypeDef;
rootTypeDefEntry = checkTypeDefEntry; rootTypeDefEntry = checkTypeDefEntry;
@ -5016,7 +5017,10 @@ void BfCompiler::PopulateReified()
BfMethodInstance* implMethod = *implMethodRef; BfMethodInstance* implMethod = *implMethodRef;
if (implMethod == NULL) if (implMethod == NULL)
continue; 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; didWork = true;
checkType->mModule->GetMethodInstance(implMethod); checkType->mModule->GetMethodInstance(implMethod);

View file

@ -1527,22 +1527,13 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
goto NoMatch; goto NoMatch;
} }
// if (genericArg->IsPrimitiveType())
// {
// auto primType = (BfPrimitiveType*) genericArg;
// genericArg = mModule->GetPrimitiveStructType(primType->mTypeDef->mTypeCode);
// }
if (genericArg == NULL) if (genericArg == NULL)
goto NoMatch; goto NoMatch;
//SetAndRestoreValue<bool> ignoreError(mModule->mIgnoreErrors, true);
if (!mModule->CheckGenericConstraints(BfGenericParamSource(methodInstance), genericArg, NULL, genericParams[checkGenericIdx], genericArgumentsSubstitute, NULL)) if (!mModule->CheckGenericConstraints(BfGenericParamSource(methodInstance), genericArg, NULL, genericParams[checkGenericIdx], genericArgumentsSubstitute, NULL))
{
goto NoMatch; goto NoMatch;
} }
} }
}
// Method is applicable, check to see which method is better // Method is applicable, check to see which method is better
if (mBestMethodDef != NULL) if (mBestMethodDef != NULL)
@ -1904,6 +1895,11 @@ 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);
@ -5680,10 +5676,22 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
{ {
// Allow a base call to be defined // 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)) else if ((!mModule->mCurMethodInstance->mIsUnspecialized))
{ {
// Compiler error? // 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); //BF_ASSERT(mModule->mCurMethodInstance->mIsUnspecialized);
@ -6600,6 +6608,11 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
methodMatcher.CheckType(lookupTypeInst, target, true); methodMatcher.CheckType(lookupTypeInst, target, true);
} }
if ((methodMatcher.mBestMethodDef != NULL) && (methodMatcher.mBestMethodDef->mName == "Zorf"))
{
NOP;
}
BfTypedValue staticResult; BfTypedValue staticResult;
methodMatcher.TryDevirtualizeCall(target, &origTarget, &staticResult); methodMatcher.TryDevirtualizeCall(target, &origTarget, &staticResult);
if (staticResult) if (staticResult)
@ -7055,6 +7068,11 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
else else
MakeBaseConcrete(target); MakeBaseConcrete(target);
if ((moduleMethodInstance.mMethodInstance->mMethodDef->mName == "GetVal") && (targetTypeInst != NULL) && (mModule->mCurTypeInstance->mTypeDef->mName->ToString() == "ClassD"))
{
NOP;
}
BfTypedValue callTarget; BfTypedValue callTarget;
if (isSkipCall) if (isSkipCall)
{ {
@ -7070,6 +7088,13 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
} }
else else
callTarget = target; 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) 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 one of these is a constant that can be converted into a smaller type, then do that
if (rightValue.mValue.IsConst()) if (rightValue.mValue.IsConst())
{ {
if (mModule->CanCast(rightValue, leftValue.mType)) if (mModule->CanCast(rightValue, leftValue.mType, BfCastFlags_NoBox))
{ {
resultType = leftValue.mType; resultType = leftValue.mType;
handled = true; handled = true;
@ -18392,7 +18417,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
} }
else else
{ {
auto convertedValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType); auto convertedValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox);
if (!convertedValue) if (!convertedValue)
return; return;
if (binaryOp == BfBinaryOp_Equality) if (binaryOp == BfBinaryOp_Equality)

View file

@ -2542,7 +2542,6 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsUnspecializedVariation)) if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsUnspecializedVariation))
return NULL; // Ignore errors on unspecialized variations, they are always dups return NULL; // Ignore errors on unspecialized variations, they are always dups
if (!mHadBuildError) if (!mHadBuildError)
mHadBuildError = true; mHadBuildError = true;
if (mParentModule != NULL) if (mParentModule != NULL)
@ -6862,6 +6861,8 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
BfType* convCheckConstraint = genericParamInst->mTypeConstraint; BfType* convCheckConstraint = genericParamInst->mTypeConstraint;
if ((convCheckConstraint->IsUnspecializedType()) && (methodGenericArgs != NULL)) if ((convCheckConstraint->IsUnspecializedType()) && (methodGenericArgs != NULL))
convCheckConstraint = ResolveGenericType(convCheckConstraint, NULL, methodGenericArgs); convCheckConstraint = ResolveGenericType(convCheckConstraint, NULL, methodGenericArgs);
if (convCheckConstraint == NULL)
return false;
if ((checkArgType->IsMethodRef()) && (convCheckConstraint->IsDelegate())) if ((checkArgType->IsMethodRef()) && (convCheckConstraint->IsDelegate()))
{ {
auto methodRefType = (BfMethodRefType*)checkArgType; auto methodRefType = (BfMethodRefType*)checkArgType;
@ -6933,6 +6934,8 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
BfType* convCheckConstraint = checkConstraint; BfType* convCheckConstraint = checkConstraint;
if (convCheckConstraint->IsUnspecializedType()) if (convCheckConstraint->IsUnspecializedType())
convCheckConstraint = ResolveGenericType(convCheckConstraint, NULL, methodGenericArgs); convCheckConstraint = ResolveGenericType(convCheckConstraint, NULL, methodGenericArgs);
if (convCheckConstraint == NULL)
return false;
BfTypeInstance* typeConstraintInst = convCheckConstraint->ToTypeInstance(); BfTypeInstance* typeConstraintInst = convCheckConstraint->ToTypeInstance();
@ -11059,6 +11062,17 @@ bool BfModule::CompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstan
return true; 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) bool BfModule::IsCompatibleInterfaceMethod(BfMethodInstance* iMethodInst, BfMethodInstance* methodInstance)
{ {
if (iMethodInst->mMethodDef->mName != methodInstance->mMethodDef->mName) if (iMethodInst->mMethodDef->mName != methodInstance->mMethodDef->mName)
@ -13239,7 +13253,7 @@ void BfModule::EmitDefaultReturn()
{ {
if (mCurMethodInstance->mReturnType->IsVoid()) if (mCurMethodInstance->mReturnType->IsVoid())
mBfIRBuilder->CreateRetVoid(); mBfIRBuilder->CreateRetVoid();
else else if (!mCurMethodInstance->HasStructRet())
mBfIRBuilder->CreateRet(GetDefaultValue(mCurMethodInstance->mReturnType)); mBfIRBuilder->CreateRet(GetDefaultValue(mCurMethodInstance->mReturnType));
} }
@ -17564,8 +17578,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
} }
else else
{ {
// During autocomplete, the actual type may not have the proper field instance CreateReturn(GetDefaultValue(mCurMethodInstance->mReturnType));
mBfIRBuilder->CreateRet(GetDefaultValue(methodInstance->mReturnType)); EmitDefaultReturn();
} }
mCurMethodState->SetHadReturn(true); mCurMethodState->SetHadReturn(true);
} }
@ -20963,6 +20977,7 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo
if (storeIFaceMethod) if (storeIFaceMethod)
{ {
if (methodInstance->GetNumGenericParams() != 0)
_AddVirtualDecl(iMethodInst); _AddVirtualDecl(iMethodInst);
*iMethodPtr = methodInstance; *iMethodPtr = methodInstance;
} }

View file

@ -76,13 +76,14 @@ enum BfCastFlags
BfCastFlags_Unchecked = 2, BfCastFlags_Unchecked = 2,
BfCastFlags_Internal = 4, BfCastFlags_Internal = 4,
BfCastFlags_SilentFail = 8, BfCastFlags_SilentFail = 8,
BfCastFlags_NoBoxDtor = 0x10, BfCastFlags_NoBox = 0x10,
BfCastFlags_NoConversionOperator = 0x20, BfCastFlags_NoBoxDtor = 0x20,
BfCastFlags_FromCompiler = 0x40, // Not user specified BfCastFlags_NoConversionOperator = 0x40,
BfCastFlags_Force = 0x80, BfCastFlags_FromCompiler = 0x80, // Not user specified
BfCastFlags_PreferAddr = 0x100, BfCastFlags_Force = 0x100,
BfCastFlags_WarnOnBox = 0x200, BfCastFlags_PreferAddr = 0x200,
BfCastFlags_IsCastCheck = 0x400 BfCastFlags_WarnOnBox = 0x400,
BfCastFlags_IsCastCheck = 0x800
}; };
enum BfCastResultFlags enum BfCastResultFlags
@ -1778,7 +1779,8 @@ public:
BfModuleMethodInstance GetInternalMethod(const StringImpl& methodName, int paramCount = -1); BfModuleMethodInstance GetInternalMethod(const StringImpl& methodName, int paramCount = -1);
bool IsMethodImplementedAndReified(BfTypeInstance* typeInstance, const StringImpl& methodName, int paramCount = -1, bool checkBase = false); 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 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); bool IsCompatibleInterfaceMethod(BfMethodInstance* methodA, BfMethodInstance* methodB);
void UniqueSlotVirtualMethod(BfMethodInstance* methodInstance); void UniqueSlotVirtualMethod(BfMethodInstance* methodInstance);
void CompareDeclTypes(BfTypeDef* newDeclType, BfTypeDef* prevDeclType, bool& isBetter, bool& isWorse); void CompareDeclTypes(BfTypeDef* newDeclType, BfTypeDef* prevDeclType, bool& isBetter, bool& isWorse);

View file

@ -4093,10 +4093,6 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
if (ifaceMethodInst == NULL) if (ifaceMethodInst == NULL)
continue; continue;
// Don't even try to match generics
if (!ifaceMethodInst->mMethodDef->mGenericParams.IsEmpty())
continue;
auto iReturnType = ifaceMethodInst->mReturnType; auto iReturnType = ifaceMethodInst->mReturnType;
if (iReturnType->IsSelf()) if (iReturnType->IsSelf())
iReturnType = typeInstance; iReturnType = typeInstance;
@ -4117,6 +4113,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
bool hadMatch = matchedMethod != NULL; bool hadMatch = matchedMethod != NULL;
bool hadPubFailure = false; bool hadPubFailure = false;
bool hadStaticFailure = false;
bool hadMutFailure = false; bool hadMutFailure = false;
if (hadMatch) if (hadMatch)
@ -4127,6 +4124,12 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
hadPubFailure = true; hadPubFailure = true;
} }
if (matchedMethod->mMethodDef->mIsStatic != ifaceMethodInst->mMethodDef->mIsStatic)
{
hadMatch = false;
hadStaticFailure = true;
}
if (ifaceMethodInst->mVirtualTableIdx != -1) if (ifaceMethodInst->mVirtualTableIdx != -1)
{ {
if (matchedMethod->mReturnType != iReturnType) if (matchedMethod->mReturnType != iReturnType)
@ -4207,7 +4210,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
if (bestMethodInst->mReturnType != ifaceMethodInst->mReturnType) 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); MethodToString(bestMethodInst).c_str(), TypeToString(ifaceMethodInst->mReturnType).c_str()), declTypeDef->mTypeDeclaration->mNameNode);
if (error != NULL) 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; auto methodDef = bestMethodInst->mMethodDef;
BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_ForeignMethodDef; BfGetMethodInstanceFlags flags = BfGetMethodInstanceFlag_ForeignMethodDef;
@ -4251,30 +4254,51 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
} }
else else
{ {
String methodString;
///
{
SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, ifaceMethodInst);
methodString = MethodToString(ifaceMethodInst);
}
BfTypeDeclaration* typeDecl = declTypeDef->mTypeDeclaration; 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 ((matchedMethod != NULL) && (error != NULL))
{ {
if (hadPubFailure) if (hadStaticFailure)
{ {
mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' cannot match because because it is not public", auto staticNodeRef = matchedMethod->mMethodDef->GetRefNode();
MethodToString(matchedMethod).c_str()), matchedMethod->mMethodDef->mReturnTypeRef); 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()) 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'", 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) else if (hadMutFailure)
{ {
mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' cannot match because because it is market as 'mut' but interface method does not allow it", mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' cannot match because because it's market as 'mut' but interface method does not allow it",
MethodToString(matchedMethod).c_str()), matchedMethod->mMethodDef->GetMutNode()); methodString.c_str()), matchedMethod->mMethodDef->GetMutNode());
mCompiler->mPassInstance->MoreInfo(StrFormat("Declare the interface method as 'mut' to allow matching 'mut' implementations"), ifaceMethodInst->mMethodDef->mMethodDeclaration); mCompiler->mPassInstance->MoreInfo(StrFormat("Declare the interface method as 'mut' to allow matching 'mut' implementations"), ifaceMethodInst->mMethodDef->mMethodDeclaration);
} }
else else
{ {
mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' cannot match because because it does not have the return type '%s'", 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())) 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); 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; BfTypeInstance* contextTypeInstance = mCurTypeInstance;
BfMethodInstance* contextMethodInstance = mCurMethodInstance; BfMethodInstance* contextMethodInstance = mCurMethodInstance;
if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsForeignMethodDef))
contextTypeInstance = mCurMethodInstance->mMethodInfoEx->mForeignType;
if ((mCurMethodState != NULL) && (mCurMethodState->mMixinState != NULL)) if ((mCurMethodState != NULL) && (mCurMethodState->mMixinState != NULL))
{ {
contextTypeInstance = mCurMethodState->mMixinState->mMixinMethodInstance->GetOwner(); 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; BfScopeData* scopeData = NULL;
if (mCurMethodState != NULL) if (mCurMethodState != NULL)

View file

@ -4660,6 +4660,11 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF
if (tokenNode->GetToken() == BfToken_RParen) 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); MEMBER_SET(tupleTypeRef, mCloseParen, tokenNode);
//return tupleTypeRef; //return tupleTypeRef;
firstNode = 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); tokenNode = ExpectTokenAfter(enumEntry, BfToken_Comma, BfToken_AssignEquals, BfToken_LParen, BfToken_Semicolon);
if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_LParen)) if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_LParen))
{ {
auto typeRef = CreateTypeRef(tokenNode); auto typeRef = CreateTypeRef(tokenNode, CreateTypeRefFlags_AllowSingleMemberTuple);
tokenNode = NULL; tokenNode = NULL;
auto tupleType = BfNodeDynCast<BfTupleTypeRef>(typeRef); auto tupleType = BfNodeDynCast<BfTupleTypeRef>(typeRef);
if (tupleType != NULL) if (tupleType != NULL)
@ -9202,7 +9207,10 @@ BfGenericConstraintsDeclaration* BfReducer::CreateGenericConstraintsDeclaration(
if (opConstraint->mOpToken == NULL) if (opConstraint->mOpToken == NULL)
{ {
if (opToken == NULL) if (opToken == NULL)
{
Fail("Conversion operators require either 'implicit' or 'explicit' qualifiers", opConstraint->mOperatorToken);
break; break;
}
MEMBER_SET(opConstraint, mOpToken, opToken); MEMBER_SET(opConstraint, mOpToken, opToken);
mVisitorPos.MoveNext(); mVisitorPos.MoveNext();
} }

View file

@ -44,7 +44,8 @@ public:
{ {
CreateTypeRefFlags_None, CreateTypeRefFlags_None,
CreateTypeRefFlags_NoParseArrayBrackets = 1, CreateTypeRefFlags_NoParseArrayBrackets = 1,
CreateTypeRefFlags_SafeGenericParse = 2 CreateTypeRefFlags_SafeGenericParse = 2,
CreateTypeRefFlags_AllowSingleMemberTuple = 4
}; };
struct BfVisitorPos struct BfVisitorPos

View file

@ -202,7 +202,8 @@ BfNonGenericMethodRef& BfNonGenericMethodRef::operator=(BfMethodInstance* method
{ {
mTypeInstance = methodInstance->mMethodInstanceGroup->mOwner; mTypeInstance = methodInstance->mMethodInstanceGroup->mOwner;
mMethodNum = methodInstance->mMethodInstanceGroup->mMethodIdx; mMethodNum = methodInstance->mMethodInstanceGroup->mMethodIdx;
BF_ASSERT(methodInstance->GetNumGenericArguments() == 0); BF_ASSERT((methodInstance->GetNumGenericArguments() == 0) ||
((methodInstance->mIsUnspecialized) && (!methodInstance->mIsUnspecializedVariation)));
mSignatureHash = (int)mTypeInstance->mTypeDef->mSignatureHash; mSignatureHash = (int)mTypeInstance->mTypeDef->mSignatureHash;
} }
return *this; return *this;

View file

@ -1254,11 +1254,11 @@ void BfPassInstance::MessageAt(const StringImpl& msgPrefix, const StringImpl& er
if (isFullUnderline) if (isFullUnderline)
{ {
isFullUnderline = true; isFullUnderline = false;
for (int i = srcIdx; i < srcIdx + srcLen; VisibleAdvance(bfParser->mSrc, bfParser->mSrcLength, i)) for (int i = srcIdx; i <= srcIdx + srcLen; VisibleAdvance(bfParser->mSrc, bfParser->mSrcLength, i))
{ {
char c = bfParser->mSrc[i]; char c = bfParser->mSrc[i];
if (c == '\n') if ((c == '\n') || (c == '\0'))
{ {
isFullUnderline = true; isFullUnderline = true;
break; break;

View file

@ -123,5 +123,115 @@ namespace Tests
Test.Assert(UseIA2(cc) == 70); Test.Assert(UseIA2(cc) == 70);
Test.Assert(UseIA2(cca) == 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);
}
} }
} }

View file

@ -270,5 +270,17 @@ namespace Tests
TestDefaults(); 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);
}
} }
} }