diff --git a/BeefLibs/corlib/src/Attribute.bf b/BeefLibs/corlib/src/Attribute.bf index ad27c2c2..83765a96 100644 --- a/BeefLibs/corlib/src/Attribute.bf +++ b/BeefLibs/corlib/src/Attribute.bf @@ -372,7 +372,7 @@ namespace System [AttributeUsage(.Constructor)] public struct AllowAppendAttribute : Attribute { - + public bool ZeroGap; } [AttributeUsage(.Class | .Struct)] diff --git a/BeefLibs/corlib/src/IRefCounted.bf b/BeefLibs/corlib/src/IRefCounted.bf index f10b3528..04f61494 100644 --- a/BeefLibs/corlib/src/IRefCounted.bf +++ b/BeefLibs/corlib/src/IRefCounted.bf @@ -1,5 +1,6 @@ using System.Threading; using System.Diagnostics; +using System.Collections; namespace System { @@ -105,6 +106,8 @@ namespace System { String emitStr = scope .(); + HashSet foundSigs = scope .(); + for (var methodInfo in typeof(T).GetMethods(.Public | .DeclaredOnly)) { if (methodInfo.IsStatic) @@ -112,11 +115,15 @@ namespace System if (!methodInfo.IsConstructor) continue; + var sig = methodInfo.GetMethodSig(.. new .()); + if (!foundSigs.Add(sig)) + continue; + emitStr.AppendF("public static RefCounted Create("); methodInfo.GetParamsDecl(emitStr); emitStr.AppendF(")\n"); emitStr.AppendF("{{\n"); - emitStr.AppendF("\treturn new [Friend] RefCountedAppend("); + emitStr.AppendF("\treturn new [Friend]RefCountedAppend("); methodInfo.GetArgsList(emitStr); emitStr.AppendF(");\n}}\n"); } @@ -207,7 +214,16 @@ namespace System if (!methodInfo.IsConstructor) continue; - emitStr.AppendF("[AllowAppend]\nprotected this("); + if (methodInfo.AllowAppendKind == .Yes) + emitStr.AppendF("[AllowAppend]\n"); + if (methodInfo.AllowAppendKind == .ZeroGap) + emitStr.AppendF("[AllowAppend(ZeroGap=true)]\n"); + if (methodInfo.CheckedKind == .Checked) + emitStr.AppendF("[Checked]\n"); + if (methodInfo.CheckedKind == .Unchecked) + emitStr.AppendF("[Unchecked]\n"); + + emitStr.AppendF("protected this("); methodInfo.GetParamsDecl(emitStr); emitStr.AppendF(")\n"); emitStr.AppendF("{{\n"); diff --git a/BeefLibs/corlib/src/Reflection/FieldInfo.bf b/BeefLibs/corlib/src/Reflection/FieldInfo.bf index af144a43..6de95362 100644 --- a/BeefLibs/corlib/src/Reflection/FieldInfo.bf +++ b/BeefLibs/corlib/src/Reflection/FieldInfo.bf @@ -530,11 +530,8 @@ namespace System.Reflection } } - public Result GetValueReference(Object target) + Result DoGetValueReference(Object target) { - if (FieldType != typeof(T)) - return .Err; - void* targetDataAddr; if (target == null) { @@ -556,6 +553,21 @@ namespace System.Reflection } } + public Result GetValueReference(Object target) + { + if (FieldType != typeof(T)) + return .Err; + return DoGetValueReference(target); + } + + public Result GetValue(Object target) + { + if ((FieldType != typeof(T)) && (!FieldType.IsSubtypeOf(typeof(T)))) + return .Err; + T* result = Try!(DoGetValueReference(target)); + return *result; + } + public Result GetValueReference(Object target) { void* targetDataAddr; diff --git a/BeefLibs/corlib/src/Reflection/MethodInfo.bf b/BeefLibs/corlib/src/Reflection/MethodInfo.bf index d9db4b02..6047bc9e 100644 --- a/BeefLibs/corlib/src/Reflection/MethodInfo.bf +++ b/BeefLibs/corlib/src/Reflection/MethodInfo.bf @@ -82,6 +82,13 @@ namespace System.Reflection Name == "~this" : mData.mMethodData.mName === "~this"; + public AllowAppendKind AllowAppendKind => Compiler.IsComptime ? + Type.[Friend]Comptime_Method_GetInfo(mData.mComptimeMethodInstance).mMethodFlags.AllowAppendKind : + mData.mMethodData.[Friend]mFlags.AllowAppendKind; + public CheckedKind CheckedKind => Compiler.IsComptime ? + Type.[Friend]Comptime_Method_GetInfo(mData.mComptimeMethodInstance).mMethodFlags.CheckedKind : + mData.mMethodData.[Friend]mFlags.CheckedKind; + public Type ReturnType => Compiler.IsComptime ? Type.[Friend]GetType((.)Type.[Friend]Comptime_Method_GetInfo(mData.mComptimeMethodInstance).mReturnTypeId) : Type.[Friend]GetType(mData.mMethodData.mReturnType); diff --git a/BeefLibs/corlib/src/String.bf b/BeefLibs/corlib/src/String.bf index 173c7cd7..e4e56d5d 100644 --- a/BeefLibs/corlib/src/String.bf +++ b/BeefLibs/corlib/src/String.bf @@ -74,42 +74,86 @@ namespace System const uint32 cStrPtrFlag = 0x40000000; #endif - [AllowAppend] + [AllowAppend(ZeroGap=true)] public this(int count) // 0 { int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn char8* addlPtr = append char8[bufferSize]*(?); - Init(bufferSize); mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); mLength = 0; } [AllowAppend] + public this(int count) // 0 + { + int bufferSize = count; +#unwarn + char8* addlPtr = append char8[bufferSize]*(?); + mPtrOrBuffer = addlPtr; + mAllocSizeAndFlags = (uint_strsize)bufferSize | cStrPtrFlag; + mLength = 0; + } + + [AllowAppend(ZeroGap=true)] public this() { let bufferSize = 16 - sizeof(char8*); #unwarn char8* addlPtr = append char8[bufferSize]*(?); - Init(bufferSize); mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); mLength = 0; } [AllowAppend] + public this() + { + let bufferSize = 8; +#unwarn + char8* addlPtr = append char8[bufferSize]*(?); + mPtrOrBuffer = addlPtr; + mAllocSizeAndFlags = (uint_strsize)bufferSize | cStrPtrFlag; + mLength = 0; + } + + [AllowAppend(ZeroGap=true)] public this(String str) { let count = str.mLength; + /*int a = __appendIdx; + int b = offsetof(String, mPtrOrBuffer); + if (__appendIdx == offsetof(String, mPtrOrBuffer)) + { + + }*/ int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn char8* addlPtr = append char8[bufferSize]*(?); - Init(bufferSize); Internal.MemCpy(Ptr, str.Ptr, count); mLength = count; mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); } [AllowAppend] + public this(String str) + { + let count = str.mLength; + /*int a = __appendIdx; + int b = offsetof(String, mPtrOrBuffer); + if (__appendIdx == offsetof(String, mPtrOrBuffer)) + { + + }*/ + int bufferSize = count; +#unwarn + char8* addlPtr = append char8[bufferSize]*(?); + mPtrOrBuffer = addlPtr; + Internal.MemCpy(Ptr, str.Ptr, count); + mLength = count; + mAllocSizeAndFlags = (uint_strsize)bufferSize | cStrPtrFlag; + } + + [AllowAppend(ZeroGap=true)] public this(String str, int offset) { Debug.Assert((uint)offset <= (uint)str.Length); @@ -126,7 +170,7 @@ namespace System mLength = (int_strsize)count; } - [AllowAppend] + [AllowAppend(ZeroGap=true)] public this(String str, int offset, int count) { Debug.Assert((uint)offset <= (uint)str.Length); @@ -144,7 +188,7 @@ namespace System mLength = (int_strsize)count; } - [AllowAppend] + [AllowAppend(ZeroGap=true)] public this(char8 c, int count) { int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); @@ -158,7 +202,7 @@ namespace System mLength = (int_strsize)count; } - [AllowAppend] + [AllowAppend(ZeroGap=true)] public this(char8* char8Ptr) { let count = Internal.CStrLen(char8Ptr); @@ -173,7 +217,7 @@ namespace System mLength = count; } - [AllowAppend] + [AllowAppend(ZeroGap=true)] public this(char8* char8Ptr, int count) { int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); @@ -187,7 +231,7 @@ namespace System mLength = (int_strsize)count; } - [AllowAppend] + [AllowAppend(ZeroGap=true)] public this(char16* char16Ptr) { let count = UTF16.GetLengthAsUTF8(char16Ptr); @@ -200,7 +244,7 @@ namespace System UTF16.Decode(char16Ptr, this); } - [AllowAppend] + [AllowAppend(ZeroGap=true)] public this(Span chars) { let count = UTF16.GetLengthAsUTF8(chars); @@ -213,14 +257,13 @@ namespace System UTF16.Decode(chars, this); } - [AllowAppend] + [AllowAppend(ZeroGap=true)] public this(StringView strView) { let count = strView.Length; int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); #unwarn char8* addlPtr = append char8[bufferSize]*(?); - Init(bufferSize); let ptr = Ptr; Internal.MemCpy(ptr, strView.Ptr, strView.Length); mAllocSizeAndFlags = (uint_strsize)bufferSize + (int_strsize)sizeof(char8*); @@ -228,6 +271,20 @@ namespace System } [AllowAppend] + public this(StringView strView) + { + let count = strView.Length; + int bufferSize = count; +#unwarn + char8* addlPtr = append char8[bufferSize]*(?); + mPtrOrBuffer = addlPtr; + let ptr = Ptr; + Internal.MemCpy(ptr, strView.Ptr, strView.Length); + mAllocSizeAndFlags = (uint_strsize)bufferSize | cStrPtrFlag; + mLength = (int_strsize)strView.Length; + } + + [AllowAppend(ZeroGap=true)] public this(StringView strView, CreateFlags flags) { let count = strView.Length + (flags.HasFlag(.NullTerminate) ? 1 : 0); @@ -243,7 +300,7 @@ namespace System mLength = (int32)strView.Length; } - [AllowAppend] + [AllowAppend(ZeroGap=true)] public this(StringView strView, int offset) { Debug.Assert((uint)offset <= (uint)strView.Length); @@ -261,7 +318,7 @@ namespace System mLength = (int_strsize)count; } - [AllowAppend] + [AllowAppend(ZeroGap=true)] public this(StringView strView, int offset, int count) { Debug.Assert((uint)offset <= (uint)strView.Length); @@ -279,7 +336,7 @@ namespace System mLength = (int_strsize)count; } - [AllowAppend] + [AllowAppend(ZeroGap=true)] public this(char8[] chars, int offset, int count) { int bufferSize = (count == 0) ? 0 : (count - 1) & ~(sizeof(char8*) - 1); @@ -670,7 +727,7 @@ namespace System public static implicit operator Span(String str) { if (str == null) - return .(null, 0); + return .((char8*)null, 0); return .(str.Ptr, str.Length); } diff --git a/BeefLibs/corlib/src/Type.bf b/BeefLibs/corlib/src/Type.bf index ac70f5e9..4f724970 100644 --- a/BeefLibs/corlib/src/Type.bf +++ b/BeefLibs/corlib/src/Type.bf @@ -1742,9 +1742,9 @@ namespace System.Reflection Appended = 0x1000, } - public enum MethodFlags : uint16 + public enum MethodFlags : uint32 { - MethodAccessMask = 0x0007, + case MethodAccessMask = 0x0007, Protected = 0x0003, Public = 0x0006, @@ -1762,5 +1762,26 @@ namespace System.Reflection ThisCall = 0x3000, // Purposely resuing StdCall|FastCall Mutating = 0x4000, Constructor = 0x8000, + AppendBit0 = 0x10000, + AppendBit1 = 0x20000, + CheckedBit0 = 0x40000, + CheckedBit1 = 0x80000; + + public AllowAppendKind AllowAppendKind => (.)(int32)(this / AppendBit0); + public CheckedKind CheckedKind => (.)(int32)(this / CheckedBit0); + } + + public enum AllowAppendKind + { + No, + Yes, + ZeroGap + } + + public enum CheckedKind + { + NotSet, + Checked, + Unchecked } } diff --git a/IDE/mintest/minlib/src/System/Type.bf b/IDE/mintest/minlib/src/System/Type.bf index e6c2eef7..234265dc 100644 --- a/IDE/mintest/minlib/src/System/Type.bf +++ b/IDE/mintest/minlib/src/System/Type.bf @@ -1347,7 +1347,7 @@ namespace System.Reflection EnumCase = 0x0400 } - public enum MethodFlags : uint16 + public enum MethodFlags : uint32 { MethodAccessMask = 0x0007, PrivateScope = 0x0000, // Member not referenceable. @@ -1382,5 +1382,9 @@ namespace System.Reflection ThisCall = 0x3000, // Purposely resuing StdCall|FastCall Mutating = 0x4000, Constructor = 0x8000, + AppendBit0 = 0x10000, + AppendBit1 = 0x20000, + CheckedBit0 = 0x40000, + CheckedBit1 = 0x80000 } } diff --git a/IDE/src/ui/AutoComplete.bf b/IDE/src/ui/AutoComplete.bf index 42091d3f..cb006304 100644 --- a/IDE/src/ui/AutoComplete.bf +++ b/IDE/src/ui/AutoComplete.bf @@ -1817,7 +1817,7 @@ namespace IDE.ui if (!fts_fuzzy_match(filter.CStr(), entry.mEntryDisplay.CStr(), ref score, &matches, matches.Count)) { - entry.SetMatches(Span(null, 0)); + entry.SetMatches(Span((uint8*)null, 0)); entry.mScore = score; return false; } diff --git a/IDE/src/ui/WatchPanel.bf b/IDE/src/ui/WatchPanel.bf index dbeca7bb..7ad3ff57 100644 --- a/IDE/src/ui/WatchPanel.bf +++ b/IDE/src/ui/WatchPanel.bf @@ -2906,7 +2906,10 @@ namespace IDE.ui base.UpdateAll(); if (mWantRemoveSelf) + { mParentItem?.RemoveChildItem(this); + return; + } if (mColumnIdx == 0) { diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index dd943a18..63b43478 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -2520,7 +2520,7 @@ bool BfAutoComplete::GetMethodInfo(BfMethodInstance* methodInst, StringImpl* sho auto methodDeclaration = methodDef->GetMethodDeclaration(); - if (methodDef->mHasAppend) + if (methodDef->HasAppend()) methodPrefix += "[AllowAppend]\r"; if (isInterface) @@ -4083,7 +4083,7 @@ void BfAutoComplete::FixitAddConstructor(BfTypeInstance *typeInstance) int insertPos = FixitGetMemberInsertPos(mModule->mCurTypeInstance->mTypeDef); String methodStr = "\f\a"; - if (methodInstance->mMethodDef->mHasAppend) + if (methodInstance->mMethodDef->HasAppend()) methodStr += "[AllowAppend]\r"; methodStr += "public this("; int useParamIdx = 0; diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index b8220d40..f2bdb7a0 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -829,8 +829,24 @@ void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef } else if (typeRefName == "AllowAppend") { - methodDef->mHasAppend = true; - methodDef->mIsNoSplat = true; + methodDef->mAppendKind = BfAllowAppendKind_Yes; + methodDef->mIsNoSplat = true; + if (!attributes->mArguments.IsEmpty()) + { + if (auto assignExpr = BfNodeDynCast(attributes->mArguments[0])) + { + if ((assignExpr->mLeft != NULL) && (assignExpr->mRight != NULL) && + (assignExpr->mLeft->Equals("ZeroGap"))) + { + if (assignExpr->mRight->Equals("true")) + methodDef->mAppendKind = BfAllowAppendKind_ZeroGap; + else if (assignExpr->mRight->Equals("false")) + methodDef->mAppendKind = BfAllowAppendKind_Yes; + else + Fail("Can only use 'true' or 'false' for 'ZeroGap'", assignExpr->mRight); + } + } + } } else if (typeRefName == "Checked") methodDef->mCheckedKind = BfCheckedKind_Checked; @@ -1754,7 +1770,7 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration) mCurTypeDef->mSource = mCurSource; mCurTypeDef->mSource->mRefCount++; mCurTypeDef->mTypeDeclaration = typeDeclaration; - mCurTypeDef->mIsAbstract = (typeDeclaration->mAbstractSpecifier != NULL) && (typeDeclaration->mAbstractSpecifier->GetToken() == BfToken_Abstract); + mCurTypeDef->mIsAbstract = (typeDeclaration->mAbstractSpecifier != NULL) && (typeDeclaration->mAbstractSpecifier->GetToken() == BfToken_Abstract); mCurTypeDef->mIsStatic = typeDeclaration->mStaticSpecifier != NULL; mCurTypeDef->mIsDelegate = false; mCurTypeDef->mIsFunction = false; @@ -2090,7 +2106,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) hasDefaultCtor = true; auto ctorDeclaration = (BfConstructorDeclaration*)method->mMethodDeclaration; - if (method->mHasAppend) + if (method->mAppendKind != BfAllowAppendKind_No) { mCurTypeDef->mHasAppendCtor = true; @@ -2105,6 +2121,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) methodDef->mProtection = BfProtection_Public; methodDef->mMethodType = BfMethodType_CtorCalcAppend; methodDef->mIsMutating = method->mIsMutating; + methodDef->mAppendKind = method->mAppendKind; methodDef->mIsNoSplat = true; methodDef->mMethodDeclaration = method->mMethodDeclaration; @@ -2133,7 +2150,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) // Insert a 'appendIdx' BfParameterDef* newParam = new BfParameterDef(); - newParam->mName = "appendIdx"; + newParam->mName = "__appendIdx"; newParam->mTypeRef = mSystem->mDirectRefIntTypeRef; newParam->mParamKind = BfParamKind_AppendIdx; method->mParams.Insert(0, newParam); @@ -2524,7 +2541,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) mSignatureHashCtx->MixinStr(methodDef->mName); if ((methodDef->mAlwaysInline) || - (methodDef->mHasAppend) || + (methodDef->mAppendKind != BfAllowAppendKind_No) || (methodDef->mMethodType == BfMethodType_Mixin)) inlineHashCtx.Mixin(methodDef->mFullHash); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 700489f5..e0f00d1b 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -222,6 +222,7 @@ void BfMethodMatcher::Init(const BfMethodGenericArguments& methodGenericArgument mAutoFlushAmbiguityErrors = true; mMethodCheckCount = 0; mCheckedKind = BfCheckedKind_NotSet; + mAllowAppendKind = BfAllowAppendKind_No; mMatchFailKind = MatchFailKind_None; mBfEvalExprFlags = BfEvalExprFlags_None; @@ -808,7 +809,7 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp bool anyIsExtension = false; int newImplicitParamCount = newMethodInstance->GetImplicitParamCount(); - if (newMethodInstance->mMethodDef->mHasAppend) + if (newMethodInstance->mMethodDef->HasAppend()) newImplicitParamCount++; if (newMethodInstance->mMethodDef->mMethodType == BfMethodType_Extension) { @@ -817,7 +818,7 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp } int prevImplicitParamCount = prevMethodInstance->GetImplicitParamCount(); - if (prevMethodInstance->mMethodDef->mHasAppend) + if (prevMethodInstance->mMethodDef->HasAppend()) prevImplicitParamCount++; if (prevMethodInstance->mMethodDef->mMethodType == BfMethodType_Extension) { @@ -1281,6 +1282,7 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp } RETURN_BETTER_OR_WORSE(newMethodDef->mCheckedKind == mCheckedKind, prevMethodDef->mCheckedKind == mCheckedKind); + RETURN_BETTER_OR_WORSE(newMethodDef->mAppendKind == mAllowAppendKind, prevMethodDef->mAppendKind == mAllowAppendKind); RETURN_BETTER_OR_WORSE(newMethodDef->mCommutableKind != BfCommutableKind_Reverse, prevMethodDef->mCommutableKind != BfCommutableKind_Reverse); // If one of these methods is local to the current extension then choose that one @@ -1775,7 +1777,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst ((!mHadExplicitGenericArguments) || (mHadPartialGenericArguments)); int paramIdx = 0; BfType* paramsElementType = NULL; - if (checkMethod->mHasAppend) + if (checkMethod->HasAppend()) paramIdx++; int uniqueGenericStartIdx = mModule->GetLocalInferrableGenericArgCount(checkMethod); @@ -1887,7 +1889,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst int argIdx = 0; int paramIdx = 0; - if (checkMethod->mHasAppend) + if (checkMethod->HasAppend()) paramIdx++; if (checkMethod->mMethodType == BfMethodType_Extension) @@ -2636,7 +2638,7 @@ Done: return mBestMethodDef == checkMethod; } -void BfMethodMatcher::FlushAmbiguityError() +void BfMethodMatcher::FlushAmbiguityError(bool useWarning) { if (!mAmbiguousEntries.empty()) { @@ -2644,9 +2646,20 @@ void BfMethodMatcher::FlushAmbiguityError() { BfError* error; if (!mMethodName.empty()) - error = mModule->Fail(StrFormat("Ambiguous method call for '%s'", mMethodName.c_str()), mTargetSrc); + { + if (useWarning) + error = mModule->Warn(0, StrFormat("Ambiguous method call for '%s'", mMethodName.c_str()), mTargetSrc); + else + error = mModule->Fail(StrFormat("Ambiguous method call for '%s'", mMethodName.c_str()), mTargetSrc); + } else - error = mModule->Fail("Ambiguous method call", mTargetSrc); + { + if (useWarning) + error = mModule->Warn(0, "Ambiguous method call", mTargetSrc); + else + error = mModule->Fail("Ambiguous method call", mTargetSrc); + } + if (error != NULL) { BfMethodInstance* bestMethodInstance = mModule->GetUnspecializedMethodInstance(mBestRawMethodInstance, true); @@ -8037,7 +8050,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu arrayType, false); BfResolvedArgs resolvedArgs; - MatchConstructor(targetSrc, NULL, expandedParamsArray, arrayType, resolvedArgs, false, BfMethodGenericArguments(), false); + MatchConstructor(targetSrc, NULL, expandedParamsArray, arrayType, resolvedArgs, false, BfMethodGenericArguments(), BfAllowAppendKind_No); //TODO: Assert 'length' var is at slot 1 auto arrayBits = mModule->mBfIRBuilder->CreateBitCast(expandedParamsArray.mValue, mModule->mBfIRBuilder->MapType(arrayType->mBaseType)); @@ -8806,15 +8819,21 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu } BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBoundExpression* methodBoundExpr, BfTypedValue target, BfTypeInstance* targetType, BfResolvedArgs& argValues, bool callCtorBodyOnly, - const BfMethodGenericArguments& methodGenericArguments, bool allowAppendAlloc, BfTypedValue* appendIndexValue) + const BfMethodGenericArguments& methodGenericArguments, BfAllowAppendKind allowAppendKind, BfTypedValue* appendIndexValue) { // Temporarily disable so we don't capture calls in params SetAndRestoreValue prevBindResult(mFunctionBindResult, NULL); + auto origAllowAppendKind = allowAppendKind; + + if (allowAppendKind == BfAllowAppendKind_Infer) + allowAppendKind = targetType->IsZeroGap() ? BfAllowAppendKind_ZeroGap : BfAllowAppendKind_Yes; + static int sCtorCount = 0; sCtorCount++; BfMethodMatcher methodMatcher(targetSrc, mModule, "", argValues.mResolvedArgs, methodGenericArguments); + methodMatcher.mAllowAppendKind = allowAppendKind; methodMatcher.mBfEvalExprFlags = mBfEvalExprFlags; BfTypeVector typeGenericArguments; @@ -8942,17 +8961,29 @@ BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBou } BfConstructorDeclaration* ctorDecl = (BfConstructorDeclaration*)methodMatcher.mBestMethodDef->mMethodDeclaration; - if ((methodMatcher.mBestMethodDef->mHasAppend) && (targetType->IsObject())) - { - if (!allowAppendAlloc) + if ((methodMatcher.mBestMethodDef->HasAppend()) && (targetType->IsObject())) + { + if (allowAppendKind == BfAllowAppendKind_No) { if (mModule->mCurMethodInstance->mMethodDef->mMethodDeclaration == NULL) mModule->Fail("Constructors with append allocations cannot be called from a default constructor. Considering adding an explicit default constructor with the [AllowAppend] specifier.", targetSrc); else mModule->Fail("Constructors with append allocations cannot be called from a constructor without [AllowAppend] specified.", targetSrc); - } + } else { + if ((allowAppendKind == BfAllowAppendKind_Yes) && (methodMatcher.mBestMethodDef->mAppendKind == BfAllowAppendKind_ZeroGap)) + { + BfError* error; + if (origAllowAppendKind == BfAllowAppendKind_Infer) + error = mModule->Fail(StrFormat("Cannot call ZeroGap constructor for type '%s' because of fields added from type extensions", mModule->TypeToString(targetType).c_str()), targetSrc); + else + error = mModule->Fail(StrFormat("Cannot call ZeroGap constructor for type '%s' from here", mModule->TypeToString(targetType).c_str()), targetSrc); + + if ((error != NULL) && (methodMatcher.mBestMethodDef->mMethodDeclaration != NULL)) + mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("See method declaration"), methodMatcher.mBestMethodDef->GetRefNode()); + } + BfResolvedArg resolvedArg; if (appendIndexValue != NULL) { @@ -8975,6 +9006,9 @@ BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBou } } + if (methodMatcher.mAutoFlushAmbiguityErrors) + methodMatcher.FlushAmbiguityError(true); + if (isFailurePass) mModule->Fail(StrFormat("'%s' is inaccessible due to its protection level", mModule->MethodToString(moduleMethodInstance.mMethodInstance).c_str()), targetSrc); prevBindResult.Restore(); @@ -10215,7 +10249,8 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp mResultLocalVar = NULL; mResultFieldInstance = NULL; mResultLocalVarRefNode = NULL; - BfTypedValue result = MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, BfMethodGenericArguments(), resolvedTypeInstance->IsObject()); + BfTypedValue result = MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, BfMethodGenericArguments(), + resolvedTypeInstance->IsObject() ? BfAllowAppendKind_Infer : BfAllowAppendKind_No); if ((result) && (!result.mType->IsVoid())) return result; mModule->ValidateAllocation(resolvedTypeInstance, targetSrc); @@ -14222,7 +14257,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) } BfResolvedArgs resolvedArgs; - MatchConstructor(delegateBindExpr, delegateBindExpr, mResult, useTypeInstance, resolvedArgs, false, BfMethodGenericArguments(), false); + MatchConstructor(delegateBindExpr, delegateBindExpr, mResult, useTypeInstance, resolvedArgs, false, BfMethodGenericArguments(), BfAllowAppendKind_No); auto baseDelegateType = VerifyBaseDelegateType(delegateTypeInstance->mBaseType); auto baseDelegate = mModule->mBfIRBuilder->CreateBitCast(mResult.mValue, mModule->mBfIRBuilder->MapType(baseDelegateType, BfIRPopulateType_Full)); @@ -15951,7 +15986,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs mModule->Fail("Append allocations are only allowed as local variable declarations in the main method body", allocNode); isAppendAlloc = false; } - else if (!methodDef->mHasAppend) + else if (!methodDef->HasAppend()) { mModule->Fail("Append allocations can only be used on constructors with [AllowAppend] specified", allocNode); isAppendAlloc = false; @@ -16319,11 +16354,11 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs if (rawAutoComplete != NULL) { SetAndRestoreValue prevCapturing(rawAutoComplete->mIsCapturingMethodMatchInfo, false); - MatchConstructor(refNode, objCreateExpr, arrayValue, arrayType, resolvedArgs, false, methodGenericArguments, false); + MatchConstructor(refNode, objCreateExpr, arrayValue, arrayType, resolvedArgs, false, methodGenericArguments, BfAllowAppendKind_No); } else { - MatchConstructor(refNode, objCreateExpr, arrayValue, arrayType, resolvedArgs, false, methodGenericArguments, false); + MatchConstructor(refNode, objCreateExpr, arrayValue, arrayType, resolvedArgs, false, methodGenericArguments, BfAllowAppendKind_No); } //TODO: Assert 'length' var is at slot 1 @@ -16506,7 +16541,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs auto checkTypeInst = typeInstance; if (checkTypeInst->IsAnonymousInitializerType()) checkTypeInst = checkTypeInst->mBaseType; - MatchConstructor(refNode, objCreateExpr, emtpyThis, checkTypeInst, argValues, false, methodGenericArguments, true); + MatchConstructor(refNode, objCreateExpr, emtpyThis, checkTypeInst, argValues, false, methodGenericArguments, BfAllowAppendKind_Infer); if ((wasCapturingMethodInfo) && (!autoComplete->mIsCapturingMethodMatchInfo)) { if (autoComplete->mMethodMatchInfo != NULL) @@ -16524,7 +16559,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs auto checkTypeInst = typeInstance; if (checkTypeInst->IsAnonymousInitializerType()) checkTypeInst = checkTypeInst->mBaseType; - MatchConstructor(refNode, objCreateExpr, emtpyThis, checkTypeInst, argValues, false, methodGenericArguments, true); + MatchConstructor(refNode, objCreateExpr, emtpyThis, checkTypeInst, argValues, false, methodGenericArguments, BfAllowAppendKind_Infer); } if (objCreateExpr != NULL) mModule->ValidateAllocation(typeInstance, objCreateExpr->mTypeRef); @@ -16536,7 +16571,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs allocAlign = typeInstance->mInstAlign; int appendAllocAlign = 0; - if ((bindResult.mMethodInstance != NULL) && (bindResult.mMethodInstance->mMethodDef->mHasAppend)) + if ((bindResult.mMethodInstance != NULL) && (bindResult.mMethodInstance->mMethodDef->HasAppend())) { if (!bindResult.mFunc) { @@ -16736,7 +16771,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs thisTypedValue = mModule->Cast(allocNode, thisTypedValue, wantType); } - if ((bindResult.mMethodInstance->mMethodDef->mHasAppend) && (mResult.mType->IsObject())) + if ((bindResult.mMethodInstance->mMethodDef->HasAppend()) && (mResult.mType->IsObject())) { BF_ASSERT(bindResult.mIRArgs[0].IsFake()); auto typeInst = mResult.mType->ToTypeInstance(); @@ -18542,7 +18577,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m else mResult = BfTypedValue(mModule->CreateAlloca(expectingType), expectingType, BfTypedValueKind_TempAddr); - auto ctorResult = MatchConstructor(target, methodBoundExpr, mResult, expectingType->ToTypeInstance(), argValues, false, BfMethodGenericArguments(), false); + auto ctorResult = MatchConstructor(target, methodBoundExpr, mResult, expectingType->ToTypeInstance(), argValues, false, BfMethodGenericArguments(), BfAllowAppendKind_No); if ((ctorResult) && (!ctorResult.mType->IsVoid())) mResult = ctorResult; mModule->ValidateAllocation(expectingType, invocationExpr->mTarget); @@ -23916,7 +23951,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExp ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval); mResult = BfTypedValue(alloca, allocType, true); - auto result = MatchConstructor(opToken, NULL, mResult, allocType, argValues, true, BfMethodGenericArguments(), false); + auto result = MatchConstructor(opToken, NULL, mResult, allocType, argValues, true, BfMethodGenericArguments(), BfAllowAppendKind_No); if ((result) && (!result.mType->IsVoid())) mResult = result; diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index 3d79d99a..b648030d 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -219,6 +219,7 @@ public: BfType* mCheckReturnType; BfMethodType mMethodType; BfCheckedKind mCheckedKind; + BfAllowAppendKind mAllowAppendKind; Array*>* mUsingLists; bool mHasArgNames; bool mHadExplicitGenericArguments; @@ -261,7 +262,7 @@ public: void CompareMethods(BfMethodInstance* prevMethodInstance, BfTypeVector* prevGenericArgumentsSubstitute, BfMethodInstance* newMethodInstance, BfTypeVector* genericArgumentsSubstitute, bool* outNewIsBetter, bool* outNewIsWorse, bool allowSpecializeFail); - void FlushAmbiguityError(); + void FlushAmbiguityError(bool useWarning = false); bool IsType(BfTypedValue& val, BfType* type); int GetMostSpecificType(BfType* lhs, BfType* rhs); // 0, 1, or -1 @@ -498,7 +499,7 @@ public: void PushArg(BfTypedValue argVal, SizedArrayImpl& irArgs, bool disableSplat = false, bool disableLowering = false, bool isIntrinsic = false, bool createCompositeCopy = false); void PushThis(BfAstNode* targetSrc, BfTypedValue callTarget, BfMethodInstance* methodInstance, SizedArrayImpl& irArgs, bool skipMutCheck = false); BfTypedValue MatchConstructor(BfAstNode* targetSrc, BfMethodBoundExpression* methodBoundExpr, BfTypedValue target, BfTypeInstance* targetType, - BfResolvedArgs& argValues, bool callCtorBodyOnly, const BfMethodGenericArguments& methodGenericArguments, bool allowAppendAlloc, BfTypedValue* appendIndexValue = NULL); + BfResolvedArgs& argValues, bool callCtorBodyOnly, const BfMethodGenericArguments& methodGenericArguments, BfAllowAppendKind allowAppendKind, BfTypedValue* appendIndexValue = NULL); BfTypedValue CheckEnumCreation(BfAstNode* targetSrc, BfTypeInstance* enumType, const StringImpl& caseName, BfResolvedArgs& argValues); BfTypedValue MatchMethod(BfAstNode* targetSrc, BfMethodBoundExpression* methodBoundExpr, BfTypedValue target, bool allowImplicitThis, bool bypassVirtual, const StringImpl& name, BfResolvedArgs& argValue, const BfMethodGenericArguments& methodGenericArguments, BfCheckedKind checkedKind = BfCheckedKind_NotSet); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index bf3e7156..d18767aa 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -778,13 +778,13 @@ public: if (typeInst != NULL) { exprEvaluator.ResolveArgValues(argValues); - exprEvaluator.MatchConstructor(objCreateExpr->mTypeRef, objCreateExpr, emtpyThis, typeInst, argValues, false, BfMethodGenericArguments(), true); + exprEvaluator.MatchConstructor(objCreateExpr->mTypeRef, objCreateExpr, emtpyThis, typeInst, argValues, false, BfMethodGenericArguments(), BfAllowAppendKind_Infer); } exprEvaluator.mFunctionBindResult = NULL; if (bindResult.mMethodInstance != NULL) { - if (bindResult.mMethodInstance->mMethodDef->mHasAppend) + if (bindResult.mMethodInstance->mMethodDef->HasAppend()) { auto calcAppendArgs = bindResult.mIRArgs; BF_ASSERT(calcAppendArgs[0].IsFake()); @@ -4808,9 +4808,9 @@ bool BfModule::TryGetAppendedObjectInfo(BfFieldInstance* fieldInstance, int& dat BfTypedValue emptyThis(mBfIRBuilder->GetFakeVal(), mCurTypeInstance, mCurTypeInstance->IsStruct()); exprEvaluator.mBfEvalExprFlags = BfEvalExprFlags_Comptime; - auto ctorResult = exprEvaluator.MatchConstructor(nameRefNode, NULL, emptyThis, fieldTypeInst, resolvedArgs, false, BfMethodGenericArguments(), true); + auto ctorResult = exprEvaluator.MatchConstructor(nameRefNode, NULL, emptyThis, fieldTypeInst, resolvedArgs, false, BfMethodGenericArguments(), BfAllowAppendKind_Infer); - if ((bindResult.mMethodInstance != NULL) && (bindResult.mMethodInstance->mMethodDef->mHasAppend)) + if ((bindResult.mMethodInstance != NULL) && (bindResult.mMethodInstance->mMethodDef->HasAppend())) { auto calcAppendMethodModule = GetMethodInstanceAtIdx(bindResult.mMethodInstance->GetOwner(), bindResult.mMethodInstance->mMethodDef->mIdx + 1, BF_METHODNAME_CALCAPPEND); @@ -4934,7 +4934,7 @@ void BfModule::AppendedObjectInit(BfFieldInstance* fieldInst) mBfIRBuilder->CreateStore(GetConstValue8(BfObjectFlag_AppendAlloc), thisFlagsPtr); } - exprEvaluator.MatchConstructor(fieldDef->GetNameNode(), NULL, thisValue, fieldInst->mResolvedType->ToTypeInstance(), resolvedArgs, false, BfMethodGenericArguments(), true, &indexVal); + exprEvaluator.MatchConstructor(fieldDef->GetNameNode(), NULL, thisValue, fieldInst->mResolvedType->ToTypeInstance(), resolvedArgs, false, BfMethodGenericArguments(), BfAllowAppendKind_Infer, &indexVal); } void BfModule::CheckInterfaceMethod(BfMethodInstance* methodInstance) @@ -7839,7 +7839,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, BfCreateTypeDataContext& ctx, b paramsVal, GetConstValue(defaultMethod->mReturnType->mTypeId, typeIdType), GetConstValue((int)paramVals.size(), shortType), - GetConstValue(methodFlags, shortType), + GetConstValue(methodFlags, intType), GetConstValue(methodIdx, intType), GetConstValue(vDataVal, intType), GetConstValue(customAttrIdx, intType), @@ -10544,7 +10544,7 @@ void BfModule::EmitAppendAlign(int align, int sizeMultiple) else if (mCurMethodInstance->mMethodDef->mMethodType == BfMethodType_Ctor) { auto localVar = mCurMethodState->GetRootMethodState()->mLocals[1]; - BF_ASSERT(localVar->mName == "appendIdx"); + BF_ASSERT(localVar->mName == "__appendIdx"); auto appendIdxVal = BfTypedValue(localVar->mValue, localVar->mResolvedType, true); BfIRValue appendCurIdx = mBfIRBuilder->CreateLoad(appendIdxVal.mValue); if (align > 1) @@ -10579,7 +10579,7 @@ void BfModule::EmitAppendAlign(int align, int sizeMultiple) BfIRValue BfModule::AppendAllocFromType(BfType* type, BfIRValue appendSizeValue, int appendAllocAlign, BfIRValue arraySize, int arrayDim, bool isRawArrayAlloc, bool zeroMemory) { auto localVar = mCurMethodState->GetRootMethodState()->mLocals[1]; - BF_ASSERT(localVar->mName == "appendIdx"); + BF_ASSERT(localVar->mName == "__appendIdx"); BfTypedValue appendIdxVal(localVar->mValue, localVar->mResolvedType, true); BfIRValue retValue; @@ -14043,6 +14043,8 @@ bool BfModule::CompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstan } else if (methodA->mMethodDef->mName != methodB->mMethodDef->mName) return false; + if (methodA->mMethodDef->mAppendKind != methodB->mMethodDef->mAppendKind) + return false; if (methodA->mMethodDef->mCheckedKind != methodB->mMethodDef->mCheckedKind) return false; if (methodA->mMethodDef->mHasComptime != methodB->mMethodDef->mHasComptime) @@ -15190,6 +15192,11 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM methodInstance->mMangleWithIdx = true; } + if (methodDef->mAppendKind > BfAllowAppendKind_No) + { + methodInstance->mMangleWithIdx = true; + } + BF_ASSERT(typeInst == methodInstance->GetOwner()); auto methodDeclaration = methodDef->GetMethodDeclaration(); @@ -17243,6 +17250,24 @@ void BfModule::CalcAppendAlign(BfMethodInstance* methodInst) methodInst->mAppendAllocAlign = 1; } +BfAllowAppendKind BfModule::GetBaseAllowAppend(BfMethodInstance* curMethodInstance) +{ + auto typeInstance = curMethodInstance->GetOwner(); + auto methodDef = curMethodInstance->mMethodDef; + + if (methodDef->mAppendKind == BfAllowAppendKind_No) + return BfAllowAppendKind_No; + + if ((typeInstance->mInstSize == typeInstance->mBaseType->mInstSize) && + (typeInstance->IsZeroGap()) && + (typeInstance->mBaseType->IsZeroGap()) && + (methodDef->mAppendKind == BfAllowAppendKind_ZeroGap)) + { + return BfAllowAppendKind_ZeroGap; + } + return BfAllowAppendKind_Yes; +} + BfTypedValue BfModule::TryConstCalcAppend(BfMethodInstance* methodInst, SizedArrayImpl& args, bool force) { BP_ZONE("BfModule::TryConstCalcAppend"); @@ -17423,7 +17448,7 @@ BfTypedValue BfModule::TryConstCalcAppend(BfMethodInstance* methodInst, SizedArr } BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly) -{ +{ // Any errors should only be shown in the actual CTOR call SetAndRestoreValue prevIgnoreWrites(mIgnoreErrors, true); @@ -17431,6 +17456,8 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly) BF_ASSERT((methodDef->mMethodType == BfMethodType_Ctor) || (methodDef->mMethodType == BfMethodType_CtorCalcAppend)); auto ctorDeclaration = (BfConstructorDeclaration*)methodDef->mMethodDeclaration; + BfAllowAppendKind allowAppendKind = GetBaseAllowAppend(mCurMethodInstance); + BfCustomAttributes* customAttributes = NULL; defer(delete customAttributes); BfInvocationExpression* ctorInvocation = NULL; @@ -17473,11 +17500,11 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly) BfFunctionBindResult bindResult; bindResult.mSkipThis = true; bindResult.mWantsArgs = true; - { + { SetAndRestoreValue prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true); exprEvaluator.ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval); SetAndRestoreValue prevBindResult(exprEvaluator.mFunctionBindResult, &bindResult); - exprEvaluator.MatchConstructor(targetRefNode, NULL, target, targetType, argValues, true, BfMethodGenericArguments(), true); + exprEvaluator.MatchConstructor(targetRefNode, NULL, target, targetType, argValues, true, BfMethodGenericArguments(), allowAppendKind, NULL); } if (bindResult.mMethodInstance == NULL) @@ -17486,7 +17513,7 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly) return BfTypedValue(); } - if (!bindResult.mMethodInstance->mMethodDef->mHasAppend) + if (!bindResult.mMethodInstance->mMethodDef->HasAppend()) { return BfTypedValue(); } @@ -17524,7 +17551,7 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly) bindResult.mSkipThis = true; bindResult.mWantsArgs = true; SetAndRestoreValue prevBindResult(exprEvaluator.mFunctionBindResult, &bindResult); - exprEvaluator.MatchConstructor(targetRefNode, NULL, target, targetType, argValues, true, BfMethodGenericArguments(), true); + exprEvaluator.MatchConstructor(targetRefNode, NULL, target, targetType, argValues, true, BfMethodGenericArguments(), allowAppendKind, NULL); BF_ASSERT(bindResult.mIRArgs[0].IsFake()); bindResult.mIRArgs.RemoveAt(0); calcAppendArgs = bindResult.mIRArgs; @@ -18975,7 +19002,7 @@ void BfModule::EmitCtorBody(bool& skipBody) } } - if (methodDef->mHasAppend) + if (methodDef->HasAppend()) { mCurMethodState->mCurAppendAlign = methodInstance->mAppendAllocAlign; } @@ -19028,16 +19055,18 @@ void BfModule::EmitCtorBody(bool& skipBody) } exprEvaluator.ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval); + BfAllowAppendKind allowAppendKind = GetBaseAllowAppend(mCurMethodInstance); + BfTypedValue appendIdxVal; - if (methodDef->mHasAppend) + if (methodDef->HasAppend()) { auto localVar = mCurMethodState->GetRootMethodState()->mLocals[1]; - BF_ASSERT(localVar->mName == "appendIdx"); + BF_ASSERT(localVar->mName == "__appendIdx"); auto intRefType = localVar->mResolvedType; appendIdxVal = BfTypedValue(localVar->mValue, intRefType); mCurMethodState->mCurAppendAlign = 1; // Don't make any assumptions about how the base leaves the alignment } - exprEvaluator.MatchConstructor(targetRefNode, NULL, target, targetType, argValues, true, BfMethodGenericArguments(), methodDef->mHasAppend, &appendIdxVal); + exprEvaluator.MatchConstructor(targetRefNode, NULL, target, targetType, argValues, true, BfMethodGenericArguments(), allowAppendKind, &appendIdxVal); if (autoComplete != NULL) { @@ -25488,6 +25517,12 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool silentlyAllow = true; } + if (checkMethod->mMethodType == BfMethodType_CtorCalcAppend) + { + // Only use the main ctor as the error method + silentlyAllow = true; + } + if (!silentlyAllow) { if ((!methodDef->mName.IsEmpty()) || (checkMethodInstance->mMethodDef->mIsOperator)) diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 61214730..ac072582 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -2020,6 +2020,7 @@ public: void AddMethodToWorkList(BfMethodInstance* methodInstance); bool IsInterestedInMethod(BfTypeInstance* typeInstance, BfMethodDef* methodDef); void CalcAppendAlign(BfMethodInstance* methodInst); + BfAllowAppendKind GetBaseAllowAppend(BfMethodInstance* curMethodInstance); BfTypedValue TryConstCalcAppend(BfMethodInstance* methodInst, SizedArrayImpl& args, bool force = false); BfTypedValue CallBaseCtorCalc(bool constOnly); void EmitCtorCalcAppend(); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 8d2bf531..4e0227d1 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -841,6 +841,9 @@ BfMethodFlags BfMethodInstance::GetMethodFlags() else if (callingConvention == BfIRCallingConv_FastCall) methodFlags = (BfMethodFlags)(methodFlags | BfMethodFlags_FastCall); + methodFlags = (BfMethodFlags)(methodFlags | (mMethodDef->mAppendKind * BfMethodFlags_AppendBit0)); + methodFlags = (BfMethodFlags)(methodFlags | (mMethodDef->mCheckedKind * BfMethodFlags_CheckedBit0)); + return methodFlags; } @@ -2704,6 +2707,23 @@ bool BfTypeInstance::IsTypeMemberIncluded(BfTypeDef* typeDef, BfTypeDef* activeT return genericExEntry->mConstraintsPassed; } +bool BfTypeInstance::IsZeroGap() +{ + BF_ASSERT(mDefineState >= BfTypeDefineState_Defined); + + for (int fieldIdx = mFieldInstances.mSize - 1; fieldIdx >= 0; fieldIdx--) + { + auto fieldInstance = &mFieldInstances[fieldIdx]; + auto fieldDef = fieldInstance->GetFieldDef(); + if (fieldDef == NULL) + continue; + if ((!fieldDef->mIsStatic) && (fieldDef->mDeclaringType->IsExtension()) && (!fieldInstance->mResolvedType->IsValuelessType())) + return false; + } + + return true; +} + void BfGenericTypeInfo::ReportMemory(MemReporter* memReporter) { memReporter->Add(sizeof(BfGenericTypeInfo)); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 2189ecf2..4d05e516 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -633,6 +633,7 @@ public: virtual bool GetLoweredType(BfTypeUsage typeUsage, BfTypeCode* outTypeCode = NULL, BfTypeCode* outTypeCode2 = NULL) { return false; } virtual BfType* GetUnderlyingType() { return NULL; } virtual bool HasWrappedRepresentation() { return IsWrappableType(); } + virtual bool IsZeroGap() { return true; } 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; } @@ -973,7 +974,7 @@ public: bool IsMixin() { return mMethodDef->mMethodType == BfMethodType_Mixin; - } + } BfImportKind GetImportKind(); BfMethodFlags GetMethodFlags(); @@ -2182,6 +2183,7 @@ public: virtual bool IsNullable() override; virtual bool HasVarConstraints(); virtual bool IsTypeMemberIncluded(BfTypeDef* declaringTypeDef, BfTypeDef* activeTypeDef = NULL, BfModule* module = NULL) override; + virtual bool IsZeroGap() override; virtual BfTypeInstance* GetImplBaseType() { return mBaseType; } diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index a2758a63..7d3123c1 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -253,7 +253,11 @@ enum BfMethodFlags BfMethodFlags_FastCall = 0x2000, BfMethodFlags_ThisCall = 0x3000, BfMethodFlags_Mutating = 0x4000, - BfMethodFlags_Constructor = 0x8000 + BfMethodFlags_Constructor = 0x8000, + BfMethodFlags_AppendBit0 = 0x10000, + BfMethodFlags_AppendBit1 = 0x20000, + BfMethodFlags_CheckedBit0 = 0x40000, + BfMethodFlags_CheckedBit1 = 0x80000, }; enum BfComptimeMethodFlags @@ -888,6 +892,15 @@ enum BfComptimeFlags : int8 BfComptimeFlag_ConstEval = 4 }; +enum BfAllowAppendKind : int8 +{ + BfAllowAppendKind_No, + BfAllowAppendKind_Yes, + BfAllowAppendKind_ZeroGap, + + BfAllowAppendKind_Infer +}; + class BfMethodDef : public BfMemberDef { public: @@ -916,7 +929,7 @@ public: bool mCodeChanged; bool mWantsBody; bool mCLink; - bool mHasAppend; + BfAllowAppendKind mAppendKind; bool mAlwaysInline; bool mIsNoReturn; bool mIsMutating; @@ -970,7 +983,7 @@ public: mImportKind = BfImportKind_None; mMethodType = BfMethodType_Normal; mCallingConvention = BfCallingConvention_Unspecified; - mHasAppend = false; + mAppendKind = BfAllowAppendKind_No; mAlwaysInline = false; mParamNameMap = NULL; mNextWithSameName = NULL; @@ -980,6 +993,7 @@ public: static BfImportKind GetImportKindFromPath(const StringImpl& filePath); bool HasNoThisSplat() { return mIsMutating || mIsNoSplat; } + bool HasAppend() { return mAppendKind != BfAllowAppendKind_No; } void Reset(); void FreeMembers(); BfMethodDeclaration* GetMethodDeclaration(); @@ -1144,7 +1158,7 @@ public: BfShow mShow; bool mIsAlwaysInclude; bool mIsNoDiscard; - bool mIsPartial; + bool mIsPartial; bool mIsExplicitPartial; bool mPartialUsed; bool mIsCombinedPartial; diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index 7b958a0a..82a319ac 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -6610,10 +6610,11 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* // int32 mReturnType // int32 mParamCount // int32 mGenericArgCount - // int16 mFlags + // int32 mFlags + // int8 ComptimeMethodFlags // int32 mMethodIdx - int64 methodHandle = *(int64*)((uint8*)stackPtr + 4+4+4+2+1+4); + int64 methodHandle = *(int64*)((uint8*)stackPtr + 4+4+4+4+1+4); auto methodInstance = mCeMachine->GetMethodInstance(methodHandle); if (methodInstance == NULL) @@ -6630,9 +6631,9 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8* *(int32*)(stackPtr + 0) = methodInstance->mReturnType->mTypeId; *(int32*)(stackPtr + 4) = methodInstance->GetParamCount(); *(int32*)(stackPtr + 4+4) = genericArgCount; - *(int16*)(stackPtr + 4+4+4) = methodInstance->GetMethodFlags(); - *(int32*)(stackPtr + 4+4+4+2) = methodInstance->GetComptimeMethodFlags(); - *(int32*)(stackPtr + 4+4+4+2+1) = methodInstance->mMethodDef->mIdx; + *(int32*)(stackPtr + 4+4+4) = methodInstance->GetMethodFlags(); + *(int32*)(stackPtr + 4+4+4+4) = methodInstance->GetComptimeMethodFlags(); + *(int32*)(stackPtr + 4+4+4+4+1) = methodInstance->mMethodDef->mIdx; } else if (checkFunction->mFunctionKind == CeFunctionKind_Method_GetParamInfo) {