diff --git a/IDE/Tests/CompileFail001/src/Methods.bf b/IDE/Tests/CompileFail001/src/Methods.bf index 4097cabb..2794fa2b 100644 --- a/IDE/Tests/CompileFail001/src/Methods.bf +++ b/IDE/Tests/CompileFail001/src/Methods.bf @@ -17,6 +17,24 @@ namespace IDETest } } + class ClassT + { + public void Test(T t, T2 t2) + { + + } + + public void Test(T t, T2 t2) //FAIL + { + + } + } + + public static void Boing() + { + ClassT.Test(default, default); //FAIL 'IDETest.Methods.ClassT.Test(TC t, TB t2)' is a candidate + } + public static void MethodA(ClassA zong, int arg) { diff --git a/IDE/src/ScriptManager.bf b/IDE/src/ScriptManager.bf index 4d897471..6d191e8e 100644 --- a/IDE/src/ScriptManager.bf +++ b/IDE/src/ScriptManager.bf @@ -2444,7 +2444,16 @@ namespace IDE { bool foundErrorText = false; if (var error = FindError(lineIdx)) - foundErrorText = error.mError.Contains(wantsError); + { + if (error.mError.Contains(wantsError)) + foundErrorText = true; + if (error.mMoreInfo != null) + { + for (var moreInfo in error.mMoreInfo) + if (moreInfo.mError.Contains(wantsError)) + foundErrorText = true; + } + } if (!foundErrorText) { mScriptManager.Fail("Error at line {0} in {1} did not contain error text '{2}'\n\t", lineIdx + 1, textPanel.mFilePath, wantsError); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 027e63b9..089c5979 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -932,6 +932,9 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp paramDiff = (int) newMethodInstance->GetParamCount() - (int) prevMethodInstance->GetParamCount(); RETURN_BETTER_OR_WORSE(paramDiff < 0, paramDiff > 0); + BfMethodInstance* typeUnspecNewMethodInstance = mModule->GetUnspecializedMethodInstance(newMethodInstance, true); + BfMethodInstance* typeUnspecPrevMethodInstance = mModule->GetUnspecializedMethodInstance(prevMethodInstance, true); + // Check specificity of args std::function _CompareParamTypes = [&](BfType* newType, BfType* prevType) @@ -942,8 +945,8 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp auto prevGenericParamType = (BfGenericParamType*)prevType; if ((newGenericParamType->mGenericParamKind == BfGenericParamKind_Method) && (prevGenericParamType->mGenericParamKind == BfGenericParamKind_Method)) { - auto newMethodGenericParam = newMethodInstance->mMethodInfoEx->mGenericParams[newGenericParamType->mGenericParamIdx]; - auto prevMethodGenericParam = prevMethodInstance->mMethodInfoEx->mGenericParams[prevGenericParamType->mGenericParamIdx]; + auto newMethodGenericParam = typeUnspecNewMethodInstance->mMethodInfoEx->mGenericParams[newGenericParamType->mGenericParamIdx]; + auto prevMethodGenericParam = typeUnspecPrevMethodInstance->mMethodInfoEx->mGenericParams[prevGenericParamType->mGenericParamIdx]; SET_BETTER_OR_WORSE(mModule->AreConstraintsSubset(prevMethodGenericParam, newMethodGenericParam), mModule->AreConstraintsSubset(newMethodGenericParam, prevMethodGenericParam)); } } @@ -973,14 +976,14 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp { int newArgIdx = argIdx + newImplicitParamCount; int prevArgIdx = argIdx + prevImplicitParamCount; - _CompareParamTypes(newMethodInstance->GetParamType(newArgIdx), prevMethodInstance->GetParamType(prevArgIdx)); - } + _CompareParamTypes(typeUnspecNewMethodInstance->GetParamType(newArgIdx), typeUnspecPrevMethodInstance->GetParamType(prevArgIdx)); + } // Do generic constraint subset test directly to handle cases like "NotDisposed()" vs "NotDisposed() where T : IDisposable" if ((newMethodInstance->GetNumGenericArguments() > 0) && (newMethodInstance->GetNumGenericArguments() == prevMethodInstance->GetNumGenericArguments())) { for (int genericParamIdx = 0; genericParamIdx < (int)newMethodInstance->GetNumGenericArguments(); genericParamIdx++) - { + { auto newMethodGenericParam = newMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; auto prevMethodGenericParam = prevMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; SET_BETTER_OR_WORSE(mModule->AreConstraintsSubset(prevMethodGenericParam, newMethodGenericParam), mModule->AreConstraintsSubset(newMethodGenericParam, prevMethodGenericParam)); @@ -1385,13 +1388,17 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst return false; mMethodCheckCount++; - - BfMethodInstance* methodInstance = mModule->GetRawMethodInstance(typeInstance, checkMethod); + + BfMethodInstance* methodInstance = mModule->GetRawMethodInstance(typeInstance, checkMethod); if (methodInstance == NULL) { BFMODULE_FATAL(mModule, "Failed to get raw method in BfMethodMatcher::CheckMethod"); return false; } + BfMethodInstance* typeUnspecMethodInstance = mModule->GetUnspecializedMethodInstance(methodInstance, true); + BfTypeVector* typeGenericArguments = NULL; + if (typeInstance->mGenericTypeInfo != NULL) + typeGenericArguments = &typeInstance->mGenericTypeInfo->mTypeGenericArguments; if ((mInterfaceMethodInstance != NULL) && (methodInstance->GetExplicitInterface() != NULL)) { @@ -1773,7 +1780,8 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst auto wantType = methodInstance->GetParamType(paramIdx); if ((genericArgumentsSubstitute != NULL) && (wantType->IsUnspecializedType())) { - auto resolvedType = mModule->ResolveGenericType(wantType, NULL, genericArgumentsSubstitute, false); + wantType = typeUnspecMethodInstance->GetParamType(paramIdx); + auto resolvedType = mModule->ResolveGenericType(wantType, typeGenericArguments, genericArgumentsSubstitute, false); if (resolvedType == NULL) goto NoMatch; wantType = resolvedType; @@ -2039,15 +2047,27 @@ void BfMethodMatcher::FlushAmbiguityError() error = mModule->Fail("Ambiguous method call", mTargetSrc); if (error != NULL) { - BfMethodInstance* bestMethodInstance = mModule->GetRawMethodInstance(mBestMethodTypeInstance, mBestMethodDef); + auto unspecializedType = mModule->GetUnspecializedTypeInstance(mBestMethodTypeInstance); + BfMethodInstance* bestMethodInstance = mModule->GetRawMethodInstance(unspecializedType, mBestMethodDef); + BfTypeVector* typeGenericArguments = NULL; + if (mBestMethodTypeInstance->mGenericTypeInfo != NULL) + typeGenericArguments = &mBestMethodTypeInstance->mGenericTypeInfo->mTypeGenericArguments; + mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' is a candidate", mModule->MethodToString(bestMethodInstance, BfMethodNameFlag_ResolveGenericParamNames, - mBestMethodGenericArguments.empty() ? NULL : &mBestMethodGenericArguments).c_str()), + typeGenericArguments, mBestMethodGenericArguments.empty() ? NULL : &mBestMethodGenericArguments).c_str()), bestMethodInstance->mMethodDef->GetRefNode()); for (auto& ambiguousEntry : mAmbiguousEntries) { - mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' is a candidate", mModule->MethodToString(ambiguousEntry.mMethodInstance, BfMethodNameFlag_ResolveGenericParamNames, - ambiguousEntry.mBestMethodGenericArguments.empty() ? NULL : &ambiguousEntry.mBestMethodGenericArguments).c_str()), + auto typeInstance = ambiguousEntry.mMethodInstance->GetOwner(); + auto unspecTypeMethodInstance = mModule->GetUnspecializedMethodInstance(ambiguousEntry.mMethodInstance, true); + + BfTypeVector* typeGenericArguments = NULL; + if (typeInstance->mGenericTypeInfo != NULL) + typeGenericArguments = &typeInstance->mGenericTypeInfo->mTypeGenericArguments; + + mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("'%s' is a candidate", mModule->MethodToString(unspecTypeMethodInstance, BfMethodNameFlag_ResolveGenericParamNames, + typeGenericArguments, ambiguousEntry.mBestMethodGenericArguments.empty() ? NULL : &ambiguousEntry.mBestMethodGenericArguments).c_str()), ambiguousEntry.mMethodInstance->mMethodDef->GetRefNode()); } } @@ -9435,6 +9455,10 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie _BoolResult(type->IsNullable()); else if (memberName == "IsGenericType") _BoolResult(type->IsGenericTypeInstance()); + else if (memberName == "IsArray") + _BoolResult(type->IsArray()); + else if (memberName == "IsSizedArray") + _BoolResult(type->IsSizedArray()); else if (memberName == "TypeId") _Int32Result(type->mTypeId); else if (memberName == "GenericParamCount") diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index f01a7e86..d728836a 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -9750,7 +9750,7 @@ BfMethodInstance* BfModule::GetUnspecializedMethodInstance(BfMethodInstance* met BF_ASSERT(!owner->IsTuple()); auto genericType = (BfTypeInstance*)owner; - if (genericType->IsUnspecializedType()) + if ((genericType->IsUnspecializedType()) && (!genericType->IsUnspecializedTypeVariation())) return methodInstance; auto unspecializedType = ResolveTypeDef(genericType->mTypeDef); @@ -10113,16 +10113,18 @@ bool BfModule::HasMixin(BfTypeInstance* typeInstance, const StringImpl& methodNa return BfModuleMethodInstance(); } -StringT<128> BfModule::MethodToString(BfMethodInstance* methodInst, BfMethodNameFlags methodNameFlags, BfTypeVector* methodGenericArgs) -{ +StringT<128> BfModule::MethodToString(BfMethodInstance* methodInst, BfMethodNameFlags methodNameFlags, BfTypeVector* typeGenericArgs, BfTypeVector* methodGenericArgs) +{ auto methodDef = methodInst->mMethodDef; bool allowResolveGenericParamNames = ((methodNameFlags & BfMethodNameFlag_ResolveGenericParamNames) != 0); BfTypeNameFlags typeNameFlags = BfTypeNameFlags_None; + bool hasGenericArgs = (typeGenericArgs != NULL) || (methodGenericArgs != NULL); + BfType* type = methodInst->mMethodInstanceGroup->mOwner; - if ((methodGenericArgs != NULL) && (type->IsUnspecializedType())) - type = ResolveGenericType(type, NULL, methodGenericArgs); + if ((hasGenericArgs) && (type->IsUnspecializedType())) + type = ResolveGenericType(type, typeGenericArgs, methodGenericArgs); if ((type == NULL) || (!type->IsUnspecializedTypeVariation())) typeNameFlags = BfTypeNameFlag_ResolveGenericParamNames; if (allowResolveGenericParamNames) @@ -10135,8 +10137,8 @@ StringT<128> BfModule::MethodToString(BfMethodInstance* methodInst, BfMethodName auto typeNameFlags = BfTypeNameFlags_None; if (allowResolveGenericParamNames) typeNameFlags = BfTypeNameFlag_ResolveGenericParamNames; - if ((methodGenericArgs != NULL) && (type->IsUnspecializedType())) - type = ResolveGenericType(type, NULL, methodGenericArgs); + if ((hasGenericArgs) && (type->IsUnspecializedType())) + type = ResolveGenericType(type, typeGenericArgs, methodGenericArgs); methodName += TypeToString(type, typeNameFlags); }; diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index d1a27ab9..835d1377 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1516,7 +1516,7 @@ public: StringT<128> TypeToString(BfType* resolvedType, Array* genericMethodParamNameOverrides = NULL); StringT<128> TypeToString(BfType* resolvedType, BfTypeNameFlags typeNameFlags, Array* genericMethodParamNameOverrides = NULL); void DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameFlags typeNameFlags = BfTypeNameFlags_None, Array* genericMethodParamNameOverrides = NULL); - StringT<128> MethodToString(BfMethodInstance* methodInst, BfMethodNameFlags methodNameFlags = BfMethodNameFlag_ResolveGenericParamNames, BfTypeVector* methodGenericArgs = NULL); + StringT<128> MethodToString(BfMethodInstance* methodInst, BfMethodNameFlags methodNameFlags = BfMethodNameFlag_ResolveGenericParamNames, BfTypeVector* typeGenericArgs = NULL, BfTypeVector* methodGenericArgs = NULL); void pv(BfType* type); void CurrentAddToConstHolder(BfIRValue& irVal); void ClearConstData();