1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 04:22:20 +02:00

Refactoring of operator constraints, generic param population

This commit is contained in:
Brian Fiete 2020-09-18 17:00:33 -07:00
parent b975acb711
commit 75eeb25555
9 changed files with 301 additions and 85 deletions

View file

@ -1551,7 +1551,7 @@ bool BfAutoComplete::CheckMemberReference(BfAstNode* target, BfAstNode* dotToken
// We need this for Result<T>
SetAndRestoreValue<bool> prevIgnore(mModule->mBfIRBuilder->mIgnoreWrites, true);
BfExprEvaluator exprEvaluator(mModule);
auto opResult = exprEvaluator.PerformUnaryOperation_TryOperator(targetValue, NULL, BfUnaryOp_NullConditional, dotTokenNode);
auto opResult = exprEvaluator.PerformUnaryOperation_TryOperator(targetValue, NULL, BfUnaryOp_NullConditional, dotTokenNode, BfUnaryOpFlag_None);
if (opResult)
targetValue = opResult;
}

View file

@ -1028,6 +1028,8 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild
genericTypeInstance->mGenericTypeInfo->mTypeGenericArgumentRefs.Clear();
for (auto genericParam : genericTypeInstance->mGenericTypeInfo->mGenericParams)
genericParam->Release();
genericTypeInstance->mGenericTypeInfo->mInitializedGenericParams = false;
genericTypeInstance->mGenericTypeInfo->mFinishedGenericParams = false;
genericTypeInstance->mGenericTypeInfo->mGenericParams.Clear();
genericTypeInstance->mGenericTypeInfo->mValidatedGenericConstraints = false;
genericTypeInstance->mGenericTypeInfo->mHadValidateErrors = false;

View file

