From b6db69d2b0c9f9fdefb0c40e5b0153d67fcac0eb Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 22 Oct 2020 11:33:13 -0700 Subject: [PATCH] Fixed extension initializers and dtors. [NoExtension]. Extension warning --- BeefLibs/corlib/src/Attribute.bf | 6 + IDEHelper/Compiler/BfAst.h | 2 +- IDEHelper/Compiler/BfCompiler.cpp | 8 +- IDEHelper/Compiler/BfCompiler.h | 1 + IDEHelper/Compiler/BfDefBuilder.cpp | 4 +- IDEHelper/Compiler/BfExprEvaluator.cpp | 16 ++- IDEHelper/Compiler/BfModule.cpp | 150 +++++++++++++++++-------- IDEHelper/Compiler/BfReducer.cpp | 29 ++++- IDEHelper/Compiler/BfSystem.cpp | 7 +- IDEHelper/Compiler/BfSystem.h | 2 + IDEHelper/Tests/LibA/src/LibA0.bf | 27 ++++- IDEHelper/Tests/LibB/src/LibB0.bf | 16 ++- IDEHelper/Tests/LibC/src/LibC0.bf | 12 +- IDEHelper/Tests/TestsB/src/TestsB0.bf | 6 +- IDEHelper/Tests/src/Extensions.bf | 13 ++- 15 files changed, 235 insertions(+), 64 deletions(-) diff --git a/BeefLibs/corlib/src/Attribute.bf b/BeefLibs/corlib/src/Attribute.bf index c5d5f582..6611594c 100644 --- a/BeefLibs/corlib/src/Attribute.bf +++ b/BeefLibs/corlib/src/Attribute.bf @@ -149,6 +149,12 @@ namespace System } + [AttributeUsage(.MemberAccess)] + public struct NoExtensionAttribute : Attribute + { + + } + [AttributeUsage(.Block)] public struct IgnoreErrorsAttribute : Attribute { diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index 8394aa1e..811adeaf 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -2949,7 +2949,7 @@ public: BfTokenNode* mThisToken; BfTokenNode* mInitializerColonToken; - BfInvocationExpression* mInitializer; + BfExpression* mInitializer; }; BF_AST_DECL(BfConstructorDeclaration, BfMethodDeclaration); diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 162f6905..53d90e1f 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -395,6 +395,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly) mActionTypeDef = NULL; mEnumTypeDef = NULL; mFriendAttributeTypeDef = NULL; + mNoExtensionAttributeTypeDef = NULL; mCheckedAttributeTypeDef = NULL; mUncheckedAttributeTypeDef = NULL; mFunctionTypeDef = NULL; @@ -6491,14 +6492,14 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) return typeDef; }; - mArray1TypeDef = _GetRequiredType("System.Array1", 1); - mArray2TypeDef = _GetRequiredType("System.Array2", 1); + mArray1TypeDef = _GetRequiredType("System.Array1", 1); + mArray2TypeDef = _GetRequiredType("System.Array2", 1); mArray3TypeDef = _GetRequiredType("System.Array3", 1); mArray4TypeDef = _GetRequiredType("System.Array4", 1); mSpanTypeDef = _GetRequiredType("System.Span", 1); mAttributeTypeDef = _GetRequiredType("System.Attribute"); mAttributeUsageAttributeTypeDef = _GetRequiredType("System.AttributeUsageAttribute"); - mBfObjectTypeDef = _GetRequiredType("System.Object"); + mBfObjectTypeDef = _GetRequiredType("System.Object"); mClassVDataTypeDef = _GetRequiredType("System.ClassVData"); mCLinkAttributeTypeDef = _GetRequiredType("System.CLinkAttribute"); mImportAttributeTypeDef = _GetRequiredType("System.ImportAttribute"); @@ -6516,6 +6517,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) mActionTypeDef = _GetRequiredType("System.Action"); mEnumTypeDef = _GetRequiredType("System.Enum"); mFriendAttributeTypeDef = _GetRequiredType("System.FriendAttribute"); + mNoExtensionAttributeTypeDef = _GetRequiredType("System.NoExtensionAttribute"); mCheckedAttributeTypeDef = _GetRequiredType("System.CheckedAttribute"); mUncheckedAttributeTypeDef = _GetRequiredType("System.UncheckedAttribute"); mResultTypeDef = _GetRequiredType("System.Result", 1); diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index 8df75221..653915b5 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -394,6 +394,7 @@ public: BfTypeDef* mDisableChecksAttributeTypeDef; BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef; BfTypeDef* mFriendAttributeTypeDef; + BfTypeDef* mNoExtensionAttributeTypeDef; BfTypeDef* mCheckedAttributeTypeDef; BfTypeDef* mUncheckedAttributeTypeDef; BfTypeDef* mStaticInitAfterAttributeTypeDef; diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index 772bcf8b..9dda3c7b 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -2008,8 +2008,10 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) if (mCurTypeDef->mTypeCode == BfTypeCode_TypeAlias) needsDefaultCtor = false; + if (mCurTypeDef->mTypeCode == BfTypeCode_Extension) + needsDefaultCtor = false; - if ((needsDefaultCtor) && (!hasDefaultCtor)) + if ((needsDefaultCtor) && ((!hasDefaultCtor))) { BfProtection prot = hasCtor ? BfProtection_Hidden : BfProtection_Public; if (mCurTypeDef->mName == mSystem->mEmptyAtom) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 03fe4570..a6819824 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -2167,6 +2167,13 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe // if (checkMethod->mName != mMethodName) // continue; + if ((checkMethod->mDeclaringType->IsExtension()) && (mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL) && + (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mNoExtensionAttributeTypeDef))) + { + mModule->mAttributeState->mUsed = true; + continue; + } + if (!isDelegate) { if ((!curTypeInst->IsTypeMemberIncluded(checkMethod->mDeclaringType, activeTypeDef, mModule)) || @@ -6408,8 +6415,15 @@ BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBou if (checkMethod->mIsStatic) continue; - if (!mModule->IsInSpecializedSection()) + if ((checkMethod->mDeclaringType->IsExtension()) && (mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL) && + (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mNoExtensionAttributeTypeDef))) { + mModule->mAttributeState->mUsed = true; + continue; + } + + if (!mModule->IsInSpecializedSection()) + { if ((!curTypeInst->IsTypeMemberIncluded(checkMethod->mDeclaringType, activeTypeDef, mModule)) || (!curTypeInst->IsTypeMemberAccessible(checkMethod->mDeclaringType, visibleProjectSet))) continue; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 930f8d4f..db1cecf8 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -14592,14 +14592,28 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly) { // Any errors should only be shown in the actual CTOR call SetAndRestoreValue prevIgnoreWrites(mIgnoreErrors, true); - + auto methodDef = mCurMethodInstance->mMethodDef; BF_ASSERT((methodDef->mMethodType == BfMethodType_Ctor) || (methodDef->mMethodType == BfMethodType_CtorCalcAppend)); auto ctorDeclaration = (BfConstructorDeclaration*)methodDef->mMethodDeclaration; - BfTypeInstance* targetType = NULL; - if (ctorDeclaration->mInitializer != NULL) + + BfCustomAttributes* customAttributes = NULL; + defer(delete customAttributes); + BfInvocationExpression* ctorInvocation = NULL; + if (ctorDeclaration != NULL) { - auto targetToken = BfNodeDynCast(ctorDeclaration->mInitializer->mTarget); + ctorInvocation = BfNodeDynCast(ctorDeclaration->mInitializer); + if (auto attributedExpr = BfNodeDynCast(ctorDeclaration->mInitializer)) + { + ctorInvocation = BfNodeDynCast(attributedExpr->mExpression); + customAttributes = GetCustomAttributes(attributedExpr->mAttributes, BfAttributeTargets_MemberAccess); + } + } + + BfTypeInstance* targetType = NULL; + if (ctorInvocation != NULL) + { + auto targetToken = BfNodeDynCast(ctorInvocation->mTarget); targetType = (targetToken->GetToken() == BfToken_This) ? mCurTypeInstance : mCurTypeInstance->mBaseType; } else @@ -14614,9 +14628,9 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly) BfExprEvaluator exprEvaluator(this); BfResolvedArgs argValues; - if ((ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL)) + if ((ctorDeclaration != NULL) && (ctorInvocation != NULL)) { - argValues.Init(&ctorDeclaration->mInitializer->mArguments); + argValues.Init(&ctorInvocation->mArguments); } // @@ -14670,7 +14684,7 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly) { // Do it again, but without mIgnoreWrites set BfResolvedArgs argValues; - argValues.Init(&ctorDeclaration->mInitializer->mArguments); + argValues.Init(&ctorInvocation->mArguments); exprEvaluator.ResolveArgValues(argValues, BfResolveArgFlag_DeferParamEval); BfFunctionBindResult bindResult; @@ -15445,13 +15459,31 @@ void BfModule::EmitCtorBody(bool& skipBody) auto ctorDeclaration = (BfConstructorDeclaration*)methodDef->mMethodDeclaration; auto typeDef = mCurTypeInstance->mTypeDef; + BfCustomAttributes* customAttributes = NULL; + defer(delete customAttributes); + BfInvocationExpression* ctorInvocation = NULL; + + BfAttributeState attributeState; + attributeState.mTarget = BfAttributeTargets_MemberAccess; + if (ctorDeclaration != NULL) + { + ctorInvocation = BfNodeDynCast(ctorDeclaration->mInitializer); + if (auto attributedExpr = BfNodeDynCast(ctorDeclaration->mInitializer)) + { + ctorInvocation = BfNodeDynCast(attributedExpr->mExpression); + attributeState.mCustomAttributes = GetCustomAttributes(attributedExpr->mAttributes, attributeState.mTarget); + } + } + + SetAndRestoreValue prevAttributeState(mAttributeState, &attributeState); + // Prologue mBfIRBuilder->ClearDebugLocation(); bool hadThisInitializer = false; - if ((ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL)) + if ((ctorDeclaration != NULL) && (ctorInvocation != NULL)) { - auto targetToken = BfNodeDynCast(ctorDeclaration->mInitializer->mTarget); + auto targetToken = BfNodeDynCast(ctorInvocation->mTarget); auto targetType = (targetToken->GetToken() == BfToken_This) ? mCurTypeInstance : mCurTypeInstance->mBaseType; if (targetToken->GetToken() == BfToken_This) { @@ -15480,8 +15512,8 @@ void BfModule::EmitCtorBody(bool& skipBody) } BfAstNode* baseCtorNode = NULL; - if ((ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL) && (ctorDeclaration->mInitializer->mTarget != NULL)) - baseCtorNode = ctorDeclaration->mInitializer->mTarget; + if ((ctorDeclaration != NULL) && (ctorInvocation != NULL) && (ctorInvocation->mTarget != NULL)) + baseCtorNode = ctorInvocation->mTarget; else if (methodDef->mBody != NULL) baseCtorNode = methodDef->mBody; else if (ctorDeclaration != NULL) @@ -15493,10 +15525,12 @@ void BfModule::EmitCtorBody(bool& skipBody) else baseCtorNode = mContext->mBfObjectType->mTypeDef->mTypeDeclaration; - if ((!mCurTypeInstance->IsBoxed()) && (methodDef->mMethodType == BfMethodType_Ctor)) + bool calledCtorNoBody = false; + + if ((!mCurTypeInstance->IsBoxed()) && (methodDef->mMethodType == BfMethodType_Ctor) && (!hadThisInitializer)) { - // Call the root type's default ctor (with no body) to initialize its fields and call the chained ctors - if (methodDef->mDeclaringType->mTypeCode == BfTypeCode_Extension) + // Call the root type's default ctor (with no body) to initialize its fields and call the chained ctors + if (mCurTypeInstance->mTypeDef->mHasCtorNoBody) { BfMethodDef* defaultCtor = NULL; @@ -15520,6 +15554,8 @@ void BfModule::EmitCtorBody(bool& skipBody) SizedArray irArgs; exprEvaluator.PushThis(NULL, GetThis(), moduleMethodInstance.mMethodInstance, irArgs); exprEvaluator.CreateCall(moduleMethodInstance.mMethodInstance, moduleMethodInstance.mFunc, false, irArgs); + + calledCtorNoBody = true; } } } @@ -15533,7 +15569,7 @@ void BfModule::EmitCtorBody(bool& skipBody) { // Field initializers occur in CtorNoBody methods for extensions } - else if (!hadThisInitializer) + else if ((!hadThisInitializer) && (!calledCtorNoBody)) { // If we had a 'this' initializer, that other ctor will have initialized our fields @@ -15711,9 +15747,9 @@ void BfModule::EmitCtorBody(bool& skipBody) if (methodDef->mBody == NULL) SetIllegalSrcPos(); } - if ((ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL)) + if ((ctorDeclaration != NULL) && (ctorInvocation != NULL)) { - auto targetToken = BfNodeDynCast(ctorDeclaration->mInitializer->mTarget); + auto targetToken = BfNodeDynCast(ctorInvocation->mTarget); targetType = (targetToken->GetToken() == BfToken_This) ? mCurTypeInstance : mCurTypeInstance->mBaseType; } else if ((mCurTypeInstance->mBaseType != NULL) && (!mCurTypeInstance->IsUnspecializedType())) @@ -15801,9 +15837,9 @@ void BfModule::EmitCtorBody(bool& skipBody) mCurMethodState->mCurAppendAlign = methodInstance->mAppendAllocAlign; } - if ((ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL) && (ctorDeclaration->mInitializer->mArguments.size() == 1) && (targetType != NULL)) + if ((ctorDeclaration != NULL) && (ctorInvocation != NULL) && (ctorInvocation->mArguments.size() == 1) && (targetType != NULL)) { - if (auto tokenNode = BfNodeDynCast(ctorDeclaration->mInitializer->mArguments[0])) + if (auto tokenNode = BfNodeDynCast(ctorInvocation->mArguments[0])) { if (targetType == mCurTypeInstance) { @@ -15829,9 +15865,9 @@ void BfModule::EmitCtorBody(bool& skipBody) auto autoComplete = mCompiler->GetAutoComplete(); auto wasCapturingMethodInfo = (autoComplete != NULL) && (autoComplete->mIsCapturingMethodMatchInfo); - if ((autoComplete != NULL) && (ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL)) + if ((autoComplete != NULL) && (ctorDeclaration != NULL) && (ctorInvocation != NULL)) { - auto invocationExpr = ctorDeclaration->mInitializer; + auto invocationExpr = ctorInvocation; autoComplete->CheckInvocation(invocationExpr, invocationExpr->mOpenParen, invocationExpr->mCloseParen, invocationExpr->mCommas); } @@ -15839,9 +15875,9 @@ void BfModule::EmitCtorBody(bool& skipBody) auto target = Cast(targetRefNode, GetThis(), targetThisType); BfExprEvaluator exprEvaluator(this); BfResolvedArgs argValues; - if ((ctorDeclaration != NULL) && (ctorDeclaration->mInitializer != NULL)) + if ((ctorDeclaration != NULL) && (ctorInvocation != NULL)) { - argValues.Init(&ctorDeclaration->mInitializer->mArguments); + argValues.Init(&ctorInvocation->mArguments); if (gDebugStuff) { OutputDebugStrF("Expr: %@ %d\n", argValues.mArguments->mVals, argValues.mArguments->mSize); @@ -21367,6 +21403,8 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool Fail("Interfaces cannot contain constructors", methodDeclaration); } + bool foundHiddenMethod = false; + // Don't compare specialized generic methods against normal methods if ((((mCurMethodInstance->mIsUnspecialized) || (mCurMethodInstance->mMethodDef->mGenericParams.size() == 0))) && (!methodDef->mIsLocalMethod)) @@ -21436,7 +21474,8 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool if (!typeInstance->IsTypeMemberAccessible(checkMethod->mDeclaringType, methodDef->mDeclaringType)) continue; - bool silentlyAllow = false; + bool silentlyAllow = false; + bool extensionWarn = false; if (checkMethod->mDeclaringType != methodDef->mDeclaringType) { if (typeInstance->IsInterface()) @@ -21445,7 +21484,21 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool silentlyAllow = true; } else - silentlyAllow = true; + { + if ((methodDef->mDeclaringType->mProject != checkMethod->mDeclaringType->mProject) && + (!checkMethod->mDeclaringType->IsExtension())) + { + foundHiddenMethod = true; + if ((methodDef->mMethodType == BfMethodType_Ctor) && (methodDef->mIsStatic)) + silentlyAllow = true; + else if (methodDef->mIsNew) + silentlyAllow = true; + else + extensionWarn = true; + } + else + silentlyAllow = true; + } } if ((checkMethod->mCommutableKind == BfCommutableKind_Reverse) || (methodDef->mCommutableKind == BfCommutableKind_Reverse)) @@ -21456,7 +21509,13 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool if ((!methodDef->mName.IsEmpty()) || (checkMethodInstance->mMethodDef->mIsOperator)) { auto refNode = methodDef->GetRefNode(); - auto bfError = Fail("Method already declared with the same parameter types", refNode, true); + BfError* bfError; + if (extensionWarn) + bfError = Warn(BfWarning_CS0114_MethodHidesInherited, + StrFormat("This method hides a method in the root type definition. Use the 'new' keyword if the hiding was intentional. Note that this method is not callable from project '%s'.", + checkMethod->mDeclaringType->mProject->mName.c_str()), refNode); + else + bfError = Fail("Method already declared with the same parameter types", refNode, true); if (bfError != NULL) mCompiler->mPassInstance->MoreInfo("First declaration", checkMethod->GetRefNode()); } @@ -21472,8 +21531,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool (!methodDef->mIsLocalMethod) && (!methodInstance->mIsForeignMethodDef) && (typeInstance->mBaseType != NULL) && (methodDef->mMethodType == BfMethodType_Normal) && (methodDef->mMethodDeclaration != NULL)) - { - bool foundHiddenMethod = false; + { auto baseType = typeInstance->mBaseType; while (baseType != NULL) { @@ -21623,12 +21681,7 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo if (mCurTypeInstance->IsUnspecializedTypeVariation()) return false; - - if ((mCurTypeInstance->mTypeDef->mName->ToString() == "Zornk") && (methodInstance->mMethodDef->mName == "GCMarkMembers")) - { - NOP; - } - + auto _AddVirtualDecl = [&](BfMethodInstance* declMethodInstance) { if (!mCompiler->mOptions.mAllowHotSwapping) @@ -21956,13 +22009,17 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo { methodInstance->mVirtualTableIdx = virtualMethodMatchIdx; + bool preferRootDefinition = (methodDef->mName == BF_METHODNAME_MARKMEMBERS) || (methodDef->mMethodType == BfMethodType_Dtor); + + BfMethodInstance* setMethodInstance = methodInstance; + bool doOverride = false; + auto& overridenRef = typeInstance->mVirtualMethodTable[virtualMethodMatchIdx].mImplementingMethod; if (overridenRef.mKind != BfMethodRefKind_AmbiguousRef) { methodOverriden = overridenRef; - BfMethodInstance* setMethodInstance = methodInstance; - bool doOverride = true; + doOverride = true; if (methodOverriden->GetOwner() == methodInstance->GetOwner()) { bool isBetter = false; @@ -21990,7 +22047,7 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo if ((isBetter) && (methodInstance->GetOwner() == methodOverriden->GetOwner())) { - if (methodDef->mName == BF_METHODNAME_MARKMEMBERS) + if (preferRootDefinition) { // Leave the master GCMarkMember isBetter = false; @@ -22001,14 +22058,19 @@ bool BfModule::SlotVirtualMethod(BfMethodInstance* methodInstance, BfAmbiguityCo doOverride = isBetter; } } + } + else if ((preferRootDefinition) && (!methodDef->mDeclaringType->IsExtension())) + { + methodOverriden = overridenRef; + doOverride = true; + } - if (doOverride) - { - auto declMethodInstance = (BfMethodInstance*)typeInstance->mVirtualMethodTable[virtualMethodMatchIdx].mDeclaringMethod; - _AddVirtualDecl(declMethodInstance); - setMethodInstance->mVirtualTableIdx = virtualMethodMatchIdx; - typeInstance->mVirtualMethodTable[virtualMethodMatchIdx].mImplementingMethod = setMethodInstance; - } + if (doOverride) + { + auto declMethodInstance = (BfMethodInstance*)typeInstance->mVirtualMethodTable[virtualMethodMatchIdx].mDeclaringMethod; + _AddVirtualDecl(declMethodInstance); + setMethodInstance->mVirtualTableIdx = virtualMethodMatchIdx; + typeInstance->mVirtualMethodTable[virtualMethodMatchIdx].mImplementingMethod = setMethodInstance; } } diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 151e40e8..31878c9d 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -9147,8 +9147,23 @@ bool BfReducer::ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayIm MEMBER_SET(ctorDecl, mInitializerColonToken, endToken); mVisitorPos.MoveNext(); + BfAstNode* invokeAfter = ctorDecl; auto nextNode = mVisitorPos.GetNext(); - endToken = ExpectTokenAfter(ctorDecl, BfToken_This, BfToken_Base); + + BfAttributeDirective* attributeDirective = NULL; + if (auto nextToken = BfNodeDynCast(nextNode)) + { + if (nextToken->mToken == BfToken_LBracket) + { + mVisitorPos.MoveNext(); + attributeDirective = CreateAttributeDirective(nextToken); + nextNode = mVisitorPos.GetNext(); + if (attributeDirective != NULL) + invokeAfter = attributeDirective; + } + } + + endToken = ExpectTokenAfter(invokeAfter, BfToken_This, BfToken_Base); if (endToken != NULL) { auto invocationExpr = CreateInvocationExpression(endToken); @@ -9162,6 +9177,18 @@ bool BfReducer::ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayIm // In process of typing - just eat identifier so we don't error out on whole method MoveNode(identifierAfter, ctorDecl); } + + if (attributeDirective != NULL) + { + BfAttributedExpression* attribExpr = mAlloc->Alloc(); + ReplaceNode(attributeDirective, attribExpr); + attribExpr->mAttributes = attributeDirective; + if (ctorDecl->mInitializer != NULL) + { + MEMBER_SET(attribExpr, mExpression, ctorDecl->mInitializer); + } + MEMBER_SET(ctorDecl, mInitializer, attribExpr); + } } endToken = NULL; diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index 002b5ee8..712682fd 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -2640,6 +2640,7 @@ void BfSystem::InjectNewRevision(BfTypeDef* typeDef) typeDef->mIsConcrete = nextTypeDef->mIsConcrete; typeDef->mIsStatic = nextTypeDef->mIsStatic; typeDef->mHasAppendCtor = nextTypeDef->mHasAppendCtor; + typeDef->mHasCtorNoBody = nextTypeDef->mHasCtorNoBody; typeDef->mHasOverrideMethods = nextTypeDef->mHasOverrideMethods; typeDef->mHasExtensionMethods = nextTypeDef->mHasExtensionMethods; typeDef->mIsOpaque = nextTypeDef->mIsOpaque; @@ -2744,6 +2745,7 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co typeDef->mIsConcrete = partialTypeDef->mIsConcrete; typeDef->mIsStatic = partialTypeDef->mIsStatic; typeDef->mHasAppendCtor = partialTypeDef->mHasAppendCtor; + typeDef->mHasCtorNoBody = partialTypeDef->mHasCtorNoBody; typeDef->mHasExtensionMethods = partialTypeDef->mHasExtensionMethods; typeDef->mHasOverrideMethods = partialTypeDef->mHasOverrideMethods; @@ -2780,7 +2782,7 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co typeDef->mIsAbstract |= partialTypeDef->mIsAbstract; typeDef->mIsConcrete |= partialTypeDef->mIsConcrete; typeDef->mIsStatic |= partialTypeDef->mIsStatic; - typeDef->mHasAppendCtor |= partialTypeDef->mHasAppendCtor; + typeDef->mHasAppendCtor |= partialTypeDef->mHasAppendCtor; typeDef->mHasExtensionMethods |= partialTypeDef->mHasExtensionMethods; typeDef->mHasOverrideMethods |= partialTypeDef->mHasOverrideMethods; typeDef->mProtection = BF_MIN(typeDef->mProtection, partialTypeDef->mProtection); @@ -2956,6 +2958,7 @@ void BfSystem::FinishCompositePartial(BfTypeDef* compositeTypeDef) anyHasFieldInitializers = true; if (!isExtension) primaryHasFieldInitializers = true; + nextRevision->mHasCtorNoBody = true; auto methodDef = BfDefBuilder::AddMethod(nextRevision, BfMethodType_CtorNoBody, BfProtection_Protected, false, ""); methodDef->mDeclaringType = partialTypeDef; methodDef->mIsMutating = true; @@ -2964,6 +2967,7 @@ void BfSystem::FinishCompositePartial(BfTypeDef* compositeTypeDef) if ((anyHasFieldInitializers) && (!primaryHasFieldInitializers)) { + nextRevision->mHasCtorNoBody = true; auto methodDef = BfDefBuilder::AddMethod(nextRevision, BfMethodType_CtorNoBody, BfProtection_Protected, false, ""); methodDef->mDeclaringType = primaryDef; methodDef->mIsMutating = true; @@ -2991,6 +2995,7 @@ void BfSystem::FinishCompositePartial(BfTypeDef* compositeTypeDef) if ((allHasMethods[0][0].mDtor == 0) && (allHasMethods[1][0].mDtor > 1)) { + nextRevision->mDtorDef = NULL; auto methodDef = BfDefBuilder::AddMethod(nextRevision, BfMethodType_Dtor, BfProtection_Public, false, ""); methodDef->mDeclaringType = primaryDef; } diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index beb4cbf1..23234fe1 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -919,6 +919,7 @@ public: bool mIsConcrete; bool mIsStatic; bool mHasAppendCtor; + bool mHasCtorNoBody; bool mHasExtensionMethods; bool mHasOverrideMethods; bool mIsOpaque; @@ -956,6 +957,7 @@ public: mIsClosure = false; mIsStatic = false; mHasAppendCtor = false; + mHasCtorNoBody = false; mHasExtensionMethods = false; mHasOverrideMethods = false; mIsOpaque = false; diff --git a/IDEHelper/Tests/LibA/src/LibA0.bf b/IDEHelper/Tests/LibA/src/LibA0.bf index ce11ddb5..108c6c37 100644 --- a/IDEHelper/Tests/LibA/src/LibA0.bf +++ b/IDEHelper/Tests/LibA/src/LibA0.bf @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Diagnostics; namespace LibA { @@ -90,11 +91,18 @@ namespace LibA class LibClassA { - public int32 mA = GetVal(7, "LibA.LibClassA.mA"); + public int32 mA = GetVal(7, 10, "LibA.LibClassA.mA"); + + public static int32 sMagic = 1; + + public static this() + { + sMagic += 10; + } public this() { - PrintF("LibA.LibClassA()\n"); + Debug.WriteLine("LibA.LibClassA()\n"); mA += 100; } @@ -103,9 +111,15 @@ class LibClassA mA += a; } - public static int32 GetVal(int32 val, String str) + public ~this() { - PrintF("GetVal: %s\n", str.CStr()); + sMagic += 20; + } + + public static int32 GetVal(int32 val, int32 magic, String str) + { + Debug.WriteLine("GetVal: {}", str); + sMagic += magic; return val; } @@ -118,6 +132,11 @@ class LibClassA { return 30; } + + public static LibClassA Create() + { + return new LibClassA(); + } } class LibClassB diff --git a/IDEHelper/Tests/LibB/src/LibB0.bf b/IDEHelper/Tests/LibB/src/LibB0.bf index 3a8cbc5a..402b71c8 100644 --- a/IDEHelper/Tests/LibB/src/LibB0.bf +++ b/IDEHelper/Tests/LibB/src/LibB0.bf @@ -14,15 +14,25 @@ namespace LibB extension LibClassA { - public int32 mB = GetVal(8, "LibB.LibClassA.mB"); + public int32 mB = GetVal(8, 100, "LibB.LibClassA.mB"); - public this() + public static this() + { + sMagic += 100; + } + + public ~this() + { + sMagic += 200; + } + + public new this() : [NoExtension]this() { PrintF("LibB.LibClassA()\n"); mB += 100; } - public this(int32 a) + public new this(int32 a) { PrintF("LibB.LibClassA(int32)\n"); mB += 1000; diff --git a/IDEHelper/Tests/LibC/src/LibC0.bf b/IDEHelper/Tests/LibC/src/LibC0.bf index 93ddfe51..c7cdb4f5 100644 --- a/IDEHelper/Tests/LibC/src/LibC0.bf +++ b/IDEHelper/Tests/LibC/src/LibC0.bf @@ -12,7 +12,17 @@ namespace LibC extension LibClassA { - public int32 mB = GetVal(13, "LibC.LibClassA.mB"); + public int32 mB = GetVal(13, 1000, "LibC.LibClassA.mB"); + + public static this() + { + sMagic += 1000; + } + + public ~this() + { + sMagic += 2000; + } public this(int8 i8) { diff --git a/IDEHelper/Tests/TestsB/src/TestsB0.bf b/IDEHelper/Tests/TestsB/src/TestsB0.bf index 74d1fd44..e571e317 100644 --- a/IDEHelper/Tests/TestsB/src/TestsB0.bf +++ b/IDEHelper/Tests/TestsB/src/TestsB0.bf @@ -2,15 +2,15 @@ using System; extension LibClassA { - public int32 mC = GetVal(9, "TestsB.LibClassA.mC"); + public int32 mC = GetVal(9, 10000, "TestsB.LibClassA.mC"); - public this() + public new this() { PrintF("TestB.LibClassA()\n"); mB += 10000; } - public int GetVal2() + public new int GetVal2() { return 11; } diff --git a/IDEHelper/Tests/src/Extensions.bf b/IDEHelper/Tests/src/Extensions.bf index 0b85013b..8a2b897c 100644 --- a/IDEHelper/Tests/src/Extensions.bf +++ b/IDEHelper/Tests/src/Extensions.bf @@ -227,21 +227,32 @@ namespace Tests [Test] public static void TestSharedData() { + Test.Assert(LibClassA.sMagic == 1111); + LibClassA ca = scope LibClassA(); - Test.Assert(ca.mA == 7); + Test.Assert(LibClassA.sMagic == 2221); + Test.Assert(ca.mA == 107); Test.Assert(ca.LibB_GetB() == 108); Test.Assert(ca.LibC_GetB() == 13); Test.Assert(ca.GetVal2() == 9); ca = scope LibClassA(12345); + Test.Assert(LibClassA.sMagic == 3331); Test.Assert(ca.mA == 7); Test.Assert(ca.LibB_GetB() == 1008); Test.Assert(ca.LibC_GetB() == 13); ca = scope LibClassA((int8)2); + Test.Assert(LibClassA.sMagic == 4441); Test.Assert(ca.mA == 7); Test.Assert(ca.LibB_GetB() == 8); Test.Assert(ca.LibC_GetB() == 30013); + + ca = LibClassA.Create(); + Test.Assert(LibClassA.sMagic == 5551); + Test.Assert(ca.mA == 107); + delete ca; + Test.Assert(LibClassA.sMagic == 7771); } [Test]