From 04ea8a66349843be9b68aa26f6d547d8fb44323b Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 6 Nov 2024 07:31:55 -0500 Subject: [PATCH] Generic constructors --- IDEHelper/Compiler/BfAst.cpp | 5 + IDEHelper/Compiler/BfAst.h | 13 +++ IDEHelper/Compiler/BfDefBuilder.cpp | 11 +- IDEHelper/Compiler/BfElementVisitor.cpp | 10 ++ IDEHelper/Compiler/BfElementVisitor.h | 1 + IDEHelper/Compiler/BfExprEvaluator.cpp | 89 +++++++++++---- IDEHelper/Compiler/BfExprEvaluator.h | 2 +- IDEHelper/Compiler/BfModule.cpp | 10 +- IDEHelper/Compiler/BfModuleTypeUtils.cpp | 2 +- IDEHelper/Compiler/BfPrinter.cpp | 4 + IDEHelper/Compiler/BfReducer.cpp | 133 +++++++++++++++++++++-- IDEHelper/Compiler/BfReducer.h | 2 +- IDEHelper/Tests/src/Generics.bf | 22 ++++ 13 files changed, 267 insertions(+), 37 deletions(-) diff --git a/IDEHelper/Compiler/BfAst.cpp b/IDEHelper/Compiler/BfAst.cpp index e8945e2a..50a5027a 100644 --- a/IDEHelper/Compiler/BfAst.cpp +++ b/IDEHelper/Compiler/BfAst.cpp @@ -116,6 +116,11 @@ void BfStructuralVisitor::Visit(BfGenericArgumentsNode* genericArgumentsNode) Visit(genericArgumentsNode->ToBase()); } +void BfStructuralVisitor::Visit(BfCtorExplicitNode* ctorExplicitNode) +{ + Visit(ctorExplicitNode->ToBase()); +} + void BfStructuralVisitor::Visit(BfStatement* stmt) { Visit(stmt->ToBase()); diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index 00a74785..229f4119 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -337,6 +337,7 @@ class BfScopeNode; class BfNewNode; class BfLabeledBlock; class BfGenericArgumentsNode; +class BfCtorExplicitNode; class BfStatement; class BfLabelableStatement; class BfExpression; @@ -529,6 +530,7 @@ public: virtual void Visit(BfGenericOperatorConstraint* genericConstraints); virtual void Visit(BfGenericConstraintsDeclaration* genericConstraints); virtual void Visit(BfGenericArgumentsNode* genericArgumentsNode); + virtual void Visit(BfCtorExplicitNode* genericArgumentsNode); virtual void Visit(BfEmptyStatement* emptyStmt); virtual void Visit(BfTokenNode* tokenNode); @@ -2911,6 +2913,16 @@ public: BfAstNode* mStatement; }; BF_AST_DECL(BfAttributedStatement, BfStatement); +class BfCtorExplicitNode : public BfAstNode +{ +public: + BF_AST_TYPE(BfCtorExplicitNode, BfAstNode); + + BfAstNode* mDotToken; + BfTokenNode* mThisToken; + BfGenericArgumentsNode* mGenericArgs; +}; BF_AST_DECL(BfCtorExplicitNode, BfAstNode); + class BfObjectCreateExpression : public BfMethodBoundExpression { public: @@ -2919,6 +2931,7 @@ public: BfAstNode* mNewNode; BfTokenNode* mStarToken; BfTypeReference* mTypeRef; + BfCtorExplicitNode* mCtorExplicit; BfTokenNode* mOpenToken; BfTokenNode* mCloseToken; BfSizedArray mArguments; diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index 35fd6068..79c71ada 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -604,7 +604,8 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio if ((methodDef->mMethodType == BfMethodType_Normal) || (methodDef->mMethodType == BfMethodType_Operator) || (methodDef->mMethodType == BfMethodType_Mixin) || - (methodDef->mMethodType == BfMethodType_Extension)) + (methodDef->mMethodType == BfMethodType_Extension) || + (methodDef->mMethodType == BfMethodType_Ctor)) { bool isGeneric = (methodDeclaration->mGenericParams != NULL) || (!mCurTypeDef->mGenericParamDefs.IsEmpty()); ParseGenericParams(methodDeclaration->mGenericParams, methodDeclaration->mGenericConstraintsDeclaration, methodDef->mGenericParams, &methodDef->mExternalConstraints, outerGenericSize, isGeneric); @@ -2085,6 +2086,14 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) methodDef->mParams.push_back(newParam); } + for (auto genericParam : method->mGenericParams) + { + BfGenericParamDef* newGenericParam = new BfGenericParamDef(); + *newGenericParam = *genericParam; + methodDef->mGenericParams.Add(newGenericParam); + } + methodDef->mExternalConstraints = method->mExternalConstraints; + // Insert a 'appendIdx' BfParameterDef* newParam = new BfParameterDef(); newParam->mName = "appendIdx"; diff --git a/IDEHelper/Compiler/BfElementVisitor.cpp b/IDEHelper/Compiler/BfElementVisitor.cpp index ae457245..05300009 100644 --- a/IDEHelper/Compiler/BfElementVisitor.cpp +++ b/IDEHelper/Compiler/BfElementVisitor.cpp @@ -114,6 +114,15 @@ void BfElementVisitor::Visit(BfGenericArgumentsNode* genericArgumentsNode) VisitChild(genericArgumentsNode->mCloseChevron); } +void BfElementVisitor::Visit(BfCtorExplicitNode* ctorExplicitNode) +{ + Visit(ctorExplicitNode->ToBase()); + + VisitChild(ctorExplicitNode->mDotToken); + VisitChild(ctorExplicitNode->mThisToken); + VisitChild(ctorExplicitNode->mGenericArgs); +} + void BfElementVisitor::Visit(BfStatement* stmt) { Visit(stmt->ToBase()); @@ -627,6 +636,7 @@ void BfElementVisitor::Visit(BfObjectCreateExpression* newExpr) VisitChild(newExpr->mNewNode); VisitChild(newExpr->mStarToken); VisitChild(newExpr->mTypeRef); + VisitChild(newExpr->mCtorExplicit); VisitChild(newExpr->mOpenToken); VisitChild(newExpr->mCloseToken); for (auto& val : newExpr->mArguments) diff --git a/IDEHelper/Compiler/BfElementVisitor.h b/IDEHelper/Compiler/BfElementVisitor.h index dc8d1115..9e16a604 100644 --- a/IDEHelper/Compiler/BfElementVisitor.h +++ b/IDEHelper/Compiler/BfElementVisitor.h @@ -33,6 +33,7 @@ public: virtual void Visit(BfGenericOperatorConstraint* genericConstraints); virtual void Visit(BfGenericConstraintsDeclaration* genericConstraints); virtual void Visit(BfGenericArgumentsNode* genericArgumentsNode); + virtual void Visit(BfCtorExplicitNode* genericArgumentsNode); virtual void Visit(BfEmptyStatement* emptyStmt); virtual void Visit(BfTokenNode* tokenNode); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 438048b6..6f9781d4 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -7977,7 +7977,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu arrayType, false); BfResolvedArgs resolvedArgs; - MatchConstructor(targetSrc, NULL, expandedParamsArray, arrayType, resolvedArgs, false, false); + MatchConstructor(targetSrc, NULL, expandedParamsArray, arrayType, resolvedArgs, false, BfMethodGenericArguments(), false); //TODO: Assert 'length' var is at slot 1 auto arrayBits = mModule->mBfIRBuilder->CreateBitCast(expandedParamsArray.mValue, mModule->mBfIRBuilder->MapType(arrayType->mBaseType)); @@ -8742,7 +8742,8 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu return callResult; } -BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBoundExpression* methodBoundExpr, BfTypedValue target, BfTypeInstance* targetType, BfResolvedArgs& argValues, bool callCtorBodyOnly, bool allowAppendAlloc, BfTypedValue* appendIndexValue) +BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBoundExpression* methodBoundExpr, BfTypedValue target, BfTypeInstance* targetType, BfResolvedArgs& argValues, bool callCtorBodyOnly, + const BfMethodGenericArguments& methodGenericArguments, bool allowAppendAlloc, BfTypedValue* appendIndexValue) { // Temporarily disable so we don't capture calls in params SetAndRestoreValue prevBindResult(mFunctionBindResult, NULL); @@ -8750,7 +8751,7 @@ BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBou static int sCtorCount = 0; sCtorCount++; - BfMethodMatcher methodMatcher(targetSrc, mModule, "", argValues.mResolvedArgs, BfMethodGenericArguments()); + BfMethodMatcher methodMatcher(targetSrc, mModule, "", argValues.mResolvedArgs, methodGenericArguments); methodMatcher.mBfEvalExprFlags = mBfEvalExprFlags; BfTypeVector typeGenericArguments; @@ -8842,11 +8843,13 @@ BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBou // There should always be a constructor BF_ASSERT(methodMatcher.mBestMethodDef != NULL); - auto moduleMethodInstance = mModule->GetMethodInstance(methodMatcher.mBestMethodTypeInstance, methodMatcher.mBestMethodDef, methodMatcher.mBestMethodGenericArguments); - if (!mModule->CheckUseMethodInstance(moduleMethodInstance.mMethodInstance, targetSrc)) - { + //auto moduleMethodInstance = mModule->GetMethodInstance(methodMatcher.mBestMethodTypeInstance, methodMatcher.mBestMethodDef, methodMatcher.mBestMethodGenericArguments); + + auto moduleMethodInstance = GetSelectedMethod(methodMatcher); + if (!moduleMethodInstance) return BfTypedValue(); - } + if (!mModule->CheckUseMethodInstance(moduleMethodInstance.mMethodInstance, targetSrc)) + return BfTypedValue(); BfAutoComplete* autoComplete = GetAutoComplete(); if (autoComplete != NULL) @@ -10142,7 +10145,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp mResultLocalVar = NULL; mResultFieldInstance = NULL; mResultLocalVarRefNode = NULL; - auto result = MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, resolvedTypeInstance->IsObject()); + auto result = MatchConstructor(targetSrc, methodBoundExpr, structInst, resolvedTypeInstance, argValues, false, BfMethodGenericArguments(), resolvedTypeInstance->IsObject()); if ((result) && (!result.mType->IsVoid())) return result; mModule->ValidateAllocation(resolvedTypeInstance, targetSrc); @@ -14042,7 +14045,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) } BfResolvedArgs resolvedArgs; - MatchConstructor(delegateBindExpr, delegateBindExpr, mResult, useTypeInstance, resolvedArgs, false, false); + MatchConstructor(delegateBindExpr, delegateBindExpr, mResult, useTypeInstance, resolvedArgs, false, BfMethodGenericArguments(), false); auto baseDelegateType = VerifyBaseDelegateType(delegateTypeInstance->mBaseType); auto baseDelegate = mModule->mBfIRBuilder->CreateBitCast(mResult.mValue, mModule->mBfIRBuilder->MapType(baseDelegateType, BfIRPopulateType_Full)); @@ -15490,6 +15493,10 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs } } + BfMethodGenericArguments methodGenericArguments; + if ((objCreateExpr != NULL) && (objCreateExpr->mCtorExplicit != NULL) && (objCreateExpr->mCtorExplicit->mGenericArgs != NULL)) + methodGenericArguments.mArguments = &objCreateExpr->mCtorExplicit->mGenericArgs->mGenericArgs; + CheckObjectCreateTypeRef(mExpectingType, allocNode); BfAttributeState attributeState; @@ -15499,12 +15506,18 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs BfAllocTarget allocTarget; ResolveAllocTarget(allocTarget, allocNode, newToken, &attributeState.mCustomAttributes); - bool isScopeAlloc = newToken->GetToken() == BfToken_Scope; - bool isAppendAlloc = newToken->GetToken() == BfToken_Append; - bool isStackAlloc = (newToken->GetToken() == BfToken_Stack) || (isScopeAlloc); + bool isStructAlloc = newToken == NULL; + bool isScopeAlloc = (newToken != NULL) && (newToken->GetToken() == BfToken_Scope); + bool isAppendAlloc = (newToken != NULL) && (newToken->GetToken() == BfToken_Append); + bool isStackAlloc = ((newToken != NULL) && (newToken->GetToken() == BfToken_Stack)) || (isScopeAlloc) || (isStructAlloc); bool isArrayAlloc = false;// (objCreateExpr->mArraySizeSpecifier != NULL); bool isRawArrayAlloc = (objCreateExpr != NULL) && (objCreateExpr->mStarToken != NULL); + if ((objCreateExpr != NULL) && (objCreateExpr->mCtorExplicit != NULL) && (objCreateExpr->mCtorExplicit->mThisToken != NULL)) + { + mModule->SetElementType(objCreateExpr->mCtorExplicit->mThisToken, BfSourceElementType_Method); + } + if (isScopeAlloc) { if ((mBfEvalExprFlags & BfEvalExprFlags_FieldInitializer) != 0) @@ -15579,6 +15592,10 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs { unresolvedTypeRef = mExpectingType->GetUnderlyingType(); } + else if (mExpectingType->IsStruct()) + { + unresolvedTypeRef = mExpectingType; + } else if (mExpectingType->IsVar()) unresolvedTypeRef = mExpectingType; } @@ -16107,18 +16124,18 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs } break; } - + BfResolvedArgs resolvedArgs; auto rawAutoComplete = mModule->mCompiler->GetAutoComplete(); if (rawAutoComplete != NULL) { SetAndRestoreValue prevCapturing(rawAutoComplete->mIsCapturingMethodMatchInfo, false); - MatchConstructor(refNode, objCreateExpr, arrayValue, arrayType, resolvedArgs, false, false); + MatchConstructor(refNode, objCreateExpr, arrayValue, arrayType, resolvedArgs, false, methodGenericArguments, false); } else { - MatchConstructor(refNode, objCreateExpr, arrayValue, arrayType, resolvedArgs, false, false); + MatchConstructor(refNode, objCreateExpr, arrayValue, arrayType, resolvedArgs, false, methodGenericArguments, false); } //TODO: Assert 'length' var is at slot 1 @@ -16294,7 +16311,11 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs { auto wasCapturingMethodInfo = autoComplete->mIsCapturingMethodMatchInfo; autoComplete->CheckInvocation(objCreateExpr, objCreateExpr->mOpenToken, objCreateExpr->mCloseToken, objCreateExpr->mCommas); - MatchConstructor(objCreateExpr->mTypeRef, objCreateExpr, emtpyThis, typeInstance, argValues, false, true); + + BfAstNode* refNode = objCreateExpr->mTypeRef; + if ((objCreateExpr->mCtorExplicit != NULL) && (objCreateExpr->mCtorExplicit->mThisToken != NULL)) + refNode = objCreateExpr->mCtorExplicit->mThisToken; + MatchConstructor(refNode, objCreateExpr, emtpyThis, typeInstance, argValues, false, methodGenericArguments, true); if ((wasCapturingMethodInfo) && (!autoComplete->mIsCapturingMethodMatchInfo)) { if (autoComplete->mMethodMatchInfo != NULL) @@ -16308,7 +16329,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs auto refNode = allocNode; if (objCreateExpr != NULL) refNode = objCreateExpr->mTypeRef; - MatchConstructor(refNode, objCreateExpr, emtpyThis, typeInstance, argValues, false, true); + MatchConstructor(refNode, objCreateExpr, emtpyThis, typeInstance, argValues, false, methodGenericArguments, true); } if (objCreateExpr != NULL) mModule->ValidateAllocation(typeInstance, objCreateExpr->mTypeRef); @@ -16329,7 +16350,16 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs } else { - auto calcAppendMethodModule = mModule->GetMethodInstanceAtIdx(bindResult.mMethodInstance->GetOwner(), bindResult.mMethodInstance->mMethodDef->mIdx + 1, BF_METHODNAME_CALCAPPEND); + //auto calcAppendMethodModule = mModule->GetMethodInstanceAtIdx(bindResult.mMethodInstance->GetOwner(), bindResult.mMethodInstance->mMethodDef->mIdx + 1, BF_METHODNAME_CALCAPPEND); + + BfTypeVector methodGenericArguments; + if (bindResult.mMethodInstance->mMethodInfoEx != NULL) + methodGenericArguments = bindResult.mMethodInstance->mMethodInfoEx->mMethodGenericArguments; + + auto methodOwner = bindResult.mMethodInstance->GetOwner(); + auto calcAppendMethodDef = methodOwner->mTypeDef->mMethods[bindResult.mMethodInstance->mMethodDef->mIdx + 1]; + BF_ASSERT(calcAppendMethodDef->mName == BF_METHODNAME_CALCAPPEND); + auto calcAppendMethodModule = mModule->GetMethodInstance(methodOwner, calcAppendMethodDef, methodGenericArguments); SizedArray irArgs; if (bindResult.mIRArgs.size() > 1) @@ -16523,6 +16553,17 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs { mModule->mCompiler->mCeMachine->ClearAppendAllocInfo(); } + + if ((mResult) && (isStructAlloc)) + { + if (mResult.mType->IsPointer()) + { + mResult = mModule->LoadValue(mResult); + mResult = BfTypedValue(mResult.mValue, mResult.mType->GetUnderlyingType(), true); + } + else + mModule->Fail(StrFormat("Allocation specifier such as 'new' is required for reference type '%s'", mModule->TypeToString(mResult.mType).c_str()), objCreateExpr); + } } void BfExprEvaluator::Visit(BfBoxExpression* boxExpr) @@ -16612,7 +16653,13 @@ void BfExprEvaluator::ResolveAllocTarget(BfAllocTarget& allocTarget, BfAstNode* allocTarget.mRefNode = allocNode; newToken = BfNodeDynCast(allocNode); - if (newToken == NULL) + if (allocNode == NULL) + { + // Scope + if (mModule->mCurMethodState != NULL) + allocTarget.mScopeData = mModule->mCurMethodState->mCurScope->GetTargetable(); + } + else if (newToken == NULL) { if (auto scopeNode = BfNodeDynCast(allocNode)) { @@ -18269,7 +18316,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, false); + auto ctorResult = MatchConstructor(target, methodBoundExpr, mResult, expectingType->ToTypeInstance(), argValues, false, BfMethodGenericArguments(), false); if ((ctorResult) && (!ctorResult.mType->IsVoid())) mResult = ctorResult; mModule->ValidateAllocation(expectingType, invocationExpr->mTarget); @@ -23591,7 +23638,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, false); + auto result = MatchConstructor(opToken, NULL, mResult, allocType, argValues, true, BfMethodGenericArguments(), false); if ((result) && (!result.mType->IsVoid())) mResult = result; diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index 4a2df611..1899a489 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -497,7 +497,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, bool allowAppendAlloc, BfTypedValue* appendIndexValue = NULL); + BfResolvedArgs& argValues, bool callCtorBodyOnly, const BfMethodGenericArguments& methodGenericArguments, bool allowAppendAlloc, 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 ca0c8337..4167f860 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -778,7 +778,7 @@ public: if (typeInst != NULL) { exprEvaluator.ResolveArgValues(argValues); - exprEvaluator.MatchConstructor(objCreateExpr->mTypeRef, objCreateExpr, emtpyThis, typeInst, argValues, false, true); + exprEvaluator.MatchConstructor(objCreateExpr->mTypeRef, objCreateExpr, emtpyThis, typeInst, argValues, false, BfMethodGenericArguments(), true); } exprEvaluator.mFunctionBindResult = NULL; @@ -4765,7 +4765,7 @@ void BfModule::AppendedObjectInit(BfFieldInstance* fieldInst) mBfIRBuilder->CreateStore(GetConstValue8(BfObjectFlag_AppendAlloc), thisFlagsPtr); } - exprEvaluator.MatchConstructor(fieldDef->GetNameNode(), NULL, thisValue, fieldInst->mResolvedType->ToTypeInstance(), resolvedArgs, false, true, &indexVal); + exprEvaluator.MatchConstructor(fieldDef->GetNameNode(), NULL, thisValue, fieldInst->mResolvedType->ToTypeInstance(), resolvedArgs, false, BfMethodGenericArguments(), true, &indexVal); } void BfModule::CheckInterfaceMethod(BfMethodInstance* methodInstance) @@ -17149,7 +17149,7 @@ BfTypedValue BfModule::CallBaseCtorCalc(bool constOnly) SetAndRestoreValue prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true); exprEvaluator.ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval); SetAndRestoreValue prevBindResult(exprEvaluator.mFunctionBindResult, &bindResult); - exprEvaluator.MatchConstructor(targetRefNode, NULL, target, targetType, argValues, true, true); + exprEvaluator.MatchConstructor(targetRefNode, NULL, target, targetType, argValues, true, BfMethodGenericArguments(), true); } if (bindResult.mMethodInstance == NULL) @@ -17196,7 +17196,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, true); + exprEvaluator.MatchConstructor(targetRefNode, NULL, target, targetType, argValues, true, BfMethodGenericArguments(), true); BF_ASSERT(bindResult.mIRArgs[0].IsFake()); bindResult.mIRArgs.RemoveAt(0); calcAppendArgs = bindResult.mIRArgs; @@ -18704,7 +18704,7 @@ void BfModule::EmitCtorBody(bool& skipBody) 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, methodDef->mHasAppend, &appendIdxVal); + exprEvaluator.MatchConstructor(targetRefNode, NULL, target, targetType, argValues, true, BfMethodGenericArguments(), methodDef->mHasAppend, &appendIdxVal); if (autoComplete != NULL) { diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index e6884f80..867a466d 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -5537,7 +5537,7 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy BfTypedValue emptyThis(mBfIRBuilder->GetFakeVal(), resolvedTypeRef, resolvedTypeRef->IsStruct()); exprEvaluator.mBfEvalExprFlags = BfEvalExprFlags_Comptime; - auto ctorResult = exprEvaluator.MatchConstructor(nameRefNode, NULL, emptyThis, fieldTypeInst, resolvedArgs, false, true); + auto ctorResult = exprEvaluator.MatchConstructor(nameRefNode, NULL, emptyThis, fieldTypeInst, resolvedArgs, false, BfMethodGenericArguments(), true); if ((bindResult.mMethodInstance != NULL) && (bindResult.mMethodInstance->mMethodDef->mHasAppend)) { diff --git a/IDEHelper/Compiler/BfPrinter.cpp b/IDEHelper/Compiler/BfPrinter.cpp index 6421be52..b2c81ae4 100644 --- a/IDEHelper/Compiler/BfPrinter.cpp +++ b/IDEHelper/Compiler/BfPrinter.cpp @@ -1913,6 +1913,7 @@ void BfPrinter::Visit(BfObjectCreateExpression* newExpr) ExpectSpace(); VisitChild(newExpr->mTypeRef); + VisitChild(newExpr->mCtorExplicit); if (newExpr->mStarToken != NULL) { @@ -2497,6 +2498,7 @@ void BfPrinter::Visit(BfConstructorDeclaration* ctorDeclaration) { QueueVisitChild(ctorDeclaration->mThisToken); } + QueueVisitChild(ctorDeclaration->mGenericParams); QueueVisitChild(ctorDeclaration->mOpenParen); for (int i = 0; i < (int) ctorDeclaration->mParams.size(); i++) @@ -2513,6 +2515,8 @@ void BfPrinter::Visit(BfConstructorDeclaration* ctorDeclaration) QueueVisitChild(ctorDeclaration->mInitializerColonToken); ExpectSpace(); QueueVisitChild(ctorDeclaration->mInitializer); + ExpectSpace(); + QueueVisitChild(ctorDeclaration->mGenericConstraintsDeclaration); if (ctorDeclaration->mFatArrowToken != NULL) { diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index 72a93b0a..26b2f4b2 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -2051,17 +2051,30 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat return caseExpr; } else if (token == BfToken_Dot) // Abbreviated dot syntax ".EnumVal" - { - // Initializer ".{ x = 1, y = 2 }" + { + bool handled = false; + if (auto nextTokenNode = BfNodeDynCast(mVisitorPos.GetNext())) + { + if (nextTokenNode->mToken == BfToken_This) + { + auto invocationExpr = CreateObjectCreateExpression(NULL, tokenNode); + if (invocationExpr == NULL) + return exprLeft; + exprLeft = invocationExpr; + handled = true; + } + } + if (auto blockNode = BfNodeDynCast(mVisitorPos.GetNext())) { + // Initializer ".{ x = 1, y = 2 }" auto typeRef = CreateTypeRef(mVisitorPos.GetCurrent()); if (typeRef) { exprLeft = TryCreateInitializerExpression(typeRef); } } - else + else if (!handled) { auto memberReferenceExpr = mAlloc->Alloc(); ReplaceNode(tokenNode, memberReferenceExpr); @@ -2933,6 +2946,29 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat BF_ASSERT(tokenNode->GetToken() == token); + if (token == BfToken_Dot) + { + if (auto nextToken = BfNodeDynCast(mVisitorPos.Get(mVisitorPos.mReadPos + 2))) + { + if (nextToken->mToken == BfToken_This) + { + int outNodeIdx = -1; + bool isGenericType; + bool isTypeRef = ((IsTypeReference(exprLeft, BfToken_This, -1, &outNodeIdx, NULL, &isGenericType)) && + (outNodeIdx != -1)); + + if (isTypeRef) + { + auto invocationExpr = CreateObjectCreateExpression(NULL, exprLeft); + if (invocationExpr == NULL) + return exprLeft; + exprLeft = invocationExpr; + continue; + } + } + } + } + // Not a binary op, it's a 'close' if (token == BfToken_Bang) { @@ -4875,6 +4911,11 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF } firstNode = qualifiedTypeRef; } + else if (auto typeRef = BfNodeDynCast(firstNode)) + { + // Already a typeRef + return typeRef; + } else { bool isHandled = false; @@ -5169,6 +5210,15 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF BfToken token = tokenNode->GetToken(); if (token == BfToken_Dot) { + if (auto nextToken = BfNodeDynCast(mVisitorPos.Get(mVisitorPos.mReadPos + 2))) + { + if (nextToken->mToken == BfToken_This) + { + // Don't encode '.this' in type ref + break; + } + } + BfQualifiedTypeReference* qualifiedTypeRef = mAlloc->Alloc(); ReplaceNode(typeRef, qualifiedTypeRef); qualifiedTypeRef->mLeft = typeRef; @@ -5216,6 +5266,15 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF { if (tokenNode->GetToken() == BfToken_Dot) { + if (auto nextToken = BfNodeDynCast(mVisitorPos.Get(mVisitorPos.mReadPos + 2))) + { + if (nextToken->mToken == BfToken_This) + { + // Don't encode '.this' in type ref + break; + } + } + BfQualifiedTypeReference* outerQualifiedTypeRef = mAlloc->Alloc(); ReplaceNode(qualifiedTypeRef, outerQualifiedTypeRef); outerQualifiedTypeRef->mLeft = qualifiedTypeRef; @@ -5578,6 +5637,11 @@ BfIdentifierNode* BfReducer::CompactQualifiedName(BfAstNode* leftNode) { if (auto rightToken = BfNodeDynCast(nextNextToken)) { + if (rightToken->mToken == BfToken_This) + { + return leftIdentifier; + } + if (BfTokenIsKeyword(rightToken->mToken)) { rightIdentifier = mAlloc->Alloc(); @@ -8122,14 +8186,26 @@ BfAstNode* BfReducer::CreateAllocNode(BfTokenNode* allocToken) return allocToken; } -BfObjectCreateExpression* BfReducer::CreateObjectCreateExpression(BfAstNode* allocNode) +BfObjectCreateExpression* BfReducer::CreateObjectCreateExpression(BfAstNode* allocNode, BfAstNode* targetNode) { auto objectCreateExpr = mAlloc->Alloc(); BfDeferredAstSizedArray arguments(objectCreateExpr->mArguments, mAlloc); BfDeferredAstSizedArray commas(objectCreateExpr->mCommas, mAlloc); - ReplaceNode(allocNode, objectCreateExpr); - MEMBER_SET(objectCreateExpr, mNewNode, allocNode); + BfTypeReference* typeRef = NULL; + + if (allocNode != NULL) + { + ReplaceNode(allocNode, objectCreateExpr); + MEMBER_SET(objectCreateExpr, mNewNode, allocNode); + } + else + { + ReplaceNode(targetNode, objectCreateExpr); + typeRef = CreateTypeRef(targetNode); + if (typeRef == NULL) + return NULL; + } auto nextNode = mVisitorPos.GetNext(); @@ -8145,7 +8221,8 @@ BfObjectCreateExpression* BfReducer::CreateObjectCreateExpression(BfAstNode* all // } // } - auto typeRef = CreateTypeRefAfter(objectCreateExpr); + if (typeRef == NULL) + typeRef = CreateTypeRefAfter(objectCreateExpr); if (typeRef == NULL) return objectCreateExpr; @@ -8206,6 +8283,42 @@ BfObjectCreateExpression* BfReducer::CreateObjectCreateExpression(BfAstNode* all } else { + auto nextToken = BfNodeDynCast(mVisitorPos.GetNext()); + auto nextNextToken = BfNodeDynCast(mVisitorPos.Get(mVisitorPos.mReadPos + 2)); + if ((nextToken != NULL) && (nextToken->mToken == BfToken_Dot) && + (nextNextToken != NULL) && (nextNextToken->mToken == BfToken_This)) + { + auto ctorExplicitNode = mAlloc->Alloc(); + ReplaceNode(nextToken, ctorExplicitNode); + ctorExplicitNode->mDotToken = nextToken; + MEMBER_SET(ctorExplicitNode, mThisToken, nextNextToken); + mVisitorPos.MoveNext(); + mVisitorPos.MoveNext(); + MEMBER_SET(objectCreateExpr, mCtorExplicit, ctorExplicitNode); + } + else if ((nextToken != NULL) && (nextToken->mToken == BfToken_This)) + { + auto ctorExplicitNode = mAlloc->Alloc(); + ReplaceNode(nextToken, ctorExplicitNode); + ctorExplicitNode->mThisToken = nextToken; + mVisitorPos.MoveNext(); + MEMBER_SET(objectCreateExpr, mCtorExplicit, ctorExplicitNode); + } + + if (objectCreateExpr->mCtorExplicit != NULL) + { + nextToken = BfNodeDynCast(mVisitorPos.GetNext()); + if ((nextToken->mToken != NULL) && (nextToken->mToken == BfToken_LChevron)) + { + mVisitorPos.MoveNext(); + auto genericParamsDecl = CreateGenericArguments(nextToken, true); + if (genericParamsDecl == NULL) + return objectCreateExpr; + MEMBER_SET(objectCreateExpr->mCtorExplicit, mGenericArgs, genericParamsDecl); + objectCreateExpr->mSrcEnd = objectCreateExpr->mCtorExplicit->mSrcEnd; + } + } + // Note- if there WERE an LBracket here then we'd have an 'isArray' case. We pass this in here for // error display purposes tokenNode = ExpectTokenAfter(objectCreateExpr, BfToken_LParen, BfToken_LBracket); @@ -8308,6 +8421,12 @@ BfMemberReferenceExpression* BfReducer::CreateMemberReferenceExpression(BfAstNod MEMBER_SET(memberReferenceExpr, mMemberName, attrIdentifier); } } + + if (tokenNode->GetToken() == BfToken_This) + { + mVisitorPos.MoveNext(); + MEMBER_SET(memberReferenceExpr, mMemberName, tokenNode); + } } if (memberReferenceExpr->mMemberName == NULL) diff --git a/IDEHelper/Compiler/BfReducer.h b/IDEHelper/Compiler/BfReducer.h index 6188cd9d..4a6a88eb 100644 --- a/IDEHelper/Compiler/BfReducer.h +++ b/IDEHelper/Compiler/BfReducer.h @@ -204,7 +204,7 @@ public: BfLambdaBindExpression* CreateLambdaBindExpression(BfAstNode* allocNode, BfTokenNode* parenToken = NULL); BfCollectionInitializerExpression* CreateCollectionInitializerExpression(BfBlock* block); BfCollectionInitializerExpression* CreateCollectionInitializerExpression(BfTokenNode* openToken); - BfObjectCreateExpression* CreateObjectCreateExpression(BfAstNode* allocNode); + BfObjectCreateExpression* CreateObjectCreateExpression(BfAstNode* allocNode, BfAstNode* targetNode = NULL); BfScopedInvocationTarget* CreateScopedInvocationTarget(BfAstNode*& targetRef, BfTokenNode* colonToken); BfInvocationExpression* CreateInvocationExpression(BfAstNode* target, CreateExprFlags createExprFlags = CreateExprFlags_None); BfInitializerExpression* TryCreateInitializerExpression(BfAstNode* target); diff --git a/IDEHelper/Tests/src/Generics.bf b/IDEHelper/Tests/src/Generics.bf index b53a77b1..7d0790ff 100644 --- a/IDEHelper/Tests/src/Generics.bf +++ b/IDEHelper/Tests/src/Generics.bf @@ -385,7 +385,22 @@ namespace Tests public class InnerB { + public T mVal; + public this(T3 val) where T : operator implicit T3 + { + mVal = (.)val; + } + } + + public struct InnerC + { + public T mVal; + + public this(T3 val) where T : operator implicit T3 + { + mVal = (.)val; + } } public static OuterA.Inner sVal; @@ -491,6 +506,13 @@ namespace Tests Test.Assert(specializedType.UnspecializedType == typeof(Dictionary<,>.Enumerator)); var t = typeof(Array2<>); t = typeof(ClassH<,>.Inner<>); + + var innerB = new OuterA.InnerB.this(123); + Test.Assert(innerB.mVal == 123); + delete innerB; + + var innerC = OuterA.InnerC.this(123); + Test.Assert(innerC.mVal == 123); } }