1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 03:28: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;
mAlignAttributeTypeDef = NULL;
mNoDiscardAttributeTypeDef = NULL;
mDisableChecksAttributeTypeDef = NULL;
mDisableObjectAccessChecksAttributeTypeDef = NULL;
mDbgRawAllocDataTypeDef = NULL;
mDeferredCallTypeDef = NULL;
@ -5835,6 +5836,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
mCReprAttributeTypeDef = _GetRequiredType("System.CReprAttribute");
mAlignAttributeTypeDef = _GetRequiredType("System.AlignAttribute");
mNoDiscardAttributeTypeDef = _GetRequiredType("System.NoDiscardAttribute");
mDisableChecksAttributeTypeDef = _GetRequiredType("System.DisableChecksAttribute");
mDisableObjectAccessChecksAttributeTypeDef = _GetRequiredType("System.DisableObjectAccessChecksAttribute");
mDbgRawAllocDataTypeDef = _GetRequiredType("System.DbgRawAllocData");
mDeferredCallTypeDef = _GetRequiredType("System.DeferredCall");

View file

@ -380,6 +380,7 @@ public:
BfTypeDef* mCReprAttributeTypeDef;
BfTypeDef* mAlignAttributeTypeDef;
BfTypeDef* mNoDiscardAttributeTypeDef;
BfTypeDef* mDisableChecksAttributeTypeDef;
BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef;
BfTypeDef* mFriendAttributeTypeDef;
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);
if ((caseValAddr) &&
@ -5171,8 +5171,13 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
}
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)
{
failed = true;
@ -7367,9 +7372,7 @@ void BfExprEvaluator::LookupQualifiedName(BfAstNode* nameNode, BfIdentifierNode*
prevDef = mPropDef;
prevTarget = mPropTarget;
}
}
/*if ((mResult) || (mPropDef != NULL))
break;*/
}
}
if (mPropDef != NULL)
@ -13738,72 +13741,100 @@ void BfExprEvaluator::CheckPropFail(BfMethodDef* propMethodDef, BfMethodInstance
BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericType)
{
if ((!mResult) && (mPropDef != NULL))
{
BfMethodDef* matchedMethod = GetPropertyMethodDef(mPropDef, BfMethodType_PropertyGetter, mPropCheckedKind);
if (matchedMethod == NULL)
{
bool handled = false;
if (mPropTarget.mType->IsGenericTypeInstance())
{
mModule->Fail("Property has no getter", mPropSrc);
return mResult;
}
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))
auto genericTypeInst = (BfGenericTypeInstance*)mPropTarget.mType;
if (genericTypeInst->mTypeDef == mModule->mCompiler->mSizedArrayTypeDef)
{
if (mPropDef->mName == "Count")
{
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);
else
mResult = CreateCall(methodInstance.mMethodInstance, methodInstance.mFunc, mPropDefBypassVirtual, args);
if (mResult.mType != NULL)
}
if (!handled)
{
BfMethodDef* matchedMethod = GetPropertyMethodDef(mPropDef, BfMethodType_PropertyGetter, mPropCheckedKind);
if (matchedMethod == NULL)
{
if ((mResult.mType->IsVar()) && (mModule->mCompiler->mIsResolveOnly))
mModule->Fail("Property type reference failed to resolve", mPropSrc);
BF_ASSERT(!mResult.mType->IsRef());
mModule->Fail("Property has no getter", mPropSrc);
return mResult;
}
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;
@ -15838,6 +15869,10 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
return;
}
bool wantsChecks = checkedKind == BfCheckedKind_Checked;
if (checkedKind == BfCheckedKind_NotSet)
wantsChecks = mModule->GetDefaultCheckedKind() == BfCheckedKind_Checked;
//target.mType = mModule->ResolveGenericType(target.mType);
if (target.mType->IsVar())
{
@ -15914,7 +15949,7 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr)
return;
}
}
else if (mModule->HasCompiledOutput())
else if ((mModule->HasCompiledOutput()) && (wantsChecks))
{
if (checkedKind == BfCheckedKind_NotSet)
checkedKind = mModule->GetDefaultCheckedKind();

View file

@ -816,7 +816,7 @@ BfModule::BfModule(BfContext* context, const StringImpl& moduleName)
mCompiler = context->mCompiler;
mSystem = mCompiler->mSystem;
mProject = NULL;
mCurMethodState = NULL;
mCurMethodState = NULL;
mAttributeState = NULL;
mCurLocalMethodId = 0;
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());
String errorString = error;
String errorString = error;
bool isWhileSpecializing = 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());
else if (mProject != NULL)
errorString += StrFormat("\n while compiling project '%s'", mProject->mName.c_str());
}
}
if ((mCurTypeInstance != NULL) && (mCurMethodState != NULL))
{
auto checkMethodState = mCurMethodState;
while (checkMethodState != NULL)
if (mCurTypeInstance != NULL)
{
auto _CheckMethodInstance = [&](BfMethodInstance* methodInstance)
{
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)
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 = methodInstance->mMethodInstanceGroup->mDefault;
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)
@ -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());
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
@ -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)
mHadBuildError = true;
@ -3028,6 +3048,8 @@ BfModuleOptions BfModule::GetModuleOptions()
BfCheckedKind BfModule::GetDefaultCheckedKind()
{
if ((mCurMethodState != NULL) && (mCurMethodState->mDisableChecks))
return BfCheckedKind_Unchecked;
bool runtimeChecks = mCompiler->mOptions.mRuntimeChecks;
auto typeOptions = GetTypeOptions();
if (typeOptions != NULL)
@ -16922,6 +16944,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
auto customAttributes = methodInstance->GetCustomAttributes();
if ((customAttributes != NULL) && (customAttributes->Contains(mCompiler->mDisableObjectAccessChecksAttributeTypeDef)))
mCurMethodState->mIgnoreObjectAccessCheck = true;
if ((customAttributes != NULL) && (customAttributes->Contains(mCompiler->mDisableChecksAttributeTypeDef)))
mCurMethodState->mDisableChecks = true;
if ((methodDef->mMethodType == BfMethodType_CtorNoBody) && (!methodDef->mIsStatic) &&
((methodInstance->mChainType == BfMethodChainType_ChainHead) || (methodInstance->mChainType == BfMethodChainType_None)))

View file

@ -899,6 +899,7 @@ public:
int mBlockNestLevel; // 0 = top level
bool mIsEmbedded; // Is an embedded statement (ie: if () stmt) not wrapped in a block
bool mIgnoreObjectAccessCheck;
bool mDisableChecks;
BfMixinState* mMixinState;
BfClosureState* mClosureState;
BfDeferredCallEmitState* mDeferredCallEmitState;
@ -910,6 +911,7 @@ public:
BfScopeData mHeadScope;
BfScopeData* mCurScope;
BfScopeData* mTailScope; // Usually equals mCurScope
BfScopeData* mOverrideScope;
TempKind mTempKind; // Used for var inference, etc
bool mInDeferredBlock;
bool mHadReturn;
@ -942,6 +944,7 @@ public:
mHeadScope.mIsScopeHead = true;
mCurScope = &mHeadScope;
mTailScope = &mHeadScope;
mOverrideScope = NULL;
mHadReturn = false;
mLeftBlockUncond = false;
mLeftBlockCond = false;
@ -956,6 +959,7 @@ public:
mNoBind = false;
mIsEmbedded = false;
mIgnoreObjectAccessCheck = false;
mDisableChecks = false;
mInConditionalBlock = false;
mAllowUinitReads = false;
mCancelledDeferredCall = false;
@ -1332,7 +1336,7 @@ public:
Array<BfIRBuilder*> mPrevIRBuilders; // Before extensions
BfIRBuilder* mBfIRBuilder;
BfMethodState* mCurMethodState;
BfMethodState* mCurMethodState;
BfAttributeState* mAttributeState;
BfFilePosition mCurFilePosition;
BfMethodInstance* mCurMethodInstance;

View file

@ -4338,10 +4338,19 @@ BfTypeInstance* BfModule::GetWrappedStructType(BfType* type, bool allowSpecializ
{
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;
BfTypeVector typeVector;
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));
return ResolveTypeDef(mCompiler->mSizedArrayTypeDef, typeVector, BfPopulateType_Data)->ToTypeInstance();
}
@ -9038,7 +9047,12 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
{
BfScopeData* scopeData = NULL;
if (mCurMethodState != NULL)
scopeData = mCurMethodState->mCurScope;
{
if (mCurMethodState->mOverrideScope)
scopeData = mCurMethodState->mOverrideScope;
else
scopeData = mCurMethodState->mCurScope;
}
if ((castFlags & BfCastFlags_WarnOnBox) != 0)
{

View file

@ -2155,8 +2155,8 @@ public:
virtual bool IsDependentOnUnderlyingType() override { return true; }
virtual BfType* GetUnderlyingType() override { return mElementType; }
virtual bool IsUnspecializedType() override { return mElementType->IsUnspecializedType(); }
virtual bool IsUnspecializedTypeVariation() override { return mElementType->IsUnspecializedTypeVariation(); }
virtual bool IsUnspecializedType() override { return mElementType->IsUnspecializedType() || mElementCountSource->IsUnspecializedType(); }
virtual bool IsUnspecializedTypeVariation() override { return mElementType->IsUnspecializedTypeVariation() || mElementCountSource->IsUnspecializedTypeVariation(); }
virtual bool CanBeValuelessType() override { return true; }
// Leave the default "zero sized" definition
//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);
}
}
}