mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 19:48:20 +02:00
Fixed deferred targeted boxing, DisableChecks, sized array generics
This commit is contained in:
parent
a94b52ff58
commit
b640bf9d5e
8 changed files with 189 additions and 89 deletions
|
@ -382,6 +382,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
|
||||||
mCReprAttributeTypeDef = NULL;
|
mCReprAttributeTypeDef = NULL;
|
||||||
mAlignAttributeTypeDef = NULL;
|
mAlignAttributeTypeDef = NULL;
|
||||||
mNoDiscardAttributeTypeDef = NULL;
|
mNoDiscardAttributeTypeDef = NULL;
|
||||||
|
mDisableChecksAttributeTypeDef = NULL;
|
||||||
mDisableObjectAccessChecksAttributeTypeDef = NULL;
|
mDisableObjectAccessChecksAttributeTypeDef = NULL;
|
||||||
mDbgRawAllocDataTypeDef = NULL;
|
mDbgRawAllocDataTypeDef = NULL;
|
||||||
mDeferredCallTypeDef = NULL;
|
mDeferredCallTypeDef = NULL;
|
||||||
|
@ -5835,6 +5836,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
|
||||||
mCReprAttributeTypeDef = _GetRequiredType("System.CReprAttribute");
|
mCReprAttributeTypeDef = _GetRequiredType("System.CReprAttribute");
|
||||||
mAlignAttributeTypeDef = _GetRequiredType("System.AlignAttribute");
|
mAlignAttributeTypeDef = _GetRequiredType("System.AlignAttribute");
|
||||||
mNoDiscardAttributeTypeDef = _GetRequiredType("System.NoDiscardAttribute");
|
mNoDiscardAttributeTypeDef = _GetRequiredType("System.NoDiscardAttribute");
|
||||||
|
mDisableChecksAttributeTypeDef = _GetRequiredType("System.DisableChecksAttribute");
|
||||||
mDisableObjectAccessChecksAttributeTypeDef = _GetRequiredType("System.DisableObjectAccessChecksAttribute");
|
mDisableObjectAccessChecksAttributeTypeDef = _GetRequiredType("System.DisableObjectAccessChecksAttribute");
|
||||||
mDbgRawAllocDataTypeDef = _GetRequiredType("System.DbgRawAllocData");
|
mDbgRawAllocDataTypeDef = _GetRequiredType("System.DbgRawAllocData");
|
||||||
mDeferredCallTypeDef = _GetRequiredType("System.DeferredCall");
|
mDeferredCallTypeDef = _GetRequiredType("System.DeferredCall");
|
||||||
|
|
|
@ -380,6 +380,7 @@ public:
|
||||||
BfTypeDef* mCReprAttributeTypeDef;
|
BfTypeDef* mCReprAttributeTypeDef;
|
||||||
BfTypeDef* mAlignAttributeTypeDef;
|
BfTypeDef* mAlignAttributeTypeDef;
|
||||||
BfTypeDef* mNoDiscardAttributeTypeDef;
|
BfTypeDef* mNoDiscardAttributeTypeDef;
|
||||||
|
BfTypeDef* mDisableChecksAttributeTypeDef;
|
||||||
BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef;
|
BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef;
|
||||||
BfTypeDef* mFriendAttributeTypeDef;
|
BfTypeDef* mFriendAttributeTypeDef;
|
||||||
BfTypeDef* mCheckedAttributeTypeDef;
|
BfTypeDef* mCheckedAttributeTypeDef;
|
||||||
|
|
|
@ -2396,7 +2396,7 @@ void BfExprEvaluator::Visit(BfCaseExpression* caseExpr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPayloadEnum = caseValAddr.mType->IsPayloadEnum();
|
bool isPayloadEnum = (caseValAddr.mType != NULL) && (caseValAddr.mType->IsPayloadEnum());
|
||||||
auto tupleExpr = BfNodeDynCast<BfTupleExpression>(caseExpr->mCaseExpression);
|
auto tupleExpr = BfNodeDynCast<BfTupleExpression>(caseExpr->mCaseExpression);
|
||||||
|
|
||||||
if ((caseValAddr) &&
|
if ((caseValAddr) &&
|
||||||
|
@ -5172,7 +5172,12 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
|
|
||||||
if ((argValue) && (arg != NULL))
|
if ((argValue) && (arg != NULL))
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
{
|
||||||
|
SetAndRestoreValue<BfScopeData*> prevScopeData(mModule->mCurMethodState->mOverrideScope, boxScopeData);
|
||||||
argValue = mModule->Cast(arg, argValue, wantType);
|
argValue = mModule->Cast(arg, argValue, wantType);
|
||||||
|
}
|
||||||
|
|
||||||
if (!argValue)
|
if (!argValue)
|
||||||
{
|
{
|
||||||
failed = true;
|
failed = true;
|
||||||
|
@ -7368,8 +7373,6 @@ void BfExprEvaluator::LookupQualifiedName(BfAstNode* nameNode, BfIdentifierNode*
|
||||||
prevTarget = mPropTarget;
|
prevTarget = mPropTarget;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*if ((mResult) || (mPropDef != NULL))
|
|
||||||
break;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPropDef != NULL)
|
if (mPropDef != NULL)
|
||||||
|
@ -13738,6 +13741,33 @@ void BfExprEvaluator::CheckPropFail(BfMethodDef* propMethodDef, BfMethodInstance
|
||||||
BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericType)
|
BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericType)
|
||||||
{
|
{
|
||||||
if ((!mResult) && (mPropDef != NULL))
|
if ((!mResult) && (mPropDef != NULL))
|
||||||
|
{
|
||||||
|
bool handled = false;
|
||||||
|
if (mPropTarget.mType->IsGenericTypeInstance())
|
||||||
|
{
|
||||||
|
auto genericTypeInst = (BfGenericTypeInstance*)mPropTarget.mType;
|
||||||
|
if (genericTypeInst->mTypeDef == mModule->mCompiler->mSizedArrayTypeDef)
|
||||||
|
{
|
||||||
|
if (mPropDef->mName == "Count")
|
||||||
|
{
|
||||||
|
auto sizedType = genericTypeInst->mTypeGenericArguments[1];
|
||||||
|
if (sizedType->IsConstExprValue())
|
||||||
|
{
|
||||||
|
auto constExprType = (BfConstExprValueType*)sizedType;
|
||||||
|
mResult = BfTypedValue(mModule->GetConstValue(constExprType->mValue.mInt64), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BF_ASSERT(mModule->mCurMethodInstance->mIsUnspecialized);
|
||||||
|
mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(BfTypeCode_IntPtr), mModule->GetPrimitiveType(BfTypeCode_IntPtr));
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!handled)
|
||||||
{
|
{
|
||||||
BfMethodDef* matchedMethod = GetPropertyMethodDef(mPropDef, BfMethodType_PropertyGetter, mPropCheckedKind);
|
BfMethodDef* matchedMethod = GetPropertyMethodDef(mPropDef, BfMethodType_PropertyGetter, mPropCheckedKind);
|
||||||
if (matchedMethod == NULL)
|
if (matchedMethod == NULL)
|
||||||
|
@ -13806,6 +13836,7 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp
|
||||||
BF_ASSERT(!mResult.mType->IsRef());
|
BF_ASSERT(!mResult.mType->IsRef());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
mPropDef = NULL;
|
mPropDef = NULL;
|
||||||
mPropDefBypassVirtual = false;
|
mPropDefBypassVirtual = false;
|
||||||
mIndexerValues.clear();
|
mIndexerValues.clear();
|
||||||
|
@ -15838,6 +15869,10 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wantsChecks = checkedKind == BfCheckedKind_Checked;
|
||||||
|
if (checkedKind == BfCheckedKind_NotSet)
|
||||||
|
wantsChecks = mModule->GetDefaultCheckedKind() == BfCheckedKind_Checked;
|
||||||
|
|
||||||
//target.mType = mModule->ResolveGenericType(target.mType);
|
//target.mType = mModule->ResolveGenericType(target.mType);
|
||||||
if (target.mType->IsVar())
|
if (target.mType->IsVar())
|
||||||
{
|
{
|
||||||
|
@ -15914,7 +15949,7 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (mModule->HasCompiledOutput())
|
else if ((mModule->HasCompiledOutput()) && (wantsChecks))
|
||||||
{
|
{
|
||||||
if (checkedKind == BfCheckedKind_NotSet)
|
if (checkedKind == BfCheckedKind_NotSet)
|
||||||
checkedKind = mModule->GetDefaultCheckedKind();
|
checkedKind = mModule->GetDefaultCheckedKind();
|
||||||
|
|
|
@ -2495,18 +2495,10 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
|
||||||
errorString += StrFormat("\n while compiling project '%s'", mProject->mName.c_str());
|
errorString += StrFormat("\n while compiling project '%s'", mProject->mName.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mCurTypeInstance != NULL) && (mCurMethodState != NULL))
|
if (mCurTypeInstance != NULL)
|
||||||
{
|
{
|
||||||
auto checkMethodState = mCurMethodState;
|
auto _CheckMethodInstance = [&](BfMethodInstance* methodInstance)
|
||||||
while (checkMethodState != NULL)
|
|
||||||
{
|
{
|
||||||
auto methodInstance = checkMethodState->mMethodInstance;
|
|
||||||
if (methodInstance == NULL)
|
|
||||||
{
|
|
||||||
checkMethodState = checkMethodState->mPrevMethodState;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Propogatea the fail all the way to the main method (assuming we're in a local method or lambda)
|
// Propogatea the fail all the way to the main method (assuming we're in a local method or lambda)
|
||||||
methodInstance->mHasFailed = true;
|
methodInstance->mHasFailed = true;
|
||||||
|
|
||||||
|
@ -2516,7 +2508,7 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
|
||||||
//auto unspecializedMethod = &mCurMethodInstance->mMethodInstanceGroup->mMethodSpecializationMap.begin()->second;
|
//auto unspecializedMethod = &mCurMethodInstance->mMethodInstanceGroup->mMethodSpecializationMap.begin()->second;
|
||||||
auto unspecializedMethod = methodInstance->mMethodInstanceGroup->mDefault;
|
auto unspecializedMethod = methodInstance->mMethodInstanceGroup->mDefault;
|
||||||
if (unspecializedMethod->mHasFailed)
|
if (unspecializedMethod->mHasFailed)
|
||||||
return NULL; // At least SOME error has already been reported
|
return false; // At least SOME error has already been reported
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSpecializedMethod)
|
if (isSpecializedMethod)
|
||||||
|
@ -2536,8 +2528,30 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
|
||||||
errorString += StrFormat("\n while specializing type '%s'", TypeToString(mCurTypeInstance).c_str());
|
errorString += StrFormat("\n while specializing type '%s'", TypeToString(mCurTypeInstance).c_str());
|
||||||
isWhileSpecializing = true;
|
isWhileSpecializing = true;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mCurMethodState != NULL)
|
||||||
|
{
|
||||||
|
auto checkMethodState = mCurMethodState;
|
||||||
|
while (checkMethodState != NULL)
|
||||||
|
{
|
||||||
|
auto methodInstance = checkMethodState->mMethodInstance;
|
||||||
|
if (methodInstance == NULL)
|
||||||
|
{
|
||||||
checkMethodState = checkMethodState->mPrevMethodState;
|
checkMethodState = checkMethodState->mPrevMethodState;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_CheckMethodInstance(methodInstance))
|
||||||
|
return NULL;
|
||||||
|
checkMethodState = checkMethodState->mPrevMethodState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mCurMethodInstance != NULL)
|
||||||
|
{
|
||||||
|
if (!_CheckMethodInstance(mCurMethodInstance))
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep in mind that all method specializations with generic type instances as its method generic params
|
// Keep in mind that all method specializations with generic type instances as its method generic params
|
||||||
|
@ -2553,6 +2567,12 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((!isWhileSpecializing) && ((mCurTypeInstance->IsGenericTypeInstance()) && (!mCurTypeInstance->IsUnspecializedType())))
|
||||||
|
{
|
||||||
|
errorString += StrFormat("\n while specializing type '%s'", TypeToString(mCurTypeInstance).c_str());
|
||||||
|
isWhileSpecializing = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mHadBuildError)
|
if (!mHadBuildError)
|
||||||
mHadBuildError = true;
|
mHadBuildError = true;
|
||||||
|
|
||||||
|
@ -3028,6 +3048,8 @@ BfModuleOptions BfModule::GetModuleOptions()
|
||||||
|
|
||||||
BfCheckedKind BfModule::GetDefaultCheckedKind()
|
BfCheckedKind BfModule::GetDefaultCheckedKind()
|
||||||
{
|
{
|
||||||
|
if ((mCurMethodState != NULL) && (mCurMethodState->mDisableChecks))
|
||||||
|
return BfCheckedKind_Unchecked;
|
||||||
bool runtimeChecks = mCompiler->mOptions.mRuntimeChecks;
|
bool runtimeChecks = mCompiler->mOptions.mRuntimeChecks;
|
||||||
auto typeOptions = GetTypeOptions();
|
auto typeOptions = GetTypeOptions();
|
||||||
if (typeOptions != NULL)
|
if (typeOptions != NULL)
|
||||||
|
@ -16922,6 +16944,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
|
||||||
auto customAttributes = methodInstance->GetCustomAttributes();
|
auto customAttributes = methodInstance->GetCustomAttributes();
|
||||||
if ((customAttributes != NULL) && (customAttributes->Contains(mCompiler->mDisableObjectAccessChecksAttributeTypeDef)))
|
if ((customAttributes != NULL) && (customAttributes->Contains(mCompiler->mDisableObjectAccessChecksAttributeTypeDef)))
|
||||||
mCurMethodState->mIgnoreObjectAccessCheck = true;
|
mCurMethodState->mIgnoreObjectAccessCheck = true;
|
||||||
|
if ((customAttributes != NULL) && (customAttributes->Contains(mCompiler->mDisableChecksAttributeTypeDef)))
|
||||||
|
mCurMethodState->mDisableChecks = true;
|
||||||
|
|
||||||
if ((methodDef->mMethodType == BfMethodType_CtorNoBody) && (!methodDef->mIsStatic) &&
|
if ((methodDef->mMethodType == BfMethodType_CtorNoBody) && (!methodDef->mIsStatic) &&
|
||||||
((methodInstance->mChainType == BfMethodChainType_ChainHead) || (methodInstance->mChainType == BfMethodChainType_None)))
|
((methodInstance->mChainType == BfMethodChainType_ChainHead) || (methodInstance->mChainType == BfMethodChainType_None)))
|
||||||
|
|
|
@ -899,6 +899,7 @@ public:
|
||||||
int mBlockNestLevel; // 0 = top level
|
int mBlockNestLevel; // 0 = top level
|
||||||
bool mIsEmbedded; // Is an embedded statement (ie: if () stmt) not wrapped in a block
|
bool mIsEmbedded; // Is an embedded statement (ie: if () stmt) not wrapped in a block
|
||||||
bool mIgnoreObjectAccessCheck;
|
bool mIgnoreObjectAccessCheck;
|
||||||
|
bool mDisableChecks;
|
||||||
BfMixinState* mMixinState;
|
BfMixinState* mMixinState;
|
||||||
BfClosureState* mClosureState;
|
BfClosureState* mClosureState;
|
||||||
BfDeferredCallEmitState* mDeferredCallEmitState;
|
BfDeferredCallEmitState* mDeferredCallEmitState;
|
||||||
|
@ -910,6 +911,7 @@ public:
|
||||||
BfScopeData mHeadScope;
|
BfScopeData mHeadScope;
|
||||||
BfScopeData* mCurScope;
|
BfScopeData* mCurScope;
|
||||||
BfScopeData* mTailScope; // Usually equals mCurScope
|
BfScopeData* mTailScope; // Usually equals mCurScope
|
||||||
|
BfScopeData* mOverrideScope;
|
||||||
TempKind mTempKind; // Used for var inference, etc
|
TempKind mTempKind; // Used for var inference, etc
|
||||||
bool mInDeferredBlock;
|
bool mInDeferredBlock;
|
||||||
bool mHadReturn;
|
bool mHadReturn;
|
||||||
|
@ -942,6 +944,7 @@ public:
|
||||||
mHeadScope.mIsScopeHead = true;
|
mHeadScope.mIsScopeHead = true;
|
||||||
mCurScope = &mHeadScope;
|
mCurScope = &mHeadScope;
|
||||||
mTailScope = &mHeadScope;
|
mTailScope = &mHeadScope;
|
||||||
|
mOverrideScope = NULL;
|
||||||
mHadReturn = false;
|
mHadReturn = false;
|
||||||
mLeftBlockUncond = false;
|
mLeftBlockUncond = false;
|
||||||
mLeftBlockCond = false;
|
mLeftBlockCond = false;
|
||||||
|
@ -956,6 +959,7 @@ public:
|
||||||
mNoBind = false;
|
mNoBind = false;
|
||||||
mIsEmbedded = false;
|
mIsEmbedded = false;
|
||||||
mIgnoreObjectAccessCheck = false;
|
mIgnoreObjectAccessCheck = false;
|
||||||
|
mDisableChecks = false;
|
||||||
mInConditionalBlock = false;
|
mInConditionalBlock = false;
|
||||||
mAllowUinitReads = false;
|
mAllowUinitReads = false;
|
||||||
mCancelledDeferredCall = false;
|
mCancelledDeferredCall = false;
|
||||||
|
|
|
@ -4338,10 +4338,19 @@ BfTypeInstance* BfModule::GetWrappedStructType(BfType* type, bool allowSpecializ
|
||||||
{
|
{
|
||||||
if (allowSpecialized)
|
if (allowSpecialized)
|
||||||
{
|
{
|
||||||
|
if (type->IsUnknownSizedArray())
|
||||||
|
{
|
||||||
|
BfUnknownSizedArrayType* sizedArrayType = (BfUnknownSizedArrayType*)type;
|
||||||
|
BfTypeVector typeVector;
|
||||||
|
typeVector.Add(sizedArrayType->mElementType);
|
||||||
|
typeVector.Add(sizedArrayType->mElementCountSource);
|
||||||
|
return ResolveTypeDef(mCompiler->mSizedArrayTypeDef, typeVector, BfPopulateType_Data)->ToTypeInstance();
|
||||||
|
}
|
||||||
|
|
||||||
BfSizedArrayType* sizedArrayType = (BfSizedArrayType*)type;
|
BfSizedArrayType* sizedArrayType = (BfSizedArrayType*)type;
|
||||||
BfTypeVector typeVector;
|
BfTypeVector typeVector;
|
||||||
typeVector.Add(sizedArrayType->mElementType);
|
typeVector.Add(sizedArrayType->mElementType);
|
||||||
auto sizeValue = BfTypedValue(GetConstValue(sizedArrayType->mElementCount), GetPrimitiveType(BfTypeCode_IntPtr));
|
auto sizeValue = BfTypedValue(GetConstValue(BF_MAX(sizedArrayType->mElementCount, 0)), GetPrimitiveType(BfTypeCode_IntPtr));
|
||||||
typeVector.Add(CreateConstExprValueType(sizeValue));
|
typeVector.Add(CreateConstExprValueType(sizeValue));
|
||||||
return ResolveTypeDef(mCompiler->mSizedArrayTypeDef, typeVector, BfPopulateType_Data)->ToTypeInstance();
|
return ResolveTypeDef(mCompiler->mSizedArrayTypeDef, typeVector, BfPopulateType_Data)->ToTypeInstance();
|
||||||
}
|
}
|
||||||
|
@ -9038,7 +9047,12 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
|
||||||
{
|
{
|
||||||
BfScopeData* scopeData = NULL;
|
BfScopeData* scopeData = NULL;
|
||||||
if (mCurMethodState != NULL)
|
if (mCurMethodState != NULL)
|
||||||
|
{
|
||||||
|
if (mCurMethodState->mOverrideScope)
|
||||||
|
scopeData = mCurMethodState->mOverrideScope;
|
||||||
|
else
|
||||||
scopeData = mCurMethodState->mCurScope;
|
scopeData = mCurMethodState->mCurScope;
|
||||||
|
}
|
||||||
|
|
||||||
if ((castFlags & BfCastFlags_WarnOnBox) != 0)
|
if ((castFlags & BfCastFlags_WarnOnBox) != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2155,8 +2155,8 @@ public:
|
||||||
|
|
||||||
virtual bool IsDependentOnUnderlyingType() override { return true; }
|
virtual bool IsDependentOnUnderlyingType() override { return true; }
|
||||||
virtual BfType* GetUnderlyingType() override { return mElementType; }
|
virtual BfType* GetUnderlyingType() override { return mElementType; }
|
||||||
virtual bool IsUnspecializedType() override { return mElementType->IsUnspecializedType(); }
|
virtual bool IsUnspecializedType() override { return mElementType->IsUnspecializedType() || mElementCountSource->IsUnspecializedType(); }
|
||||||
virtual bool IsUnspecializedTypeVariation() override { return mElementType->IsUnspecializedTypeVariation(); }
|
virtual bool IsUnspecializedTypeVariation() override { return mElementType->IsUnspecializedTypeVariation() || mElementCountSource->IsUnspecializedTypeVariation(); }
|
||||||
virtual bool CanBeValuelessType() override { return true; }
|
virtual bool CanBeValuelessType() override { return true; }
|
||||||
// Leave the default "zero sized" definition
|
// Leave the default "zero sized" definition
|
||||||
//virtual bool IsValuelessType() override { return mElementType->IsValuelessType(); }
|
//virtual bool IsValuelessType() override { return mElementType->IsValuelessType(); }
|
||||||
|
|
|
@ -42,4 +42,24 @@ namespace Tests
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ConstGenerics
|
||||||
|
{
|
||||||
|
public static float GetSum<TCount>(float[TCount] vals) where TCount : const int
|
||||||
|
{
|
||||||
|
float total = 0;
|
||||||
|
for (int i < vals.Count)
|
||||||
|
total += vals[i];
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public static void TestBasics()
|
||||||
|
{
|
||||||
|
float[5] fVals = .(10, 20, 30, 40, 50);
|
||||||
|
|
||||||
|
float totals = GetSum(fVals);
|
||||||
|
Test.Assert(totals == 10+20+30+40+50);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue