mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 11:38:21 +02:00
Support for operators with ref
parameters, sized array->span
This commit is contained in:
parent
5c05b15b37
commit
1e52dce7c4
9 changed files with 183 additions and 31 deletions
|
@ -20,11 +20,23 @@ namespace System
|
|||
return val.mVal;
|
||||
}
|
||||
|
||||
public implicit static operator Span<T> (ref Self val)
|
||||
{
|
||||
#unwarn
|
||||
return .(&val.mVal, CSize);
|
||||
}
|
||||
|
||||
public override void ToString(String strBuffer) mut
|
||||
{
|
||||
if (typeof(T) == typeof(char8))
|
||||
{
|
||||
strBuffer.Append((char8*)&mVal, CSize);
|
||||
int len = 0;
|
||||
for (; len < CSize; len++)
|
||||
{
|
||||
if (mVal[len] == default)
|
||||
break;
|
||||
}
|
||||
strBuffer.Append((char8*)&mVal, len);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -177,6 +177,7 @@ void BfMethodMatcher::Init(/*SizedArrayImpl<BfResolvedArg>& arguments, */BfSized
|
|||
mAllowNonStatic = true;
|
||||
mSkipImplicitParams = false;
|
||||
mAllowImplicitThis = false;
|
||||
mAllowImplicitRef = false;
|
||||
mHadVarConflictingReturnType = false;
|
||||
mAutoFlushAmbiguityErrors = true;
|
||||
mMethodCheckCount = 0;
|
||||
|
@ -2066,9 +2067,14 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
|||
|
||||
goto NoMatch;
|
||||
}
|
||||
else if (!mModule->CanCast(argTypedValue, wantType))
|
||||
else
|
||||
{
|
||||
if ((mAllowImplicitRef) && (wantType->IsRef()) && (!argTypedValue.mType->IsRef()))
|
||||
wantType = wantType->GetUnderlyingType();
|
||||
if (!mModule->CanCast(argTypedValue, wantType))
|
||||
goto NoMatch;
|
||||
}
|
||||
}
|
||||
|
||||
paramIdx++;
|
||||
argIdx++;
|
||||
|
@ -5964,7 +5970,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodMatcher* methodMatcher, BfTyped
|
|||
|
||||
PerformCallChecks(moduleMethodInstance.mMethodInstance, methodMatcher->mTargetSrc);
|
||||
|
||||
return CreateCall(methodMatcher->mTargetSrc, target, BfTypedValue(), methodMatcher->mBestMethodDef, moduleMethodInstance, false, methodMatcher->mArguments);
|
||||
BfCreateFallFlags callFlags = BfCreateFallFlags_None;
|
||||
if (methodMatcher->mAllowImplicitRef)
|
||||
callFlags = (BfCreateFallFlags)(callFlags | BfCreateFallFlags_AllowImplicitRef);
|
||||
return CreateCall(methodMatcher->mTargetSrc, target, BfTypedValue(), methodMatcher->mBestMethodDef, moduleMethodInstance, callFlags, methodMatcher->mArguments);
|
||||
}
|
||||
|
||||
void BfExprEvaluator::MakeBaseConcrete(BfTypedValue& typedValue)
|
||||
|
@ -6295,8 +6304,11 @@ void BfExprEvaluator::AddCallDependencies(BfMethodInstance* methodInstance)
|
|||
}
|
||||
|
||||
//TODO: delete argumentsZ
|
||||
BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValue& inTarget, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance moduleMethodInstance, bool bypassVirtual, SizedArrayImpl<BfResolvedArg>& argValues, BfTypedValue* argCascade, bool skipThis)
|
||||
BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValue& inTarget, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance moduleMethodInstance, BfCreateFallFlags callFlags, SizedArrayImpl<BfResolvedArg>& argValues, BfTypedValue* argCascade)
|
||||
{
|
||||
bool bypassVirtual = (callFlags & BfCreateFallFlags_BypassVirtual) != 0;
|
||||
bool skipThis = (callFlags & BfCreateFallFlags_SkipThis) != 0;;
|
||||
|
||||
static int sCallIdx = 0;
|
||||
if (!mModule->mCompiler->mIsResolveOnly)
|
||||
sCallIdx++;
|
||||
|
@ -6999,6 +7011,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
|||
if (refNode == NULL)
|
||||
refNode = targetSrc;
|
||||
|
||||
if (((callFlags & BfCreateFallFlags_AllowImplicitRef) != 0) &&
|
||||
(wantType->IsRef()) && (!argValue.mType->IsRef()))
|
||||
argValue = mModule->ToRef(argValue, (BfRefType*)wantType);
|
||||
|
||||
if (mModule->mCurMethodState != NULL)
|
||||
{
|
||||
SetAndRestoreValue<BfScopeData*> prevScopeData(mModule->mCurMethodState->mOverrideScope, boxScopeData);
|
||||
|
@ -7413,7 +7429,7 @@ BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBou
|
|||
if (isFailurePass)
|
||||
mModule->Fail(StrFormat("'%s' is inaccessible due to its protection level", mModule->MethodToString(moduleMethodInstance.mMethodInstance).c_str()), targetSrc);
|
||||
prevBindResult.Restore();
|
||||
return CreateCall(methodMatcher.mTargetSrc, target, BfTypedValue(), methodMatcher.mBestMethodDef, moduleMethodInstance, false, methodMatcher.mArguments);
|
||||
return CreateCall(methodMatcher.mTargetSrc, target, BfTypedValue(), methodMatcher.mBestMethodDef, moduleMethodInstance, BfCreateFallFlags_None, methodMatcher.mArguments);
|
||||
}
|
||||
|
||||
static int sInvocationIdx = 0;
|
||||
|
@ -8987,7 +9003,12 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
mModule->Fail(StrFormat("Method '%s' can only be invoked at comptime. Consider adding [Comptime] to the current method.", mModule->MethodToString(moduleMethodInstance.mMethodInstance).c_str()), targetSrc);
|
||||
}
|
||||
|
||||
result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, bypassVirtual, argValues.mResolvedArgs, &argCascade, skipThis);
|
||||
BfCreateFallFlags subCallFlags = BfCreateFallFlags_None;
|
||||
if (bypassVirtual)
|
||||
subCallFlags = (BfCreateFallFlags)(subCallFlags | BfCreateFallFlags_BypassVirtual);
|
||||
if (skipThis)
|
||||
subCallFlags = (BfCreateFallFlags)(subCallFlags | BfCreateFallFlags_SkipThis);
|
||||
result = CreateCall(targetSrc, callTarget, origTarget, methodDef, moduleMethodInstance, subCallFlags, argValues.mResolvedArgs, &argCascade);
|
||||
}
|
||||
|
||||
if (overrideReturnType != NULL)
|
||||
|
@ -19429,6 +19450,7 @@ BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedVal
|
|||
args.push_back(resolvedArg);
|
||||
BfMethodMatcher methodMatcher(opToken, mModule, "", args, NULL);
|
||||
methodMatcher.mBfEvalExprFlags = BfEvalExprFlags_NoAutoComplete;
|
||||
methodMatcher.mAllowImplicitRef = true;
|
||||
BfBaseClassWalker baseClassWalker(inValue.mType, NULL, mModule);
|
||||
|
||||
BfUnaryOp findOp = unaryOp;
|
||||
|
@ -20885,9 +20907,13 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
|
|||
args.push_back(leftArg);
|
||||
}
|
||||
|
||||
auto checkLeftType = leftValue.mType;
|
||||
auto checkRightType = rightValue.mType;
|
||||
|
||||
BfMethodMatcher methodMatcher(opToken, mModule, "", args, NULL);
|
||||
methodMatcher.mAllowImplicitRef = true;
|
||||
methodMatcher.mBfEvalExprFlags = BfEvalExprFlags_NoAutoComplete;
|
||||
BfBaseClassWalker baseClassWalker(leftValue.mType, rightValue.mType, mModule);
|
||||
BfBaseClassWalker baseClassWalker(checkLeftType, checkRightType, mModule);
|
||||
|
||||
bool invertResult = false;
|
||||
BfType* operatorConstraintReturnType = NULL;
|
||||
|
@ -21461,7 +21487,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
|
|||
argValues.push_back(resolvedArg);
|
||||
resolvedArg.mTypedValue = rightValue;
|
||||
argValues.push_back(resolvedArg);
|
||||
mResult = CreateCall(opToken, BfTypedValue(), BfTypedValue(), moduleMethodInstance.mMethodInstance->mMethodDef, moduleMethodInstance, false, argValues);
|
||||
mResult = CreateCall(opToken, BfTypedValue(), BfTypedValue(), moduleMethodInstance.mMethodInstance->mMethodDef, moduleMethodInstance, BfCreateFallFlags_None, argValues);
|
||||
if ((mResult) &&
|
||||
((binaryOp == BfBinaryOp_InEquality) || (binaryOp == BfBinaryOp_StrictInEquality)))
|
||||
mResult.mValue = mModule->mBfIRBuilder->CreateNot(mResult.mValue);
|
||||
|
|
|
@ -41,6 +41,14 @@ enum BfResolveArgFlags
|
|||
BfResolveArgFlag_FromGenericParam = 2
|
||||
};
|
||||
|
||||
enum BfCreateFallFlags
|
||||
{
|
||||
BfCreateFallFlags_None,
|
||||
BfCreateFallFlags_BypassVirtual = 1,
|
||||
BfCreateFallFlags_SkipThis = 2,
|
||||
BfCreateFallFlags_AllowImplicitRef = 4
|
||||
};
|
||||
|
||||
class BfResolvedArg
|
||||
{
|
||||
public:
|
||||
|
@ -186,6 +194,7 @@ public:
|
|||
bool mHadVarConflictingReturnType;
|
||||
bool mBypassVirtual;
|
||||
bool mAllowImplicitThis;
|
||||
bool mAllowImplicitRef;
|
||||
bool mAllowStatic;
|
||||
bool mAllowNonStatic;
|
||||
bool mSkipImplicitParams;
|
||||
|
@ -435,7 +444,7 @@ public:
|
|||
void AddCallDependencies(BfMethodInstance* methodInstance);
|
||||
void PerformCallChecks(BfMethodInstance* methodInstance, BfAstNode* targetSrc);
|
||||
BfTypedValue CreateCall(BfAstNode* targetSrc, BfMethodInstance* methodInstance, BfIRValue func, bool bypassVirtual, SizedArrayImpl<BfIRValue>& irArgs, BfTypedValue* sret = NULL, bool isTailCall = false);
|
||||
BfTypedValue CreateCall(BfAstNode* targetSrc, const BfTypedValue& target, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance methodInstance, bool bypassVirtual, SizedArrayImpl<BfResolvedArg>& argValues, BfTypedValue* argCascade = NULL, bool skipThis = false);
|
||||
BfTypedValue CreateCall(BfAstNode* targetSrc, const BfTypedValue& target, const BfTypedValue& origTarget, BfMethodDef* methodDef, BfModuleMethodInstance methodInstance, BfCreateFallFlags callFlags, SizedArrayImpl<BfResolvedArg>& argValues, BfTypedValue* argCascade = NULL);
|
||||
BfTypedValue CreateCall(BfMethodMatcher* methodMatcher, BfTypedValue target);
|
||||
void MakeBaseConcrete(BfTypedValue& typedValue);
|
||||
void SplatArgs(BfTypedValue value, SizedArrayImpl<BfIRValue>& irArgs);
|
||||
|
|
|
@ -11512,6 +11512,23 @@ BfTypedValue BfModule::RemoveRef(BfTypedValue typedValue)
|
|||
return typedValue;
|
||||
}
|
||||
|
||||
BfTypedValue BfModule::ToRef(BfTypedValue typedValue, BfRefType* refType)
|
||||
{
|
||||
if (refType == NULL)
|
||||
refType = CreateRefType(typedValue.mType);
|
||||
|
||||
if ((refType->mRefKind == BfRefType::RefKind_Mut) && (typedValue.mType->IsObjectOrInterface()))
|
||||
{
|
||||
return LoadValue(typedValue);
|
||||
}
|
||||
|
||||
if (refType->mRefKind == BfRefType::RefKind_Mut)
|
||||
refType = CreateRefType(typedValue.mType);
|
||||
|
||||
typedValue = MakeAddressable(typedValue);
|
||||
return BfTypedValue(typedValue.mValue, refType);
|
||||
}
|
||||
|
||||
BfTypedValue BfModule::LoadValue(BfTypedValue typedValue, BfAstNode* refNode, bool isVolatile)
|
||||
{
|
||||
if (!typedValue.IsAddr())
|
||||
|
@ -18300,8 +18317,15 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((mCurMethodInstance->GetParamType(0) != mCurTypeInstance) && (!mCurMethodInstance->GetParamType(0)->IsSelf()) &&
|
||||
(mCurMethodInstance->GetParamType(1) != mCurTypeInstance) && (!mCurMethodInstance->GetParamType(1)->IsSelf()))
|
||||
auto checkParam0 = mCurMethodInstance->GetParamType(0);
|
||||
if ((checkParam0->IsRef()) && (!checkParam0->IsOut()))
|
||||
checkParam0 = checkParam0->GetUnderlyingType();
|
||||
auto checkParam1 = mCurMethodInstance->GetParamType(1);
|
||||
if ((checkParam1->IsRef()) && (!checkParam1->IsOut()))
|
||||
checkParam1 = checkParam1->GetUnderlyingType();
|
||||
|
||||
if ((checkParam0 != mCurTypeInstance) && (!checkParam0->IsSelf()) &&
|
||||
(checkParam1 != mCurTypeInstance) && (!checkParam1->IsSelf()))
|
||||
{
|
||||
Fail("At least one of the parameters of a binary operator must be the containing type", paramErrorRefNode);
|
||||
}
|
||||
|
@ -18321,11 +18345,15 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
|
|||
{
|
||||
if (methodDef->mIsStatic)
|
||||
{
|
||||
auto checkParam0 = mCurMethodInstance->GetParamType(0);
|
||||
if ((checkParam0->IsRef()) && (!checkParam0->IsOut()))
|
||||
checkParam0 = checkParam0->GetUnderlyingType();
|
||||
|
||||
if (methodDef->mParams.size() != 1)
|
||||
{
|
||||
Fail("Unary operators must declare one parameter", paramErrorRefNode);
|
||||
}
|
||||
else if ((mCurMethodInstance->GetParamType(0) != mCurTypeInstance) && (!mCurMethodInstance->GetParamType(0)->IsSelf()))
|
||||
else if ((checkParam0 != mCurTypeInstance) && (!checkParam0->IsSelf()))
|
||||
{
|
||||
Fail("The parameter of a unary operator must be the containing type", paramErrorRefNode);
|
||||
}
|
||||
|
@ -18379,18 +18407,22 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((mCurMethodInstance->GetParamType(0) != mCurTypeInstance) && (!mCurMethodInstance->GetParamType(0)->IsSelf()) &&
|
||||
auto checkParam0 = mCurMethodInstance->GetParamType(0);
|
||||
if ((checkParam0->IsRef()) && (!checkParam0->IsOut()))
|
||||
checkParam0 = checkParam0->GetUnderlyingType();
|
||||
|
||||
if ((checkParam0 != mCurTypeInstance) && (!checkParam0->IsSelf()) &&
|
||||
(mCurMethodInstance->mReturnType != mCurTypeInstance) && (!mCurMethodInstance->mReturnType->IsSelf()))
|
||||
Fail("User-defined conversion must convert to or from the enclosing type", paramErrorRefNode);
|
||||
if (mCurMethodInstance->GetParamType(0) == mCurMethodInstance->mReturnType)
|
||||
if (checkParam0 == mCurMethodInstance->mReturnType)
|
||||
Fail("User-defined operator cannot take an object of the enclosing type and convert to an object of the enclosing type", operatorDef->mOperatorDeclaration->mReturnType);
|
||||
|
||||
// On type lookup error we default to 'object', so don't do the 'base class' error if that may have
|
||||
// happened here
|
||||
if ((!mHadBuildError) || ((mCurMethodInstance->mReturnType != mContext->mBfObjectType) && (mCurMethodInstance->GetParamType(0) != mContext->mBfObjectType)))
|
||||
if ((!mHadBuildError) || ((mCurMethodInstance->mReturnType != mContext->mBfObjectType) && (checkParam0 != mContext->mBfObjectType)))
|
||||
{
|
||||
auto isToBase = TypeIsSubTypeOf(mCurTypeInstance->mBaseType, mCurMethodInstance->mReturnType->ToTypeInstance());
|
||||
bool isFromBase = TypeIsSubTypeOf(mCurTypeInstance->mBaseType, mCurMethodInstance->GetParamType(0)->ToTypeInstance());
|
||||
bool isFromBase = TypeIsSubTypeOf(mCurTypeInstance->mBaseType, checkParam0->ToTypeInstance());
|
||||
|
||||
if ((mCurTypeInstance->IsObject()) && (isToBase || isFromBase))
|
||||
Fail("User-defined conversions to or from a base class are not allowed", paramErrorRefNode);
|
||||
|
@ -22218,16 +22250,22 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
|
|||
methodDef->mIsVirtual = false;
|
||||
}
|
||||
|
||||
if ((methodDeclaration != NULL) && (methodDeclaration->mMutSpecifier != NULL) && (!mCurTypeInstance->IsBoxed()) && (!methodInstance->mIsForeignMethodDef))
|
||||
BfAstNode* mutSpecifier = NULL;
|
||||
if (methodDeclaration != NULL)
|
||||
mutSpecifier = methodDeclaration->mMutSpecifier;
|
||||
else if (methodDef->GetPropertyMethodDeclaration() != NULL)
|
||||
mutSpecifier = methodDef->GetPropertyMethodDeclaration()->mMutSpecifier;
|
||||
|
||||
if ((mutSpecifier != NULL) && (!mCurTypeInstance->IsBoxed()) && (!methodInstance->mIsForeignMethodDef))
|
||||
{
|
||||
if (methodDef->mIsStatic)
|
||||
Warn(0, "Unnecessary 'mut' specifier, static methods have no implicit 'this' target to mutate", methodDeclaration->mMutSpecifier);
|
||||
Warn(0, "Unnecessary 'mut' specifier, static methods have no implicit 'this' target to mutate", mutSpecifier);
|
||||
else if ((!mCurTypeInstance->IsValueType()) && (!mCurTypeInstance->IsInterface()))
|
||||
Warn(0, "Unnecessary 'mut' specifier, methods of reference types are implicitly mutating", methodDeclaration->mMutSpecifier);
|
||||
Warn(0, "Unnecessary 'mut' specifier, methods of reference types are implicitly mutating", mutSpecifier);
|
||||
else if (methodDef->mMethodType == BfMethodType_Ctor)
|
||||
Warn(0, "Unnecessary 'mut' specifier, constructors are implicitly mutating", methodDeclaration->mMutSpecifier);
|
||||
Warn(0, "Unnecessary 'mut' specifier, constructors are implicitly mutating", mutSpecifier);
|
||||
else if (methodDef->mMethodType == BfMethodType_Dtor)
|
||||
Warn(0, "Unnecessary 'mut' specifier, destructors are implicitly mutating", methodDeclaration->mMutSpecifier);
|
||||
Warn(0, "Unnecessary 'mut' specifier, destructors are implicitly mutating", mutSpecifier);
|
||||
}
|
||||
|
||||
if (isTemporaryFunc)
|
||||
|
|
|
@ -1627,6 +1627,7 @@ public:
|
|||
void EmitDynamicCastCheck(BfTypedValue typedVal, BfType* type, bool allowNull);
|
||||
void CheckStaticAccess(BfTypeInstance* typeInstance);
|
||||
BfTypedValue RemoveRef(BfTypedValue typedValue);
|
||||
BfTypedValue ToRef(BfTypedValue typedValue, BfRefType* refType = NULL);
|
||||
BfTypedValue LoadOrAggregateValue(BfTypedValue typedValue);
|
||||
BfTypedValue LoadValue(BfTypedValue typedValue, BfAstNode* refNode = NULL, bool isVolatile = false);
|
||||
BfTypedValue PrepareConst(BfTypedValue& typedValue);
|
||||
|
|
|
@ -11643,8 +11643,12 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
|||
break;
|
||||
}
|
||||
|
||||
BfType* searchFromType = checkFromType;
|
||||
if (searchFromType->IsSizedArray())
|
||||
searchFromType = GetWrappedStructType(checkFromType);
|
||||
|
||||
bool isConstraintCheck = ((castFlags & BfCastFlags_IsConstraintCheck) != 0);
|
||||
BfBaseClassWalker baseClassWalker(fromType, toType, this);
|
||||
BfBaseClassWalker baseClassWalker(searchFromType, toType, this);
|
||||
|
||||
while (true)
|
||||
{
|
||||
|
@ -11687,6 +11691,9 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
|||
methodToType = methodInst->mReturnType;
|
||||
}
|
||||
|
||||
if (methodFromType->IsRef())
|
||||
methodFromType = methodFromType->GetUnderlyingType();
|
||||
|
||||
if (methodFromType->IsSelf())
|
||||
methodFromType = entry.mSrcType;
|
||||
if (methodToType->IsSelf())
|
||||
|
@ -11708,6 +11715,11 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
|||
}
|
||||
|
||||
int fromDist = GetTypeDistance(methodCheckFromType, checkFromType);
|
||||
if ((fromDist == INT_MAX) && (searchFromType != checkFromType))
|
||||
{
|
||||
fromDist = GetTypeDistance(methodCheckFromType, searchFromType);
|
||||
}
|
||||
|
||||
if (fromDist < 0)
|
||||
{
|
||||
// Allow us to cast a constant int to a smaller type if it satisfies the cast operator
|
||||
|
@ -11845,7 +11857,16 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
|||
|
||||
// Actually perform conversion
|
||||
BfExprEvaluator exprEvaluator(this);
|
||||
auto castedFromValue = Cast(srcNode, typedVal, bestFromType, castFlags);
|
||||
BfTypedValue castedFromValue;
|
||||
if ((typedVal.mType->IsSizedArray()) && (bestFromType->IsInstanceOf(mCompiler->mSizedArrayTypeDef)))
|
||||
{
|
||||
castedFromValue = MakeAddressable(typedVal);
|
||||
if (!bestFromType->IsValuelessType())
|
||||
castedFromValue.mValue = mBfIRBuilder->CreateBitCast(castedFromValue.mValue, mBfIRBuilder->MapTypeInstPtr(bestFromType->ToTypeInstance()));
|
||||
castedFromValue.mType = bestFromType;
|
||||
}
|
||||
else
|
||||
castedFromValue = Cast(srcNode, typedVal, bestFromType, castFlags);
|
||||
if (!castedFromValue)
|
||||
return BfIRValue();
|
||||
|
||||
|
@ -11864,6 +11885,9 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
|||
BfModuleMethodInstance moduleMethodInstance = GetMethodInstance(opMethodInstance->GetOwner(), opMethodInstance->mMethodDef, BfTypeVector());
|
||||
exprEvaluator.PerformCallChecks(moduleMethodInstance.mMethodInstance, srcNode);
|
||||
|
||||
if (moduleMethodInstance.mMethodInstance->GetParamType(0)->IsRef())
|
||||
castedFromValue = ToRef(castedFromValue);
|
||||
|
||||
SizedArray<BfIRValue, 1> args;
|
||||
exprEvaluator.PushArg(castedFromValue, args);
|
||||
operatorOut = exprEvaluator.CreateCall(NULL, moduleMethodInstance.mMethodInstance, IsSkippingExtraResolveChecks() ? BfIRValue() : moduleMethodInstance.mFunc, false, args);
|
||||
|
|
|
@ -568,6 +568,8 @@ public:
|
|||
virtual bool IsAllocType() { return false; }
|
||||
virtual bool IsIntPtrable() { return false; }
|
||||
virtual bool IsRef() { return false; }
|
||||
virtual bool IsMut() { return false; }
|
||||
virtual bool IsOut() { return false; }
|
||||
virtual bool IsGenericParam() { return false; }
|
||||
virtual bool IsClosure() { return false; }
|
||||
virtual bool IsMethodRef() { return false; }
|
||||
|
@ -2280,6 +2282,8 @@ public:
|
|||
virtual bool IsReified() override { return mElementType->IsReified(); }
|
||||
|
||||
virtual bool IsRef() override { return true; }
|
||||
virtual bool IsMut() override { return mRefKind == RefKind_Mut; }
|
||||
virtual bool IsOut() override { return mRefKind == RefKind_Out; }
|
||||
virtual bool IsDependentOnUnderlyingType() override { return true; }
|
||||
virtual BfType* GetUnderlyingType() override { return mElementType; }
|
||||
virtual bool IsUnspecializedType() override { return mElementType->IsUnspecializedType(); }
|
||||
|
|
|
@ -176,6 +176,28 @@ namespace Tests
|
|||
}
|
||||
}
|
||||
|
||||
struct StructG : this(int a)
|
||||
{
|
||||
public static StructG operator+(ref StructG lhs, ref StructG rhs)
|
||||
{
|
||||
lhs.a += 1000;
|
||||
rhs.a += 1000;
|
||||
|
||||
return .(lhs.a + rhs.a);
|
||||
}
|
||||
|
||||
public static StructG operator-(ref StructG val)
|
||||
{
|
||||
val.a += 1000;
|
||||
return val;
|
||||
}
|
||||
|
||||
public static implicit operator int(ref StructG val)
|
||||
{
|
||||
return val.a;
|
||||
}
|
||||
}
|
||||
|
||||
struct StructOp<T, T2> where T : operator T + T2
|
||||
{
|
||||
public T DoIt(T val, T2 val2)
|
||||
|
@ -407,6 +429,15 @@ namespace Tests
|
|||
Test.Assert(sf + 1.0f == 3);
|
||||
Test.Assert(2.0f + sf == 3);
|
||||
|
||||
StructG sg = .(100);
|
||||
StructG sg2 = .(200);
|
||||
var sg3 = sg + sg2;
|
||||
var sg4 = -sg3;
|
||||
Test.Assert(sg.a == 1100);
|
||||
Test.Assert(sg2.a == 1200);
|
||||
Test.Assert(sg3.a == 3300);
|
||||
Test.Assert(sg4.a == 3300);
|
||||
|
||||
/*let oai = OuterOp<float>.InnerOp<int>.Op(1.0f, 100);
|
||||
Test.Assert(oai == 101.0f);
|
||||
|
||||
|
@ -443,6 +474,8 @@ namespace Tests
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Test]
|
||||
public static void TestCompareWithCastOperator()
|
||||
{
|
||||
|
@ -504,3 +537,4 @@ namespace Tests
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,10 @@ namespace Tests
|
|||
ClassA[2] caArr0 = .(ca0, ca0);
|
||||
ClassA[2] caArr1 = .(ca1, ca1);
|
||||
Test.Assert(caArr0 == caArr1);
|
||||
|
||||
Span<int> span = val1;
|
||||
Test.Assert(span[0] == 7);
|
||||
Test.Assert(span[1] == 8);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue