From b640bf9d5e039005b0cd676039d63eac8ba26522 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 28 Nov 2019 09:11:54 -0800 Subject: [PATCH] Fixed deferred targeted boxing, DisableChecks, sized array generics --- IDEHelper/Compiler/BfCompiler.cpp | 2 + IDEHelper/Compiler/BfCompiler.h | 1 + IDEHelper/Compiler/BfExprEvaluator.cpp | 171 ++++++++++++++--------- IDEHelper/Compiler/BfModule.cpp | 56 +++++--- IDEHelper/Compiler/BfModule.h | 6 +- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 18 ++- IDEHelper/Compiler/BfResolvedTypeUtils.h | 4 +- IDEHelper/Tests/src/Generics.bf | 20 +++ 8 files changed, 189 insertions(+), 89 deletions(-) diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 01a92593..ceac2332 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -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"); diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index 95e794a0..92a96747 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -380,6 +380,7 @@ public: BfTypeDef* mCReprAttributeTypeDef; BfTypeDef* mAlignAttributeTypeDef; BfTypeDef* mNoDiscardAttributeTypeDef; + BfTypeDef* mDisableChecksAttributeTypeDef; BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef; BfTypeDef* mFriendAttributeTypeDef; BfTypeDef* mCheckedAttributeTypeDef; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 37a950f2..401f1e07 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -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(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 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 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 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(); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 7677005c..1d145d34 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -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))) diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index a525f3d5..5df4388f 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -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 mPrevIRBuilders; // Before extensions BfIRBuilder* mBfIRBuilder; - BfMethodState* mCurMethodState; + BfMethodState* mCurMethodState; BfAttributeState* mAttributeState; BfFilePosition mCurFilePosition; BfMethodInstance* mCurMethodInstance; diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 246b4747..0c34611f 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -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) { diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index c9ade3f9..59dd71de 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -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(); } diff --git a/IDEHelper/Tests/src/Generics.bf b/IDEHelper/Tests/src/Generics.bf index e9564c36..111e0438 100644 --- a/IDEHelper/Tests/src/Generics.bf +++ b/IDEHelper/Tests/src/Generics.bf @@ -42,4 +42,24 @@ namespace Tests } } + + class ConstGenerics + { + public static float GetSum(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); + } + } }