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)
|
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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue