1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 04:22:20 +02:00

Fixed deferred targeted boxing, DisableChecks, sized array generics

This commit is contained in:
Brian Fiete 2019-11-28 09:11:54 -08:00
parent a94b52ff58
commit b640bf9d5e
8 changed files with 189 additions and 89 deletions

View file

@ -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");

View file

@ -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;

View file

@ -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) &&
@ -5171,8 +5171,13 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
} }
if ((argValue) && (arg != NULL)) if ((argValue) && (arg != NULL))
{ {
argValue = mModule->Cast(arg, argValue, wantType); //
{
SetAndRestoreValue<BfScopeData*> prevScopeData(mModule->mCurMethodState->mOverrideScope, boxScopeData);
argValue = mModule->Cast(arg, argValue, wantType);
}
if (!argValue) if (!argValue)
{ {
failed = true; failed = true;
@ -7367,9 +7372,7 @@ void BfExprEvaluator::LookupQualifiedName(BfAstNode* nameNode, BfIdentifierNode*
prevDef = mPropDef; prevDef = mPropDef;
prevTarget = mPropTarget; prevTarget = mPropTarget;
} }
} }
/*if ((mResult) || (mPropDef != NULL))
break;*/
} }
if (mPropDef != NULL) if (mPropDef != NULL)
@ -13738,72 +13741,100 @@ 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))
{ {
BfMethodDef* matchedMethod = GetPropertyMethodDef(mPropDef, BfMethodType_PropertyGetter, mPropCheckedKind); bool handled = false;
if (matchedMethod == NULL) if (mPropTarget.mType->IsGenericTypeInstance())
{ {
mModule->Fail("Property has no getter", mPropSrc); auto genericTypeInst = (BfGenericTypeInstance*)mPropTarget.mType;
return mResult; if (genericTypeInst->mTypeDef == mModule->mCompiler->mSizedArrayTypeDef)
} {
if (mPropDef->mName == "Count")
auto methodInstance = GetPropertyMethodInstance(matchedMethod);
if (methodInstance.mMethodInstance == NULL)
return mResult;
if (!mModule->mBfIRBuilder->mIgnoreWrites)
{
BF_ASSERT(!methodInstance.mFunc.IsFake());
}
if (mPropSrc != NULL)
mModule->UpdateExprSrcPos(mPropSrc);
CheckPropFail(matchedMethod, methodInstance.mMethodInstance);
PerformCallChecks(methodInstance.mMethodInstance, mPropSrc);
if (methodInstance.mMethodInstance->IsSkipCall())
{
mResult = mModule->GetDefaultTypedValue(methodInstance.mMethodInstance->mReturnType);
}
else
{
SizedArray<BfIRValue, 4> args;
if (!matchedMethod->mIsStatic)
{
if ((mPropDefBypassVirtual) && (mPropTarget.mType != methodInstance.mMethodInstance->GetOwner()))
mPropTarget = mModule->Cast(mPropSrc, mOrigPropTarget, methodInstance.mMethodInstance->GetOwner());
mModule->EmitObjectAccessCheck(mPropTarget);
PushThis(mPropSrc, mPropTarget, methodInstance.mMethodInstance, args);
}
bool failed = false;
for (int paramIdx = 0; paramIdx < (int)mIndexerValues.size(); paramIdx++)
{
auto val = mModule->Cast(mPropSrc, mIndexerValues[paramIdx].mTypedValue, methodInstance.mMethodInstance->GetParamType(paramIdx));
if (!val)
failed = true;
else
PushArg(val, args);
}
if (mPropDefBypassVirtual)
{
auto methodDef = methodInstance.mMethodInstance->mMethodDef;
if ((methodDef->mIsAbstract) && (mPropDefBypassVirtual))
{ {
mModule->Fail(StrFormat("Abstract base property method '%s' cannot be invoked", mModule->MethodToString(methodInstance.mMethodInstance).c_str()), mPropSrc); 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 (failed)
mResult = mModule->GetDefaultTypedValue(methodInstance.mMethodInstance->mReturnType); if (!handled)
else {
mResult = CreateCall(methodInstance.mMethodInstance, methodInstance.mFunc, mPropDefBypassVirtual, args); BfMethodDef* matchedMethod = GetPropertyMethodDef(mPropDef, BfMethodType_PropertyGetter, mPropCheckedKind);
if (mResult.mType != NULL) if (matchedMethod == NULL)
{ {
if ((mResult.mType->IsVar()) && (mModule->mCompiler->mIsResolveOnly)) mModule->Fail("Property has no getter", mPropSrc);
mModule->Fail("Property type reference failed to resolve", mPropSrc); return mResult;
BF_ASSERT(!mResult.mType->IsRef()); }
auto methodInstance = GetPropertyMethodInstance(matchedMethod);
if (methodInstance.mMethodInstance == NULL)
return mResult;
if (!mModule->mBfIRBuilder->mIgnoreWrites)
{
BF_ASSERT(!methodInstance.mFunc.IsFake());
}
if (mPropSrc != NULL)
mModule->UpdateExprSrcPos(mPropSrc);
CheckPropFail(matchedMethod, methodInstance.mMethodInstance);
PerformCallChecks(methodInstance.mMethodInstance, mPropSrc);
if (methodInstance.mMethodInstance->IsSkipCall())
{
mResult = mModule->GetDefaultTypedValue(methodInstance.mMethodInstance->mReturnType);
}
else
{
SizedArray<BfIRValue, 4> args;
if (!matchedMethod->mIsStatic)
{
if ((mPropDefBypassVirtual) && (mPropTarget.mType != methodInstance.mMethodInstance->GetOwner()))
mPropTarget = mModule->Cast(mPropSrc, mOrigPropTarget, methodInstance.mMethodInstance->GetOwner());
mModule->EmitObjectAccessCheck(mPropTarget);
PushThis(mPropSrc, mPropTarget, methodInstance.mMethodInstance, args);
}
bool failed = false;
for (int paramIdx = 0; paramIdx < (int)mIndexerValues.size(); paramIdx++)
{
auto val = mModule->Cast(mPropSrc, mIndexerValues[paramIdx].mTypedValue, methodInstance.mMethodInstance->GetParamType(paramIdx));
if (!val)
failed = true;
else
PushArg(val, args);
}
if (mPropDefBypassVirtual)
{
auto methodDef = methodInstance.mMethodInstance->mMethodDef;
if ((methodDef->mIsAbstract) && (mPropDefBypassVirtual))
{
mModule->Fail(StrFormat("Abstract base property method '%s' cannot be invoked", mModule->MethodToString(methodInstance.mMethodInstance).c_str()), mPropSrc);
}
}
if (failed)
mResult = mModule->GetDefaultTypedValue(methodInstance.mMethodInstance->mReturnType);
else
mResult = CreateCall(methodInstance.mMethodInstance, methodInstance.mFunc, mPropDefBypassVirtual, args);
if (mResult.mType != NULL)
{
if ((mResult.mType->IsVar()) && (mModule->mCompiler->mIsResolveOnly))
mModule->Fail("Property type reference failed to resolve", mPropSrc);
BF_ASSERT(!mResult.mType->IsRef());
}
} }
} }
mPropDef = NULL; mPropDef = NULL;
@ -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();

View file

@ -816,7 +816,7 @@ BfModule::BfModule(BfContext* context, const StringImpl& moduleName)
mCompiler = context->mCompiler; mCompiler = context->mCompiler;
mSystem = mCompiler->mSystem; mSystem = mCompiler->mSystem;
mProject = NULL; mProject = NULL;
mCurMethodState = NULL; mCurMethodState = NULL;
mAttributeState = NULL; mAttributeState = NULL;
mCurLocalMethodId = 0; mCurLocalMethodId = 0;
mParentNodeEntry = NULL; mParentNodeEntry = NULL;
@ -2479,7 +2479,7 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
BfLogSysM("BfModule::Fail module %p type %p %s\n", this, mCurTypeInstance, error.c_str()); BfLogSysM("BfModule::Fail module %p type %p %s\n", this, mCurTypeInstance, error.c_str());
String errorString = error; String errorString = error;
bool isWhileSpecializing = false; bool isWhileSpecializing = false;
bool isWhileSpecializingMethod = false; bool isWhileSpecializingMethod = false;
@ -2493,20 +2493,12 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
errorString += StrFormat("\n while compiling '%s'", TypeToString(mCurTypeInstance, BfTypeNameFlags_None).c_str()); errorString += StrFormat("\n while compiling '%s'", TypeToString(mCurTypeInstance, BfTypeNameFlags_None).c_str());
else if (mProject != NULL) else if (mProject != NULL)
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;
};
checkMethodState = checkMethodState->mPrevMethodState; if (mCurMethodState != NULL)
{
auto checkMethodState = mCurMethodState;
while (checkMethodState != NULL)
{
auto methodInstance = checkMethodState->mMethodInstance;
if (methodInstance == NULL)
{
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)))

View file

@ -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;
@ -1332,7 +1336,7 @@ public:
Array<BfIRBuilder*> mPrevIRBuilders; // Before extensions Array<BfIRBuilder*> mPrevIRBuilders; // Before extensions
BfIRBuilder* mBfIRBuilder; BfIRBuilder* mBfIRBuilder;
BfMethodState* mCurMethodState; BfMethodState* mCurMethodState;
BfAttributeState* mAttributeState; BfAttributeState* mAttributeState;
BfFilePosition mCurFilePosition; BfFilePosition mCurFilePosition;
BfMethodInstance* mCurMethodInstance; BfMethodInstance* mCurMethodInstance;

View file

@ -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)
scopeData = mCurMethodState->mCurScope; {
if (mCurMethodState->mOverrideScope)
scopeData = mCurMethodState->mOverrideScope;
else
scopeData = mCurMethodState->mCurScope;
}
if ((castFlags & BfCastFlags_WarnOnBox) != 0) if ((castFlags & BfCastFlags_WarnOnBox) != 0)
{ {

View file

@ -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(); }

View file

@ -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);
}
}
} }