diff --git a/IDE/Tests/CompileFail001/scripts/CompileFail.txt b/IDE/Tests/CompileFail001/scripts/CompileFail.txt index b86161f4..76ebc1aa 100644 --- a/IDE/Tests/CompileFail001/scripts/CompileFail.txt +++ b/IDE/Tests/CompileFail001/scripts/CompileFail.txt @@ -23,6 +23,11 @@ WaitForResolve() SleepTicks(20) AssertFileErrors() +ShowFile("src/Methods.bf") +WaitForResolve() +SleepTicks(20) +AssertFileErrors() + ShowFile("src/Properties.bf") WaitForResolve() SleepTicks(20) diff --git a/IDE/Tests/CompileFail001/src/Methods.bf b/IDE/Tests/CompileFail001/src/Methods.bf new file mode 100644 index 00000000..4097cabb --- /dev/null +++ b/IDE/Tests/CompileFail001/src/Methods.bf @@ -0,0 +1,47 @@ +using System; + +namespace IDETest +{ + class Methods + { + public class ClassA + { + + } + + public class ClassB + { + public static implicit operator ClassA(ClassB zongo) + { + return default; + } + } + + public static void MethodA(ClassA zong, int arg) + { + + } + + public static void MethodA(ClassB zong, params Object[] args) + { + + } + + public static void MethodB(ClassB zong, params Object[] args) + { + + } + + public static void MethodB(ClassA zong, int arg) + { + + } + + public static void Test() + { + ClassB cb = scope .(); + MethodA(cb, 123); //FAIL + MethodB(cb, 234); //FAIL + } + } +} diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 6cc479f5..d44288ef 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -718,18 +718,22 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp bool betterByConstExprParam = false; bool worseByConstExprParam = false; + bool someArgWasBetter = false; + bool someArgWasWorse = false; for (argIdx = anyIsExtension ? -1 : 0; argIdx < (int)mArguments.size(); argIdx++) { BfTypedValue arg; - BfResolvedArg* resolvedArg = NULL; + BfResolvedArg* resolvedArg = NULL; + bool wasArgDeferred = false; if (argIdx == -1) { arg = mTarget; } else - { + { resolvedArg = &mArguments[argIdx]; + wasArgDeferred = resolvedArg->mArgFlags != 0; arg = resolvedArg->mTypedValue; } @@ -739,8 +743,8 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp bool wasGenericParam = (newArgIdx >= 0) && newMethodInstance->WasGenericParam(newArgIdx); bool prevWasGenericParam = (prevArgIdx >= 0) && prevMethodInstance->WasGenericParam(prevArgIdx); - BfType* paramType = newMethodInstance->GetParamType(newArgIdx); - BfType* prevParamType = prevMethodInstance->GetParamType(prevArgIdx); + BfType* paramType = newMethodInstance->GetParamType(newArgIdx, true); + BfType* prevParamType = prevMethodInstance->GetParamType(prevArgIdx, true); numUsedParams++; prevNumUsedParams++; @@ -796,9 +800,10 @@ 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 ((!wasGenericParam) && (IsType(arg, paramType)) && ((resolvedArg == NULL) || (prevParamType != resolvedArg->mBestBoundType))) + if ((!wasArgDeferred) && (!wasGenericParam) && (IsType(arg, paramType)) && ((resolvedArg == NULL) || (prevParamType != resolvedArg->mBestBoundType))) isBetter = true; - else if ((!prevWasGenericParam) && (IsType(arg, prevParamType)) && (!IsType(arg, paramType))) + //else if ((!prevWasGenericParam) && (IsType(arg, prevParamType)) && (!IsType(arg, paramType))) + else if ((!wasArgDeferred) && (!prevWasGenericParam) && (IsType(arg, prevParamType)) && ((resolvedArg == NULL) || (paramType != resolvedArg->mBestBoundType))) isWorse = true; else { @@ -830,6 +835,10 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp isWorse = true; } } + else if ((wasArgDeferred) && ((paramType->IsIntegral()) || (prevParamType->IsIntegral()))) + { + SET_BETTER_OR_WORSE(paramType->IsIntegral(), prevParamType->IsIntegral()); + } } } } @@ -858,7 +867,14 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp if ((usedExtendedForm) || (prevUsedExtendedForm)) break; + + someArgWasBetter |= isBetter; + someArgWasWorse |= isWorse; + isBetter = false; + isWorse = false; } + isBetter |= someArgWasBetter; + isWorse |= someArgWasWorse; if ((!isBetter) && (!isWorse)) { @@ -1869,7 +1885,8 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst { BF_ASSERT(!ambiguousEntry.mBestMethodGenericArguments.empty()); } - mAmbiguousEntries.push_back(ambiguousEntry); + mAmbiguousEntries.push_back(ambiguousEntry); + goto Done; } } diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 44ef932a..7d86e155 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -16338,15 +16338,13 @@ void BfModule::ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfTyp BfTypeCode loweredTypeCode2 = BfTypeCode_None; bool isParamSkipped = methodInstance->IsParamSkipped(paramIdx); - - BfType* unresolvedType = methodInstance->GetParamType(paramIdx, false); - if (unresolvedType == NULL) + + auto resolvedType = methodInstance->GetParamType(paramIdx); + if (resolvedType == NULL) { AssertErrorState(); - unresolvedType = mContext->mBfObjectType; paramVar->mParamFailed = true; } - auto resolvedType = methodInstance->GetParamType(paramIdx, true); prevIgnoreErrors.Restore(); PopulateType(resolvedType, BfPopulateType_Declaration); paramVar->mResolvedType = resolvedType; diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 0b919bfd..aa6ca246 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -868,7 +868,7 @@ String BfMethodInstance::GetParamName(int paramIdx) return paramName; } -BfType* BfMethodInstance::GetParamType(int paramIdx, bool useResolvedType) +BfType* BfMethodInstance::GetParamType(int paramIdx, bool returnUnderlyingParamsType) { if (paramIdx == -1) { @@ -892,6 +892,19 @@ BfType* BfMethodInstance::GetParamType(int paramIdx, bool useResolvedType) BfMethodInstance* invokeMethodInstance = methodParam->GetDelegateParamInvoke(); return invokeMethodInstance->GetParamType(methodParam->mDelegateParamIdx, true); } + + if (returnUnderlyingParamsType) + { + BfParameterDef* paramDef = mMethodDef->mParams[methodParam->mParamDefIdx]; + if (paramDef->mParamKind == BfParamKind_Params) + { + auto underlyingType = methodParam->mResolvedType->GetUnderlyingType(); + if (underlyingType != NULL) + return underlyingType; + return methodParam->mResolvedType; + } + } + return methodParam->mResolvedType; } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 6b357fb4..c2af26df 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -902,7 +902,7 @@ public: int GetImplicitParamCount(); void GetParamName(int paramIdx, StringImpl& name); String GetParamName(int paramIdx); - BfType* GetParamType(int paramIdx, bool useResolvedType = true); + BfType* GetParamType(int paramIdx, bool returnUnderlyingParamsType = false); bool GetParamIsSplat(int paramIdx); BfParamKind GetParamKind(int paramIdx); bool WasGenericParam(int paramIdx);