diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index 5f80dbfe..132ce539 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -1551,7 +1551,7 @@ bool BfAutoComplete::CheckMemberReference(BfAstNode* target, BfAstNode* dotToken // We need this for Result SetAndRestoreValue 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; } diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index 0e814b6f..e5410c7d 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -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; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 1d162c4d..2581b9e7 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -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 oppositeOperatorDefs; + Array 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()) && (!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); diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index f5c49b0a..5664051e 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -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); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 3d24c803..b4c4a333 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -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 prevIgnoreErrors(mIgnoreErrors, true); SetAndRestoreValue 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 ignoreErrors(mIgnoreErrors, true); + SetAndRestoreValue prevTypeInstance(mCurTypeInstance, typeInstance); + SetAndRestoreValue 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) diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index a44773a7..53b845a9 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -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& 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 diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index d424cfa3..a19c10c4 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -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 prevTypeState(mContext->mCurTypeState, &typeState); + SetAndRestoreValue 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 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 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 prevTypeRef(mContext->mCurTypeState->mCurBaseTypeRef, checkTypeRef); - SetAndRestoreValue 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 prevTypeRef(mContext->mCurTypeState->mCurBaseTypeRef, checkTypeRef); + SetAndRestoreValue 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(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; diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index fb452cd4..ae8d085e 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -1382,6 +1382,8 @@ BfTypeInstance::~BfTypeInstance() delete mAttributeData; for (auto methodInst : mInternalMethods) delete methodInst; + for (auto operatorInfo : mOperatorInfo) + delete operatorInfo; delete mHotTypeData; delete mConstHolder; } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 6270b571..878a5b2c 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -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 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 mInterfaces; Array mInterfaceMethodTable; Array mMethodInstanceGroups; + Array mOperatorInfo; Array mVirtualMethodTable; BfHotTypeData* mHotTypeData; int mVirtualMethodTableSize; // With hot reloading, mVirtualMethodTableSize can be larger than mInterfaceMethodTable (live vtable versioning)