mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-11 04:52:21 +02:00
Improvements to new conversion operator overload invoker
This commit is contained in:
parent
5267e18783
commit
7c6bdeffbe
4 changed files with 220 additions and 13 deletions
|
@ -773,6 +773,8 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
||||||
anyIsExtension = true;
|
anyIsExtension = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BfCastFlags implicitCastFlags = ((mBfEvalExprFlags & BfEvalExprFlags_FromConversionOp) != 0) ? BfCastFlags_NoConversionOperator : BfCastFlags_None;
|
||||||
|
|
||||||
int newMethodParamCount = newMethodInstance->GetParamCount();
|
int newMethodParamCount = newMethodInstance->GetParamCount();
|
||||||
int prevMethodParamCount = prevMethodInstance->GetParamCount();
|
int prevMethodParamCount = prevMethodInstance->GetParamCount();
|
||||||
|
|
||||||
|
@ -794,6 +796,7 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
||||||
|
|
||||||
bool someArgWasBetter = false;
|
bool someArgWasBetter = false;
|
||||||
bool someArgWasWorse = false;
|
bool someArgWasWorse = false;
|
||||||
|
|
||||||
for (argIdx = anyIsExtension ? -1 : 0; argIdx < (int)mArguments.size(); argIdx++)
|
for (argIdx = anyIsExtension ? -1 : 0; argIdx < (int)mArguments.size(); argIdx++)
|
||||||
{
|
{
|
||||||
BfTypedValue arg;
|
BfTypedValue arg;
|
||||||
|
@ -856,8 +859,8 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
||||||
{
|
{
|
||||||
prevParamWasConstExpr = true;
|
prevParamWasConstExpr = true;
|
||||||
prevParamType = ((BfConstExprValueType*)prevParamType)->mType;
|
prevParamType = ((BfConstExprValueType*)prevParamType)->mType;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool paramsEquivalent = paramType == prevParamType;
|
bool paramsEquivalent = paramType == prevParamType;
|
||||||
|
|
||||||
if ((prevParamType == NULL) || (paramType == NULL))
|
if ((prevParamType == NULL) || (paramType == NULL))
|
||||||
|
@ -871,6 +874,14 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
||||||
SET_BETTER_OR_WORSE((!isUnspecializedParam) && (!paramType->IsVar()),
|
SET_BETTER_OR_WORSE((!isUnspecializedParam) && (!paramType->IsVar()),
|
||||||
(!isPrevUnspecializedParam) && (!prevParamType->IsVar()));
|
(!isPrevUnspecializedParam) && (!prevParamType->IsVar()));
|
||||||
|
|
||||||
|
if ((mBfEvalExprFlags & BfEvalExprFlags_FromConversionOp_Explicit) != 0)
|
||||||
|
{
|
||||||
|
// Pick the one that can implicitly cast
|
||||||
|
SET_BETTER_OR_WORSE(
|
||||||
|
mModule->CanCast(arg, paramType, implicitCastFlags),
|
||||||
|
mModule->CanCast(arg, prevParamType, implicitCastFlags));
|
||||||
|
}
|
||||||
|
|
||||||
// Why did we have this !isUnspecializedParam check? We need the 'canCast' logic still
|
// Why did we have this !isUnspecializedParam check? We need the 'canCast' logic still
|
||||||
if ((!isBetter) && (!isWorse) /*&& (!isUnspecializedParam) && (!isPrevUnspecializedParam)*/)
|
if ((!isBetter) && (!isWorse) /*&& (!isUnspecializedParam) && (!isPrevUnspecializedParam)*/)
|
||||||
{
|
{
|
||||||
|
@ -887,8 +898,8 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
||||||
isWorse = true;
|
isWorse = true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool canCastFromCurToPrev = mModule->CanCast(mModule->GetFakeTypedValue(paramType), prevParamType);
|
bool canCastFromCurToPrev = mModule->CanCast(mModule->GetFakeTypedValue(paramType), prevParamType, implicitCastFlags);
|
||||||
bool canCastFromPrevToCur = mModule->CanCast(mModule->GetFakeTypedValue(prevParamType), paramType);
|
bool canCastFromPrevToCur = mModule->CanCast(mModule->GetFakeTypedValue(prevParamType), paramType, implicitCastFlags);
|
||||||
|
|
||||||
if ((canCastFromCurToPrev) && (canCastFromPrevToCur))
|
if ((canCastFromCurToPrev) && (canCastFromPrevToCur))
|
||||||
paramsEquivalent = true;
|
paramsEquivalent = true;
|
||||||
|
@ -983,6 +994,37 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
|
||||||
RETURN_RESULTS;
|
RETURN_RESULTS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Choose by return type for conversion operators
|
||||||
|
if (((mBfEvalExprFlags & BfEvalExprFlags_FromConversionOp) != 0) && (!isBetter) && (!isWorse))
|
||||||
|
{
|
||||||
|
auto returnType = newMethodInstance->mReturnType;
|
||||||
|
auto prevReturnType = prevMethodInstance->mReturnType;
|
||||||
|
|
||||||
|
if ((mBfEvalExprFlags & BfEvalExprFlags_FromConversionOp_Explicit) != 0)
|
||||||
|
{
|
||||||
|
// Pick the one that can implicitly cast
|
||||||
|
SET_BETTER_OR_WORSE(
|
||||||
|
mModule->CanCast(mModule->GetFakeTypedValue(returnType), mCheckReturnType, implicitCastFlags),
|
||||||
|
mModule->CanCast(mModule->GetFakeTypedValue(prevReturnType), mCheckReturnType, implicitCastFlags));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!isBetter) && (!isWorse))
|
||||||
|
{
|
||||||
|
bool canCastFromCurToPrev = mModule->CanCast(mModule->GetFakeTypedValue(returnType), prevReturnType, implicitCastFlags);
|
||||||
|
bool canCastFromPrevToCur = mModule->CanCast(mModule->GetFakeTypedValue(prevReturnType), returnType, implicitCastFlags);
|
||||||
|
|
||||||
|
if ((canCastFromCurToPrev) && (!canCastFromPrevToCur))
|
||||||
|
isWorse = true;
|
||||||
|
else if ((canCastFromPrevToCur) && (!canCastFromCurToPrev))
|
||||||
|
isBetter = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((isBetter) || (isWorse))
|
||||||
|
{
|
||||||
|
RETURN_RESULTS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check for unused extended params as next param - that still counts as using extended form
|
// Check for unused extended params as next param - that still counts as using extended form
|
||||||
usedExtendedForm = newMethodInstance->HasParamsArray();
|
usedExtendedForm = newMethodInstance->HasParamsArray();
|
||||||
|
|
|
@ -12649,9 +12649,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
methodMatcher.FlushAmbiguityError();
|
|
||||||
|
|
||||||
if (methodMatcher.mBestMethodDef != NULL)
|
if (methodMatcher.mBestMethodDef != NULL)
|
||||||
{
|
{
|
||||||
if (mayBeBox)
|
if (mayBeBox)
|
||||||
|
@ -12755,12 +12753,30 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
||||||
if (moduleMethodInstance.mMethodInstance != NULL)
|
if (moduleMethodInstance.mMethodInstance != NULL)
|
||||||
{
|
{
|
||||||
auto returnType = moduleMethodInstance.mMethodInstance->mReturnType;
|
auto returnType = moduleMethodInstance.mMethodInstance->mReturnType;
|
||||||
if (typedVal.mType->IsTypedPrimitive())
|
auto paramType = moduleMethodInstance.mMethodInstance->GetParamType(0);
|
||||||
{
|
|
||||||
|
BfCastFlags implicitCastFlags = (BfCastFlags)(castFlags & ~BfCastFlags_Explicit | BfCastFlags_NoConversionOperator);
|
||||||
|
|
||||||
|
// Check typedPrimitive->underlying cast
|
||||||
|
if ((explicitCast) && (typedVal.mType->IsTypedPrimitive()))
|
||||||
|
{
|
||||||
auto underlyingType = typedVal.mType->GetUnderlyingType();
|
auto underlyingType = typedVal.mType->GetUnderlyingType();
|
||||||
if ((returnType != underlyingType) && (CanCast(GetFakeTypedValue(underlyingType), toType, (BfCastFlags)(castFlags | BfCastFlags_NoConversionOperator))))
|
if ((returnType != underlyingType) && (CanCast(GetFakeTypedValue(underlyingType), toType, (BfCastFlags)(castFlags | BfCastFlags_NoConversionOperator))))
|
||||||
{
|
{
|
||||||
if ((CanCast(GetFakeTypedValue(underlyingType), returnType)) &&
|
float underlyingCanCast = CanCast(GetFakeTypedValue(underlyingType), toType, implicitCastFlags);
|
||||||
|
float returnCanCast = CanCast(GetFakeTypedValue(returnType), toType, implicitCastFlags);
|
||||||
|
|
||||||
|
if ((underlyingCanCast) &&
|
||||||
|
(!returnCanCast))
|
||||||
|
{
|
||||||
|
doCall = false;
|
||||||
|
}
|
||||||
|
else if ((returnCanCast) &&
|
||||||
|
(!underlyingCanCast))
|
||||||
|
{
|
||||||
|
doCall = true;
|
||||||
|
}
|
||||||
|
else if ((CanCast(GetFakeTypedValue(underlyingType), returnType, implicitCastFlags)) &&
|
||||||
(!CanCast(GetFakeTypedValue(returnType), underlyingType)))
|
(!CanCast(GetFakeTypedValue(returnType), underlyingType)))
|
||||||
{
|
{
|
||||||
doCall = true;
|
doCall = true;
|
||||||
|
@ -12770,9 +12786,26 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check underlying->typedPrimitive cast
|
||||||
|
if ((explicitCast) && (toType->IsTypedPrimitive()))
|
||||||
|
{
|
||||||
|
auto underlyingType = toType->GetUnderlyingType();
|
||||||
|
if ((paramType != underlyingType) && (CanCast(typedVal, underlyingType, (BfCastFlags)(castFlags | BfCastFlags_NoConversionOperator))))
|
||||||
|
{
|
||||||
|
if ((CanCast(GetFakeTypedValue(underlyingType), paramType, implicitCastFlags)) &&
|
||||||
|
(!CanCast(GetFakeTypedValue(paramType), underlyingType, implicitCastFlags)))
|
||||||
|
{
|
||||||
|
doCall = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
doCall = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (doCall)
|
if (doCall)
|
||||||
{
|
{
|
||||||
auto paramType = moduleMethodInstance.mMethodInstance->GetParamType(0);
|
methodMatcher.FlushAmbiguityError();
|
||||||
|
|
||||||
auto wantType = paramType;
|
auto wantType = paramType;
|
||||||
if (wantType->IsRef())
|
if (wantType->IsRef())
|
||||||
wantType = wantType->GetUnderlyingType();
|
wantType = wantType->GetUnderlyingType();
|
||||||
|
|
|
@ -900,8 +900,8 @@ public:
|
||||||
{
|
{
|
||||||
if (mOperatorDeclaration->mExplicitToken != NULL)
|
if (mOperatorDeclaration->mExplicitToken != NULL)
|
||||||
return mOperatorDeclaration->mExplicitToken->mToken == BfToken_Explicit;
|
return mOperatorDeclaration->mExplicitToken->mToken == BfToken_Explicit;
|
||||||
if (mOperatorDeclaration->mOperatorToken != NULL)
|
if (mOperatorDeclaration->mOpTypeToken != NULL)
|
||||||
return mOperatorDeclaration->mOperatorToken->mToken == BfToken_Explicit;
|
return mOperatorDeclaration->mOpTypeToken->mToken == BfToken_Explicit;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -267,6 +267,74 @@ namespace Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum MyEnum
|
||||||
|
{
|
||||||
|
Case1,
|
||||||
|
Case2,
|
||||||
|
Case3
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MyOtherEnum
|
||||||
|
{
|
||||||
|
case One;
|
||||||
|
case Two;
|
||||||
|
case Three;
|
||||||
|
|
||||||
|
public static explicit operator MyEnum(Self self)
|
||||||
|
{
|
||||||
|
return .Case1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StructI : int32
|
||||||
|
{
|
||||||
|
public static int8 operator implicit(Self self)
|
||||||
|
{
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int16 operator implicit(Self self)
|
||||||
|
{
|
||||||
|
return 23;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StructJ
|
||||||
|
{
|
||||||
|
public int mVal;
|
||||||
|
|
||||||
|
public static int8 operator implicit(Self self)
|
||||||
|
{
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int16 operator implicit(Self self)
|
||||||
|
{
|
||||||
|
return 23;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int32 operator explicit(Self self)
|
||||||
|
{
|
||||||
|
return 34;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Self operator explicit(int8 val)
|
||||||
|
{
|
||||||
|
return .(){mVal = 45};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Self operator implicit(int16 val)
|
||||||
|
{
|
||||||
|
return .(){mVal = 56};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Self operator implicit(int32 val)
|
||||||
|
{
|
||||||
|
return .(){mVal = 67};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*struct OuterOp<T>
|
/*struct OuterOp<T>
|
||||||
{
|
{
|
||||||
public struct InnerOp<T2>
|
public struct InnerOp<T2>
|
||||||
|
@ -503,6 +571,70 @@ namespace Tests
|
||||||
int8 a = 123;
|
int8 a = 123;
|
||||||
int32 b = a + 100;
|
int32 b = a + 100;
|
||||||
Test.Assert(b == 223);
|
Test.Assert(b == 223);
|
||||||
|
|
||||||
|
MyOtherEnum myEnum = .One;
|
||||||
|
MyEnum me = (MyEnum)myEnum;
|
||||||
|
Test.Assert(me == .Case1);
|
||||||
|
|
||||||
|
//
|
||||||
|
{
|
||||||
|
StructI si = (.)123;
|
||||||
|
|
||||||
|
int32 i32i = si;
|
||||||
|
int32 i32e = (int32)si;
|
||||||
|
int16 i16i = si;
|
||||||
|
int16 i16e = (int16)si;
|
||||||
|
int8 i8i = si;
|
||||||
|
int8 i8e = (int8)si;
|
||||||
|
float fi = si;
|
||||||
|
float fe = (float)si;
|
||||||
|
|
||||||
|
Test.Assert(i32i == 23);
|
||||||
|
Test.Assert(i32e == 123);
|
||||||
|
Test.Assert(i16i == 23);
|
||||||
|
Test.Assert(i16e == 23);
|
||||||
|
Test.Assert(i8i == 12);
|
||||||
|
Test.Assert(i8e == 12);
|
||||||
|
Test.Assert(fi == 23);
|
||||||
|
Test.Assert(fe == 123);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
{
|
||||||
|
StructJ sj = default;
|
||||||
|
|
||||||
|
int32 i32i = sj;
|
||||||
|
int32 i32e = (int32)sj;
|
||||||
|
int16 i16i = sj;
|
||||||
|
int16 i16e = (int16)sj;
|
||||||
|
int8 i8i = sj;
|
||||||
|
int8 i8e = (int8)sj;
|
||||||
|
float fi = sj;
|
||||||
|
float fe = (float)sj;
|
||||||
|
|
||||||
|
StructJ sji32i = i32i;
|
||||||
|
StructJ sji32e = (.)i32e;
|
||||||
|
StructJ sji16i = i16i;
|
||||||
|
StructJ sji16e = (.)i16e;
|
||||||
|
StructJ sji8i = i8i;
|
||||||
|
StructJ sji8e = (.)i8e;
|
||||||
|
|
||||||
|
Test.Assert(i32i == 23);
|
||||||
|
Test.Assert(i32e == 32);
|
||||||
|
Test.Assert(i16i == 23);
|
||||||
|
Test.Assert(i16e == 23);
|
||||||
|
Test.Assert(i8i == 12);
|
||||||
|
Test.Assert(i8e == 12);
|
||||||
|
Test.Assert(fi == 23);
|
||||||
|
Test.Assert(fe == 34);
|
||||||
|
|
||||||
|
Test.Assert(sji32i.mVal == 67);
|
||||||
|
Test.Assert(sji32e.mVal == 67);
|
||||||
|
Test.Assert(sji16i.mVal == 56);
|
||||||
|
Test.Assert(sji16e.mVal == 56);
|
||||||
|
Test.Assert(sji8i.mVal == 56);
|
||||||
|
Test.Assert(sji8e.mVal == 45);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IntStruct
|
struct IntStruct
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue