From 5af6428bf474ccc479c29e76caaf566917d1c216 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 9 Oct 2019 16:16:01 -0700 Subject: [PATCH] Boxed struct ptr changes. --- BeefLibs/corlib/src/Pointer.bf | 21 +- BeefLibs/corlib/src/Reflection/MethodInfo.bf | 35 ++- BeefLibs/corlib/src/Type.bf | 16 ++ IDEHelper/Backend/BeIRCodeGen.cpp | 7 +- IDEHelper/Backend/BeModule.cpp | 18 +- IDEHelper/Backend/BeModule.h | 1 + IDEHelper/Compiler/BfAst.h | 6 - IDEHelper/Compiler/BfAutoComplete.cpp | 2 +- IDEHelper/Compiler/BfCompiler.cpp | 13 +- IDEHelper/Compiler/BfCompiler.h | 47 +-- IDEHelper/Compiler/BfContext.cpp | 11 +- IDEHelper/Compiler/BfIRBuilder.cpp | 15 +- IDEHelper/Compiler/BfMangler.cpp | 10 +- IDEHelper/Compiler/BfModule.cpp | 155 +++++++--- IDEHelper/Compiler/BfModule.h | 1 + IDEHelper/Compiler/BfModuleTypeUtils.cpp | 287 ++++++++++--------- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 45 +-- IDEHelper/Compiler/BfResolvedTypeUtils.h | 54 +++- IDEHelper/DebugManager.cpp | 72 +---- IDEHelper/Tests/src/Boxing.bf | 84 +++++- 20 files changed, 573 insertions(+), 327 deletions(-) diff --git a/BeefLibs/corlib/src/Pointer.bf b/BeefLibs/corlib/src/Pointer.bf index 6dda7f60..b799b376 100644 --- a/BeefLibs/corlib/src/Pointer.bf +++ b/BeefLibs/corlib/src/Pointer.bf @@ -1,12 +1,29 @@ namespace System { - struct Pointer + [AlwaysInclude] + struct Pointer : IHashable { + void* mVal; + public int GetHashCode() + { + return (int)mVal; + } + + [AlwaysInclude] + Object GetBoxed() + { + return new box this; + } } - struct Pointer + struct Pointer : IHashable { T* mVal; + + public int GetHashCode() + { + return (int)mVal; + } } } diff --git a/BeefLibs/corlib/src/Reflection/MethodInfo.bf b/BeefLibs/corlib/src/Reflection/MethodInfo.bf index 7f917dac..6de0d25b 100644 --- a/BeefLibs/corlib/src/Reflection/MethodInfo.bf +++ b/BeefLibs/corlib/src/Reflection/MethodInfo.bf @@ -154,26 +154,35 @@ namespace System.Reflection Type underlyingType = argType.UnderlyingType; if ((paramType.IsPrimitive) && (underlyingType.IsTypedPrimitive)) // Boxed primitive? underlyingType = underlyingType.UnderlyingType; - if (!underlyingType.IsSubtypeOf(paramType)) + + if (argType.IsBoxedStructPtr) { - if (underlyingType.IsGenericType) + dataPtr = *(void**)dataPtr; + handled = true; + } + else + { + if (!underlyingType.IsSubtypeOf(paramType)) { - var ptrTypedPrimitive = (SpecializedGenericType)underlyingType; - if ((ptrTypedPrimitive.mTypeFlags.HasFlag(.Sys_PointerT))) + if (underlyingType.IsGenericType) { - let elementType = Type.GetType(ptrTypedPrimitive.mResolvedTypeRefs[0]); - if (elementType == paramType) + var ptrTypedPrimitive = (SpecializedGenericType)underlyingType; + if ((ptrTypedPrimitive.mTypeFlags.HasFlag(.Sys_PointerT))) { - dataPtr = *(void**)dataPtr; - handled = true; + let elementType = Type.GetType(ptrTypedPrimitive.mResolvedTypeRefs[0]); + if (elementType == paramType) + { + dataPtr = *(void**)dataPtr; + handled = true; + } } } + + /*if (underlyingType.IsSpecialType(TypeInstance.[Friend]sPointerTType, "System", "Pointer", 2)) + { + + }*/ } - - /*if (underlyingType.IsSpecialType(TypeInstance.[Friend]sPointerTType, "System", "Pointer", 2)) - { - - }*/ } if (!handled) diff --git a/BeefLibs/corlib/src/Type.bf b/BeefLibs/corlib/src/Type.bf index 7a33868a..388df281 100644 --- a/BeefLibs/corlib/src/Type.bf +++ b/BeefLibs/corlib/src/Type.bf @@ -213,6 +213,14 @@ namespace System } } + public bool IsPointer + { + get + { + return (mTypeFlags & (TypeFlags.Boxed | TypeFlags.Pointer)) == TypeFlags.Pointer; + } + } + public bool IsBoxed { get @@ -221,6 +229,14 @@ namespace System } } + public bool IsBoxedStructPtr + { + get + { + return (mTypeFlags & (TypeFlags.Boxed | TypeFlags.Pointer)) == TypeFlags.Boxed | TypeFlags.Pointer; + } + } + public bool IsEnum { get diff --git a/IDEHelper/Backend/BeIRCodeGen.cpp b/IDEHelper/Backend/BeIRCodeGen.cpp index 796131ec..fc090bd6 100644 --- a/IDEHelper/Backend/BeIRCodeGen.cpp +++ b/IDEHelper/Backend/BeIRCodeGen.cpp @@ -1357,13 +1357,12 @@ void BeIRCodeGen::HandleNextCmd() { CMD_PARAM(BeValue*, val); CMD_PARAM(int, idx); + + BF_ASSERT(val->GetType()->IsComposite()); auto extractValueInst = mBeModule->AllocInst(); extractValueInst->mAggVal = val; - extractValueInst->mIdx = idx; - - BF_ASSERT(val->GetType()->IsComposite()); - + extractValueInst->mIdx = idx; SetResult(curId, extractValueInst); } break; diff --git a/IDEHelper/Backend/BeModule.cpp b/IDEHelper/Backend/BeModule.cpp index 437ea285..40e373fe 100644 --- a/IDEHelper/Backend/BeModule.cpp +++ b/IDEHelper/Backend/BeModule.cpp @@ -2394,6 +2394,20 @@ void BeModule::Print(BeFunction* func) OutputDebugStr(ToString(func)); } +void BeModule::PrintValue(BeValue* val) +{ + BeDumpContext dumpCtx; + dumpCtx.mModule = this; + String str; + dumpCtx.ToString(str, val); + str += "\n"; + OutputDebugStr(str); + + auto type = val->GetType(); + if (type != NULL) + bpt(type); +} + void BeModule::DoInlining(BeFunction* func) { //bool debugging = func->mName == "?Test@Program@bf@@CAXXZ"; @@ -3138,9 +3152,9 @@ BeGEPInst* BeModule::CreateGEP(BeValue* ptr, BeValue* idx0, BeValue* idx1) inst->mIdx0 = idx0; inst->mIdx1 = idx1; AddInst(inst); - - BF_ASSERT(ptr->GetType()->IsPointer()); + #ifdef _DEBUG + BF_ASSERT(ptr->GetType()->IsPointer()); inst->GetType(); #endif diff --git a/IDEHelper/Backend/BeModule.h b/IDEHelper/Backend/BeModule.h index 7638c2e4..5aa5f0f9 100644 --- a/IDEHelper/Backend/BeModule.h +++ b/IDEHelper/Backend/BeModule.h @@ -2109,6 +2109,7 @@ public: String ToString(BeFunction* func = NULL); void Print(); void Print(BeFunction* func); + void PrintValue(BeValue* val); void DoInlining(BeFunction* func); void DoInlining(); diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index b6e7af0f..d75755ef 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -2427,12 +2427,6 @@ public: BfTokenNode* mRefToken; }; BF_AST_DECL(BfRefTypeRef, BfElementedTypeRef); -class BfBoxedTypeRef : public BfElementedTypeRef -{ -public: - BF_AST_TYPE(BfBoxedTypeRef, BfElementedTypeRef); -}; BF_AST_DECL(BfBoxedTypeRef, BfElementedTypeRef); - class BfParamsExpression : public BfExpression { public: diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index 5be0678d..5f176c58 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -1394,7 +1394,7 @@ void BfAutoComplete::CheckIdentifier(BfIdentifierNode* identifierNode, bool isIn "delegate", "extern", "enum", "explicit", "extension", "function", "interface", "in", "internal", "mixin", "namespace", "new", "operator", "out", "override", "params", "private", "protected", "public", "readonly", "ref", "rettype", "return", - "sealed", "static", "struct", "this", "typealias", + "scope", "sealed", "static", "struct", "this", "typealias", "using", "virtual", "volatile", "T", "where" }; for (int i = 0; i < sizeof(tokens)/sizeof(char*); i++) diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index c437c0f6..206855f0 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -397,6 +397,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly) mInlineAttributeTypeDef = NULL; mInternalTypeDef = NULL; mIPrintableTypeDef = NULL; + mIHashableTypeDef = NULL; mLinkNameAttributeTypeDef = NULL; mMethodRefTypeDef = NULL; mNullableTypeDef = NULL; @@ -422,6 +423,9 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly) mTypeTypeDef = NULL; mUnboundAttributeTypeDef = NULL; mValueTypeTypeDef = NULL; + mObsoleteAttributeTypeDef = NULL; + mErrorAttributeTypeDef = NULL; + mWarnAttributeTypeDef = NULL; mLastAutocompleteModule = NULL; } @@ -4679,7 +4683,7 @@ void BfCompiler::PopulateReified() if (!unspecializedType->mIsReified) unspecializedType->mIsReified = true; } - + // Check reifications forced by virtuals or interfaces if ((!mIsResolveOnly) && (typeInst != NULL) && (typeInst->mIsReified) && (typeInst->IsObject()) && (!typeInst->IsUnspecializedType()) && (typeInst->mHasBeenInstantiated) && (!typeInst->IsIncomplete())) @@ -4826,6 +4830,9 @@ void BfCompiler::PopulateReified() void BfCompiler::HotCommit() { + if (mHotState == NULL) + return; + mHotState->mCommittedHotCompileIdx = mOptions.mHotCompileIdx; for (auto type : mContext->mResolvedTypes) @@ -5808,6 +5815,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) mInlineAttributeTypeDef = _GetRequiredType("System.InlineAttribute"); mInternalTypeDef = _GetRequiredType("System.Internal"); mIPrintableTypeDef = _GetRequiredType("System.IPrintable"); + mIHashableTypeDef = _GetRequiredType("System.IHashable"); mLinkNameAttributeTypeDef = _GetRequiredType("System.LinkNameAttribute"); mMethodRefTypeDef = _GetRequiredType("System.MethodReference", 1); mNullableTypeDef = _GetRequiredType("System.Nullable"); @@ -5834,6 +5842,9 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) mTypeTypeDef = _GetRequiredType("System.Type"); mUnboundAttributeTypeDef = _GetRequiredType("System.UnboundAttribute"); mValueTypeTypeDef = _GetRequiredType("System.ValueType"); + mObsoleteAttributeTypeDef = _GetRequiredType("System.ObsoleteAttribute"); + mErrorAttributeTypeDef = _GetRequiredType("System.ErrorAttribute"); + mWarnAttributeTypeDef = _GetRequiredType("System.WarnAttribute"); for (int i = 0; i < BfTypeCode_Length; i++) mContext->mPrimitiveStructTypes[i] = NULL; diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index cb3af9ea..c73a9ed7 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -325,33 +325,30 @@ public: BfTypeDef* mArray3TypeDef; BfTypeDef* mArray4TypeDef; BfTypeDef* mSpanTypeDef; - BfTypeDef* mAttributeTypeDef; - BfTypeDef* mAttributeUsageAttributeTypeDef; + BfTypeDef* mBfObjectTypeDef; BfTypeDef* mClassVDataTypeDef; - BfTypeDef* mCLinkAttributeTypeDef; - BfTypeDef* mCReprAttributeTypeDef; - BfTypeDef* mNoDiscardAttributeTypeDef; - BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef; + BfTypeDef* mDbgRawAllocDataTypeDef; BfTypeDef* mDeferredCallTypeDef; BfTypeDef* mDelegateTypeDef; BfTypeDef* mEnumTypeDef; - BfTypeDef* mFriendAttributeTypeDef; - BfTypeDef* mCheckedAttributeTypeDef; - BfTypeDef* mUncheckedAttributeTypeDef; + BfTypeDef* mStringTypeDef; + BfTypeDef* mTypeTypeDef; + BfTypeDef* mValueTypeTypeDef; BfTypeDef* mFunctionTypeDef; BfTypeDef* mGCTypeDef; BfTypeDef* mGenericIEnumerableTypeDef; BfTypeDef* mGenericIEnumeratorTypeDef; BfTypeDef* mGenericIRefEnumeratorTypeDef; - BfTypeDef* mInlineAttributeTypeDef; + BfTypeDef* mInternalTypeDef; BfTypeDef* mIPrintableTypeDef; - BfTypeDef* mLinkNameAttributeTypeDef; + BfTypeDef* mIHashableTypeDef; + BfTypeDef* mMethodRefTypeDef; BfTypeDef* mNullableTypeDef; - BfTypeDef* mOrderedAttributeTypeDef; + BfTypeDef* mPointerTTypeDef; BfTypeDef* mPointerTypeDef; BfTypeDef* mReflectArrayType; @@ -364,16 +361,30 @@ public: BfTypeDef* mReflectSpecializedGenericType; BfTypeDef* mReflectTypeInstanceTypeDef; BfTypeDef* mReflectUnspecializedGenericType; + BfTypeDef* mSizedArrayTypeDef; + BfTypeDef* mAttributeTypeDef; + BfTypeDef* mAttributeUsageAttributeTypeDef; + BfTypeDef* mLinkNameAttributeTypeDef; + BfTypeDef* mOrderedAttributeTypeDef; + BfTypeDef* mInlineAttributeTypeDef; + BfTypeDef* mCLinkAttributeTypeDef; + BfTypeDef* mCReprAttributeTypeDef; + BfTypeDef* mNoDiscardAttributeTypeDef; + BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef; + BfTypeDef* mFriendAttributeTypeDef; + BfTypeDef* mCheckedAttributeTypeDef; + BfTypeDef* mUncheckedAttributeTypeDef; BfTypeDef* mSkipAccessCheckAttributeTypeDef; BfTypeDef* mStaticInitAfterAttributeTypeDef; - BfTypeDef* mStaticInitPriorityAttributeTypeDef; - BfTypeDef* mStringTypeDef; + BfTypeDef* mStaticInitPriorityAttributeTypeDef; BfTypeDef* mTestAttributeTypeDef; - BfTypeDef* mThreadStaticAttributeTypeDef; - BfTypeDef* mTypeTypeDef; - BfTypeDef* mUnboundAttributeTypeDef; - BfTypeDef* mValueTypeTypeDef; + BfTypeDef* mThreadStaticAttributeTypeDef; + BfTypeDef* mUnboundAttributeTypeDef; + BfTypeDef* mObsoleteAttributeTypeDef; + BfTypeDef* mErrorAttributeTypeDef; + BfTypeDef* mWarnAttributeTypeDef; + int mCurTypeId; int mTypeInitCount; diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index bc6097a2..b7930839 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -88,6 +88,7 @@ BfContext::~BfContext() int numTypesDeleted = 0; for (auto type : mResolvedTypes) { + //_CrtCheckMemory(); delete type; } @@ -930,6 +931,11 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild typeInst->mIsSplattable = false; typeInst->mHasPackingHoles = false; typeInst->mWantsGCMarking = false; + if (typeInst->mTypeInfoEx != NULL) + { + delete typeInst->mTypeInfoEx; + typeInst->mTypeInfoEx = NULL; + } if (typeInst->IsGenericTypeInstance()) { @@ -2082,7 +2088,10 @@ void BfContext::GenerateModuleName_Type(BfType* type, String& name) if (type->IsBoxed()) { auto boxedType = (BfBoxedType*)type; - name += "BOX_"; + if (boxedType->IsBoxedStructPtr()) + name += "BOXPTR_"; + else + name += "BOX_"; GenerateModuleName_Type(boxedType->mElementType, name); return; } diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index c1024230..4d96dab4 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -1730,6 +1730,8 @@ String BfIRBuilder::GetDebugTypeName(BfTypeInstance* typeInstance, bool includeO { BfBoxedType* boxedType = (BfBoxedType*)typeInstance; typeName = mModule->TypeToString(boxedType->mElementType, (BfTypeNameFlags)(BfTypeNameFlag_ResolveGenericParamNames | BfTypeNameFlag_AddGlobalContainerName)); + if (boxedType->IsBoxedStructPtr()) + typeName += "*"; typeName = "Box<" + typeName + ">"; } else if (includeOuterTypeName) @@ -2547,7 +2549,7 @@ void BfIRBuilder::CreateDbgTypeDefinition(BfType* type) } else if (type->IsBoxed()) { - auto underlyingType = typeInstance->GetUnderlyingType(); + auto underlyingType = ((BfBoxedType*)type)->GetModifiedElementType(); if (!underlyingType->IsValuelessType()) { auto fieldInstance = &typeInstance->mFieldInstances.back(); @@ -2705,9 +2707,14 @@ void BfIRBuilder::CreateTypeDefinition(BfType* type, bool forceDefine) if (typeInstance->IsBoxed()) { auto boxedType = (BfBoxedType*)typeInstance; - if (!boxedType->mElementType->IsValuelessType()) - { - irFieldTypes.push_back(MapTypeInst(boxedType->mElementType, boxedType->mElementType->IsValueType() ? BfIRPopulateType_Eventually_Full : BfIRPopulateType_Declaration)); + BF_ASSERT(!boxedType->mFieldInstances.IsEmpty()); + + auto& fieldInst = boxedType->mFieldInstances.back(); + auto elementType = fieldInst.mResolvedType; + + if (!elementType->IsValuelessType()) + { + irFieldTypes.push_back(MapType(elementType, elementType->IsValueType() ? BfIRPopulateType_Eventually_Full : BfIRPopulateType_Declaration)); } } else diff --git a/IDEHelper/Compiler/BfMangler.cpp b/IDEHelper/Compiler/BfMangler.cpp index d3930382..2f1243ba 100644 --- a/IDEHelper/Compiler/BfMangler.cpp +++ b/IDEHelper/Compiler/BfMangler.cpp @@ -328,10 +328,10 @@ void BfGNUMangler::MangleTypeInst(MangleContext& mangleContext, StringImpl& name } else if (typeInst->IsBoxed()) { - auto boxedType = (BfBoxedType*)typeInst; + auto boxedType = (BfBoxedType*)typeInst; name += "N3BoxI"; - mangleContext.mSubstituteList.push_back(NameSubstitute(BfGNUMangler::NameSubstitute::Kind_None, NULL)); // Insert entry for 'Box' - Mangle(mangleContext, name, boxedType->mElementType, postfixTypeInstance); + mangleContext.mSubstituteList.push_back(NameSubstitute(BfGNUMangler::NameSubstitute::Kind_None, NULL)); // Insert entry for 'Box' + Mangle(mangleContext, name, boxedType->GetModifiedElementType(), postfixTypeInstance); name += "E"; mangleContext.mSubstituteList.push_back(NameSubstitute(BfGNUMangler::NameSubstitute::Kind_None, NULL)); // Insert entry for 'Box' if (isEndOpen != NULL) @@ -1154,11 +1154,11 @@ bool BfMSMangler::FindOrCreateNameSub(MangleContext& mangleContext, StringImpl& // name += '@'; } else if (newNameSub.mTypeInst->IsBoxed()) - { + { auto boxedType = (BfBoxedType*)newNameSub.mTypeInst; name += "?$Box@"; BfTypeVector typeVec; - typeVec.push_back(boxedType->mElementType); + typeVec.push_back(boxedType->GetModifiedElementType()); AddGenericArgs(mangleContext, name, typeVec); name += '@'; } diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 2cdc236d..2347d953 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -1130,7 +1130,7 @@ void BfModule::EnsureIRBuilder(bool dbgVerifyCodeGen) // code as we walk the AST //mBfIRBuilder->mDbgVerifyCodeGen = true; if ( - (mModuleName == "-") + (mModuleName == "Program") //|| (mModuleName == "System_Internal") //|| (mModuleName == "vdata") //|| (mModuleName == "Hey_Dude_Bro_TestClass") @@ -1583,6 +1583,17 @@ int BfModule::GetStringPoolIdx(BfIRValue constantStr, BfIRConstHolder* constHold return -1; } +String* BfModule::GetStringPoolString(BfIRValue constantStr, BfIRConstHolder * constHolder) +{ + int strId = GetStringPoolIdx(constantStr, constHolder); + if (strId != -1) + { + auto& entry = mContext->mStringObjectIdMap[strId]; + return &entry.mString; + } + return NULL; +} + BfIRValue BfModule::GetStringCharPtr(int stringId) { BfIRValue* irValue = NULL; @@ -4264,10 +4275,6 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin BfTypeInstance* typeInstance = type->ToTypeInstance(); -// BfType* typeInstanceType = ResolveTypeDef(mCompiler->mReflectTypeInstanceTypeDef, BfPopulateType_Identity); -// mBfIRBuilder->PopulateType(typeInstanceType, BfIRPopulateType_Full_ForceDefinition); -// PopulateType(typeInstanceType); - BfType* typeInstanceType = ResolveTypeDef(mCompiler->mReflectTypeInstanceTypeDef); mBfIRBuilder->PopulateType(typeInstanceType, BfIRPopulateType_Full_ForceDefinition); @@ -4379,7 +4386,11 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin if (type->IsStruct()) typeFlags |= BfTypeFlags_Struct; if (type->IsBoxed()) - typeFlags |= BfTypeFlags_Boxed; + { + typeFlags |= BfTypeFlags_Boxed; + if (((BfBoxedType*)type)->IsBoxedStructPtr()) + typeFlags |= BfTypeFlags_Pointer; + } if (type->IsPrimitiveType()) typeFlags |= BfTypeFlags_Primitive; if (type->IsTypedPrimitive()) @@ -4565,7 +4576,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin for (int i = 0; i < mCompiler->mMaxInterfaceSlots; i++) dynCastData.Add(0); dynCastData.Add(0); - + auto checkTypeInst = typeInstance; while (checkTypeInst != NULL) { @@ -4573,10 +4584,11 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin { if (interfaceEntry.mInterfaceType->mSlotNum >= 0) { - dynCastData[interfaceEntry.mInterfaceType->mSlotNum + 1] = interfaceEntry.mInterfaceType->mTypeId; + if (dynCastData[interfaceEntry.mInterfaceType->mSlotNum + 1] == 0) + dynCastData[interfaceEntry.mInterfaceType->mSlotNum + 1] = interfaceEntry.mInterfaceType->mTypeId; } } - checkTypeInst = checkTypeInst->mBaseType; + checkTypeInst = checkTypeInst->GetImplBaseType(); } if (mSystem->mPtrSize == 8) @@ -4633,6 +4645,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin Dictionary interfaceMap; auto checkTypeInst = typeInstance; + bool forceInterfaceSet = false; while (checkTypeInst != NULL) { for (auto&& interfaceEntry : checkTypeInst->mInterfaces) @@ -4648,6 +4661,11 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin auto prevEntry = matchEntry->mEntry; bool isBetter = TypeIsSubTypeOf(checkTypeInst, matchEntry->mEntrySource); bool isWorse = TypeIsSubTypeOf(matchEntry->mEntrySource, checkTypeInst); + if (forceInterfaceSet) + { + isBetter = true; + isWorse = false; + } if (isBetter == isWorse) CompareDeclTypes(interfaceEntry.mDeclaringType, prevEntry->mDeclaringType, isBetter, isWorse); if (isBetter == isWorse) @@ -4675,8 +4693,8 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin } } - checkTypeInst = checkTypeInst->mBaseType; - } + checkTypeInst = checkTypeInst->GetImplBaseType(); + } for (auto interfacePair : interfaceMap) { @@ -4701,7 +4719,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin while (checkTypeInst != NULL) { origVirtTypeStack.push_back(checkTypeInst); - checkTypeInst = checkTypeInst->mBaseType; + checkTypeInst = checkTypeInst->GetImplBaseType(); } Array origVTable; @@ -4860,14 +4878,6 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin makeEmpty = true; int endVirtualIdx = interfaceEntry->mStartVirtualIdx + interfaceEntry->mInterfaceType->mVirtualMethodTableSize; -// for (int methodIdx = 0; methodIdx < (int)interfaceEntry->mInterfaceType->mMethodInstanceGroups.size(); methodIdx++) -// { -// BfMethodInstance* ifaceMethodInstance = interfaceEntry->mInterfaceType->mMethodInstanceGroups[methodIdx].mDefault; -// if ((ifaceMethodInstance == NULL) || (ifaceMethodInstance->mVirtualTableIdx == -1)) -// continue; -// endVirtualIdx = BF_MAX(endVirtualIdx, interfaceEntry->mStartVirtualIdx + ifaceMethodInstance->mVirtualTableIdx); -// } - bool useExt = endVirtualIdx > ifaceMethodExtStart; for (int methodIdx = 0; methodIdx < (int)interfaceEntry->mInterfaceType->mMethodInstanceGroups.size(); methodIdx++) @@ -4893,8 +4903,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin { BF_ASSERT(methodInstance->mIsReified); // This doesn't work because we may have FOREIGN methods from implicit interface methods - //auto moduleMethodInst = GetMethodInstanceAtIdx(methodRef.mTypeInstance, methodRef.mMethodNum); - BfMethodInstance* methodInstance = methodRef; + //auto moduleMethodInst = GetMethodInstanceAtIdx(methodRef.mTypeInstance, methodRef.mMethodNum); auto moduleMethodInst = ReferenceExternalMethodInstance(methodInstance); auto funcPtr = mBfIRBuilder->CreateBitCast(moduleMethodInst.mFunc, voidPtrIRType); pushValue = funcPtr; @@ -4906,8 +4915,6 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin } int idx = interfaceEntry->mStartVirtualIdx + ifaceMethodInstance->mVirtualTableIdx; -// if (!useExt) -// vData[iFaceMethodStartIdx + idx] = pushValue; if (idx < ifaceMethodExtStart) { BF_ASSERT(iFaceMethodStartIdx + idx < (int)vData.size()); @@ -4922,7 +4929,46 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin ifaceMethodExtData[extIdx] = pushValue; } } - } + } + + if (typeInstance->IsBoxed()) + { + BfBoxedType* boxedType = (BfBoxedType*)typeInstance; + if (boxedType->IsBoxedStructPtr()) + { + // Force override of GetHashCode so we use the pointer address as the hash code + checkTypeInst = CreateBoxedType(ResolveTypeDef(mCompiler->mPointerTypeDef)); + + // Force override of GetHashCode so we use the pointer address as the hash code + for (auto& checkIFace : checkTypeInst->mInterfaces) + { + for (int methodIdx = 0; methodIdx < (int)checkIFace.mInterfaceType->mMethodInstanceGroups.size(); methodIdx++) + { + BfIRValue pushValue; + + BfMethodInstance* ifaceMethodInstance = checkIFace.mInterfaceType->mMethodInstanceGroups[methodIdx].mDefault; + if ((ifaceMethodInstance == NULL) || (ifaceMethodInstance->mVirtualTableIdx == -1)) + continue; + + if ((!ifaceMethodInstance->mIsReified) || (!ifaceMethodInstance->mMethodInstanceGroup->IsImplemented())) + continue; + + auto& methodRef = checkTypeInst->mInterfaceMethodTable[checkIFace.mStartInterfaceTableIdx + methodIdx].mMethodRef; + + auto methodInstance = (BfMethodInstance*)methodRef; + BF_ASSERT(methodInstance->mIsReified); + // This doesn't work because we may have FOREIGN methods from implicit interface methods + //auto moduleMethodInst = GetMethodInstanceAtIdx(methodRef.mTypeInstance, methodRef.mMethodNum); + auto moduleMethodInst = ReferenceExternalMethodInstance(methodInstance); + auto funcPtr = mBfIRBuilder->CreateBitCast(moduleMethodInst.mFunc, voidPtrIRType); + + int idx = checkIFace.mStartVirtualIdx + ifaceMethodInstance->mVirtualTableIdx; + vData[iFaceMethodStartIdx + idx] = funcPtr; + } + + } + } + } if ((needsVData) && (!typeInstance->mTypeDef->mIsStatic)) { @@ -6540,8 +6586,16 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS convCheckConstraint = ResolveGenericType(convCheckConstraint, *methodGenericArgs); BfTypeInstance* typeConstraintInst = convCheckConstraint->ToTypeInstance(); - - bool implementsInterface = CanImplicitlyCast(checkArgType, convCheckConstraint); + + bool implementsInterface = false; + if (origCheckArgType != checkArgType) + { + implementsInterface = CanImplicitlyCast(origCheckArgType, convCheckConstraint); + } + + if (!implementsInterface) + implementsInterface = CanImplicitlyCast(checkArgType, convCheckConstraint); + if ((!implementsInterface) && (origCheckArgType->IsWrappableType())) { BfTypeInstance* wrappedStructType = GetWrappedStructType(origCheckArgType, false); @@ -8228,23 +8282,40 @@ BfTypedValue BfModule::BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp return BfTypedValue(phi, resultType); } - if (fromStructTypeInstance == NULL) - { - auto primType = (BfPrimitiveType*) typedVal.mType; - fromStructTypeInstance = GetWrappedStructType(typedVal.mType); - } - if (fromStructTypeInstance == NULL) - return BfTypedValue(); + bool alreadyCheckedCast = false; + BfTypeInstance* toTypeInstance = NULL; if (toType != NULL) toTypeInstance = toType->ToTypeInstance(); - // Need to box it - bool isBoxedType = (fromStructTypeInstance != NULL) && (toType->IsBoxed()) && (CreateBoxedType(fromStructTypeInstance) == toType); + bool isStructPtr = typedVal.mType->IsStructPtr(); + if (fromStructTypeInstance == NULL) + { + auto primType = (BfPrimitiveType*)typedVal.mType; + fromStructTypeInstance = GetWrappedStructType(typedVal.mType); - if ((toType == NULL) || (toType == mContext->mBfObjectType) || (isBoxedType) || (TypeIsSubTypeOf(fromStructTypeInstance, toTypeInstance))) + if (isStructPtr) + { + if ((toTypeInstance != NULL) && (TypeIsSubTypeOf(fromStructTypeInstance, toTypeInstance))) + alreadyCheckedCast = true; + + fromStructTypeInstance = typedVal.mType->GetUnderlyingType()->ToTypeInstance(); + } + } + if (fromStructTypeInstance == NULL) + return BfTypedValue(); + + // Need to box it + auto boxedType = CreateBoxedType(typedVal.mType); + bool isBoxedType = (fromStructTypeInstance != NULL) && (toType->IsBoxed()) && (boxedType == toType); + + if ((toType == NULL) || (toType == mContext->mBfObjectType) || (isBoxedType) || (alreadyCheckedCast) || (TypeIsSubTypeOf(fromStructTypeInstance, toTypeInstance))) { - auto boxedType = CreateBoxedType(fromStructTypeInstance); + if (typedVal.mType->IsPointer()) + { + NOP; + } + mBfIRBuilder->PopulateType(boxedType); AddDependency(boxedType, mCurTypeInstance, BfDependencyMap::DependencyFlag_ReadFields); auto allocaInst = AllocFromType(boxedType, allocTarget, BfIRValue(), BfIRValue(), 0, callDtor ? BfAllocFlags_None : BfAllocFlags_NoDtorCall); @@ -8264,7 +8335,7 @@ BfTypedValue BfModule::BoxValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp typedVal = LoadValue(typedVal); auto valPtr = mBfIRBuilder->CreateInBoundsGEP(allocaInst, 0, 1); - if (typedVal.mType != fromStructTypeInstance) + if ((typedVal.mType != fromStructTypeInstance) && (!isStructPtr)) { auto ptrType = CreatePointerType(typedVal.mType); valPtr = mBfIRBuilder->CreateBitCast(valPtr, mBfIRBuilder->MapType(ptrType)); @@ -16573,6 +16644,12 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) { BfIRValue thisValue = mBfIRBuilder->CreateInBoundsGEP(mCurMethodState->mLocals[0]->mValue, 0, 1); BfTypedValue innerVal(thisValue, innerType, true); + if (boxedType->IsBoxedStructPtr()) + { + innerVal = LoadValue(innerVal); + innerVal = BfTypedValue(innerVal.mValue, innerType, true); + } + exprEvaluator.PushThis(NULL, innerVal, innerMethodInstance.mMethodInstance, innerParams); } diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 9bd99078..11531935 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1388,6 +1388,7 @@ public: BfIRValue CreateStringObjectValue(const StringImpl& str, int stringId, bool define); BfIRValue CreateStringCharPtr(const StringImpl& str, int stringId, bool define); int GetStringPoolIdx(BfIRValue constantStr, BfIRConstHolder* constHolder = NULL); + String* GetStringPoolString(BfIRValue constantStr, BfIRConstHolder* constHolder = NULL); BfIRValue GetStringCharPtr(int stringId); BfIRValue GetStringCharPtr(BfIRValue strValue); BfIRValue GetStringCharPtr(const StringImpl& str); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index e1f62544..542a8861 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -1749,11 +1749,6 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy if (baseType != NULL) defaultBaseTypeInst = baseType->ToTypeInstance(); - if (typeInstance->mTypeId == 260) - { - NOP; - } - BfTypeReference* baseTypeRef = NULL; if ((typeDef->mIsDelegate) && (!typeInstance->IsClosure())) { @@ -1901,7 +1896,19 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy } if (resolvedTypeRef->IsBoxed()) - { + { + if ((baseType != NULL) && (baseType->IsStruct())) + { + BfBoxedType* boxedType = (BfBoxedType*)resolvedTypeRef; + BfType* modifiedBaseType = baseType; + if (boxedType->IsBoxedStructPtr()) + modifiedBaseType = CreatePointerType(modifiedBaseType); + boxedType->mBoxedBaseType = CreateBoxedType(modifiedBaseType); + + PopulateType(boxedType->mBoxedBaseType); + AddDependency(boxedType->mBoxedBaseType, typeInstance, BfDependencyMap::DependencyFlag_DerivedFrom); + } + baseType = mContext->mBfObjectType; } @@ -2097,16 +2104,18 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy if (resolvedTypeRef->IsBoxed()) { BfBoxedType* boxedType = (BfBoxedType*)resolvedTypeRef; - BfTypeInstance* innerType = boxedType->mElementType->ToTypeInstance(); + BfType* innerType = boxedType->mElementType; + if (boxedType->IsBoxedStructPtr()) + innerType = CreatePointerType(innerType); if (innerType->IsIncomplete()) - PopulateType(innerType, BfPopulateType_Data); + PopulateType(innerType, BfPopulateType_Data); auto baseType = typeInstance->mBaseType; dataPos = baseType->mInstSize; - int alignSize = std::max(innerType->mInstAlign, baseType->mInstAlign); + int alignSize = BF_MAX(innerType->mAlign, baseType->mInstAlign); if (alignSize > 1) dataPos = (dataPos + (alignSize - 1)) & ~(alignSize - 1); - int dataSize = innerType->mInstSize; + int dataSize = innerType->mSize; typeInstance->mFieldInstances.push_back(BfFieldInstance()); BfFieldInstance* fieldInstance = &typeInstance->mFieldInstances.back(); @@ -2946,67 +2955,96 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy BfLogSysM("Setting underlying type %p %d\n", typeInstance, underlyingTypeDeferred); } - if (underlyingTypeDeferred) + if (typeInstance->IsEnum()) { int64 min = 0; - int64 max = 0; + int64 max = 0; + + bool isFirst = false; + + if (typeInstance->mTypeInfoEx == NULL) + typeInstance->mTypeInfoEx = new BfTypeInfoEx(); for (auto& fieldInstanceRef : typeInstance->mFieldInstances) { - auto fieldInstance = &fieldInstanceRef; + auto fieldInstance = &fieldInstanceRef; auto fieldDef = fieldInstance->GetFieldDef(); if ((fieldDef != NULL) && (fieldDef->IsEnumCaseEntry())) { + if (fieldInstance->mConstIdx == -1) + continue; + auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); - BF_ASSERT(constant->mTypeCode == BfTypeCode_Int64); + BF_ASSERT((constant->mTypeCode == BfTypeCode_Int64) || (!underlyingTypeDeferred)); - min = BF_MIN(constant->mInt64, min); - max = BF_MAX(constant->mInt64, max); - } - } - - BfTypeCode typeCode; - - if ((min >= -0x80) && (max <= 0x7F)) - typeCode = BfTypeCode_Int8; - else if ((min >= 0) && (max <= 0xFF)) - typeCode = BfTypeCode_UInt8; - else if ((min >= -0x8000) && (max <= 0x7FFF)) - typeCode = BfTypeCode_Int16; - else if ((min >= 0) && (max <= 0xFFFF)) - typeCode = BfTypeCode_UInt16; - else if ((min >= -0x80000000LL) && (max <= 0x7FFFFFFF)) - typeCode = BfTypeCode_Int32; - else if ((min >= 0) && (max <= 0xFFFFFFFFLL)) - typeCode = BfTypeCode_UInt32; - else - typeCode = BfTypeCode_Int64; - - if (typeCode != BfTypeCode_Int64) - { - for (auto& fieldInstanceRef : typeInstance->mFieldInstances) - { - auto fieldInstance = &fieldInstanceRef; - if (fieldInstance->mConstIdx != -1) + if (isFirst) { - auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); - BfIRValue newConstant = typeInstance->mConstHolder->CreateConst(typeCode, constant->mUInt64); - fieldInstance->mConstIdx = newConstant.mId; + min = constant->mInt64; + max = constant->mInt64; + isFirst = false; + } + else + { + min = BF_MIN(constant->mInt64, min); + max = BF_MAX(constant->mInt64, max); } } - } - - underlyingType = GetPrimitiveType(typeCode); - auto fieldInstance = &typeInstance->mFieldInstances.back(); - fieldInstance->mResolvedType = underlyingType; - fieldInstance->mDataSize = underlyingType->mSize; - - typeInstance->mSize = underlyingType->mSize; - typeInstance->mAlign = underlyingType->mAlign; - typeInstance->mInstSize = underlyingType->mSize; - typeInstance->mInstAlign = underlyingType->mAlign; + } - typeInstance->mRebuildFlags = (BfTypeRebuildFlags)(typeInstance->mRebuildFlags & ~BfTypeRebuildFlag_UnderlyingTypeDeferred); + typeInstance->mTypeInfoEx->mMinValue = min; + typeInstance->mTypeInfoEx->mMaxValue = max; + + if (underlyingTypeDeferred) + { + BfTypeCode typeCode; + + if ((min >= -0x80) && (max <= 0x7F)) + typeCode = BfTypeCode_Int8; + else if ((min >= 0) && (max <= 0xFF)) + typeCode = BfTypeCode_UInt8; + else if ((min >= -0x8000) && (max <= 0x7FFF)) + typeCode = BfTypeCode_Int16; + else if ((min >= 0) && (max <= 0xFFFF)) + typeCode = BfTypeCode_UInt16; + else if ((min >= -0x80000000LL) && (max <= 0x7FFFFFFF)) + typeCode = BfTypeCode_Int32; + else if ((min >= 0) && (max <= 0xFFFFFFFFLL)) + typeCode = BfTypeCode_UInt32; + else + typeCode = BfTypeCode_Int64; + + if (typeCode != BfTypeCode_Int64) + { + for (auto& fieldInstanceRef : typeInstance->mFieldInstances) + { + auto fieldInstance = &fieldInstanceRef; + if (fieldInstance->mConstIdx != -1) + { + auto constant = typeInstance->mConstHolder->GetConstantById(fieldInstance->mConstIdx); + BfIRValue newConstant = typeInstance->mConstHolder->CreateConst(typeCode, constant->mUInt64); + fieldInstance->mConstIdx = newConstant.mId; + } + } + } + + underlyingType = GetPrimitiveType(typeCode); + auto fieldInstance = &typeInstance->mFieldInstances.back(); + fieldInstance->mResolvedType = underlyingType; + fieldInstance->mDataSize = underlyingType->mSize; + + typeInstance->mTypeInfoEx->mUnderlyingType = underlyingType; + + typeInstance->mSize = underlyingType->mSize; + typeInstance->mAlign = underlyingType->mAlign; + typeInstance->mInstSize = underlyingType->mSize; + typeInstance->mInstAlign = underlyingType->mAlign; + + typeInstance->mRebuildFlags = (BfTypeRebuildFlags)(typeInstance->mRebuildFlags & ~BfTypeRebuildFlag_UnderlyingTypeDeferred); + } + } + else + { + BF_ASSERT(!underlyingTypeDeferred); } if ((typeInstance->IsPayloadEnum()) && (!typeInstance->IsBoxed())) @@ -3104,33 +3142,8 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy } } - //TODO: We moved this to much earlier in InitType - // This allows us to properly deleted a dependent generic type if a typeGenericArg gets deleted. - //... - // Add generic dependencies if needed -// auto genericTypeInstance = typeInstance->ToGenericTypeInstance(); -// if (genericTypeInstance != NULL) -// { -// for (auto genericType : genericTypeInstance->mTypeGenericArguments) -// { -// if (genericType->IsPrimitiveType()) -// genericType = GetWrappedStructType(genericType); -// if (genericType != NULL) -// { -// AddDependency(genericType, genericTypeInstance, BfDependencyMap::DependencyFlag_TypeGenericArg); -// BfLogSysM("Adding generic dependency of %p for type %p\n", genericTypeInstance, genericTypeInstance); -// } -// } -// -// if (typeInstance->IsSpecializedType()) -// { -// // This ensures we rebuild the unspecialized type whenever the specialized type rebuilds. This is important -// // for generic type binding -// auto unspecializedTypeInstance = GetUnspecializedTypeInstance(typeInstance); -// BF_ASSERT(!unspecializedTypeInstance->IsUnspecializedTypeVariation()); -// mContext->mScratchModule->AddDependency(typeInstance, unspecializedTypeInstance, BfDependencyMap::DependencyFlag_UnspecializedType); -// } -// } + if (typeInstance == mContext->mBfObjectType) + typeInstance->mHasBeenInstantiated = true; if (populateType == BfPopulateType_Data) return true; @@ -3181,25 +3194,25 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) } int newIntefaceStartIdx = 0; - auto baseType = typeInstance->mBaseType; - if (baseType != NULL) + auto implBaseType = typeInstance->GetImplBaseType(); + if (implBaseType != NULL) { - auto baseTypeInst = baseType->ToTypeInstance(); - if (baseType->IsIncomplete()) - PopulateType(baseType, BfPopulateType_Full_Force); + auto baseTypeInst = implBaseType->ToTypeInstance(); + if (implBaseType->IsIncomplete()) + PopulateType(implBaseType, BfPopulateType_Full_Force); typeInstance->mInterfaceMethodTable = baseTypeInst->mInterfaceMethodTable; - typeInstance->mVirtualMethodTable = baseType->mVirtualMethodTable; - typeInstance->mVirtualMethodTableSize = baseType->mVirtualMethodTableSize; + typeInstance->mVirtualMethodTable = implBaseType->mVirtualMethodTable; + typeInstance->mVirtualMethodTableSize = implBaseType->mVirtualMethodTableSize; if ((!mCompiler->IsHotCompile()) && (!mCompiler->mPassInstance->HasFailed()) && ((mCompiler->mResolvePassData == NULL) || (mCompiler->mResolvePassData->mAutoComplete == NULL))) - { + { BF_ASSERT(typeInstance->mVirtualMethodTable.size() == typeInstance->mVirtualMethodTableSize); } else { BF_ASSERT(typeInstance->mVirtualMethodTableSize >= (int)typeInstance->mVirtualMethodTable.size()); } - } + } // Add new interfaces for (int iFaceIdx = 0; iFaceIdx < (int)typeInstance->mInterfaces.size(); iFaceIdx++) @@ -3231,7 +3244,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) { AddDependency(interfaceEntry.mInterfaceType, typeInstance, BfDependencyMap::DependencyFlag_ImplementsInterface); } - checkTypeInstance = checkTypeInstance->mBaseType; + checkTypeInstance = checkTypeInstance->GetImplBaseType(); } //for (auto& intefaceInst : typeInstance->mInterfaces) @@ -3240,12 +3253,17 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) { BF_ASSERT(typeInstance->mInterfaceMethodTable.size() == 1); } + + if (typeInstance->mTypeDef == mCompiler->mPointerTypeDef) + { + NOP; + } // Slot interfaces method blocks in vtable { int ifaceVirtIdx = 0; std::unordered_map interfaceMap; - BfTypeInstance* checkType = typeInstance->mBaseType; + BfTypeInstance* checkType = typeInstance->GetImplBaseType(); while (checkType != NULL) { for (auto&& ifaceEntry : checkType->mInterfaces) @@ -3253,7 +3271,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) interfaceMap[ifaceEntry.mInterfaceType] = &ifaceEntry; ifaceVirtIdx = std::max(ifaceVirtIdx, ifaceEntry.mStartVirtualIdx + ifaceEntry.mInterfaceType->mVirtualMethodTableSize); } - checkType = checkType->mBaseType; + checkType = checkType->GetImplBaseType(); } for (int iFaceIdx = 0; iFaceIdx < (int)typeInstance->mInterfaces.size(); iFaceIdx++) @@ -3279,12 +3297,12 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) typeInstance->mNeedsMethodProcessing = false; typeInstance->mTypeIncomplete = false; - auto checkBaseType = typeInstance->mBaseType; + auto checkBaseType = typeInstance->GetImplBaseType(); while (checkBaseType != NULL) { PopulateType(checkBaseType, BfPopulateType_Full_Force); BF_ASSERT((!checkBaseType->IsIncomplete()) || (checkBaseType->mTypeFailed)); - checkBaseType = checkBaseType->mBaseType; + checkBaseType = checkBaseType->GetImplBaseType(); } if ((mCompiler->mOptions.mHasVDataExtender) && (!typeInstance->IsInterface())) @@ -3733,8 +3751,8 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) BF_ASSERT(mCompiler->mOptions.mHasVDataExtender); if (methodRef.mTypeInstance == typeInstance) { - if (typeInstance->mBaseType != NULL) - BF_ASSERT(methodIdx == (int)typeInstance->mBaseType->mVirtualMethodTableSize); + if (typeInstance->GetImplBaseType() != NULL) + BF_ASSERT(methodIdx == (int)typeInstance->GetImplBaseType()->mVirtualMethodTableSize); } continue; } @@ -3782,7 +3800,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) { // Attempt to find matching entries in base types ambiguityContext.mIsReslotting = true; - auto checkType = typeInstance->mBaseType; + auto checkType = typeInstance->GetImplBaseType(); while (checkType != NULL) { for (auto& methodGroup : checkType->mMethodInstanceGroups) @@ -3798,7 +3816,7 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance) } } } - checkType = checkType->mBaseType; + checkType = checkType->GetImplBaseType(); } } @@ -4626,8 +4644,10 @@ BfTypeInstance* BfModule::GetPrimitiveStructType(BfTypeCode typeCode) BfBoxedType* BfModule::CreateBoxedType(BfType* resolvedTypeRef) { - if (resolvedTypeRef->IsPointer()) - resolvedTypeRef = ((BfPointerType*)resolvedTypeRef)->mElementType; + bool isStructPtr = false; + +// if (resolvedTypeRef->IsPointer()) +// resolvedTypeRef = ((BfPointerType*)resolvedTypeRef)->mElementType; if (resolvedTypeRef->IsPrimitiveType()) { auto primType = (BfPrimitiveType*)resolvedTypeRef; @@ -4641,9 +4661,17 @@ BfBoxedType* BfModule::CreateBoxedType(BfType* resolvedTypeRef) else if (resolvedTypeRef->IsPointer()) { BfPointerType* pointerType = (BfPointerType*)resolvedTypeRef; - BfTypeVector typeVector; - typeVector.Add(pointerType->mElementType); - resolvedTypeRef = ResolveTypeDef(mCompiler->mPointerTTypeDef, typeVector, BfPopulateType_Data)->ToTypeInstance(); + if (pointerType->mElementType->IsStruct()) + { + resolvedTypeRef = pointerType->mElementType; + isStructPtr = true; + } + else + { + BfTypeVector typeVector; + typeVector.Add(pointerType->mElementType); + resolvedTypeRef = ResolveTypeDef(mCompiler->mPointerTTypeDef, typeVector, BfPopulateType_Data)->ToTypeInstance(); + } } else if (resolvedTypeRef->IsMethodRef()) { @@ -4670,6 +4698,7 @@ BfBoxedType* BfModule::CreateBoxedType(BfType* resolvedTypeRef) boxedType->mContext = mContext; boxedType->mElementType = typeInst; boxedType->mTypeDef = boxedType->mElementType->mTypeDef; + boxedType->mBoxedFlags = isStructPtr ? BfBoxedType::BoxedFlags_StructPtr : BfBoxedType::BoxedFlags_None; auto resolvedBoxedType = ResolveType(boxedType); if (resolvedBoxedType != boxedType) mContext->mBoxedTypePool.GiveBack(boxedType); @@ -6903,8 +6932,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula auto outerType = typeDef->mOuterType; BF_ASSERT(!outerType->mIsPartial); - if (TypeHasParent(mCurTypeInstance->mTypeDef, outerType)) - + if (TypeHasParent(mCurTypeInstance->mTypeDef, outerType)) { BfType* checkCurType = mCurTypeInstance; if (checkCurType->IsBoxed()) @@ -6974,25 +7002,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula BF_ASSERT(BfResolvedTypeSet::Hash(typeInst, &lookupCtx) == resolvedEntry->mHash); InitType(typeInst, populateType); return ResolveTypeResult(typeRef, typeInst, populateType, resolveFlags); - } - else if (auto boxedTypeRef = BfNodeDynCast(typeRef)) - { - BfBoxedType* boxedType = new BfBoxedType(); - auto innerType = ResolveTypeRef(boxedTypeRef->mElementType, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue); - if ((innerType == NULL) || (!innerType->IsStruct())) - { - Fail("Invalid box target", boxedTypeRef->mElementType); - delete boxedType; - mContext->mResolvedTypes.RemoveEntry(resolvedEntry); - return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags); - } - boxedType->mElementType = innerType->ToTypeInstance(); - boxedType->mTypeDef = boxedType->mElementType->mTypeDef; - resolvedEntry->mValue = boxedType; - BF_ASSERT(BfResolvedTypeSet::Hash(boxedType, &lookupCtx) == resolvedEntry->mHash); - InitType(boxedType, populateType); - return ResolveTypeResult(typeRef, boxedType, populateType, resolveFlags); - } + } else if (auto arrayTypeRef = BfNodeDynCast(typeRef)) { if (arrayTypeRef->mDimensions > 4) @@ -10019,7 +10029,7 @@ bool BfModule::TypeIsSubTypeOf(BfTypeInstance* srcType, BfTypeInstance* wantType } if (wantType->IsInterface()) - { + { BfTypeDef* checkActiveTypeDef = NULL; bool checkAccessibility = true; if (IsInSpecializedSection()) @@ -10059,13 +10069,24 @@ bool BfModule::TypeIsSubTypeOf(BfTypeInstance* srcType, BfTypeInstance* wantType return true; } } - checkType = checkType->mBaseType; + checkType = checkType->GetImplBaseType(); if ((checkType != NULL) && (checkType->mDefineState < BfTypeDefineState_HasInterfaces)) { PopulateType(checkType, BfPopulateType_Interfaces); } } + if (srcType->IsTypedPrimitive()) + { + BfType* underlyingType = srcType->GetUnderlyingType(); + if (underlyingType->IsWrappableType()) + { + BfTypeInstance* wrappedType = GetWrappedStructType(underlyingType); + if ((wrappedType != NULL) && (wrappedType != srcType)) + return TypeIsSubTypeOf(wrappedType, wantType, checkAccessibility); + } + } + return false; } @@ -10243,9 +10264,11 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF if (resolvedType->IsBoxed()) { - auto boxedeType = (BfBoxedType*)resolvedType; + auto boxedType = (BfBoxedType*)resolvedType; str += "boxed "; - DoTypeToString(str, boxedeType->mElementType, typeNameFlags, genericMethodNameOverrides); + DoTypeToString(str, boxedType->mElementType, typeNameFlags, genericMethodNameOverrides); + if (boxedType->mBoxedFlags == BfBoxedType::BoxedFlags_StructPtr) + str += "*"; return; } else if ((resolvedType->IsArray()) && ((typeNameFlags & BfTypeNameFlag_UseArrayImplType) == 0)) diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 69f84b0a..262c5d8d 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -1087,6 +1087,7 @@ BfMethodInstanceGroup::~BfMethodInstanceGroup() BfTypeInstance::~BfTypeInstance() { + delete mTypeInfoEx; delete mCustomAttributes; delete mAttributeData; for (auto methodInst : mInternalMethods) @@ -1622,17 +1623,25 @@ BfType* BfTypeInstance::GetUnderlyingType() if (!mIsTypedPrimitive) return NULL; + if (mTypeInfoEx == NULL) + mTypeInfoEx = new BfTypeInfoEx(); + if (mTypeInfoEx->mUnderlyingType != NULL) + return mTypeInfoEx->mUnderlyingType; + auto checkTypeInst = this; while (checkTypeInst != NULL) { if (!checkTypeInst->mFieldInstances.empty()) - return checkTypeInst->mFieldInstances.back().mResolvedType; + { + mTypeInfoEx->mUnderlyingType = checkTypeInst->mFieldInstances.back().mResolvedType; + return mTypeInfoEx->mUnderlyingType; + } checkTypeInst = checkTypeInst->mBaseType; if (checkTypeInst->IsIncomplete()) mModule->PopulateType(checkTypeInst, BfPopulateType_Data); } BF_FATAL("Failed"); - return NULL; + return mTypeInfoEx->mUnderlyingType; } bool BfTypeInstance::IsValuelessType() @@ -1857,6 +1866,15 @@ void BfTupleType::Finish() ////////////////////////////////////////////////////////////////////////// +BfType* BfBoxedType::GetModifiedElementType() +{ + if ((mBoxedFlags & BoxedFlags_StructPtr) != 0) + return mModule->CreatePointerType(mElementType); + return mElementType; +} + +////////////////////////////////////////////////////////////////////////// + int BfArrayType::GetLengthBitCount() { if (mBaseType == NULL) @@ -2460,12 +2478,7 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash int hashVal = ctx->mModule->mCompiler->mNullableTypeDef->mHash; hashVal = ((hashVal ^ (Hash(nullableType->mElementType, ctx))) << 5) - hashVal; return hashVal; - } - else if (auto boxedType = BfNodeDynCastExact(typeRef)) - { - int elemHash = Hash(boxedType->mElementType, ctx) ^ HASH_VAL_BOXED; - return (elemHash << 5) - elemHash; - } + } else if (auto refType = BfNodeDynCastExact(typeRef)) { if ((flags & BfHashFlag_AllowRef) != 0) @@ -2654,8 +2667,10 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx) { if (!rhs->IsBoxed()) return false; - BfBoxedType* lhsBoxedType = (BfBoxedType*) lhs; - BfBoxedType* rhsBoxedType = (BfBoxedType*) rhs; + BfBoxedType* lhsBoxedType = (BfBoxedType*)lhs; + BfBoxedType* rhsBoxedType = (BfBoxedType*)rhs; + if (lhsBoxedType->mBoxedFlags != rhsBoxedType->mBoxedFlags) + return false; return Equals(lhsBoxedType->mElementType, rhsBoxedType->mElementType, ctx); } else if (lhs->IsArray()) @@ -3050,11 +3065,7 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfTypeReference* rhs, LookupContext* if (lhs->IsBoxed()) { - auto rhsBoxedTypeRef = BfNodeDynCastExact(rhs); - if (rhsBoxedTypeRef == NULL) - return false; - BfBoxedType* lhsBoxedType = (BfBoxedType*) lhs; - return Equals(lhsBoxedType->mElementType, rhsBoxedTypeRef->mElementType, ctx); + return false; } else if (lhs->IsArray()) { @@ -3700,9 +3711,7 @@ String BfTypeUtils::TypeToString(BfTypeReference* typeRef) } if (auto ptrType = BfNodeDynCast(typeRef)) - return TypeToString(ptrType->mElementType) + "*"; - if (auto boxedType = BfNodeDynCast(typeRef)) - return "boxed " + TypeToString(boxedType->mElementType); + return TypeToString(ptrType->mElementType) + "*"; if (auto ptrType = BfNodeDynCast(typeRef)) { String name = TypeToString(ptrType->mElementType) + "["; diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 704106e0..65434704 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -450,6 +450,7 @@ public: virtual bool IsTypedPrimitive() { return false; } virtual bool IsComposite() { return IsStruct(); } virtual bool IsStruct() { return false; } + virtual bool IsStructPtr() { return false; } virtual bool IsUnion() { return false; } virtual bool IsStructOrStructPtr() { return false; } virtual bool IsObject() { return false; } @@ -494,6 +495,7 @@ public: virtual bool WantsGCMarking() { return false; } virtual BfTypeCode GetLoweredType() { return BfTypeCode_None; } virtual BfType* GetUnderlyingType() { return NULL; } + virtual bool HasWrappedRepresentation() { return IsWrappableType(); } virtual bool IsTypeMemberIncluded(BfTypeDef* declaringTypeDef, BfTypeDef* activeTypeDef = NULL, BfModule* module = NULL) { return true; } // May be 'false' only for generic extensions with constraints virtual bool IsTypeMemberAccessible(BfTypeDef* declaringTypeDef, BfTypeDef* activeTypeDef) { return true; } virtual bool IsTypeMemberAccessible(BfTypeDef* declaringTypeDef, BfProject* curProject) { return true; } @@ -1451,6 +1453,21 @@ public: Array mStaticTypes; }; +class BfTypeInfoEx +{ +public: + BfType* mUnderlyingType; + int64 mMinValue; + int64 mMaxValue; + + BfTypeInfoEx() + { + mUnderlyingType = NULL; + mMinValue = 0; + mMaxValue = 0; + } +}; + // Instance of struct or class class BfTypeInstance : public BfDependedType { @@ -1465,6 +1482,7 @@ public: BfTypeInstance* mBaseType; BfCustomAttributes* mCustomAttributes; BfAttributeData* mAttributeData; + BfTypeInfoEx* mTypeInfoEx; Array mInterfaces; Array mInterfaceMethodTable; @@ -1528,6 +1546,7 @@ public: mBaseType = NULL; mCustomAttributes = NULL; mAttributeData = NULL; + mTypeInfoEx = NULL; //mClassVData = NULL; mVirtualMethodTableSize = 0; mHotTypeData = NULL; @@ -1566,7 +1585,8 @@ public: virtual BfTypeInstance* ToTypeInstance() override { return this; } virtual bool IsDependentOnUnderlyingType() override { return true; } virtual BfPrimitiveType* ToPrimitiveType() override { return GetUnderlyingType()->ToPrimitiveType(); } - + virtual bool HasWrappedRepresentation() { return IsTypedPrimitive(); } + int GetEndingInstanceAlignment() { if (mInstSize % mInstAlign == 0) return mInstAlign; return mInstSize % mInstAlign; } virtual bool HasTypeFailed() override { return mTypeFailed; } virtual bool IsReified() override { return mIsReified; } @@ -1602,6 +1622,8 @@ public: virtual bool WantsGCMarking() override; virtual BfTypeCode GetLoweredType() override; + virtual BfTypeInstance* GetImplBaseType() { return mBaseType; } + virtual bool IsIRFuncUsed(BfIRFunction func); void CalcHotVirtualData(/*Val128& vtHash, */Array* ifaceMapping); @@ -1626,9 +1648,25 @@ public: class BfBoxedType : public BfTypeInstance { public: - BfTypeInstance* mElementType; + enum BoxedFlags + { + BoxedFlags_None = 0, + BoxedFlags_StructPtr = 1 + }; public: + BfTypeInstance* mElementType; + BfBoxedType* mBoxedBaseType; + BoxedFlags mBoxedFlags; + +public: + BfBoxedType() + { + mElementType = NULL; + mBoxedBaseType = NULL; + mBoxedFlags = BoxedFlags_None; + } + virtual bool IsBoxed() override { return true; } virtual bool IsValueType() override { return false; } @@ -1645,6 +1683,15 @@ public: virtual bool IsSpecializedType() override { return !mElementType->IsUnspecializedType(); } virtual bool IsUnspecializedType() override { return mElementType->IsUnspecializedType(); } virtual bool IsUnspecializedTypeVariation() override { return mElementType->IsUnspecializedTypeVariation(); } + + virtual BfTypeInstance* GetImplBaseType() { return (mBoxedBaseType != NULL) ? mBoxedBaseType : mBaseType; } + + bool IsBoxedStructPtr() + { + return (mBoxedFlags & BoxedFlags_StructPtr) != 0; + } + + BfType* GetModifiedElementType(); }; class BfGenericExtensionEntry @@ -1862,6 +1909,7 @@ public: virtual bool IsReified() { return mElementType->IsReified(); } virtual bool IsPointer() override { return true; } virtual bool IsIntPtrable() override { return true; } + virtual bool IsStructPtr() override { return mElementType->IsStruct(); } virtual bool IsStructOrStructPtr() override { return mElementType->IsStruct(); } virtual bool IsValueTypeOrValueTypePtr() override { return mElementType->IsValueType(); } virtual bool IsDependentOnUnderlyingType() override { return true; } @@ -2174,7 +2222,7 @@ public: } mCount++; - Entry* entry = new Entry(); + Entry* entry = (Entry*)BfResolvedTypeSetFuncs::Allocate(sizeof(Entry), alignof(Entry)); entry->mValue = NULL; // if (mHashHeads[bucket] != NULL) // mHashHeads[bucket]->mPrev = entry; diff --git a/IDEHelper/DebugManager.cpp b/IDEHelper/DebugManager.cpp index a352287b..e0f26671 100644 --- a/IDEHelper/DebugManager.cpp +++ b/IDEHelper/DebugManager.cpp @@ -582,25 +582,7 @@ BOOL WINAPI DllMain( DWORD dwReason, LPVOID lpreserved) { - //::MessageBoxA(NULL, "A", "B", MB_OK); - -// MemReporter memReporter; -// memReporter.mShowInKB = false; -// { -// memReporter.BeginSection("A"); -// { -// memReporter.BeginSection("B"); -// memReporter.Add(10); -// -// memReporter.Add("C", 1); -// memReporter.Add("D", 2); -// -// memReporter.EndSection(); -// } -// memReporter.EndSection(); -// } -// -// memReporter.Report(); + if (dwReason == DLL_PROCESS_ATTACH) { @@ -640,58 +622,10 @@ void WdAllocTest(); static _CrtMemState gStartMemCheckpoint; #endif BF_EXPORT void BF_CALLTYPE Debugger_Create() -{ - String outStr = BfDemangler::Demangle( - "??0?$_String_alloc@U?$_String_base_types@DV?$allocator@D@std@@@std@@@std@@QEAA@AEBV?$allocator@D@1@@Z" - //"?_Tidy@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAX_N_K@Z" - //"?gamma@Class1@@2PAY04NA" - //"?alpha@@3HA" - //"?Fis_i@myclass@@SAHH@Z" - //"??$?0AEBV?$allocator@D@std@@$$V@?$_Compressed_pair@U?$_Wrap_alloc@V?$allocator@D@std@@@std@@V?$_String_val@U?$_Simple_types@D@std@@@2@$00@std@@QEAA@U_One_then_variadic_args_t@1@AEBV?$allocator@D@1@@Z" - - //"??0?$map@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IU?$less@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@I@std@@@2@@std@@QEAA@XZ" - //"??4?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAAEAV01@PEBD@Z" - //"??0?$allocator@_W@std@@QEAA@XZ" - //"??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@XZ" - , DbgLanguage_C); - - /*{ - - struct TestStruct - { - TestStruct* mNext; - int mInt; - - TestStruct(int i) - { - mNext = NULL; - mInt = i; - } - }; - - TestStruct tsArr[5] = { 1, 2, 3, 4, 5 }; - SLIList sliList; - - sliList.PushBack(&tsArr[0]); - //sliList.PushBack(&tsArr[1]); - //sliList.PushBack(&tsArr[2]); - - auto itr = sliList.begin(); - auto* val = *itr; - //++itr; - //val = *itr; - //++itr; - //val = *itr; - sliList.erase(itr); - bool isEnd = itr == sliList.end(); - }*/ - - String str = StrFormat("%d:%@:%l@", 123, (intptr)0x1234567890LL, 0xABCDEF7890LL); - //String str = StrFormat("%l@", "Yo"); - +{ //TODO: Very slow, remove //_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF); - + //_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_EVERY_16_DF); //TODO: _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_EVERY_16_DF*/); //_CrtSetAllocHook(BfAllocHook); diff --git a/IDEHelper/Tests/src/Boxing.bf b/IDEHelper/Tests/src/Boxing.bf index 53141730..85cd548b 100644 --- a/IDEHelper/Tests/src/Boxing.bf +++ b/IDEHelper/Tests/src/Boxing.bf @@ -9,10 +9,9 @@ namespace Tests int Get() mut; } - struct Struct : IFace + struct StructA : IFace { public int mA = 100; - public int mB = 200; public int Get() mut { @@ -21,20 +20,87 @@ namespace Tests } } + struct StructB : StructA, IHashable + { + public int mB = 200; + + public int GetHashCode() + { + return mB; + } + } + + struct StructC : StructB + { + public int mC = 300; + } + + public static int GetFromIFace(mut T val) where T : IFace + { + return val.Get(); + } + [Test] public static void TestBasics() { - Struct val0 = .(); - Object obj0 = val0; + StructA valA = .(); + Object obj0 = valA; IFace iface0 = (IFace)obj0; + Test.Assert(GetFromIFace(mut valA) == 1100); Test.Assert(iface0.Get() == 1100); - Test.Assert(val0.mA == 100); // This should copy values + Test.Assert(GetFromIFace(iface0) == 2100); + Test.Assert(valA.mA == 1100); // This should copy values - /*Struct val1 = .(); - Object obj1 = (Object)(ref val1); - IFace iface1 = (IFace)obj1; + StructB valB = .(); + IFace iface1 = valB; + Test.Assert(GetFromIFace(mut valB) == 1100); Test.Assert(iface1.Get() == 1100); - Test.Assert(val1.mA == 1100); // This should reference values*/ + Test.Assert(GetFromIFace(iface1) == 2100); + Test.Assert(valB.mA == 1100); // This should copy values + } + + [Test] + public static void TestPtr() + { + StructA* valA = scope .(); + Object obj0 = valA; + IFace iface0 = (IFace)obj0; + Test.Assert(GetFromIFace(mut valA) == 1100); + Test.Assert(iface0.Get() == 2100); + Test.Assert(GetFromIFace(iface0) == 3100); + Test.Assert(valA.mA == 3100); // This should copy values + + StructB* valB = scope .(); + IFace iface1 = valB; + Test.Assert(GetFromIFace(mut valB) == 1100); + Test.Assert(iface1.Get() == 2100); + Test.Assert(GetFromIFace(iface1) == 3100); + Test.Assert(valB.mA == 3100); // This should copy values + } + + public static int GetHash(T val) where T : IHashable + { + return val.GetHashCode(); + } + + [Test] + public static void TestPtrHash() + { + StructA* valA = scope .(); + StructB* valB = scope .(); + StructC* valC = scope .(); + + IHashable ihA = valA; + IHashable ihB = valB; + IHashable ihC = valC; + + Test.Assert(ihA.GetHashCode() == (int)valA); + Test.Assert(ihB.GetHashCode() == (int)valB); + Test.Assert(ihC.GetHashCode() == (int)valC); + + Test.Assert(GetHash(ihA) == (int)valA); + Test.Assert(GetHash(ihB) == (int)valB); + Test.Assert(GetHash(ihC) == (int)valC); } } }