@ -1313,7 +1313,7 @@ bool BfMethodMatcher::InferFromGenericConstraints(BfGenericParamInstance* generi
{
BfExprEvaluator exprEvaluator(mModule);
exprEvaluator.mResult = rightValue;
exprEvaluator.PerformUnaryOperation(NULL, checkOpConstraint.mUnaryOp, NULL);
exprEvaluator.PerformUnaryOperation(NULL, checkOpConstraint.mUnaryOp, NULL, BfUnaryOpFlag_IsConstraintCheck);
if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Equals_Op) != 0)
checkArgType = exprEvaluator.mResult.mType;
@ -17128,7 +17128,7 @@ BfTypedValue BfExprEvaluator::SetupNullConditional(BfTypedValue thisValue, BfTok
return thisValue;
}
auto opResult = PerformUnaryOperation_TryOperator(thisValue, NULL, BfUnaryOp_NullConditional, dotToken);
auto opResult = PerformUnaryOperation_TryOperator(thisValue, NULL, BfUnaryOp_NullConditional, dotToken, BfUnaryOpFlag_None);
if (opResult)
thisValue = opResult;
@ -17858,10 +17858,10 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
void BfExprEvaluator::Visit(BfUnaryOperatorExpression* unaryOpExpr)
{
BfAutoParentNodeEntry autoParentNodeEntry(mModule, unaryOpExpr);
PerformUnaryOperation(unaryOpExpr->mExpression, unaryOpExpr->mOp, unaryOpExpr->mOpToken);
PerformUnaryOperation(unaryOpExpr->mExpression, unaryOpExpr->mOp, unaryOpExpr->mOpToken, BfUnaryOpFlag_None);
}
void BfExprEvaluator::PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken)
void BfExprEvaluator::PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags)
{
{
// If this is a cast, we don't want the value to be coerced before the unary operator is applied.
@ -17888,10 +17888,10 @@ void BfExprEvaluator::PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp
}
BfExprEvaluator::PerformUnaryOperation_OnResult(unaryOpExpr, unaryOp, opToken);
BfExprEvaluator::PerformUnaryOperation_OnResult(unaryOpExpr, unaryOp, opToken, opFlags);
}
BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedValue& inValue, BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken)
BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedValue& inValue, BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags)
{
if ((!inValue.mType->IsTypeInstance()) && (!inValue.mType->IsGenericParam()))
return BfTypedValue();
@ -17918,6 +17918,9 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal
isPostOp = true;
}
bool isConstraintCheck = ((opFlags & BfUnaryOpFlag_IsConstraintCheck) != 0);
BfType* operatorConstraintReturnType = NULL;
BfType* bestSelfType = NULL;
while (true)
{
@ -17938,8 +17941,17 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal
// Try without arg
args.mSize = 0;
}
if (methodMatcher.CheckMethod(NULL, checkType, operatorDef, false))
methodMatcher.mSelfType = entry.mSrcType;
if (isConstraintCheck)
{
operatorConstraintReturnType = mModule->CheckOperator(checkType, operatorDef, inValue, BfTypedValue());
if (operatorConstraintReturnType != NULL)
methodMatcher.mBestMethodDef = operatorDef;
}
else
{
if (methodMatcher.CheckMethod(NULL, checkType, operatorDef, false))
methodMatcher.mSelfType = entry.mSrcType;
}
args.mSize = prevArgSize;
}
}
@ -17957,7 +17969,7 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal
{
if (opConstraint.mUnaryOp == findOp)
{
if (mModule->CanCast(args[0].mTypedValue, opConstraint.mRightType))
if (mModule->CanCast(args[0].mTypedValue, opConstraint.mRightType, isConstraintCheck ? BfCastFlags_NoConversionOperator : BfCastFlags_None))
{
return BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType);
}
@ -17977,7 +17989,7 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal
{
if (opConstraint.mUnaryOp == findOp)
{
if (mModule->CanCast(args[0].mTypedValue, opConstraint.mRightType))
if (mModule->CanCast(args[0].mTypedValue, opConstraint.mRightType, isConstraintCheck ? BfCastFlags_NoConversionOperator : BfCastFlags_None))
{
return BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType);
}
@ -17989,7 +18001,7 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal
return BfTypedValue();
}
if (!baseClassWalker.mMayBeFromInterface)
if ((!baseClassWalker.mMayBeFromInterface) && (opToken != NULL))
mModule->SetElementType(opToken, BfSourceElementType_Method);
auto methodDef = methodMatcher.mBestMethodDef;
@ -18015,8 +18027,14 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal
callTarget = targetVal;
args.Clear();
}
auto result = CreateCall(&methodMatcher, callTarget);
BfTypedValue result;
if (isConstraintCheck)
{
result = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), operatorConstraintReturnType);
}
else
result = CreateCall(&methodMatcher, callTarget);
if (!methodMatcher.mBestMethodDef->mIsStatic)
{
@ -18045,7 +18063,7 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal
return result;
}
void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken)
void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags)
{
BfAstNode* propSrc = mPropSrc;
BfTypedValue propTarget = mPropTarget;
@ -18068,7 +18086,7 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
if (BfCanOverloadOperator(unaryOp))
{
auto opResult = PerformUnaryOperation_TryOperator(mResult, unaryOpExpr, unaryOp, opToken);
auto opResult = PerformUnaryOperation_TryOperator(mResult, unaryOpExpr, unaryOp, opToken, opFlags);
if (opResult)
{
mResult = opResult;
@ -18086,7 +18104,10 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
auto value = mModule->LoadValue(mResult);
value = mModule->Cast(unaryOpExpr, value, boolType);
if (!value)
{
mResult = BfTypedValue();
return;
}
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateNot(value.mValue), boolType);
}
break;
@ -18097,7 +18118,10 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
CheckResultForReading(mResult);
auto value = mModule->LoadValue(mResult);
if (!value)
{
mResult = BfTypedValue();
return;
}
BfType* origType = value.mType;
if (value.mType->IsTypedPrimitive())
@ -18151,7 +18175,10 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
{
value = mModule->Cast(unaryOpExpr, value, wantType, BfCastFlags_Explicit);
if (!value)
{
mResult = BfTypedValue();
return;
}
}
if (origType->mSize == wantType->mSize) // Allow negative of primitive typed but not if we had to upsize
@ -18176,6 +18203,7 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
isInteger = value.mType->GetUnderlyingType()->IsIntegral();
if (!isInteger)
{
mResult = BfTypedValue();
mModule->Fail("Operator can only be used on integer types", opToken);
return;
}
@ -18276,6 +18304,7 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
constValue = mModule->GetConstValue(1, ptr.mType);
if (!constValue)
{
mResult = BfTypedValue();
numericFail = true;
break;
}
@ -18285,6 +18314,7 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
}
else
{
mResult = BfTypedValue();
numericFail = true;
break;
}
@ -18384,6 +18414,7 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
if ((mBfEvalExprFlags & BfEvalExprFlags_AllowRefExpr) == 0)
{
mResult = BfTypedValue();
mModule->Fail(StrFormat("Invalid usage of '%s' expression", BfGetOpName(unaryOp)), opToken);
return;
}
@ -19269,6 +19300,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
BfBaseClassWalker baseClassWalker(leftValue.mType, rightValue.mType, mModule);
bool invertResult = false;
BfType* operatorConstraintReturnType = NULL;
while (true)
{
@ -19278,7 +19310,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
break;
bool foundExactMatch = false;
Array<BfMethodDef*> oppositeOperatorDefs;
Array<BfOperatorDef*> oppositeOperatorDefs;
for (auto operatorDef : checkType->mTypeDef->mOperators)
{
@ -19293,29 +19325,55 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
if (!methodMatcher.IsMemberAccessible(checkType, operatorDef->mDeclaringType))
continue;
if (methodMatcher.CheckMethod(NULL, checkType, operatorDef, false))
if ((flags & BfBinOpFlag_IsConstraintCheck) != 0)
{
methodMatcher.mSelfType = entry.mSrcType;
if (operatorDef->mOperatorDeclaration->mBinOp == findBinaryOp)
// We can't do CheckMethod because circular referencing means we may have to evaluate this before our type is complete,
// which means before method processing has occurred
operatorConstraintReturnType = mModule->CheckOperator(checkType, operatorDef, leftValue, rightValue);
if (operatorConstraintReturnType != NULL)
{
methodMatcher.mBestMethodDef = operatorDef;
foundExactMatch = true;
}
}
else
{
if (methodMatcher.CheckMethod(NULL, checkType, operatorDef, false))
{
methodMatcher.mSelfType = entry.mSrcType;
if (operatorDef->mOperatorDeclaration->mBinOp == findBinaryOp)
foundExactMatch = true;
}
}
}
else if (operatorDef->mOperatorDeclaration->mBinOp == oppositeBinaryOp)
oppositeOperatorDefs.Add(operatorDef);
}
if (((methodMatcher.mBestMethodDef == NULL) || (!foundExactMatch)) && (!oppositeOperatorDefs.IsEmpty()))
if ((((methodMatcher.mBestMethodDef == NULL) && (operatorConstraintReturnType == NULL)) || (!foundExactMatch)) && (!oppositeOperatorDefs.IsEmpty()))
{
foundOp = true;
for (auto oppositeOperatorDef : oppositeOperatorDefs)
{
if (methodMatcher.CheckMethod(NULL, checkType, oppositeOperatorDef, false))
methodMatcher.mSelfType = entry.mSrcType;
if ((flags & BfBinOpFlag_IsConstraintCheck) != 0)
{
operatorConstraintReturnType = mModule->CheckOperator(checkType, oppositeOperatorDef, leftValue, rightValue);
if (operatorConstraintReturnType != NULL)
{
methodMatcher.mBestMethodDef = oppositeOperatorDef;
methodMatcher.mSelfType = entry.mSrcType;
}
}
else
{
if (methodMatcher.CheckMethod(NULL, checkType, oppositeOperatorDef, false))
methodMatcher.mSelfType = entry.mSrcType;
}
}
}
}
bool hadMatch = methodMatcher.mBestMethodDef != NULL;
bool hadMatch = (methodMatcher.mBestMethodDef != NULL);
if ((methodMatcher.mBestMethodDef != NULL) && ((flags & BfBinOpFlag_IgnoreOperatorWithWrongResult) != 0))
{
@ -19355,7 +19413,14 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
if ((opToken->IsA<BfTokenNode>()) && (!noClassify) && (!baseClassWalker.mMayBeFromInterface))
mModule->SetElementType(opToken, BfSourceElementType_Method);
}
mResult = CreateCall(&methodMatcher, BfTypedValue());
if ((flags & BfBinOpFlag_IsConstraintCheck) != 0)
{
mResult = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), operatorConstraintReturnType);
}
else
{
mResult = CreateCall(&methodMatcher, BfTypedValue());
}
if ((mResult.mType != NULL) && (methodMatcher.mSelfType != NULL) && (mResult.mType->IsSelf()))
{
BF_ASSERT(mModule->IsInGeneric());
@ -20276,7 +20341,7 @@ void BfExprEvaluator::Visit(BfBinaryOperatorExpression* binOpExpr)
}
}
PerformUnaryOperation(binOpExpr->mRight, unaryOp, binOpExpr->mOpToken);
PerformUnaryOperation(binOpExpr->mRight, unaryOp, binOpExpr->mOpToken, BfUnaryOpFlag_None);
if (mResult)
{
mResult = mModule->LoadValue(mResult);

View file

@ -290,12 +290,19 @@ enum BfLookupFieldFlags
BfLookupFieldFlag_IgnoreProtection = 4
};
enum BfUnaryOpFlags
{
BfUnaryOpFlag_None = 0,
BfUnaryOpFlag_IsConstraintCheck = 1
};
enum BfBinOpFlags
{
BfBinOpFlag_None = 0,
BfBinOpFlag_NoClassify = 1,
BfBinOpFlag_ForceLeftType = 2,
BfBinOpFlag_IgnoreOperatorWithWrongResult = 4,
BfBinOpFlag_IsConstraintCheck = 8
};
class BfExprEvaluator : public BfStructuralVisitor
@ -409,9 +416,9 @@ public:
BfLambdaInstance* GetLambdaInstance(BfLambdaBindExpression* lambdaBindExpr, BfAllocTarget& allocTarget);
void VisitLambdaBodies(BfAstNode* body, BfFieldDtorDeclaration* fieldDtor);
void FixitAddMember(BfTypeInstance* typeInst, BfType* fieldType, const StringImpl& fieldName, bool isStatic);
void PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken);
BfTypedValue PerformUnaryOperation_TryOperator(const BfTypedValue& inValue, BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken);
void PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken);
void PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags);
BfTypedValue PerformUnaryOperation_TryOperator(const BfTypedValue& inValue, BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags);
void PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken, BfUnaryOpFlags opFlags);
void PerformAssignment(BfAssignmentExpression* assignExpr, bool evaluatedLeft, BfTypedValue rightValue, BfTypedValue* outCascadeValue = NULL);
void PopulateDeferrredTupleAssignData(BfTupleExpression* tupleExr, DeferredTupleAssignData& deferredTupleAssignData);
void AssignDeferrredTupleAssignData(BfAssignmentExpression* assignExpr, DeferredTupleAssignData& deferredTupleAssignData, BfTypedValue rightValue);

View file

@ -6799,7 +6799,7 @@ void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericPar
{
if (bfAutocomplete != NULL)
bfAutocomplete->CheckTypeRef(opConstraint->mLeftType, false);
opConstraintInstance.mLeftType = ResolveTypeRef(opConstraint->mLeftType);
opConstraintInstance.mLeftType = ResolveTypeRef(opConstraint->mLeftType, BfPopulateType_Interfaces);
if (opConstraintInstance.mLeftType == NULL)
continue;
}
@ -6814,7 +6814,7 @@ void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericPar
{
if (bfAutocomplete != NULL)
bfAutocomplete->CheckTypeRef(opConstraint->mRightType, false);
opConstraintInstance.mRightType = ResolveTypeRef(opConstraint->mRightType);
opConstraintInstance.mRightType = ResolveTypeRef(opConstraint->mRightType, BfPopulateType_Interfaces);
if (opConstraintInstance.mRightType == NULL)
continue;
}
@ -7405,11 +7405,11 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
{
SetAndRestoreValue<bool> prevIgnoreErrors(mIgnoreErrors, true);
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true);
exprEvaluator.PerformBinaryOperation(NULL, NULL, checkOpConstraint.mBinaryOp, NULL, BfBinOpFlag_NoClassify, leftValue, rightValue);
exprEvaluator.PerformBinaryOperation(NULL, NULL, checkOpConstraint.mBinaryOp, NULL, (BfBinOpFlags)(BfBinOpFlag_NoClassify | BfBinOpFlag_IsConstraintCheck), leftValue, rightValue);
}
if ((!exprEvaluator.mResult) ||
(!CanCast(exprEvaluator.mResult, origCheckArgType)))
(!CanCast(exprEvaluator.mResult, origCheckArgType, BfCastFlags_NoConversionOperator)))
{
if (!ignoreErrors)
{
@ -7436,7 +7436,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
if (checkOpConstraint.mCastToken == BfToken_Implicit)
{
if (!CanCast(rightValue, origCheckArgType, BfCastFlags_SilentFail))
if (!CanCast(rightValue, origCheckArgType, (BfCastFlags)(BfCastFlags_SilentFail | BfCastFlags_IsConstraintCheck)))
failedOpName = "implicit conversion from '";
}
else
@ -7446,14 +7446,14 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS
if (checkOpConstraint.mCastToken == BfToken_Explicit)
{
if (!CastToValue(NULL, rightValue, origCheckArgType, (BfCastFlags)(BfCastFlags_Explicit | BfCastFlags_SilentFail)))
if (!CastToValue(NULL, rightValue, origCheckArgType, (BfCastFlags)(BfCastFlags_Explicit | BfCastFlags_SilentFail | BfCastFlags_IsConstraintCheck)))
failedOpName = "explicit conversion from '";
}
else
{
BfExprEvaluator exprEvaluator(this);
exprEvaluator.mResult = rightValue;
exprEvaluator.PerformUnaryOperation(NULL, checkOpConstraint.mUnaryOp, NULL);
exprEvaluator.PerformUnaryOperation(NULL, checkOpConstraint.mUnaryOp, NULL, BfUnaryOpFlag_IsConstraintCheck);
if ((!exprEvaluator.mResult) ||
(!CanCast(exprEvaluator.mResult, origCheckArgType)))
@ -9652,6 +9652,55 @@ BfModuleMethodInstance BfModule::GetInternalMethod(const StringImpl& methodName,
return moduleMethodInstance;
}
BfOperatorInfo* BfModule::GetOperatorInfo(BfTypeInstance* typeInstance, BfOperatorDef* operatorDef)
{
while (operatorDef->mIdx >= typeInstance->mOperatorInfo.size())
typeInstance->mOperatorInfo.Add(NULL);
if (typeInstance->mOperatorInfo[operatorDef->mIdx] == NULL)
{
SetAndRestoreValue<bool> ignoreErrors(mIgnoreErrors, true);
SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, typeInstance);
SetAndRestoreValue<BfMethodInstance*> prevMethodInstance(mCurMethodInstance, NULL);
BfOperatorInfo* operatorInfo = new BfOperatorInfo();
if (operatorDef->mReturnTypeRef != NULL)
operatorInfo->mReturnType = ResolveTypeRef(operatorDef->mReturnTypeRef, BfPopulateType_Identity);
if (operatorDef->mParams.size() >= 1)
operatorInfo->mLHSType = ResolveTypeRef(operatorDef->mParams[0]->mTypeRef, BfPopulateType_Identity);
if (operatorDef->mParams.size() >= 2)
operatorInfo->mRHSType = ResolveTypeRef(operatorDef->mParams[1]->mTypeRef, BfPopulateType_Identity);
typeInstance->mOperatorInfo[operatorDef->mIdx] = operatorInfo;
}
return typeInstance->mOperatorInfo[operatorDef->mIdx];
}
BfType* BfModule::CheckOperator(BfTypeInstance* typeInstance, BfOperatorDef* operatorDef, const BfTypedValue& lhs, const BfTypedValue& rhs)
{
auto operatorInfo = GetOperatorInfo(typeInstance, operatorDef);
if (operatorInfo == NULL)
return NULL;
if (operatorInfo->mReturnType == NULL)
return NULL;
if (lhs)
{
if (operatorInfo->mLHSType == NULL)
return NULL;
// TODO: Make this be a special flag to do CheckOperator conversion checks?
if (!CanCast(lhs, operatorInfo->mLHSType, BfCastFlags_NoConversionOperator))
return NULL;
}
if (rhs)
{
if (operatorInfo->mRHSType == NULL)
return NULL;
// TODO: Make this be a special flag to do CheckOperator conversion checks?
if (!CanCast(rhs, operatorInfo->mRHSType, BfCastFlags_NoConversionOperator))
return NULL;
}
return operatorInfo->mReturnType;
}
bool BfModule::IsMethodImplementedAndReified(BfTypeInstance* typeInstance, const StringImpl& methodName, int paramCount, bool checkBase)
{
while (typeInstance != NULL)

View file

@ -83,7 +83,8 @@ enum BfCastFlags
BfCastFlags_Force = 0x100,
BfCastFlags_PreferAddr = 0x200,
BfCastFlags_WarnOnBox = 0x400,
BfCastFlags_IsCastCheck = 0x800
BfCastFlags_IsCastCheck = 0x800,
BfCastFlags_IsConstraintCheck = 0x1000
};
enum BfCastResultFlags
@ -1600,7 +1601,8 @@ public:
// Type helpers
BfGenericExtensionEntry* BuildGenericExtensionInfo(BfTypeInstance* genericTypeInst, BfTypeDef* partialTypeDef);
bool BuildGenericParams(BfType* resolvedTypeRef);
bool InitGenericParams(BfType* resolvedTypeRef);
bool FinishGenericParams(BfType* resolvedTypeRef);
bool ValidateGenericConstraints(BfTypeReference* typeRef, BfTypeInstance* genericTypeInstance, bool ignoreErrors);
bool AreConstraintsSubset(BfGenericParamInstance* checkInner, BfGenericParamInstance* checkOuter);
bool CheckConstraintState(BfAstNode* refNode);
@ -1794,6 +1796,8 @@ public:
BfModuleMethodInstance GetMethodByName(BfTypeInstance* typeInstance, const StringImpl& methodName, int paramCount = -1, bool checkBase = false);
BfModuleMethodInstance GetMethodByName(BfTypeInstance* typeInstance, const StringImpl& methodName, const Array<BfType*>& paramTypes, bool checkBase = false);
BfModuleMethodInstance GetInternalMethod(const StringImpl& methodName, int paramCount = -1);
BfOperatorInfo* GetOperatorInfo(BfTypeInstance* typeInstance, BfOperatorDef* operatorDef);
BfType* CheckOperator(BfTypeInstance* typeInstance, BfOperatorDef* operatorDef, const BfTypedValue& lhs, const BfTypedValue& rhs);
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 nor static

View file

@ -80,7 +80,7 @@ BfGenericExtensionEntry* BfModule::BuildGenericExtensionInfo(BfTypeInstance* gen
auto& genericConstraint = partialTypeDef->mExternalConstraints[externConstraintIdx];
auto genericParamInstance = new BfGenericTypeParamInstance(partialTypeDef, externConstraintIdx + (int)partialTypeDef->mGenericParamDefs.size());
genericParamInstance->mExternType = ResolveTypeRef(genericConstraint.mTypeRef);
genericParamInstance->mExternType = ResolveTypeRef(genericConstraint.mTypeRef, BfPopulateType_Identity);
auto autoComplete = mCompiler->GetAutoComplete();
if (autoComplete != NULL)
@ -116,17 +116,18 @@ BfGenericExtensionEntry* BfModule::BuildGenericExtensionInfo(BfTypeInstance* gen
return genericExEntry;
}
bool BfModule::BuildGenericParams(BfType* resolvedTypeRef)
bool BfModule::InitGenericParams(BfType* resolvedTypeRef)
{
BfTypeState typeState;
typeState.mPrevState = mContext->mCurTypeState;
typeState.mResolveKind = BfTypeState::ResolveKind_BuildingGenericParams;
typeState.mTypeInstance = resolvedTypeRef->ToTypeInstance();
SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
BF_ASSERT(mCurMethodInstance == NULL);
auto genericTypeInst = resolvedTypeRef->ToGenericTypeInstance();
genericTypeInst->mGenericTypeInfo->mInitializedGenericParams = true;
if (genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[0]->IsGenericParam())
{
@ -147,6 +148,38 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef)
auto genericParamInstance = new BfGenericTypeParamInstance(typeDef, externConstraintIdx + (int)typeDef->mGenericParamDefs.size());
genericTypeInst->mGenericTypeInfo->mGenericParams.push_back(genericParamInstance);
}
return true;
}
bool BfModule::FinishGenericParams(BfType* resolvedTypeRef)
{
BfTypeState typeState;
typeState.mPrevState = mContext->mCurTypeState;
typeState.mResolveKind = BfTypeState::ResolveKind_BuildingGenericParams;
typeState.mTypeInstance = resolvedTypeRef->ToTypeInstance();
SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
BF_ASSERT(mCurMethodInstance == NULL);
auto genericTypeInst = resolvedTypeRef->ToGenericTypeInstance();
genericTypeInst->mGenericTypeInfo->mFinishedGenericParams = true;
if (genericTypeInst->mGenericTypeInfo->mTypeGenericArguments[0]->IsGenericParam())
{
BF_ASSERT(genericTypeInst->mGenericTypeInfo->mIsUnspecialized);
}
auto typeDef = genericTypeInst->mTypeDef;
int startDefGenericParamIdx = (int)genericTypeInst->mGenericTypeInfo->mGenericParams.size();
if ((!resolvedTypeRef->IsTuple()) && (!resolvedTypeRef->IsDelegateFromTypeRef()) && (!resolvedTypeRef->IsFunctionFromTypeRef()))
{
startDefGenericParamIdx = startDefGenericParamIdx -
(int)genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.size() -
(int)typeDef->mExternalConstraints.size();
}
BF_ASSERT(startDefGenericParamIdx >= 0);
if (!typeDef->mPartials.empty())
{
@ -156,7 +189,7 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef)
{
typeState.mCurTypeDef = partialTypeDef;
for (int paramIdx = startDefGenericParamIdx; paramIdx < (int)genericTypeInst->mGenericTypeInfo->mGenericParams.size(); paramIdx++)
{
{
auto genericParamInstance = genericTypeInst->mGenericTypeInfo->mGenericParams[paramIdx];
auto genericParamDef = genericParamInstance->GetGenericParamDef();
@ -168,7 +201,7 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef)
{
auto externConstraintDef = genericParamInstance->GetExternConstraintDef();
genericParamInstance->mExternType = ResolveTypeRef(externConstraintDef->mTypeRef);
if (genericParamInstance->mExternType == NULL)
if (genericParamInstance->mExternType == NULL)
genericParamInstance->mExternType = GetPrimitiveType(BfTypeCode_Var);
}
@ -232,7 +265,7 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef)
{
auto externConstraintDef = genericParamInstance->GetExternConstraintDef();
genericParamInstance->mExternType = ResolveTypeRef(externConstraintDef->mTypeRef);
auto autoComplete = mCompiler->GetAutoComplete();
if (autoComplete != NULL)
autoComplete->CheckTypeRef(externConstraintDef->mTypeRef, false);
@ -264,7 +297,7 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef)
if (genericParam->mTypeConstraint != NULL)
AddDependency(genericParam->mTypeConstraint, mCurTypeInstance, BfDependencyMap::DependencyFlag_Constraint);
}
return true;
}
@ -566,8 +599,8 @@ void BfModule::InitType(BfType* resolvedTypeRef, BfPopulateType populateType)
#endif
// Do it here so the location we attempted to specialize this type will throw the failure if there is one
if (!BuildGenericParams(resolvedTypeRef))
return;
if (!InitGenericParams(resolvedTypeRef))
return;
}
BfLogSysM("%p InitType: %s Type: %p TypeDef: %p Revision:%d\n", mContext, TypeToString(resolvedTypeRef).c_str(), resolvedTypeRef, (typeInst != NULL) ? typeInst->mTypeDef : NULL, mCompiler->mRevision);
@ -1895,12 +1928,12 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
BfTypeState typeState(mCurTypeInstance, mContext->mCurTypeState);
typeState.mPopulateType = populateType;
SetAndRestoreValue<BfTypeState*> prevTypeState(mContext->mCurTypeState, &typeState);
if (typeInstance->IsGenericTypeInstance())
{
auto genericTypeInst = (BfTypeInstance*)typeInstance;
if (genericTypeInst->mGenericTypeInfo->mGenericParams.size() == 0)
BuildGenericParams(resolvedTypeRef);
if (!genericTypeInst->mGenericTypeInfo->mInitializedGenericParams)
InitGenericParams(resolvedTypeRef);
}
if (resolvedTypeRef->IsTypeAlias())
@ -2142,7 +2175,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
{
return;
}
if ((!mCompiler->mIsResolveOnly) && (!typeInstance->mHasBeenInstantiated))
{
for (auto& dep : typeInstance->mDependencyMap)
@ -2228,6 +2261,8 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
};
Array<_DeferredValidate> deferredTypeValidateList;
bool wantPopulateInterfaces = false;
BfTypeReference* baseTypeRef = NULL;
if ((typeDef->mIsDelegate) && (!typeInstance->IsClosure()))
{
@ -2250,7 +2285,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
baseType = ResolveTypeDef(mCompiler->mFunctionTypeDef)->ToTypeInstance();
}
else
{
{
for (auto checkTypeRef : typeDef->mBaseTypes)
{
auto declTypeDef = typeDef;
@ -2356,36 +2391,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
}
}
for (auto partialTypeDef : typeDef->mPartials)
{
if (!typeInstance->IsTypeMemberIncluded(partialTypeDef))
continue;
if (partialTypeDef->mTypeDeclaration == typeInstance->mTypeDef->mTypeDeclaration)
continue;
for (auto checkTypeRef : partialTypeDef->mBaseTypes)
{
SetAndRestoreValue<BfTypeReference*> prevTypeRef(mContext->mCurTypeState->mCurBaseTypeRef, checkTypeRef);
SetAndRestoreValue<BfTypeDef*> prevTypeDef(mContext->mCurTypeState->mCurTypeDef, partialTypeDef);
bool populateBase = !typeInstance->mTypeFailed;
auto checkType = ResolveTypeRef(checkTypeRef, BfPopulateType_Declaration);
if (checkType != NULL)
{
if (checkType->IsInterface())
{
BfInterfaceDecl ifaceDecl;
ifaceDecl.mIFaceTypeInst = checkType->ToTypeInstance();
ifaceDecl.mTypeRef = checkTypeRef;
ifaceDecl.mDeclaringType = partialTypeDef;
interfaces.push_back(ifaceDecl);
}
else
{
Fail(StrFormat("Extensions can only specify new interfaces, type '%s' is not a valid ", TypeToString(checkType).c_str()), checkTypeRef);
}
}
}
}
wantPopulateInterfaces = true;
}
if (resolvedTypeRef->IsBoxed())
@ -2504,6 +2510,49 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
if (populateType <= BfPopulateType_BaseType)
return;
if (typeInstance->IsGenericTypeInstance())
{
auto genericTypeInst = (BfTypeInstance*)typeInstance;
// if (!genericTypeInst->mGenericTypeInfo->mInitializedGenericParams)
// InitGenericParams(resolvedTypeRef);
if (!genericTypeInst->mGenericTypeInfo->mFinishedGenericParams)
FinishGenericParams(resolvedTypeRef);
}
if (wantPopulateInterfaces)
{
for (auto partialTypeDef : typeDef->mPartials)
{
if (!typeInstance->IsTypeMemberIncluded(partialTypeDef))
continue;
if (partialTypeDef->mTypeDeclaration == typeInstance->mTypeDef->mTypeDeclaration)
continue;
for (auto checkTypeRef : partialTypeDef->mBaseTypes)
{
SetAndRestoreValue<BfTypeReference*> prevTypeRef(mContext->mCurTypeState->mCurBaseTypeRef, checkTypeRef);
SetAndRestoreValue<BfTypeDef*> prevTypeDef(mContext->mCurTypeState->mCurTypeDef, partialTypeDef);
bool populateBase = !typeInstance->mTypeFailed;
auto checkType = ResolveTypeRef(checkTypeRef, BfPopulateType_Declaration);
if (checkType != NULL)
{
if (checkType->IsInterface())
{
BfInterfaceDecl ifaceDecl;
ifaceDecl.mIFaceTypeInst = checkType->ToTypeInstance();
ifaceDecl.mTypeRef = checkTypeRef;
ifaceDecl.mDeclaringType = partialTypeDef;
interfaces.push_back(ifaceDecl);
}
else
{
Fail(StrFormat("Extensions can only specify new interfaces, type '%s' is not a valid ", TypeToString(checkType).c_str()), checkTypeRef);
}
}
}
}
}
if ((typeInstance->mBaseType != NULL) && (!typeInstance->IsTypedPrimitive()))
{
curFieldDataIdx++;
@ -2863,7 +2912,8 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
bool populateChildType = !typeInstance->mTypeFailed;
//bool populateChildType = true;
PopulateType(resolvedFieldType, populateChildType ? BfPopulateType_Data : BfPopulateType_Declaration);
BF_ASSERT(!typeInstance->mNeedsMethodProcessing);
if (populateChildType)
{
BF_ASSERT(!resolvedFieldType->IsDataIncomplete());
@ -3790,6 +3840,13 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
_HandleTypeDeclaration(partial->mTypeDeclaration);
}
if (typeInstance->IsGenericTypeInstance())
{
auto genericTypeInst = (BfTypeInstance*)typeInstance;
if (!genericTypeInst->mGenericTypeInfo->mFinishedGenericParams)
FinishGenericParams(resolvedTypeRef);
}
if (populateType == BfPopulateType_Data)
return;
@ -6293,7 +6350,7 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty
auto actualTupleType = mContext->mTupleTypePool.Get();
delete actualTupleType->mGenericTypeInfo;
actualTupleType->mGenericTypeInfo = new BfGenericTypeInfo();
actualTupleType->mGenericTypeInfo = new BfGenericTypeInfo();
actualTupleType->mGenericTypeInfo->mIsUnspecialized = false;
actualTupleType->mGenericTypeInfo->mIsUnspecializedVariation = false;
actualTupleType->mGenericTypeInfo->mTypeGenericArguments = genericArgs;
@ -6432,6 +6489,7 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty
auto dlgType = mContext->mDelegateTypePool.Get();
delete dlgType->mGenericTypeInfo;
dlgType->mGenericTypeInfo = new BfGenericTypeInfo();
dlgType->mGenericTypeInfo->mFinishedGenericParams = true;
dlgType->mGenericTypeInfo->mIsUnspecialized = false;
dlgType->mGenericTypeInfo->mIsUnspecializedVariation = false;
dlgType->mGenericTypeInfo->mTypeGenericArguments = genericArgs;
@ -8803,6 +8861,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
{
BfTupleType* actualTupleType = new BfTupleType();
actualTupleType->mGenericTypeInfo = new BfGenericTypeInfo();
actualTupleType->mGenericTypeInfo->mFinishedGenericParams = true;
actualTupleType->Init(baseType->mTypeDef->mProject, baseType);
for (int fieldIdx = 0; fieldIdx < (int)types.size(); fieldIdx++)
{
@ -8852,10 +8911,15 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
BF_ASSERT(!types[fieldIdx]->IsVar());
fieldInstance->mOwner = tupleType;
}
resolvedEntry->mValue = tupleType;
BF_ASSERT(BfResolvedTypeSet::Hash(tupleType, &lookupCtx) == resolvedEntry->mHash);
populateModule->InitType(tupleType, populateType);
#ifdef _DEBUG
BF_ASSERT(ResolveType(tupleType, BfPopulateType_Identity) == tupleType);
#endif
return ResolveTypeResult(typeRef, tupleType, populateType, resolveFlags);
}
else if (auto nullableTypeRef = BfNodeDynCast<BfNullableTypeRef>(typeRef))
@ -9010,6 +9074,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
{
BfDelegateType* genericTypeInst = new BfDelegateType();
genericTypeInst->mGenericTypeInfo = new BfGenericTypeInfo();
genericTypeInst->mGenericTypeInfo->mFinishedGenericParams = true;
delegateType = genericTypeInst;
delegateInfo = delegateType->GetDelegateInfo();
auto parentTypeInstance = (BfTypeInstance*)mCurTypeInstance;

View file

@ -1382,6 +1382,8 @@ BfTypeInstance::~BfTypeInstance()
delete mAttributeData;
for (auto methodInst : mInternalMethods)
delete methodInst;
for (auto operatorInfo : mOperatorInfo)
delete operatorInfo;
delete mHotTypeData;
delete mConstHolder;
}

View file

@ -940,6 +940,23 @@ public:
void ReportMemory(MemReporter* memReporter);
};
class BfOperatorInfo
{
public:
BfMethodDef* mMethodDef;
BfType* mReturnType;
BfType* mLHSType;
BfType* mRHSType;
BfOperatorInfo()
{
mMethodDef = NULL;
mReturnType = NULL;
mLHSType = NULL;
mRHSType = NULL;
}
};
class BfDllImportEntry
{
public:
@ -1681,6 +1698,8 @@ public:
bool mIsUnspecializedVariation;
bool mValidatedGenericConstraints;
bool mHadValidateErrors;
bool mInitializedGenericParams;
bool mFinishedGenericParams;
Array<BfProject*> mProjectsReferenced; // Generic methods that only refer to these projects don't need a specialized extension
public:
@ -1691,6 +1710,8 @@ public:
mIsUnspecialized = false;
mIsUnspecializedVariation = false;
mValidatedGenericConstraints = false;
mInitializedGenericParams = false;
mFinishedGenericParams = false;
}
~BfGenericTypeInfo();
@ -1719,6 +1740,7 @@ public:
Array<BfTypeInterfaceEntry> mInterfaces;
Array<BfTypeInterfaceMethodEntry> mInterfaceMethodTable;
Array<BfMethodInstanceGroup> mMethodInstanceGroups;
Array<BfOperatorInfo*> mOperatorInfo;
Array<BfVirtualMethodEntry> mVirtualMethodTable;
BfHotTypeData* mHotTypeData;
int mVirtualMethodTableSize; // With hot reloading, mVirtualMethodTableSize can be larger than mInterfaceMethodTable (live vtable versioning)