diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index b4ec99ab..e57ab65f 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -1226,6 +1226,7 @@ void BfContext::PopulateHotTypeDataVTable(BfTypeInstance* typeInstance) hotTypeData->mVTableOrigLength = typeInstance->mVirtualMethodTableSize; hotTypeData->mOrigInterfaceMethodsLength = typeInstance->GetIFaceVMethodSize(); } + BfLogSysM("PopulateHotTypeDataVTable set %p HotDataType->mVTableOrigLength To %d\n", typeInstance, hotTypeData->mVTableOrigLength); } int vTableStart = -1; diff --git a/IDEHelper/Compiler/BfContext.h b/IDEHelper/Compiler/BfContext.h index 676b47f2..ea558fdf 100644 --- a/IDEHelper/Compiler/BfContext.h +++ b/IDEHelper/Compiler/BfContext.h @@ -109,6 +109,14 @@ public: class BfTypeState { +public: + enum ResolveKind + { + ResolveKind_None, + ResolveKind_BuildingGenericParams, + ResolveKind_ResolvingVarType + }; + public: BfTypeState* mPrevState; @@ -121,7 +129,7 @@ public: BfTypeReference* mCurAttributeTypeRef; BfFieldDef* mCurFieldDef; BfTypeDef* mCurTypeDef; - bool mBuildingGenericParams; + ResolveKind mResolveKind; public: BfTypeState() @@ -135,7 +143,7 @@ public: mCurFieldDef = NULL; mCurAttributeTypeRef = NULL; mCurTypeDef = NULL; - mBuildingGenericParams = false; + mResolveKind = ResolveKind_None; } BfTypeState(BfTypeInstance* typeInstance, BfTypeState* prevState = NULL) @@ -149,7 +157,7 @@ public: mCurFieldDef = NULL; mCurAttributeTypeRef = NULL; mCurTypeDef = NULL; - mBuildingGenericParams = false; + mResolveKind = ResolveKind_None; } }; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index ce658378..ecb559b6 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -1745,6 +1745,29 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe auto checkMethod = nextMethodDef; nextMethodDef = nextMethodDef->mNextWithSameName; + if (mModule->mContext->mResolvingVarField) + { + bool isResolvingVarField = false; + + auto checkTypeState = mModule->mContext->mCurTypeState; + while (checkTypeState != NULL) + { + if ((checkTypeState->mResolveKind == BfTypeState::ResolveKind_ResolvingVarType) && + (checkTypeState->mTypeInstance == typeInstance)) + isResolvingVarField = true; + checkTypeState = checkTypeState->mPrevState; + } + + if (isResolvingVarField) + { + // Don't even consider - we can't do method calls on ourselves when we are resolving var fields, because + // we are not allowed to generate methods when our field types are unknown. We may fix this in the future, + // but currently it breaks out expected order of operations. One issue is that our call signatures change + // depending on whether we are valueless or splattable, which depend on underlying type information + break; + } + } + if ((checkExtensionBase) && (curTypeInst == mModule->mCurTypeInstance)) { // Accept either a method in the same project but that's the root definition, OR a method that's in a dependent project @@ -5084,7 +5107,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu moduleMethodInstance.mFunc = mModule->mBfIRBuilder->CreateIntToPtr(target.mValue, funcPtrType); } else - { + { mModule->CheckStaticAccess(methodInstance->mMethodInstanceGroup->mOwner); if (target) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index b14d0493..6ccbc04d 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -3410,8 +3410,15 @@ BfType* BfModule::ResolveVarFieldType(BfTypeInstance* typeInstance, BfFieldInsta BfType* resolvedType = NULL; if (!hadInferenceCycle) - { - SetAndRestoreValue prevIgnoreWrite(mBfIRBuilder->mIgnoreWrites, true); + { + BfTypeState typeState; + typeState.mPrevState = mContext->mCurTypeState; + typeState.mTypeInstance = typeInstance; + typeState.mCurFieldDef = field; + typeState.mResolveKind = BfTypeState::ResolveKind_ResolvingVarType; + SetAndRestoreValue prevTypeState(mContext->mCurTypeState, &typeState); + + SetAndRestoreValue prevIgnoreWrite(mBfIRBuilder->mIgnoreWrites, true); SetAndRestoreValue prevMethodInstance(mCurMethodInstance, NULL/*ctorMethod.mMethodInstance*/); auto prevInsertBlock = mBfIRBuilder->GetInsertBlock(); @@ -3450,7 +3457,7 @@ BfType* BfModule::ResolveVarFieldType(BfTypeInstance* typeInstance, BfFieldInsta { } - else if (fieldInstance->mDataIdx <= 0) + else if (fieldInstance->mDataIdx >= 0) { } @@ -6030,6 +6037,10 @@ BfIRValue BfModule::FixClassVData(BfIRValue value) void BfModule::CheckStaticAccess(BfTypeInstance* typeInstance) { + // Note: this is not just for perf, it fixes a field var-type resolution issue + if (!mBfIRBuilder->mIgnoreWrites) + return; + PopulateType(typeInstance, BfPopulateType_DataAndMethods); //TODO: Create a hashset of these, we don't need to repeatedly call static ctors for a given type @@ -15034,7 +15045,10 @@ void BfModule::AddHotDataReferences(BfHotDataReferenceBuilder* builder) BF_ASSERT(mCurMethodInstance->mIsReified); if (mCurTypeInstance->mHotTypeData == NULL) + { mCurTypeInstance->mHotTypeData = new BfHotTypeData(); + BfLogSysM("Created HotTypeData %p created for type %p in AddHotDataReferences\n", mCurTypeInstance->mHotTypeData, mCurTypeInstance); + } auto hotMethod = mCurMethodInstance->mHotMethod; for (auto depData : hotMethod->mReferences) @@ -18653,7 +18667,8 @@ void BfModule::SetupIRFunction(BfMethodInstance* methodInstance, StringImpl& man if (isTemporaryFunc) { - BF_ASSERT((mCompiler->mIsResolveOnly) && (mCompiler->mResolvePassData->mAutoComplete != NULL)); + BF_ASSERT(((mCompiler->mIsResolveOnly) && (mCompiler->mResolvePassData->mAutoComplete != NULL)) || + (methodInstance->GetOwner()->mDefineState < BfTypeDefineState_Defined)); mangledName = "autocomplete_tmp"; } @@ -18870,6 +18885,9 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool { BP_ZONE("BfModule::BfMethodDeclaration"); + // If we are doing this then we may end up creating methods when var types are unknown still, failing on splat/zero-sized info + BF_ASSERT((!mContext->mResolvingVarField) || (mBfIRBuilder->mIgnoreWrites)); + // We could trigger a DoMethodDeclaration from a const resolver or other location, so we reset it here // to effectively make mIgnoreWrites method-scoped SetAndRestoreValue prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, mWantsIRIgnoreWrites || mCurMethodInstance->mIsUnspecialized); @@ -18882,6 +18900,12 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool mCurMethodInstance->mMethodInstanceGroup->mOnDemandKind = BfMethodOnDemandKind_Decl_AwaitingReference; bool ignoreWrites = mBfIRBuilder->mIgnoreWrites; + + if ((!isTemporaryFunc) && (mCurTypeInstance->mDefineState < BfTypeDefineState_Defined)) + { + BF_ASSERT(mContext->mResolvingVarField); + isTemporaryFunc = true; + } if (mAwaitingInitFinish) FinishInit(); @@ -19731,9 +19755,9 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool if (isTemporaryFunc) { // This handles temporary methods for autocomplete types - BF_ASSERT(mIsScratchModule); - BF_ASSERT(mCompiler->IsAutocomplete()); - BfLogSysM("DoMethodDeclaration autocomplete bailout\n"); + //BF_ASSERT(mIsScratchModule); + //BF_ASSERT(mCompiler->IsAutocomplete()); + BfLogSysM("DoMethodDeclaration isTemporaryFunc bailout\n"); return; // Bail out early for autocomplete pass } diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 5e918181..0aed0585 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -103,7 +103,7 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef) { BfTypeState typeState; typeState.mPrevState = mContext->mCurTypeState; - typeState.mBuildingGenericParams = true; + typeState.mResolveKind = BfTypeState::ResolveKind_BuildingGenericParams; SetAndRestoreValue prevTypeState(mContext->mCurTypeState, &typeState); BF_ASSERT(mCurMethodInstance == NULL); @@ -2886,7 +2886,10 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy if ((mCompiler->mOptions.mAllowHotSwapping) && (typeInstance->mDefineState < BfTypeDefineState_Defined)) { if (typeInstance->mHotTypeData == NULL) + { typeInstance->mHotTypeData = new BfHotTypeData(); + BfLogSysM("Created HotTypeData %p created for type %p in DoPopulateType\n", typeInstance->mHotTypeData, typeInstance); + } // Clear any unused versions (if we have errors, etc) if (mCompiler->mHotState != NULL) @@ -9817,7 +9820,7 @@ bool BfModule::TypeIsSubTypeOf(BfTypeInstance* srcType, BfTypeInstance* wantType // Otherwise "T where T : IB" declared in a lib won't be able to match a type B in a using project 'C', // because this check will see the lib using 'C', which it won't consider visible if ((checkActiveTypeDef != NULL) && - ((mCurMethodInstance != NULL) && (mContext->mCurTypeState != NULL) && (!mContext->mCurTypeState->mBuildingGenericParams))) + ((mCurMethodInstance != NULL) && (mContext->mCurTypeState != NULL) && (mContext->mCurTypeState->mResolveKind != BfTypeState::ResolveKind_BuildingGenericParams))) { if ((!srcType->IsTypeMemberAccessible(ifaceInst.mDeclaringType, checkActiveTypeDef)) || (!srcType->IsTypeMemberIncluded(ifaceInst.mDeclaringType, checkActiveTypeDef, this)))