浏览代码

Generic constructors

Brian Fiete 10 月之前
父节点
当前提交
04ea8a6634

+ 5 - 0
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());

+ 13 - 0
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<BfExpression*> mArguments;

+ 10 - 1
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";

+ 10 - 0
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)

+ 1 - 0
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);

+ 68 - 21
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<BfFunctionBindResult*> 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<bool> 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<BfIRValue, 2> 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<BfTokenNode>(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<BfScopeNode>(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;
 

+ 1 - 1
IDEHelper/Compiler/BfExprEvaluator.h

@@ -497,7 +497,7 @@ public:
 	void PushArg(BfTypedValue argVal, SizedArrayImpl<BfIRValue>& irArgs, bool disableSplat = false, bool disableLowering = false, bool isIntrinsic = false, bool createCompositeCopy = false);
 	void PushThis(BfAstNode* targetSrc, BfTypedValue callTarget, BfMethodInstance* methodInstance, SizedArrayImpl<BfIRValue>& 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);

+ 5 - 5
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<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true);
 		exprEvaluator.ResolveArgValues(argValues, BfResolveArgsFlag_DeferParamEval);
 		SetAndRestoreValue<BfFunctionBindResult*> 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<BfFunctionBindResult*> 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)
 		{

+ 1 - 1
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))
 							{

+ 4 - 0
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)
 	{

+ 126 - 7
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<BfTokenNode>(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<BfBlock>(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<BfMemberReferenceExpression>();
 					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<BfTokenNode>(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<BfTypeReference>(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<BfTokenNode>(mVisitorPos.Get(mVisitorPos.mReadPos + 2)))
+				{
+					if (nextToken->mToken == BfToken_This)
+					{
+						// Don't encode '.this' in type ref
+						break;
+					}
+				}
+
 				BfQualifiedTypeReference* qualifiedTypeRef = mAlloc->Alloc<BfQualifiedTypeReference>();
 				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<BfTokenNode>(mVisitorPos.Get(mVisitorPos.mReadPos + 2)))
+							{
+								if (nextToken->mToken == BfToken_This)
+								{
+									// Don't encode '.this' in type ref
+									break;
+								}
+							}
+
 							BfQualifiedTypeReference* outerQualifiedTypeRef = mAlloc->Alloc<BfQualifiedTypeReference>();
 							ReplaceNode(qualifiedTypeRef, outerQualifiedTypeRef);
 							outerQualifiedTypeRef->mLeft = qualifiedTypeRef;
@@ -5578,6 +5637,11 @@ BfIdentifierNode* BfReducer::CompactQualifiedName(BfAstNode* leftNode)
 		{
 			if (auto rightToken = BfNodeDynCast<BfTokenNode>(nextNextToken))
 			{
+				if (rightToken->mToken == BfToken_This)
+				{
+					return leftIdentifier;
+				}
+
 				if (BfTokenIsKeyword(rightToken->mToken))
 				{
 					rightIdentifier = mAlloc->Alloc<BfIdentifierNode>();
@@ -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<BfObjectCreateExpression>();
 	BfDeferredAstSizedArray<BfExpression*> arguments(objectCreateExpr->mArguments, mAlloc);
 	BfDeferredAstSizedArray<BfTokenNode*> 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<BfTokenNode>(mVisitorPos.GetNext());
+		auto nextNextToken = BfNodeDynCast<BfTokenNode>(mVisitorPos.Get(mVisitorPos.mReadPos + 2));
+		if ((nextToken != NULL) && (nextToken->mToken == BfToken_Dot) &&
+			(nextNextToken != NULL) && (nextNextToken->mToken == BfToken_This))
+		{
+			auto ctorExplicitNode = mAlloc->Alloc<BfCtorExplicitNode>();			
+			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<BfCtorExplicitNode>();
+			ReplaceNode(nextToken, ctorExplicitNode);
+			ctorExplicitNode->mThisToken = nextToken;			
+			mVisitorPos.MoveNext();
+			MEMBER_SET(objectCreateExpr, mCtorExplicit, ctorExplicitNode);
+		}
+
+		if (objectCreateExpr->mCtorExplicit != NULL)
+		{
+			nextToken = BfNodeDynCast<BfTokenNode>(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)

+ 1 - 1
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);

+ 22 - 0
IDEHelper/Tests/src/Generics.bf

@@ -385,7 +385,22 @@ namespace Tests
 
 			public class InnerB
 			{
+				public T mVal;
 
+				public this<T3>(T3 val) where T : operator implicit T3
+				{
+					mVal = (.)val;
+				}
+			}
+
+			public struct InnerC
+			{
+				public T mVal;
+
+				public this<T3>(T3 val) where T : operator implicit T3
+				{
+					mVal = (.)val;
+				}
 			}
 
 			public static OuterA<int,float>.Inner<int16> 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<int, float>.InnerB.this<int32>(123);
+			Test.Assert(innerB.mVal == 123);
+			delete innerB;
+
+			var innerC = OuterA<int, float>.InnerC.this<int32>(123);
+			Test.Assert(innerC.mVal == 123);
 		}
 	}