From 7bd29b5b692821b4e0aacc03ac2a7b4192b7dfb3 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Fri, 29 May 2020 16:10:16 -0700 Subject: [PATCH] Fixed issue choose 'int unknown' overload over generic method --- BeefySysLib/util/Array.h | 7 +++ IDEHelper/Beef/BfCommon.h | 7 +++ IDEHelper/Compiler/BfExprEvaluator.cpp | 57 ++++++++++++++++++++---- IDEHelper/Compiler/BfExprEvaluator.h | 1 + IDEHelper/Compiler/BfModule.h | 3 +- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 19 +++++++- 6 files changed, 84 insertions(+), 10 deletions(-) diff --git a/BeefySysLib/util/Array.h b/BeefySysLib/util/Array.h index e1020cdf..8b350b9d 100644 --- a/BeefySysLib/util/Array.h +++ b/BeefySysLib/util/Array.h @@ -350,6 +350,13 @@ public: return mVals[idx]; } + void GetSafe(intptr idx, T& val) + { + if ((idx < 0) || (idx >= mSize)) + return; + val = mVals[idx]; + } + T GetLastSafe() { if (mSize == 0) diff --git a/IDEHelper/Beef/BfCommon.h b/IDEHelper/Beef/BfCommon.h index d211f748..681be322 100644 --- a/IDEHelper/Beef/BfCommon.h +++ b/IDEHelper/Beef/BfCommon.h @@ -112,6 +112,13 @@ public: return mVals[idx]; } + void GetSafe(intptr idx, T& val) + { + if ((idx < 0) || (idx >= mSize)) + return; + val = mVals[idx]; + } + Iterator begin() const { return mVals; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index a2e76f07..f2cbd8b4 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -545,7 +545,7 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp { BfResolvedArg resolvedArg = mArguments[argIdx];; BfTypedValue arg = resolvedArg.mTypedValue; - + int newArgIdx = argIdx + newImplicitParamCount; int prevArgIdx = argIdx + prevImplicitParamCount; @@ -562,9 +562,15 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp BfType* origPrevParamType = prevParamType; if ((genericArgumentsSubstitute != NULL) && (paramType->IsUnspecializedType())) + { paramType = mModule->ResolveGenericType(paramType, NULL, genericArgumentsSubstitute, allowSpecializeFail); + paramType = mModule->FixIntUnknown(paramType); + } if ((prevGenericArgumentsSubstitute != NULL) && (prevParamType->IsUnspecializedType())) + { prevParamType = mModule->ResolveGenericType(prevParamType, NULL, prevGenericArgumentsSubstitute, allowSpecializeFail); + prevParamType = mModule->FixIntUnknown(prevParamType); + } if ((wasGenericParam) || (prevWasGenericParam)) { @@ -596,9 +602,9 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp { // The resolved argument type may actually match for both considered functions. IE: // Method(int8 val) and Method(int16 val) called with Method(0) will create arguments that match their param types - if ((paramType == arg.mType) && (prevParamType != resolvedArg.mBestBoundType)) + if ((IsType(arg, paramType)) && (prevParamType != resolvedArg.mBestBoundType)) isBetter = true; - else if ((prevParamType == arg.mType) && (paramType != arg.mType)) + else if ((IsType(arg, prevParamType)) && (!IsType(arg, paramType))) isWorse = true; else { @@ -629,7 +635,6 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp } } - /*if ((paramType->IsIntegral()) && (prevParamType->IsIntegral())) { if (paramType == arg.mType) @@ -1692,6 +1697,40 @@ void BfMethodMatcher::FlushAmbiguityError() } } +bool BfMethodMatcher::IsType(BfTypedValue& typedVal, BfType* type) +{ + if (typedVal.mType == type) + return true; + + if (!typedVal.mType->IsPrimitiveType()) + return false; + if (!type->IsPrimitiveType()) + return false; + + auto fromPrimType = typedVal.mType->ToPrimitiveType(); + if ((fromPrimType->mTypeDef->mTypeCode != BfTypeCode_IntUnknown) && + (fromPrimType->mTypeDef->mTypeCode != BfTypeCode_UIntUnknown)) + return false; + + auto constant = mModule->mBfIRBuilder->GetConstant(typedVal.mValue); + if (constant == NULL) + return false; + + auto toPrimType = type->ToPrimitiveType(); + if (!mModule->mBfIRBuilder->IsInt(toPrimType->mTypeDef->mTypeCode)) + return false; + + if (type->mSize == 8) + return false; + + int64 minVal = -(1LL << (8 * type->mSize - 1)); + int64 maxVal = (1LL << (8 * type->mSize - 1)) - 1; + if ((constant->mInt64 >= minVal) && (constant->mInt64 <= maxVal)) + return true; + + return false; +} + // This method checks all base classes before checking interfaces. Is that correct? bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue target, bool isFailurePass) { @@ -12131,7 +12170,7 @@ BfAllocTarget BfExprEvaluator::ResolveAllocTarget(BfAstNode* allocNode, BfTokenN { auto targetIdentifier = BfNodeDynCast(scopeNode->mTargetNode); if ((scopeNode->mTargetNode == NULL) || (targetIdentifier != NULL)) - autoComplete->CheckLabel(targetIdentifier, scopeNode->mColonToken); + autoComplete->CheckLabel(targetIdentifier, scopeNode->mColonToken, allocTarget.mScopeData); } attributeDirective = scopeNode->mAttributes; } @@ -12309,8 +12348,10 @@ BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfAstNode* targetSrc, if ((invocationExpr != NULL) && (invocationExpr->mGenericArgs != NULL)) { errorNode = invocationExpr->mGenericArgs->mGenericArgs[(int)methodDef->mGenericParams.size()]; - if ((errorNode == NULL) && (!invocationExpr->mGenericArgs->mCommas.IsEmpty())) - errorNode = invocationExpr->mGenericArgs->mCommas[(int)methodDef->mGenericParams.size() - 1]; + if (errorNode == NULL) + invocationExpr->mGenericArgs->mCommas.GetSafe((int)methodDef->mGenericParams.size() - 1, errorNode); + if (errorNode == NULL) + errorNode = targetSrc; } mModule->Fail(StrFormat("Too many generic arguments, expected %d fewer", genericArgCountDiff), errorNode); } @@ -13388,7 +13429,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m if (autoComplete != NULL) { if (auto identifier = BfNodeDynCast(scopedTarget->mScopeName)) - autoComplete->CheckLabel(identifier, scopedTarget->mColonToken); + autoComplete->CheckLabel(identifier, scopedTarget->mColonToken, NULL); } //mModule->FindScope(scopedTarget->mScopeName); } diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index 9fc75485..13e3fbe4 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -161,6 +161,7 @@ public: BfMethodInstance* newMethodInstance, BfTypeVector* genericArgumentsSubstitute, bool* outNewIsBetter, bool* outNewIsWorse, bool allowSpecializeFail); void FlushAmbiguityError(); + bool IsType(BfTypedValue& val, BfType* type); public: BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, const StringImpl& methodName, SizedArrayImpl& arguments, BfSizedArray* methodGenericArguments); diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index a2901f8f..919ce324 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1646,8 +1646,9 @@ public: BfPrimitiveType* GetPrimitiveType(BfTypeCode typeCode); BfMethodRefType* CreateMethodRefType(BfMethodInstance* methodInstance, bool mustAlreadyExist = false); BfType* FixIntUnknown(BfType* type); - void FixIntUnknown(BfTypedValue& typedVal); + void FixIntUnknown(BfTypedValue& typedVal, BfType* matchType = NULL); void FixIntUnknown(BfTypedValue& lhs, BfTypedValue& rhs); + bool TypeEquals(BfTypedValue& val, BfType* type); BfTypeDef* ResolveGenericInstanceDef(BfGenericInstanceTypeRef* genericTypeRef, BfType** outType = NULL); BfType* ResolveType(BfType* lookupType, BfPopulateType populateType = BfPopulateType_Data); void ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 98b9e173..95f7b26b 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -4806,7 +4806,7 @@ BfType* BfModule::FixIntUnknown(BfType* type) return type; } -void BfModule::FixIntUnknown(BfTypedValue& typedVal) +void BfModule::FixIntUnknown(BfTypedValue& typedVal, BfType* matchType) { if (!typedVal.mValue.IsConst()) { @@ -4832,6 +4832,23 @@ void BfModule::FixIntUnknown(BfTypedValue& typedVal) return; auto constant = mBfIRBuilder->GetConstant(typedVal.mValue); + + if ((matchType != NULL) && (matchType->IsPrimitiveType()) && (mBfIRBuilder->IsInt(matchType->ToPrimitiveType()->mTypeDef->mTypeCode))) + { + auto wantTypeCode = matchType->ToPrimitiveType()->mTypeDef->mTypeCode; + if (matchType->mSize < 8) + { + int64 minVal = -(1LL << (8 * matchType->mSize - 1)); + int64 maxVal = (1LL << (8 * matchType->mSize - 1)) - 1; + if ((constant->mInt64 >= minVal) && (constant->mInt64 <= maxVal)) + { + typedVal.mValue = mBfIRBuilder->CreateNumericCast(typedVal.mValue, mBfIRBuilder->IsSigned(wantTypeCode), wantTypeCode); + typedVal.mType = GetPrimitiveType(wantTypeCode); + return; + } + } + } + if (mSystem->mPtrSize == 4) { if (primType->mTypeDef->mTypeCode == BfTypeCode_IntUnknown)