From c7d2d2e9bd5957db0824318a75ef22114a9a4022 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 17 Jan 2022 16:14:40 -0500 Subject: [PATCH] Make conversion operators use standard method matcher --- BeefLibs/corlib/src/DateTime.bf | 2 +- BeefLibs/corlib/src/Reflection/Convert.bf | 40 +- BeefLibs/corlib/src/String.bf | 2 +- IDEHelper/Compiler/BfExprEvaluator.cpp | 69 ++- IDEHelper/Compiler/BfExprEvaluator.h | 5 +- IDEHelper/Compiler/BfModule.h | 3 + IDEHelper/Compiler/BfModuleTypeUtils.cpp | 554 ++++++++-------------- IDEHelper/Compiler/BfResolvedTypeUtils.h | 3 + 8 files changed, 280 insertions(+), 398 deletions(-) diff --git a/BeefLibs/corlib/src/DateTime.bf b/BeefLibs/corlib/src/DateTime.bf index 1b3092be..6537f2c8 100644 --- a/BeefLibs/corlib/src/DateTime.bf +++ b/BeefLibs/corlib/src/DateTime.bf @@ -154,7 +154,7 @@ namespace System // public this(int year, int month, int day) { - this.dateData = (uint64)DateToTicks(year, month, day); + this.dateData = (.)DateToTicks(year, month, day).Value; } public this(int year, int month, int day, int hour, int minute, int second) diff --git a/BeefLibs/corlib/src/Reflection/Convert.bf b/BeefLibs/corlib/src/Reflection/Convert.bf index 3418eae7..b6783508 100644 --- a/BeefLibs/corlib/src/Reflection/Convert.bf +++ b/BeefLibs/corlib/src/Reflection/Convert.bf @@ -18,16 +18,16 @@ namespace System.Reflection var (objType, dataPtr) = GetTypeAndPointer(obj); switch (objType.[Friend]mTypeCode) { - case .Int8: return (.)*(int8*)dataPtr; - case .Int16: return (.)*(int16*)dataPtr; - case .Int32: return (.)*(int32*)dataPtr; - case .Int64: return (.)*(int64*)dataPtr; - case .UInt8, .Char8: return (.)*(uint8*)dataPtr; - case .UInt16, .Char16: return (.)*(uint16*)dataPtr; - case .UInt32, .Char32: return (.)*(uint32*)dataPtr; - case .UInt64: return (.)*(uint64*)dataPtr; - case .Int: return (.)*(int*)dataPtr; - case .UInt: return (.)*(uint*)dataPtr; + case .Int8: return *(int8*)dataPtr; + case .Int16: return *(int16*)dataPtr; + case .Int32: return *(int32*)dataPtr; + case .Int64: return *(int64*)dataPtr; + case .UInt8, .Char8: return (int64)*(uint8*)dataPtr; + case .UInt16, .Char16: return *(uint16*)dataPtr; + case .UInt32, .Char32: return *(uint32*)dataPtr; + case .UInt64: return (int64)*(uint64*)dataPtr; + case .Int: return (int64)*(int*)dataPtr; + case .UInt: return (int64)*(uint*)dataPtr; default: return .Err; } } @@ -38,16 +38,16 @@ namespace System.Reflection var dataPtr = variant.DataPtr; switch (variant.VariantType.[Friend]mTypeCode) { - case .Int8: return (.)*(int8*)dataPtr; - case .Int16: return (.)*(int16*)dataPtr; - case .Int32: return (.)*(int32*)dataPtr; - case .Int64: return (.)*(int64*)dataPtr; - case .UInt8, .Char8: return (.)*(uint8*)dataPtr; - case .UInt16, .Char16: return (.)*(uint16*)dataPtr; - case .UInt32, .Char32: return (.)*(uint32*)dataPtr; - case .UInt64: return (.)*(uint64*)dataPtr; - case .Int: return (.)*(int*)dataPtr; - case .UInt: return (.)*(uint*)dataPtr; + case .Int8: return *(int8*)dataPtr; + case .Int16: return *(int16*)dataPtr; + case .Int32: return *(int32*)dataPtr; + case .Int64: return *(int64*)dataPtr; + case .UInt8, .Char8: return *(uint8*)dataPtr; + case .UInt16, .Char16: return *(uint16*)dataPtr; + case .UInt32, .Char32: return *(uint32*)dataPtr; + case .UInt64: return (int64)*(uint64*)dataPtr; + case .Int: return (int64)*(int*)dataPtr; + case .UInt: return (int64)*(uint*)dataPtr; default: return .Err; } } diff --git a/BeefLibs/corlib/src/String.bf b/BeefLibs/corlib/src/String.bf index 9e30bf2f..b901f0cd 100644 --- a/BeefLibs/corlib/src/String.bf +++ b/BeefLibs/corlib/src/String.bf @@ -1341,7 +1341,7 @@ namespace System public Result AppendF(StringView format, params Object[] args) { - return AppendF(null, format, params args); + return AppendF((IFormatProvider)null, format, params args); } public int IndexOf(StringView subStr, bool ignoreCase = false) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index bee34013..ad38b55d 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -168,6 +168,7 @@ void BfMethodMatcher::Init(/*SizedArrayImpl& arguments, */BfSized mExplicitInterfaceCheck = NULL; mSelfType = NULL; mMethodType = BfMethodType_Normal; + mCheckReturnType = NULL; mHadExplicitGenericArguments = false; mHasVarArguments = false; mInterfaceMethodInstance = NULL; @@ -178,6 +179,7 @@ void BfMethodMatcher::Init(/*SizedArrayImpl& arguments, */BfSized mSkipImplicitParams = false; mAllowImplicitThis = false; mAllowImplicitRef = false; + mAllowImplicitWrap = false; mHadVarConflictingReturnType = false; mAutoFlushAmbiguityErrors = true; mMethodCheckCount = 0; @@ -2036,8 +2038,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst goto NoMatch; wantType = resolvedType; } - if (wantType->IsSelf()) - wantType = typeInstance; + wantType = mModule->ResolveSelfType(wantType, typeInstance); if ((argIdx >= 0) && ((mArguments[argIdx].mArgFlags & BfArgFlag_ParamsExpr) != 0)) { @@ -2075,8 +2076,15 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst if ((wantType->IsRef()) && (!argTypedValue.mType->IsRef()) && ((mAllowImplicitRef) || (wantType->IsIn()))) wantType = wantType->GetUnderlyingType(); - if (!mModule->CanCast(argTypedValue, wantType)) - goto NoMatch; + if (!mModule->CanCast(argTypedValue, wantType, ((mBfEvalExprFlags & BfEvalExprFlags_FromConversionOp) != 0) ? BfCastFlags_NoConversionOperator : BfCastFlags_None)) + { + if ((mAllowImplicitWrap) && (argTypedValue.mType->IsWrappableType()) && (mModule->GetWrappedStructType(argTypedValue.mType) == wantType)) + { + // Is wrapped type + } + else + goto NoMatch; + } } } @@ -2116,6 +2124,26 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst goto NoMatch; } + if (mCheckReturnType != NULL) + { + auto wantType = mCheckReturnType; + if ((genericArgumentsSubstitute != NULL) && (wantType->IsUnspecializedType())) + { + wantType = typeUnspecMethodInstance->GetParamType(paramIdx); + auto resolvedType = mModule->ResolveGenericType(wantType, typeGenericArguments, genericArgumentsSubstitute, false); + if (resolvedType == NULL) + goto NoMatch; + wantType = resolvedType; + } + wantType = mModule->ResolveSelfType(wantType, typeInstance); + + BfCastFlags castFlags = ((mBfEvalExprFlags & BfEvalExprFlags_FromConversionOp) != 0) ? BfCastFlags_NoConversionOperator : BfCastFlags_None; + if ((mBfEvalExprFlags & BfEvalExprFlags_FromConversionOp_Explicit) != 0) + castFlags = (BfCastFlags)(castFlags | BfCastFlags_Explicit); + if (!mModule->CanCast(mModule->GetFakeTypedValue(methodInstance->mReturnType), wantType, castFlags)) + goto NoMatch; + } + if ((genericArgumentsSubstitute != NULL) && (genericArgumentsSubstitute->size() != 0)) { for (int checkGenericIdx = uniqueGenericStartIdx; checkGenericIdx < (int)genericArgumentsSubstitute->size(); checkGenericIdx++) @@ -2272,7 +2300,8 @@ NoMatch: auto resolveThisParam = mModule->ResolveGenericType(thisParam, NULL, &mCheckMethodGenericArguments); if (resolveThisParam == NULL) return false; - if (!mModule->CanCast(mTarget, resolveThisParam, BfCastFlags_Explicit)) + if (!mModule->CanCast(mTarget, resolveThisParam, + ((mBfEvalExprFlags & BfEvalExprFlags_FromConversionOp) != 0) ? (BfCastFlags)(BfCastFlags_Explicit | BfCastFlags_NoConversionOperator) : BfCastFlags_Explicit)) return false; } @@ -6127,11 +6156,11 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* return result; } + + BfTypedValue BfExprEvaluator::CreateCall(BfMethodMatcher* methodMatcher, BfTypedValue target) -{ - auto& moduleMethodInstance = methodMatcher->mBestMethodInstance; - if (!moduleMethodInstance) - moduleMethodInstance = GetSelectedMethod(methodMatcher->mTargetSrc, methodMatcher->mBestMethodTypeInstance, methodMatcher->mBestMethodDef, *methodMatcher); +{ + auto& moduleMethodInstance = GetSelectedMethod(*methodMatcher); if (moduleMethodInstance.mMethodInstance == NULL) return BfTypedValue(); if ((target) && (target.mType != moduleMethodInstance.mMethodInstance->GetOwner())) @@ -9462,6 +9491,19 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp BfModuleMethodInstance moduleMethodInstance = mModule->GetMethodByName(typeInst, "ReturnValueDiscarded", 0, true); if (moduleMethodInstance) { + bool wasCapturingMethodMatchInfo = false; + if (autoComplete != NULL) + { + wasCapturingMethodMatchInfo = autoComplete->mIsCapturingMethodMatchInfo; + autoComplete->mIsCapturingMethodMatchInfo = false; + } + + defer + ( + if (autoComplete != NULL) + autoComplete->mIsCapturingMethodMatchInfo = wasCapturingMethodMatchInfo; + ); + auto wasGetDefinition = (autoComplete != NULL) && (autoComplete->mIsGetDefinition); if (wasGetDefinition) autoComplete->mIsGetDefinition = false; @@ -15350,6 +15392,13 @@ BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfAstNode* targetSrc, return moduleMethodInstance; } +BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfMethodMatcher& methodMatcher) +{ + if (!methodMatcher.mBestMethodInstance) + methodMatcher.mBestMethodInstance = GetSelectedMethod(methodMatcher.mTargetSrc, methodMatcher.mBestMethodTypeInstance, methodMatcher.mBestMethodDef, methodMatcher); + return methodMatcher.mBestMethodInstance; +} + void BfExprEvaluator::CheckLocalMethods(BfAstNode* targetSrc, BfTypeInstance* typeInstance, const StringImpl& methodName, BfMethodMatcher& methodMatcher, BfMethodType methodType) { auto _GetNodeId = [&]() @@ -20173,6 +20222,8 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal } } + methodMatcher.FlushAmbiguityError(); + if (methodMatcher.mBestMethodDef == NULL) { // Check method generic constraints diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index c4e6b06c..e4829470 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -190,6 +190,7 @@ public: String mMethodName; BfMethodInstance* mInterfaceMethodInstance; SizedArrayImpl& mArguments; + BfType* mCheckReturnType; BfMethodType mMethodType; BfCheckedKind mCheckedKind; bool mHadExplicitGenericArguments; @@ -198,6 +199,7 @@ public: bool mBypassVirtual; bool mAllowImplicitThis; bool mAllowImplicitRef; + bool mAllowImplicitWrap; bool mAllowStatic; bool mAllowNonStatic; bool mSkipImplicitParams; @@ -405,7 +407,7 @@ public: bool IsVar(BfType* type); void GetLiteral(BfAstNode* refNode, const BfVariant& variant); void FinishExpressionResult(); - virtual bool CheckAllowValue(const BfTypedValue& typedValue, BfAstNode* refNode); + virtual bool CheckAllowValue(const BfTypedValue& typedValue, BfAstNode* refNode); BfAutoComplete* GetAutoComplete(); bool IsComptime(); bool IsComptimeEntry(); @@ -462,6 +464,7 @@ public: BfResolvedArgs& argValue, BfSizedArray* methodGenericArguments, BfCheckedKind checkedKind = BfCheckedKind_NotSet); BfTypedValue MakeCallableTarget(BfAstNode* targetSrc, BfTypedValue target); BfModuleMethodInstance GetSelectedMethod(BfAstNode* targetSrc, BfTypeInstance* curTypeInst, BfMethodDef* methodDef, BfMethodMatcher& methodMatcher, BfType** overrideReturnType = NULL); + BfModuleMethodInstance GetSelectedMethod(BfMethodMatcher& methodMatcher); bool CheckVariableDeclaration(BfAstNode* checkNode, bool requireSimpleIfExpr, bool exprMustBeTrue, bool silentFail); bool HasVariableDeclaration(BfAstNode* checkNode); void DoInvocation(BfAstNode* target, BfMethodBoundExpression* methodBoundExpr, const BfSizedArray& args, BfSizedArray* methodGenericArgs, BfTypedValue* outCascadeValue = NULL); diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 99133b62..6952b9b4 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -80,6 +80,8 @@ enum BfEvalExprFlags BfEvalExprFlags_DeclType = 0x1000000, BfEvalExprFlags_AllowBase = 0x2000000, BfEvalExprFlags_NoCeRebuildFlags = 0x4000000, + BfEvalExprFlags_FromConversionOp = 0x8000000, + BfEvalExprFlags_FromConversionOp_Explicit = 0x10000000, BfEvalExprFlags_InheritFlags = BfEvalExprFlags_NoAutoComplete | BfEvalExprFlags_Comptime | BfEvalExprFlags_DeclType }; @@ -1836,6 +1838,7 @@ public: void MarkScopeLeft(BfScopeData* scopeData); BfGenericParamType* GetGenericParamType(BfGenericParamKind paramKind, int paramIdx); BfType* ResolveGenericType(BfType* unspecializedType, BfTypeVector* typeGenericArguments, BfTypeVector* methodGenericArguments, bool allowFail = false); + BfType* ResolveSelfType(BfType* type, BfTypeInstance* selfType); bool IsUnboundGeneric(BfType* type); BfGenericParamInstance* GetGenericTypeParamInstance(int paramIdx); BfGenericParamInstance* GetGenericParamInstance(BfGenericParamType* type); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index a91899ff..3c5a1de8 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -434,9 +434,29 @@ bool BfModule::AreConstraintsSubset(BfGenericParamInstance* checkInner, BfGeneri return false; } - for (auto& innerIFace : checkInner->mInterfaceConstraints) - { - if (!checkOuter->mInterfaceConstraints.Contains(innerIFace)) + for (auto innerIFace : checkInner->mInterfaceConstraints) + { + if (checkOuter->mInterfaceConstraints.IsEmpty()) + return false; + + if (checkOuter->mInterfaceConstraintSet == NULL) + { + std::function _AddInterface = [&](BfTypeInstance* ifaceType) + { + if (!checkOuter->mInterfaceConstraintSet->Add(ifaceType)) + return; + if (ifaceType->mDefineState < BfTypeDefineState_HasInterfaces) + PopulateType(ifaceType); + for (auto& ifaceEntry : ifaceType->mInterfaces) + _AddInterface(ifaceEntry.mInterfaceType); + }; + + checkOuter->mInterfaceConstraintSet = new HashSet(); + for (auto outerIFace : checkOuter->mInterfaceConstraints) + _AddInterface(outerIFace); + } + + if (!checkOuter->mInterfaceConstraintSet->Contains(innerIFace)) return false; } @@ -2589,13 +2609,7 @@ void BfModule::DoPopulateType_TypeAlias(BfTypeInstance* typeAlias) SetAndRestoreValue prevTypeInstance(mCurTypeInstance, typeAlias); SetAndRestoreValue prevMethodInstance(mCurMethodInstance, NULL); SetAndRestoreValue prevMethodState(mCurMethodState, NULL); - - if (typeAlias->mDefineState < BfTypeDefineState_Declaring) - { - typeAlias->mDefineState = BfTypeDefineState_Declaring; - DoPopulateType_InitSearches(typeAlias); - } - + BF_ASSERT(mCurMethodInstance == NULL); auto typeDef = typeAlias->mTypeDef; auto typeAliasDecl = (BfTypeAliasDeclaration*)typeDef->mTypeDeclaration; @@ -2606,12 +2620,20 @@ void BfModule::DoPopulateType_TypeAlias(BfTypeInstance* typeAlias) if ((typeAlias->mGenericTypeInfo != NULL) && (!typeAlias->mGenericTypeInfo->mFinishedGenericParams)) FinishGenericParams(typeAlias); - - typeAlias->mDefineState = BfTypeDefineState_ResolvingBaseType; + BfTypeState typeState(mCurTypeInstance, mContext->mCurTypeState); typeState.mPopulateType = BfPopulateType_Data; typeState.mCurBaseTypeRef = typeAliasDecl->mAliasToType; SetAndRestoreValue prevTypeState(mContext->mCurTypeState, &typeState); + + if (typeAlias->mDefineState < BfTypeDefineState_Declaring) + { + typeAlias->mDefineState = BfTypeDefineState_Declaring; + DoPopulateType_InitSearches(typeAlias); + } + + typeAlias->mDefineState = BfTypeDefineState_ResolvingBaseType; + if (!CheckCircularDataError()) { if (typeAliasDecl->mAliasToType != NULL) @@ -2826,6 +2848,9 @@ void BfModule::DoPopulateType_FinishEnum(BfTypeInstance* typeInstance, bool unde else typeCode = BfTypeCode_Int64; + if (typeInstance->mIsCRepr) + typeCode = BfTypeCode_Int32; + if (typeCode != BfTypeCode_Int64) { for (auto& fieldInstanceRef : typeInstance->mFieldInstances) @@ -3861,7 +3886,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy typeInstance->mIsUnion = true; typeInstance->mIsPacked = isPacked; typeInstance->mIsCRepr = isCRepr; - + if (typeInstance->mTypeOptionsIdx >= 0) { auto typeOptions = mSystem->GetTypeOptions(typeInstance->mTypeOptionsIdx); @@ -8171,6 +8196,14 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty return unspecializedType; } +BfType* BfModule::ResolveSelfType(BfType* type, BfTypeInstance* selfType) +{ + if (!type->IsUnspecializedTypeVariation()) + return type; + SetAndRestoreValue prevCurTypeInst(mCurTypeInstance, selfType); + return ResolveGenericType(type, NULL, NULL); +} + BfType* BfModule::ResolveType(BfType* lookupType, BfPopulateType populateType, BfResolveTypeRefFlags resolveFlags) { BfResolvedTypeSet::LookupContext lookupCtx; @@ -12540,381 +12573,170 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp } // Check user-defined operators - if ((castFlags & BfCastFlags_NoConversionOperator) == 0) - { - auto fromType = typedVal.mType; - auto fromTypeInstance = typedVal.mType->ToTypeInstance(); - auto toTypeInstance = toType->ToTypeInstance(); + if (((castFlags & BfCastFlags_NoConversionOperator) == 0) && (toType != mContext->mBfObjectType)) + { + BfType* walkFromType = typedVal.mType; + if (walkFromType->IsWrappableType()) + walkFromType = GetWrappedStructType(walkFromType); + BfType* walkToType = toType; + if (walkToType->IsWrappableType()) + walkToType = GetWrappedStructType(walkToType); - auto liftedFromType = ((fromTypeInstance != NULL) && fromTypeInstance->IsNullable()) ? fromTypeInstance->GetUnderlyingType() : NULL; - auto liftedToType = ((toTypeInstance != NULL) && toTypeInstance->IsNullable()) ? toTypeInstance->GetUnderlyingType() : NULL; - - int bestFromDist = INT_MAX; - BfType* bestFromType = NULL; - int bestNegFromDist = INT_MAX; - BfType* bestNegFromType = NULL; - - int bestToDist = INT_MAX; - BfType* bestToType = NULL; - int bestNegToDist = INT_MAX; - BfType* bestNegToType = NULL; - bool isAmbiguousCast = false; - - BfIRValue conversionResult; - BfMethodInstance* opMethodInstance = NULL; - BfType* opMethodSrcType = NULL; - BfOperatorInfo* constraintOperatorInfo = NULL; + SizedArray args; + BfResolvedArg resolvedArg; + resolvedArg.mTypedValue = typedVal; + args.push_back(resolvedArg); + BfMethodMatcher methodMatcher(srcNode, this, "", args, NULL); + methodMatcher.mCheckReturnType = toType; + methodMatcher.mBfEvalExprFlags = (BfEvalExprFlags)(BfEvalExprFlags_NoAutoComplete | BfEvalExprFlags_FromConversionOp); + if ((castFlags & BfCastFlags_Explicit) != 0) + methodMatcher.mBfEvalExprFlags = (BfEvalExprFlags)(methodMatcher.mBfEvalExprFlags | BfEvalExprFlags_FromConversionOp_Explicit); + methodMatcher.mAllowImplicitRef = true; + methodMatcher.mAllowImplicitWrap = true; + BfBaseClassWalker baseClassWalker(walkFromType, walkToType, this); - // Normal, lifted, execute - for (int pass = 0; pass < 3; pass++) + bool isConstraintCheck = false;// ((opFlags& BfUnaryOpFlag_IsConstraintCheck) != 0); + + BfType* operatorConstraintReturnType = NULL; + BfType* bestSelfType = NULL; + while (true) { - auto checkToType = toType; - auto checkFromType = fromType; - - if (pass == 1) + auto entry = baseClassWalker.Next(); + auto checkType = entry.mTypeInstance; + if (checkType == NULL) + break; + for (auto operatorDef : checkType->mTypeDef->mOperators) { - if ((bestFromType != NULL) && (bestToType != NULL)) - continue; - - if (liftedFromType != NULL) - checkFromType = liftedFromType; - if (liftedToType != NULL) - checkToType = liftedToType; - } - else if (pass == 2) - { - if ((bestFromType == NULL) || (bestToType == NULL)) - break; - } - - BfType* searchFromType = checkFromType; - if (searchFromType->IsSizedArray()) - searchFromType = GetWrappedStructType(checkFromType); - - bool isConstraintCheck = ((castFlags & BfCastFlags_IsConstraintCheck) != 0); - BfBaseClassWalker baseClassWalker(searchFromType, toType, this); - - while (true) - { - auto entry = baseClassWalker.Next(); - auto checkInstance = entry.mTypeInstance; - if (checkInstance == NULL) - break; - - for (auto operatorDef : checkInstance->mTypeDef->mOperators) + if (operatorDef->mOperatorDeclaration->mIsConvOperator) { - if (operatorDef->mOperatorDeclaration->mIsConvOperator) + if ((!explicitCast) && (operatorDef->mOperatorDeclaration->mExplicitToken != NULL) && + (operatorDef->mOperatorDeclaration->mExplicitToken->GetToken() == BfToken_Explicit)) + continue; + + if (!methodMatcher.IsMemberAccessible(checkType, operatorDef->mDeclaringType)) + continue; + + int prevArgSize = (int)args.mSize; + if (!operatorDef->mIsStatic) { - if ((!explicitCast) && (operatorDef->mOperatorDeclaration->mExplicitToken != NULL) && - (operatorDef->mOperatorDeclaration->mExplicitToken->GetToken() == BfToken_Explicit)) - continue; - - BfType* methodFromType = NULL; - BfType* methodToType = NULL; - - if (isConstraintCheck) - { - auto operatorInfo = GetOperatorInfo(checkInstance, operatorDef); - methodFromType = operatorInfo->mLHSType; - methodToType = operatorInfo->mReturnType; - if ((methodFromType == NULL) || (methodToType == NULL)) - continue; - } - else - { - auto methodInst = GetRawMethodInstanceAtIdx(checkInstance, operatorDef->mIdx); - if (methodInst == NULL) - continue; - if (methodInst->GetParamCount() != 1) - { - AssertErrorState(); - continue; - } - - methodFromType = methodInst->GetParamType(0); - methodToType = methodInst->mReturnType; - } - - if (methodFromType->IsRef()) - methodFromType = methodFromType->GetUnderlyingType(); - - if (methodFromType->IsSelf()) - methodFromType = entry.mSrcType; - if (methodToType->IsSelf()) - methodToType = entry.mSrcType; - - // Selection pass - if (pass < 2) - { - auto methodCheckFromType = methodFromType; - auto methodCheckToType = methodToType; - if (pass == 1) - { - // Only check inner type on lifted types when we aren't checking conversions within lifted class - // This avoid some infinite conversions - if ((methodCheckFromType->IsNullable()) && (!checkInstance->IsNullable())) - methodCheckFromType = methodCheckFromType->GetUnderlyingType(); - if ((methodCheckToType->IsNullable()) && (!checkInstance->IsNullable())) - methodCheckToType = methodCheckToType->GetUnderlyingType(); - } - - int fromDist = GetTypeDistance(methodCheckFromType, checkFromType); - if ((fromDist == INT_MAX) && (searchFromType != checkFromType)) - { - fromDist = GetTypeDistance(methodCheckFromType, searchFromType); - } - - if (fromDist < 0) - { - // Allow us to cast a constant int to a smaller type if it satisfies the cast operator - if ((typedVal.mValue.IsConst()) && (CanCast(typedVal, methodCheckFromType, BfCastFlags_NoConversionOperator))) - { - fromDist = 0; - } - } - - int toDist = GetTypeDistance(methodCheckToType, checkToType); - - if ((fromDist == INT_MAX) || (toDist == INT_MAX)) - continue; - - if (((fromDist >= 0) && (toDist >= 0)) || (explicitCast)) - { - if ((fromDist >= 0) && (fromDist < bestFromDist)) - { - bestFromDist = fromDist; - bestFromType = methodFromType; - } - - if ((toDist >= 0) && (toDist < bestToDist)) - { - bestToDist = toDist; - bestToType = methodToType; - } - } - - if (explicitCast) - { - fromDist = abs(fromDist); - toDist = abs(toDist); - - if ((fromDist >= 0) && (fromDist < bestNegFromDist)) - { - bestNegFromDist = fromDist; - bestNegFromType = methodFromType; - } - - if ((toDist >= 0) && (toDist < bestNegToDist)) - { - bestNegToDist = toDist; - bestNegToType = methodToType; - } - } - } - else if (pass == 2) // Execution Pass - { - if ((methodFromType == bestFromType) && (methodToType == bestToType)) - { - if (isConstraintCheck) - { - auto operatorInfo = GetOperatorInfo(checkInstance, operatorDef); - constraintOperatorInfo = operatorInfo; - } - else - { - // Get in native module so our module doesn't get a reference to it - we may not end up calling it at all! - BfMethodInstance* methodInstance = GetRawMethodInstanceAtIdx(checkInstance, operatorDef->mIdx); - - if (opMethodInstance != NULL) - { - int prevGenericCount = GetGenericParamAndReturnCount(opMethodInstance); - int newGenericCount = GetGenericParamAndReturnCount(methodInstance); - if (newGenericCount > prevGenericCount) - { - // Prefer generic match - opMethodInstance = methodInstance; - opMethodSrcType = entry.mSrcType; - } - else if (newGenericCount < prevGenericCount) - { - // Previous was a generic match - continue; - } - else - { - isAmbiguousCast = true; - break; - } - } - else - { - opMethodInstance = methodInstance; - opMethodSrcType = entry.mSrcType; - } - } - } - } + // Try without arg + args.mSize = 0; } - } - - if (isAmbiguousCast) - break; - - if ((opMethodInstance != NULL) || (constraintOperatorInfo != NULL)) - { - if (mayBeBox) - { - if (!ignoreErrors) - { - if (Fail("Ambiguous cast, may be conversion operator or may be boxing request", srcNode) != NULL) - mCompiler->mPassInstance->MoreInfo("See conversion operator", opMethodInstance->mMethodDef->GetRefNode()); - } - else if (!silentFail) - SetFail(); - } - - BfType* returnType; - if (isConstraintCheck) - { - returnType = constraintOperatorInfo->mReturnType; - } - else - { - returnType = opMethodInstance->mReturnType; - BfMethodInstance* methodInstance = GetRawMethodInstance(opMethodInstance->GetOwner(), opMethodInstance->mMethodDef); - auto methodDeclaration = methodInstance->mMethodDef->GetMethodDeclaration(); - if (methodDeclaration->mBody == NULL) - { - // Handle the typedPrim<->underlying part implicitly - if (fromType->IsTypedPrimitive()) - { - auto convTypedValue = BfTypedValue(typedVal.mValue, fromType->GetUnderlyingType()); - return CastToValue(srcNode, convTypedValue, toType, (BfCastFlags)(castFlags & ~BfCastFlags_Explicit), NULL); - } - else if (toType->IsTypedPrimitive()) - { - auto castedVal = CastToValue(srcNode, typedVal, toType->GetUnderlyingType(), (BfCastFlags)(castFlags & ~BfCastFlags_Explicit), NULL); - return castedVal; - } - } - } - - // Actually perform conversion - BfExprEvaluator exprEvaluator(this); - BfTypedValue castedFromValue; - if ((typedVal.mType->IsSizedArray()) && (bestFromType->IsInstanceOf(mCompiler->mSizedArrayTypeDef))) - { - castedFromValue = MakeAddressable(typedVal); - if (!bestFromType->IsValuelessType()) - castedFromValue.mValue = mBfIRBuilder->CreateBitCast(castedFromValue.mValue, mBfIRBuilder->MapTypeInstPtr(bestFromType->ToTypeInstance())); - castedFromValue.mType = bestFromType; - } - else - castedFromValue = Cast(srcNode, typedVal, bestFromType, castFlags); - if (!castedFromValue) - return BfIRValue(); - BfTypedValue operatorOut; - if (ignoreWrites) - { - if (opMethodInstance != NULL) - exprEvaluator.PerformCallChecks(opMethodInstance, srcNode); + if (methodMatcher.CheckMethod(NULL, checkType, operatorDef, false)) + methodMatcher.mSelfType = entry.mSrcType; - if (returnType == toType) - return mBfIRBuilder->GetFakeVal(); - operatorOut = GetDefaultTypedValue(returnType, false, BfDefaultValueKind_Addr); + args.mSize = prevArgSize; + } + } + } + + methodMatcher.FlushAmbiguityError(); + + if (methodMatcher.mBestMethodDef == NULL) + { + // Check method generic constraints + if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsUnspecialized) && (mCurMethodInstance->mMethodInfoEx != NULL)) + { + for (int genericParamIdx = 0; genericParamIdx < mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++) + { + auto genericParam = mCurMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; + for (auto& opConstraint : genericParam->mOperatorConstraints) + { + if ((opConstraint.mCastToken == BfToken_Implicit) || + ((explicitCast) && (opConstraint.mCastToken == BfToken_Explicit))) + { + // If we can convert OUR fromVal to the constraint's fromVal then we may match + if (CanCast(typedVal, opConstraint.mRightType, BfCastFlags_NoConversionOperator)) + { + // .. and we can convert the constraint's toType to OUR toType then we're good + auto opToVal = genericParam->mExternType; + if (CanCast(BfTypedValue(BfIRValue::sValueless, opToVal), toType, BfCastFlags_NoConversionOperator)) + return mBfIRBuilder->GetFakeVal(); + } + } + } + } + } + + // Check type generic constraints + if ((mCurTypeInstance != NULL) && (mCurTypeInstance->IsGenericTypeInstance()) && (mCurTypeInstance->IsUnspecializedType())) + { + SizedArray genericParams; + GetActiveTypeGenericParamInstances(genericParams); + for (auto genericParam : genericParams) + { + for (auto& opConstraint : genericParam->mOperatorConstraints) + { + if ((opConstraint.mCastToken == BfToken_Implicit) || + ((explicitCast) && (opConstraint.mCastToken == BfToken_Explicit))) + { + // If we can convert OUR fromVal to the constraint's fromVal then we may match + if (CanCast(typedVal, opConstraint.mRightType, BfCastFlags_NoConversionOperator)) + { + // .. and we can convert the constraint's toType to OUR toType then we're good + auto opToVal = genericParam->mExternType; + if (CanCast(BfTypedValue(BfIRValue::sValueless, opToVal), toType, BfCastFlags_NoConversionOperator)) + return mBfIRBuilder->GetFakeVal(); + } + } + } + } + } + } + else + { + BfTypedValue result; + BfExprEvaluator exprEvaluator(this); + exprEvaluator.mBfEvalExprFlags = BfEvalExprFlags_FromConversionOp; + + auto moduleMethodInstance = exprEvaluator.GetSelectedMethod(methodMatcher); + if (moduleMethodInstance.mMethodInstance != NULL) + { + auto paramType = moduleMethodInstance.mMethodInstance->GetParamType(0); + auto wantType = paramType; + if (wantType->IsRef()) + wantType = wantType->GetUnderlyingType(); + auto typedVal = methodMatcher.mArguments[0].mTypedValue; + if (wantType != typedVal.mType) + { + if ((typedVal.mType->IsWrappableType()) && (wantType == GetWrappedStructType(typedVal.mType))) + { + typedVal = MakeAddressable(typedVal); + methodMatcher.mArguments[0].mTypedValue = BfTypedValue(mBfIRBuilder->CreateBitCast(typedVal.mValue, mBfIRBuilder->MapTypeInstPtr(wantType->ToTypeInstance())), + paramType, paramType->IsRef() ? BfTypedValueKind_Value : BfTypedValueKind_Addr); } else { - BfModuleMethodInstance moduleMethodInstance = GetMethodInstance(opMethodInstance->GetOwner(), opMethodInstance->mMethodDef, BfTypeVector()); - exprEvaluator.PerformCallChecks(moduleMethodInstance.mMethodInstance, srcNode); - - if (moduleMethodInstance.mMethodInstance->GetParamType(0)->IsRef()) - castedFromValue = ToRef(castedFromValue); - - SizedArray args; - exprEvaluator.PushArg(castedFromValue, args); - operatorOut = exprEvaluator.CreateCall(NULL, moduleMethodInstance.mMethodInstance, IsSkippingExtraResolveChecks() ? BfIRValue() : moduleMethodInstance.mFunc, false, args); - if ((operatorOut.mType != NULL) && (operatorOut.mType->IsSelf())) + methodMatcher.mArguments[0].mTypedValue = Cast(srcNode, typedVal, wantType, BfCastFlags_Explicit); + if (paramType->IsRef()) { - BF_ASSERT(IsInGeneric()); - operatorOut = GetDefaultTypedValue(opMethodSrcType); - } - } - - return CastToValue(srcNode, operatorOut, toType, castFlags, resultFlags); - } - } - - if (bestFromType == NULL) - bestFromType = bestNegFromType; - if (bestToType == NULL) - bestToType = bestNegToType; - } - - isAmbiguousCast |= ((bestFromType != NULL) && (bestToType != NULL)); - if (isAmbiguousCast) - { - if (!ignoreErrors) - { - const char* errStr = "Ambiguous conversion operators for casting from '%s' to '%s'"; - Fail(StrFormat(errStr, TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode); - } - else if (!silentFail) - SetFail(); - return BfIRValue(); - } - - // Check method generic constraints - if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsUnspecialized) && (mCurMethodInstance->mMethodInfoEx != NULL)) - { - for (int genericParamIdx = 0; genericParamIdx < mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++) - { - auto genericParam = mCurMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; - for (auto& opConstraint : genericParam->mOperatorConstraints) - { - if ((opConstraint.mCastToken == BfToken_Implicit) || - ((explicitCast) && (opConstraint.mCastToken == BfToken_Explicit))) - { - // If we can convert OUR fromVal to the constraint's fromVal then we may match - if (CanCast(typedVal, opConstraint.mRightType, BfCastFlags_NoConversionOperator)) - { - // .. and we can convert the constraint's toType to OUR toType then we're good - auto opToVal = genericParam->mExternType; - if (CanCast(BfTypedValue(BfIRValue::sValueless, opToVal), toType, BfCastFlags_NoConversionOperator)) - return mBfIRBuilder->GetFakeVal(); + typedVal = MakeAddressable(typedVal); + typedVal.mKind = BfTypedValueKind_Addr; } } } } - } - // Check type generic constraints - if ((mCurTypeInstance != NULL) && (mCurTypeInstance->IsGenericTypeInstance()) && (mCurTypeInstance->IsUnspecializedType())) - { - SizedArray genericParams; - GetActiveTypeGenericParamInstances(genericParams); - for (auto genericParam : genericParams) + result = exprEvaluator.CreateCall(&methodMatcher, BfTypedValue()); + if (resultFlags != NULL) { - for (auto& opConstraint : genericParam->mOperatorConstraints) - { - if ((opConstraint.mCastToken == BfToken_Implicit) || - ((explicitCast) && (opConstraint.mCastToken == BfToken_Explicit))) - { - // If we can convert OUR fromVal to the constraint's fromVal then we may match - if (CanCast(typedVal, opConstraint.mRightType, BfCastFlags_NoConversionOperator)) - { - // .. and we can convert the constraint's toType to OUR toType then we're good - auto opToVal = genericParam->mExternType; - if (CanCast(BfTypedValue(BfIRValue::sValueless, opToVal), toType, BfCastFlags_NoConversionOperator)) - return mBfIRBuilder->GetFakeVal(); - } - } - } + if (result.IsAddr()) + *resultFlags = (BfCastResultFlags)(*resultFlags | BfCastResultFlags_IsAddr); + if (result.mKind == BfTypedValueKind_TempAddr) + *resultFlags = (BfCastResultFlags)(*resultFlags | BfCastResultFlags_IsTemp); } + else if (result.IsAddr()) + result = LoadValue(result); + + if (result.mType != toType) + return CastToValue(srcNode, result, toType, BfCastFlags_Explicit, resultFlags); + + if (result) + return result.mValue; } } - + // Default typed primitive 'underlying casts' happen after checking cast operators if (explicitCast) { diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 5a999d87..20f90cb3 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -1141,6 +1141,7 @@ public: BfGenericParamFlags mGenericParamFlags; BfType* mExternType; Array mInterfaceConstraints; + HashSet* mInterfaceConstraintSet; Array mOperatorConstraints; Array mComptypeConstraint; BfType* mTypeConstraint; @@ -1151,6 +1152,7 @@ public: mExternType = NULL; mGenericParamFlags = BfGenericParamFlag_None; mTypeConstraint = NULL; + mInterfaceConstraintSet = NULL; mRefCount = 1; } @@ -1162,6 +1164,7 @@ public: virtual ~BfGenericParamInstance() { + delete mInterfaceConstraintSet; } virtual BfConstraintDef* GetConstraintDef() = 0; virtual BfGenericParamDef* GetGenericParamDef() = 0;