diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index ee3f1269..3aaf8a36 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -573,6 +573,15 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp BfMethodDef* prevMethodDef = prevMethodInstance->mMethodDef; BfMethodDef* newMethodDef = newMethodInstance->mMethodDef; + if (prevMethodDef == mBackupMethodDef) + { + // This can happen for extension methods and such + *outNewIsBetter = true; + *outNewIsWorse = false; + return; + } + + if (newMethodDef->mExplicitInterface != prevMethodDef->mExplicitInterface) { if (mModule->CompareMethodSignatures(newMethodInstance, prevMethodInstance)) @@ -688,9 +697,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 ((IsType(arg, paramType)) && ((resolvedArg == NULL) || (prevParamType != resolvedArg->mBestBoundType))) + if ((!wasGenericParam) && (IsType(arg, paramType)) && ((resolvedArg == NULL) || (prevParamType != resolvedArg->mBestBoundType))) isBetter = true; - else if ((IsType(arg, prevParamType)) && (!IsType(arg, paramType))) + else if ((!prevWasGenericParam) && (IsType(arg, prevParamType)) && (!IsType(arg, paramType))) isWorse = true; else { @@ -1438,8 +1447,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst auto type = argTypedValue.mType; if (!argTypedValue) goto NoMatch; - //HashSet checkedTypeSet; - + if (type->IsVar()) mHasVarArguments = true; @@ -7328,10 +7336,17 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp bool isSkipCall = moduleMethodInstance.mMethodInstance->IsSkipCall(bypassVirtual); + if ((moduleMethodInstance.mMethodInstance->mIsUnspecializedVariation) && (!mModule->mBfIRBuilder->mIgnoreWrites)) + { + // Invalid methods such as types with a HasVar tuple generic arg will be marked as mIsUnspecializedVariation and shouldn't actually be called + FinishDeferredEvals(argValues.mResolvedArgs); + return mModule->GetDefaultTypedValue(moduleMethodInstance.mMethodInstance->mReturnType, true, BfDefaultValueKind_Addr); + } + if (methodDef->IsEmptyPartial()) { // Ignore call - return mModule->GetDefaultTypedValue(moduleMethodInstance.mMethodInstance->mReturnType); + return mModule->GetDefaultTypedValue(moduleMethodInstance.mMethodInstance->mReturnType, true, BfDefaultValueKind_Addr); } if ((moduleMethodInstance.mMethodInstance->mMethodDef->mIsStatic) && (moduleMethodInstance.mMethodInstance->GetOwner()->IsInterface())) @@ -7356,7 +7371,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp else mModule->Fail(StrFormat("Static interface method '%s' can only be dispatched from a concrete type, consider using this interface as a generic constraint", mModule->MethodToString(moduleMethodInstance.mMethodInstance).c_str()), targetSrc); FinishDeferredEvals(argValues.mResolvedArgs); - return mModule->GetDefaultTypedValue(moduleMethodInstance.mMethodInstance->mReturnType); + return mModule->GetDefaultTypedValue(moduleMethodInstance.mMethodInstance->mReturnType, true, BfDefaultValueKind_Addr); } } @@ -15560,7 +15575,7 @@ void BfExprEvaluator::PopulateDeferrredTupleAssignData(BfTupleExpression* tupleE fieldNames.push_back(requestedName->mNameNode->ToString()); } - BfTypeInstance* tupleType = mModule->CreateTupleType(fieldTypes, fieldNames); + BfTypeInstance* tupleType = mModule->CreateTupleType(fieldTypes, fieldNames, true); deferredTupleAssignData.mTupleType = tupleType; } @@ -16583,7 +16598,11 @@ void BfExprEvaluator::Visit(BfTupleExpression* tupleExpr) typedVal = mModule->LoadValue(typedVal); } - if (typedVal.IsSplat()) + if (typedVal.mType->IsVar()) + { + // Do nothing + } + else if (typedVal.IsSplat()) mModule->AggregateSplatIntoAddr(typedVal, memberVal); else mModule->mBfIRBuilder->CreateStore(typedVal.mValue, memberVal); diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 07f808d2..e42fac57 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1630,7 +1630,7 @@ public: BfPointerType* CreatePointerType(BfTypeReference* typeRef); BfConstExprValueType* CreateConstExprValueType(const BfTypedValue& typedValue); BfBoxedType* CreateBoxedType(BfType* resolvedTypeRef); - BfTypeInstance* CreateTupleType(const BfTypeVector& fieldTypes, const Array& fieldNames); + BfTypeInstance* CreateTupleType(const BfTypeVector& fieldTypes, const Array& fieldNames, bool allowVar = false); BfTypeInstance* SantizeTupleType(BfTypeInstance* tupleType); BfRefType* CreateRefType(BfType* resolvedTypeRef, BfRefType::RefKind refKind = BfRefType::RefKind_Ref); BfModifiedTypeType* CreateModifiedTypeType(BfType* resolvedTypeRef, BfToken modifiedKind); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index ac87db9a..e9b6834c 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -5295,7 +5295,7 @@ BfBoxedType* BfModule::CreateBoxedType(BfType* resolvedTypeRef) return (BfBoxedType*)resolvedBoxedType; } -BfTypeInstance* BfModule::CreateTupleType(const BfTypeVector& fieldTypes, const Array& fieldNames) +BfTypeInstance* BfModule::CreateTupleType(const BfTypeVector& fieldTypes, const Array& fieldNames, bool allowVar) { auto baseType = (BfTypeInstance*)ResolveTypeDef(mContext->mCompiler->mValueTypeTypeDef); @@ -5315,7 +5315,7 @@ BfTypeInstance* BfModule::CreateTupleType(const BfTypeVector& fieldTypes, const BfFieldDef* fieldDef = actualTupleType->AddField(fieldName); auto fieldType = fieldTypes[fieldIdx]; - if (fieldType->IsUnspecializedType()) + if ((fieldType->IsUnspecializedType()) || (fieldType->IsVar())) isUnspecialzied = true; } tupleType = actualTupleType; @@ -5326,8 +5326,11 @@ BfTypeInstance* BfModule::CreateTupleType(const BfTypeVector& fieldTypes, const { BfFieldInstance* fieldInstance = (BfFieldInstance*)&tupleType->mFieldInstances[fieldIdx]; fieldInstance->mFieldIdx = fieldIdx; - fieldInstance->SetResolvedType(fieldTypes[fieldIdx]); - fieldInstance->mOwner = tupleType; + BfType* fieldType = fieldTypes[fieldIdx]; + if ((fieldType->IsVar()) && (!allowVar)) + fieldType = mContext->mBfObjectType; + fieldInstance->SetResolvedType(fieldType); + fieldInstance->mOwner = tupleType; } tupleType->mIsUnspecializedType = false; @@ -6079,6 +6082,9 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty wantGeneric = true; if (newGenericArg->IsUnspecializedType()) isUnspecialized = true; + if (newGenericArg->IsVar()) + wantGeneric = mContext->mBfObjectType; + //wantGeneric = true; if (newGenericArg != origGenericArg) hadChange = true; @@ -8475,6 +8481,9 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula wantGeneric = true; if (type->IsUnspecializedType()) isUnspecialized = true; + BF_ASSERT(!type->IsVar()); +// if (type->IsVar()) +// isUnspecialized = true; String typeName = TypeToString(type); types.push_back(type); @@ -8536,6 +8545,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula BfFieldInstance* fieldInstance = &tupleType->mFieldInstances[fieldIdx]; fieldInstance->mFieldIdx = fieldIdx; fieldInstance->SetResolvedType(types[fieldIdx]); + BF_ASSERT(!types[fieldIdx]->IsVar()); fieldInstance->mOwner = tupleType; } @@ -9715,12 +9725,18 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp // Nullable -> Nullable if ((typedVal.mType->IsNullable()) && (toType->IsNullable())) { - if (ignoreWrites) - return mBfIRBuilder->GetFakeVal(); - auto fromNullableType = (BfTypeInstance*)typedVal.mType; auto toNullableType = (BfTypeInstance*)toType; + if (ignoreWrites) + { + auto toVal = CastToValue(srcNode, BfTypedValue(mBfIRBuilder->GetFakeVal(), fromNullableType->mGenericTypeInfo->mTypeGenericArguments[0]), + toNullableType->mGenericTypeInfo->mTypeGenericArguments[0], ignoreErrors ? BfCastFlags_SilentFail : BfCastFlags_None); + if (!toVal) + return BfIRValue(); + return mBfIRBuilder->GetFakeVal(); + } + BfIRValue srcPtr = typedVal.mValue; if (!typedVal.IsAddr()) { @@ -9757,9 +9773,13 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp { auto fromTupleType = (BfTypeInstance*)typedVal.mType; auto toTupleType = (BfTypeInstance*)toType; + + PopulateType(fromTupleType); + PopulateType(toTupleType); + if (fromTupleType->mFieldInstances.size() == toTupleType->mFieldInstances.size()) { - typedVal = LoadValue(typedVal); + typedVal = LoadValue(typedVal); BfIRValue curTupleValue = mBfIRBuilder->CreateUndefValue(mBfIRBuilder->MapType(toTupleType)); for (int valueIdx = 0; valueIdx < (int)fromTupleType->mFieldInstances.size(); valueIdx++) @@ -10096,6 +10116,13 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp } } + if ((typedVal.mValue.IsConst()) && (toType->IsPointer()) && (toType->GetUnderlyingType() == GetPrimitiveType(BfTypeCode_Char8)) && (typedVal.mType->IsInstanceOf(mCompiler->mStringTypeDef))) + { + int stringId = GetStringPoolIdx(typedVal.mValue, mBfIRBuilder); + if (stringId >= 0) + return GetStringCharPtr(stringId); + } + // Check user-defined operators if ((castFlags & BfCastFlags_NoConversionOperator) == 0) { diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 25340106..7e2c3186 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -495,7 +495,7 @@ public: virtual bool IsValuelessType() { BF_ASSERT(mSize != -1); BF_ASSERT(mDefineState >= BfTypeDefineState_Defined); return mSize == 0; } virtual bool IsSelf() { return false; } virtual bool IsDot() { return false; } - virtual bool IsVar() { return false; } + virtual bool IsVar() { return false; } virtual bool IsLet() { return false; } virtual bool IsNull(){ return false; } virtual bool IsNullable() { return false; } @@ -604,7 +604,7 @@ public: virtual bool IsValuelessType() override { return mTypeDef->mTypeCode == BfTypeCode_None; } virtual bool IsSelf() override { return mTypeDef->mTypeCode == BfTypeCode_Self; } virtual bool IsDot() override { return mTypeDef->mTypeCode == BfTypeCode_Dot; } - virtual bool IsVar() override { return mTypeDef->mTypeCode == BfTypeCode_Var; } + virtual bool IsVar() override { return mTypeDef->mTypeCode == BfTypeCode_Var; } virtual bool IsLet() override { return mTypeDef->mTypeCode == BfTypeCode_Let; } }; @@ -797,8 +797,7 @@ public: bool mAlwaysInline:1; bool mIsIntrinsic:1; bool mHasMethodRefType:1; - bool mDisallowCalling:1; - bool mIsGenericMethodInstance:1; + bool mDisallowCalling:1; BfMethodChainType mChainType; BfCallingConvention mCallingConvention; BfMethodInstanceGroup* mMethodInstanceGroup; @@ -832,8 +831,7 @@ public: mAlwaysInline = false; mIsIntrinsic = false; mHasMethodRefType = false; - mDisallowCalling = false; - mIsGenericMethodInstance = false; + mDisallowCalling = false; mChainType = BfMethodChainType_None; mCallingConvention = BfCallingConvention_Unspecified; mMethodInstanceGroup = NULL; @@ -2059,7 +2057,7 @@ public: void Finish(); virtual bool IsOnDemand() override { return true; } - virtual bool IsTuple() override { return true; } + virtual bool IsTuple() override { return true; } virtual bool IsUnspecializedType() override { return mIsUnspecializedType; } virtual bool IsUnspecializedTypeVariation() override { return mIsUnspecializedTypeVariation; } diff --git a/IDEHelper/Tests/src/MethodSelection.bf b/IDEHelper/Tests/src/MethodSelection.bf index 629e1eac..9477da57 100644 --- a/IDEHelper/Tests/src/MethodSelection.bf +++ b/IDEHelper/Tests/src/MethodSelection.bf @@ -31,6 +31,46 @@ namespace Tests int mA; } + public static int MethodA(int8 a) + { + return 1; + } + + public static int MethodA(uint8 a) + { + return 2; + } + + public static int MethodA(int16 a) + { + return 3; + } + + public static int MethodA(int32 a) + { + return 4; + } + + public static int MethodB(T foo) where T : class, delete + { + return 1; + } + + public static int MethodB(T foo) where T : struct + { + return 2; + } + + public static int MethodB((K key, V value) foo) where K : var where V : var + { + return 3; + } + + public static int MethodC(T val) where T : struct + { + return MethodB(val); + } + [Test] public static void TestBasics() { @@ -55,6 +95,15 @@ namespace Tests Test.Assert(LibA.Handler.HandleT(sa) == 4); Test.Assert(LibA.Handler.HandleT(sal) == 4); Test.Assert(LibA.Handler.HandleT(las) == 0); + + Test.Assert(MethodA(1) == 1); + Test.Assert(MethodA(240) == 2); + Test.Assert(MethodA(1000) == 3); + Test.Assert(MethodA(1000000) == 4); + + Test.Assert(MethodB(11) == 2); + Test.Assert(MethodB(("A", "B")) == 3); + Test.Assert(MethodC(("A", "B")) == 3); } } }