diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index c941f998..a822e017 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -678,6 +678,9 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp bool betterByGenericParam = false; bool worseByGenericParam = false; + bool betterByConstExprParam = false; + bool worseByConstExprParam = false; + for (argIdx = anyIsExtension ? -1 : 0; argIdx < (int)mArguments.size(); argIdx++) { BfTypedValue arg; @@ -708,12 +711,20 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp BfType* origParamType = paramType; BfType* origPrevParamType = prevParamType; + bool paramWasConstExpr = false; + bool prevParamWasConstExpr = false; + bool paramWasUnspecialized = paramType->IsUnspecializedType(); if ((genericArgumentsSubstitute != NULL) && (paramWasUnspecialized)) { paramType = mModule->ResolveGenericType(paramType, NULL, genericArgumentsSubstitute, allowSpecializeFail); paramType = mModule->FixIntUnknown(paramType); } + if (paramType->IsConstExprValue()) + { + prevParamWasConstExpr = true; + paramType = ((BfConstExprValueType*)paramType)->mType; + } bool prevParamWasUnspecialized = prevParamType->IsUnspecializedType(); if ((prevGenericArgumentsSubstitute != NULL) && (prevParamWasUnspecialized)) @@ -721,6 +732,11 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp prevParamType = mModule->ResolveGenericType(prevParamType, NULL, prevGenericArgumentsSubstitute, allowSpecializeFail); prevParamType = mModule->FixIntUnknown(prevParamType); } + if (prevParamType->IsConstExprValue()) + { + prevParamWasConstExpr = true; + prevParamType = ((BfConstExprValueType*)prevParamType)->mType; + } bool paramsEquivalent = paramType == prevParamType; @@ -734,10 +750,7 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp bool isPrevUnspecializedParam = prevParamType->IsUnspecializedType(); SET_BETTER_OR_WORSE((!isUnspecializedParam) && (!paramType->IsVar()), (!isPrevUnspecializedParam) && (!prevParamType->IsVar())); - - if ((!isBetter) && (!isWorse)) - SET_BETTER_OR_WORSE(paramType->IsConstExprValue(), prevParamType->IsConstExprValue()); - + if ((!isBetter) && (!isWorse) && (!isUnspecializedParam) && (!isPrevUnspecializedParam)) { SET_BETTER_OR_WORSE((paramType != NULL) && (!paramType->IsUnspecializedType()), @@ -785,16 +798,22 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp } } - if (((!isBetter) && (!isWorse)) && (paramsEquivalent) && - ((paramWasUnspecialized) || (prevParamWasUnspecialized))) + if ((!isBetter) & (!isWorse) && (paramsEquivalent)) { - int origTypeMoreSpecific = GetMostSpecificType(origParamType, origPrevParamType); - if (origTypeMoreSpecific == 0) - betterByGenericParam = true; - else if (origTypeMoreSpecific == 1) - worseByGenericParam = true; + if ((origParamType != origPrevParamType) && (paramWasConstExpr) && (!prevParamWasConstExpr)) + betterByConstExprParam = true; + else if ((origParamType != origPrevParamType) && (!paramWasConstExpr) && (prevParamWasConstExpr)) + worseByConstExprParam = true; + else if (((paramWasUnspecialized) || (prevParamWasUnspecialized))) + { + int origTypeMoreSpecific = GetMostSpecificType(origParamType, origPrevParamType); + if (origTypeMoreSpecific == 0) + betterByGenericParam = true; + else if (origTypeMoreSpecific == 1) + worseByGenericParam = true; + } } - + if ((newArgIdx >= 0) && (newMethodInstance->GetParamKind(newArgIdx) == BfParamKind_Params)) usedExtendedForm = true; if ((prevArgIdx >= 0) && (prevMethodInstance->GetParamKind(prevArgIdx) == BfParamKind_Params)) @@ -815,6 +834,17 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp } } + if ((!isBetter) && (!isWorse)) + { + // Don't allow ambiguity + if ((betterByConstExprParam && !worseByConstExprParam) || + (!betterByConstExprParam && worseByConstExprParam)) + { + isBetter = betterByConstExprParam; + isWorse = worseByConstExprParam; + } + } + if ((isBetter) || (isWorse)) { RETURN_RESULTS; diff --git a/IDEHelper/Tests/src/MethodSelection.bf b/IDEHelper/Tests/src/MethodSelection.bf index 0c4cc826..dd9e54b7 100644 --- a/IDEHelper/Tests/src/MethodSelection.bf +++ b/IDEHelper/Tests/src/MethodSelection.bf @@ -81,6 +81,26 @@ namespace Tests return 2; } + public static int MethodE(T val, int val2) + { + return 1; + } + + public static int MethodE(T val, TVal val2) where TVal : const int + { + return 2; + } + + public static int MethodE(List val, int val2) + { + return 3; + } + + public static int MethodE(List val, TVal val2) where TVal : const int + { + return 4; + } + [Test] public static void TestBasics() { @@ -115,8 +135,14 @@ namespace Tests Test.Assert(MethodB(("A", "B")) == 3); Test.Assert(MethodC(("A", "B")) == 3); - int[][] arrArr = new int[1][]; + int[][] arrArr = scope int[1][]; Test.Assert(MethodD(ref arrArr) == 2); + + int a = 100; + Test.Assert(MethodE(sa, a) == 1); + Test.Assert(MethodE(sa, 100) == 2); + Test.Assert(MethodE(sal, a) == 3); + Test.Assert(MethodE(sal, 200) == 4); } } }