浏览代码

Reworked functions with explicit 'this'

Brian Fiete 5 年之前
父节点
当前提交
3627f8c40f

+ 4 - 0
IDEHelper/Compiler/BfAutoComplete.cpp

@@ -138,6 +138,7 @@ BfAutoComplete::BfAutoComplete(BfResolveType resolveType)
 	mIgnoreFixits = false;
 	mHasFriendSet = false;
 	mUncertain = false;
+	mForceAllowNonStatic = false;
 	mMethodMatchInfo = NULL;	
 	mIsGetDefinition = 
 		(resolveType == BfResolveType_GetSymbolInfo) ||
@@ -588,6 +589,9 @@ void BfAutoComplete::AddTypeMembers(BfTypeInstance* typeInst, bool addStatic, bo
 {
 	bool isInterface = false;
 	
+	if (mForceAllowNonStatic)
+		addNonStatic = true;
+
 	auto activeTypeDef = mModule->GetActiveTypeDef();
 
 	if ((addStatic) && (mModule->mCurMethodInstance == NULL) && (typeInst->IsEnum()))

+ 1 - 0
IDEHelper/Compiler/BfAutoComplete.h

@@ -179,6 +179,7 @@ public:
 	bool mIgnoreFixits;
 	bool mHasFriendSet;
 	bool mUncertain; // May be an unknown identifier, do not aggressively autocomplete
+	bool mForceAllowNonStatic;
 	int mCursorLineStart;
 	int mCursorLineEnd;
 	

+ 11 - 6
IDEHelper/Compiler/BfCompiler.cpp

@@ -2135,7 +2135,7 @@ void BfCompiler::UpdateDependencyMap(bool deleteUnusued, bool& didWork)
 			{				
 				auto depType = type->ToDependedType();					
 				auto typeInst = type->ToTypeInstance();
-			
+							
 				if (depType != NULL)
 				{
 					extern BfModule* gLastCreatedModule;
@@ -4272,11 +4272,16 @@ void BfCompiler::ProcessAutocompleteTempType()
 			methodInstance->GetMethodInfoEx()->mGenericParams.push_back(genericParamInstance);
 		}
 
+		bool wantsProcess = !actualTypeDef->mIsFunction;
+
 		SetAndRestoreValue<BfFilePosition> prevFilePos(module->mCurFilePosition);
 		SetAndRestoreValue<BfMethodInstance*> prevMethodInst(module->mCurMethodInstance, methodInstance);		
- 		module->DoMethodDeclaration(methodDeclaration, true);
-		module->mIncompleteMethodCount++;		
-		module->ProcessMethod(methodInstance);		
+ 		module->DoMethodDeclaration(methodDeclaration, true, wantsProcess);
+		if (wantsProcess)
+		{
+			module->mIncompleteMethodCount++;
+			module->ProcessMethod(methodInstance);
+		}
 		
 		if (methodInstance->mIRFunction)
 		{
@@ -4830,7 +4835,7 @@ void BfCompiler::GetSymbolReferences()
 						CheckSymbolReferenceTypeRef(module, externConstraintDef.mTypeRef);
 						rebuildModule->ResolveGenericParamConstraints(&genericParamInstance, rebuildMethodInstance->mIsUnspecialized);
 					}
-
+					
 					rebuildModule->ProcessMethod(rebuildMethodInstance);
 				}
 			}
@@ -7420,7 +7425,7 @@ void BfCompiler::GenerateAutocompleteInfo()
 					int dispParamIdx = 0;
 
 					StringT<64> paramName;
-					for (int paramIdx = methodInstance->HasExplicitThis() ? -1 : 0; paramIdx < (int)methodInstance->GetParamCount(); paramIdx++)
+					for (int paramIdx = 0; paramIdx < (int)methodInstance->GetParamCount(); paramIdx++)
 					{
 						auto paramKind = methodInstance->GetParamKind(paramIdx);
 						if ((paramKind == BfParamKind_ImplicitCapture) || (paramKind == BfParamKind_AppendIdx))

+ 1 - 1
IDEHelper/Compiler/BfContext.cpp

@@ -849,7 +849,7 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild
 		
 		return;
 	}
-
+	
 	// We need to verify lookups before we rebuild the type, because a type lookup change needs to count as a TypeDataChanged
 	VerifyTypeLookups(typeInst);
 

+ 34 - 14
IDEHelper/Compiler/BfDefBuilder.cpp

@@ -541,7 +541,7 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
 		methodDef->mMethodType = BfMethodType_Normal;
 		methodDef->mProtection = BfProtection_Public;
 		methodDef->mIsStatic = mCurTypeDef->mIsFunction;
-
+		
 		auto attributes = mCurTypeDef->mTypeDeclaration->mAttributes;
 		while (attributes != NULL)
 		{
@@ -621,6 +621,12 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
 		else //
 			paramDef->mParamKind = BfParamKind_Params;
 
+		if ((mCurTypeDef->mIsFunction) && (paramIdx == 0) && (paramDef->mName == "this"))
+		{
+			paramDef->mParamKind = BfParamKind_ExplicitThis;
+			methodDef->mIsStatic = false;
+		}
+
 		if (auto dotTypeRef = BfNodeDynCast<BfDotTypeReference>(paramDef->mTypeRef))
 		{
 			if (dotTypeRef->mDotToken->mToken == BfToken_DotDotDot)
@@ -658,6 +664,22 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio
 		methodDef->mParams.push_back(paramDef);
 	}	
 
+	if ((mCurTypeDef->mIsFunction) && (!methodDef->mParams.IsEmpty()) && (methodDef->mParams[0]->mName == "this"))
+	{
+		methodDef->mIsStatic = false;
+		methodDef->mHasExplicitThis = true;
+		methodDef->mParams[0]->mParamKind = BfParamKind_ExplicitThis;
+
+		if (auto refTypeRef = BfNodeDynCast<BfRefTypeRef>(methodDef->mParams[0]->mTypeRef))
+		{
+			if (refTypeRef->mRefToken->mToken != BfToken_Mut)
+			{
+				Fail("Only 'mut' is allowed here", refTypeRef->mRefToken);				
+			}
+			methodDef->mIsMutating = true;
+		}
+	}
+
 	ParseAttributes(methodDeclaration->mAttributes, methodDef);	
 	return methodDef;
 }
@@ -1911,6 +1933,16 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 		}
 	}
 	
+	bool needsDynamicCastMethod = !hasDynamicCastMethod;
+
+	if (mCurTypeDef->mIsFunction)
+	{
+		wantsToString = false;
+		needsEqualsMethod = false;
+		needsDefaultCtor = false;		
+		needsDynamicCastMethod = false;
+	}
+
 	if ((mCurTypeDef->mTypeCode == BfTypeCode_Object) && (!mCurTypeDef->mIsStatic))
 	{				
 		auto methodDef = AddMethod(mCurTypeDef, BfMethodType_CtorClear, BfProtection_Private, false, "");
@@ -1934,12 +1966,6 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 	}
 		
 	bool makeCtorPrivate = hasCtor;
-// 	if ((!mCurTypeDef->IsExtension()) && (mCurTypeDef->mMethods.empty()))
-// 	{
-// 		// This is a bit of a hack to ensure we actually generate debug info in the module
-// 		needsDefaultCtor = true;
-// 		makeCtorPrivate = true;
-// 	}
 
 	if (mCurTypeDef->mTypeCode == BfTypeCode_TypeAlias)
 		needsDefaultCtor = false;
@@ -1962,7 +1988,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 		isAutocomplete = true;
 		
 	//TODO: Don't do this for the autocomplete pass	
-	if ((!hasDynamicCastMethod) && (mCurTypeDef->mTypeCode != BfTypeCode_Interface) && (mCurTypeDef->mTypeCode != BfTypeCode_Extension) &&
+	if ((needsDynamicCastMethod) && (mCurTypeDef->mTypeCode != BfTypeCode_Interface) && (mCurTypeDef->mTypeCode != BfTypeCode_Extension) &&
 		(!mCurTypeDef->mIsStatic) && (!isAutocomplete) && (!isAlias))
 	{		
 		AddDynamicCastMethods(mCurTypeDef);
@@ -2011,12 +2037,6 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
 	
 	if (hasToStringMethod)
 		wantsToString = false;
-
-	if (mCurTypeDef->mIsFunction)
-	{
-		wantsToString = false;
-		needsEqualsMethod = false;
-	}
 	
 	if ((mCurTypeDef->mTypeCode == BfTypeCode_Enum) && (!isPayloadEnum))
 	{		

+ 128 - 32
IDEHelper/Compiler/BfExprEvaluator.cpp

@@ -542,6 +542,27 @@ bool BfGenericInferContext::InferGenericArgument(BfMethodInstance* methodInstanc
 					InferGenericArgument(methodInstance, argInvokeMethod->GetParamType(argIdx), wantInvokeMethod->GetParamType(argIdx), BfIRValue());
 			}
 		}
+		else if (argType->IsMethodRef())
+		{
+ 			auto methodTypeRef = (BfMethodRefType*)argType;
+			if (!_AddToCheckedSet(argType, mCheckedTypeSet, alreadyChecked))
+				return true;
+
+			auto argInvokeMethod = methodTypeRef->mMethodRef;
+			auto delegateInfo = wantType->GetDelegateInfo();
+			auto wantInvokeMethod = mModule->GetRawMethodByName(wantType->ToTypeInstance(), "Invoke");			
+
+			if ((delegateInfo->mHasExplicitThis) && (argInvokeMethod->HasThis()))
+				InferGenericArgument(methodInstance, argInvokeMethod->GetParamType(-1), delegateInfo->mParams[0], BfIRValue());
+
+			int wantInvokeOffset = delegateInfo->mHasExplicitThis ? 1 : 0;
+			if ((argInvokeMethod != NULL) && (wantInvokeMethod != NULL) && (argInvokeMethod->GetParamCount() == wantInvokeMethod->GetParamCount() - wantInvokeOffset))
+			{
+				InferGenericArgument(methodInstance, argInvokeMethod->mReturnType, wantInvokeMethod->mReturnType, BfIRValue());
+				for (int argIdx = 0; argIdx < (int)argInvokeMethod->GetParamCount(); argIdx++)
+					InferGenericArgument(methodInstance, argInvokeMethod->GetParamType(argIdx), wantInvokeMethod->GetParamType(argIdx + wantInvokeOffset), BfIRValue());
+			}
+		}
 	}	
 	
 	return true;
@@ -1021,7 +1042,7 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp
 	RETURN_RESULTS;
 }
 
-BfTypedValue BfMethodMatcher::ResolveArgTypedValue(BfResolvedArg& resolvedArg, BfType* checkType, BfTypeVector* genericArgumentsSubstitute)
+BfTypedValue BfMethodMatcher::ResolveArgTypedValue(BfResolvedArg& resolvedArg, BfType* checkType, BfTypeVector* genericArgumentsSubstitute, BfType *origCheckType)
 {	
 	BfTypedValue argTypedValue = resolvedArg.mTypedValue;
 	if ((resolvedArg.mArgFlags & BfArgFlag_DelegateBindAttempt) != 0)
@@ -1032,13 +1053,13 @@ BfTypedValue BfMethodMatcher::ResolveArgTypedValue(BfResolvedArg& resolvedArg, B
 		BF_ASSERT(resolvedArg.mExpression->IsA<BfDelegateBindExpression>());
 		auto delegateBindExpr = BfNodeDynCast<BfDelegateBindExpression>(resolvedArg.mExpression);
 		BfMethodInstance* boundMethodInstance = NULL;
-		if (exprEvaluator.CanBindDelegate(delegateBindExpr, &boundMethodInstance))
+		if (exprEvaluator.CanBindDelegate(delegateBindExpr, &boundMethodInstance, origCheckType, genericArgumentsSubstitute))
 		{
 			if (delegateBindExpr->mNewToken == NULL)
 			{
 				resolvedArg.mExpectedType = checkType;
 				auto methodRefType = mModule->CreateMethodRefType(boundMethodInstance);
-				mModule->AddDependency(methodRefType, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_Calls);
+				mModule->AddDependency(methodRefType, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_Calls);				
 				mModule->AddCallDependency(boundMethodInstance);
 				argTypedValue = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), methodRefType);
 			}
@@ -1509,7 +1530,7 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
 				if (argIdx == -1)
 					argTypedValue = mTarget;
 				else
-					argTypedValue = ResolveArgTypedValue(mArguments[argIdx], checkType, genericArgumentsSubstitute);
+					argTypedValue = ResolveArgTypedValue(mArguments[argIdx], checkType, genericArgumentsSubstitute, origCheckType);
 				if (!argTypedValue.IsUntypedValue())
 				{
 					auto type = argTypedValue.mType;
@@ -2615,6 +2636,16 @@ void BfExprEvaluator::Visit(BfAttributedExpression* attribExpr)
 		}
 		VisitChild(attribExpr->mExpression);
 		attributeState.mUsed = true;
+		
+		if ((!mResult) ||
+			((mResult) && (mResult.mType->IsVar())))
+		{
+			if (!mResult)
+				mModule->Fail("Expression did not result in a value", attribExpr->mExpression);
+
+			// Make empty or 'var' resolve as 'false' because var is only valid if we threw errors
+			mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Boolean));
+		}
 	}
 	else
 	{
@@ -4894,7 +4925,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
 	bool hadAttrs = false;	
 	int paramIdx = 0;
 	bool doingThis = !methodDef->mIsStatic;
-	int argIdx = 0;
+	int argIdx = 0;	
+
+	if (methodDef->mHasExplicitThis)
+		paramIdx++;
 	
 	int paramCount = methodInstance->GetParamCount();
 
@@ -4986,13 +5020,14 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
 		BfType* paramType = NULL;
 		if (doingThis)
 		{			
-			paramType = methodInstance->GetOwner();
+			int thisIdx = methodInstance->GetThisIdx();
+			paramType = methodInstance->GetThisType();
 			if (paramType->IsValuelessType())
 			{
 				doingThis = false;
 				continue;
 			}
-			bool isSplatted = methodInstance->GetParamIsSplat(-1); // (resolvedTypeRef->IsSplattable()) && (!methodDef->mIsMutating);
+			bool isSplatted = methodInstance->GetParamIsSplat(thisIdx); // (resolvedTypeRef->IsSplattable()) && (!methodDef->mIsMutating);
 			if (isSplatted)
 			{
 				BfTypeUtils::SplatIterate(_HandleParamType, paramType);
@@ -5357,7 +5392,7 @@ void BfExprEvaluator::PushThis(BfAstNode* targetSrc, BfTypedValue argVal, BfMeth
 		return;
 	}
 
-	auto thisType = methodInstance->GetParamType(-1);
+	auto thisType = methodInstance->GetThisType();
 	PushArg(argVal, irArgs, !methodInstance->AllowsThisSplatting(), thisType->IsPointer());
 }
 
@@ -5453,11 +5488,22 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 				auto bindResult = prevBindResult.mPrevVal;
 				if (bindResult->mBindType != NULL)
 				{
+					// Allow binding a function to a 'this' type even if no target is specified
 					auto delegateInfo = bindResult->mBindType->GetDelegateInfo();
-					if ((delegateInfo != NULL) && (delegateInfo->mFunctionThisType != NULL))
+					if (delegateInfo != NULL)
 					{
-						// Allow binding a function to a 'this' type even if no target is specified
-						target = mModule->GetDefaultTypedValue(delegateInfo->mFunctionThisType, false, BfDefaultValueKind_Addr);
+						if (delegateInfo->mHasExplicitThis)
+						{							
+							target = mModule->GetDefaultTypedValue(delegateInfo->mParams[0], false, BfDefaultValueKind_Addr);
+						}
+					}
+					else if (bindResult->mBindType->IsFunction())
+					{
+						BfMethodInstance* invokeMethodInstance = mModule->GetRawMethodInstanceAtIdx(bindResult->mBindType->ToTypeInstance(), 0, "Invoke");
+						if (!invokeMethodInstance->mMethodDef->mIsStatic)
+						{							
+							target = mModule->GetDefaultTypedValue(invokeMethodInstance->GetThisType(), false, BfDefaultValueKind_Addr);
+						}
 					}
 				}
 			}
@@ -5555,12 +5601,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 	if ((boxScopeData == NULL) && (mModule->mCurMethodState != NULL))
 		boxScopeData = mModule->mCurMethodState->mCurScope;
 
-	if (methodInstance->HasExplicitThis())	
-		paramIdx = -1;	
-
 	bool failed = false;
 	while (true)
 	{
+		bool isThis = (paramIdx == -1) || ((methodDef->mHasExplicitThis) && (paramIdx == 0));
 		bool isDirectPass = false;
 
 		if (paramIdx >= (int)methodInstance->GetParamCount())
@@ -6021,7 +6065,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 
 		if (argValue)
 		{	
-			if ((paramIdx == -1) && (argValue.mType->IsRef()))
+			if ((isThis) && (argValue.mType->IsRef()))
 			{
 				// Convert a 'ref this' to a 'this*'
 				argValue.mType = mModule->CreatePointerType(argValue.mType->GetUnderlyingType());
@@ -6107,7 +6151,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
 
 			if (argValue)
 			{
-				if (paramIdx == -1)
+				if (isThis)
 					PushThis(targetSrc, argValue, methodInstance, irArgs);
 				else if (wantsSplat)				
 					SplatArgs(argValue, irArgs);				
@@ -9485,7 +9529,11 @@ bool BfExprEvaluator::IsExactMethodMatch(BfMethodInstance* methodA, BfMethodInst
 		return false;
 
 	int implicitParamCountA = methodA->GetImplicitParamCount();
+	if (methodA->HasExplicitThis())
+		implicitParamCountA++;
 	int implicitParamCountB = methodB->GetImplicitParamCount();
+	if (methodB->HasExplicitThis())
+		implicitParamCountB++;
 
 	if (methodA->GetParamCount() - implicitParamCountA != methodB->GetParamCount() - implicitParamCountB)
 		return false;
@@ -9517,15 +9565,21 @@ BfTypeInstance* BfExprEvaluator::VerifyBaseDelegateType(BfTypeInstance* baseDele
 	return baseDelegateType;
 }
 
-bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr, BfMethodInstance** boundMethod)
+bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr, BfMethodInstance** boundMethod, BfType* origMethodExpectingType, BfTypeVector* methodGenericArgumentsSubstitute)
 {
-	if (mExpectingType == NULL)
+	if ((mExpectingType == NULL) && (origMethodExpectingType == NULL))
 	{
 		return false;
 	}
 	
-	auto typeInstance = mExpectingType->ToTypeInstance();
-	if ((typeInstance == NULL) || (!typeInstance->mTypeDef->mIsDelegate))
+	bool isGenericMatch = mExpectingType == NULL;
+	auto expectingType = mExpectingType;
+	if (expectingType == NULL)
+		expectingType = origMethodExpectingType;
+
+	auto typeInstance = expectingType->ToTypeInstance();
+	if ((typeInstance == NULL) || 
+		((!typeInstance->mTypeDef->mIsDelegate) && (!typeInstance->mTypeDef->mIsFunction)))
 		return false;
 	
 	mModule->PopulateType(typeInstance, BfPopulateType_DataAndMethods);
@@ -9547,11 +9601,28 @@ bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr
 	SizedArray<BfExpression*, 4> args;
 	args.resize(methodInstance->GetParamCount());
 
+	auto _FixType = [&](BfType* type)
+	{
+		if (!isGenericMatch)
+			return type;		
+		auto fixedType = mModule->ResolveGenericType(type, NULL, methodGenericArgumentsSubstitute);
+		if (fixedType != NULL)
+			return fixedType;
+		return (BfType*)mModule->GetPrimitiveType(BfTypeCode_Var);		
+	};
+
+	auto _TypeMatches = [&](BfType* lhs, BfType* rhs)
+	{
+		if (lhs == rhs)
+			return true;
+		return lhs->IsVar();	
+	};
+
 	for (int i = 0; i < (int) methodInstance->GetParamCount(); i++)
 	{
 		auto typedValueExpr = &typedValueExprs[i];
-		typedValueExpr->mTypedValue.mValue = BfIRValue(BfIRValueFlags_Value, -1);
-		typedValueExpr->mTypedValue.mType = methodInstance->GetParamType(i);
+		typedValueExpr->mTypedValue.mValue = BfIRValue(BfIRValueFlags_Value, -1);		
+		typedValueExpr->mTypedValue.mType = _FixType(methodInstance->GetParamType(i));
 		typedValueExpr->mRefNode = NULL;
 		args[i] = typedValueExpr;
 	}
@@ -9562,6 +9633,7 @@ bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr
 	
 	BfFunctionBindResult bindResult;
 	bindResult.mSkipMutCheck = true; // Allow operating on copies
+	bindResult.mBindType = expectingType;
 	mFunctionBindResult = &bindResult;
 	SetAndRestoreValue<bool> ignoreError(mModule->mIgnoreErrors, true);
 	DoInvocation(delegateBindExpr->mTarget, delegateBindExpr, args, methodGenericArguments);
@@ -9570,7 +9642,25 @@ bool BfExprEvaluator::CanBindDelegate(BfDelegateBindExpression* delegateBindExpr
 		return false;	
 	if (boundMethod != NULL)
 		*boundMethod = bindResult.mMethodInstance;
-	return IsExactMethodMatch(methodInstance, bindResult.mMethodInstance, true);
+
+	auto matchedMethod = bindResult.mMethodInstance;
+
+	if (!_TypeMatches(_FixType(methodInstance->mReturnType), matchedMethod->mReturnType))
+		return false;
+
+	int implicitParamCountA = methodInstance->GetImplicitParamCount();
+	int implicitParamCountB = matchedMethod->GetImplicitParamCount();
+
+	if (methodInstance->GetParamCount() - implicitParamCountA != matchedMethod->GetParamCount() - implicitParamCountB)
+		return false;
+	for (int i = 0; i < (int)methodInstance->GetParamCount() - implicitParamCountA; i++)
+	{
+		auto paramA = _FixType(methodInstance->GetParamType(i + implicitParamCountA));
+		auto paramB = _FixType(matchedMethod->GetParamType(i + implicitParamCountB));
+		if (!_TypeMatches(paramA, paramB))
+			return false;
+	}
+	return true;
 }
 
 BfTypedValue BfExprEvaluator::DoImplicitArgCapture(BfAstNode* refNode, BfIdentifierNode* identifierNode, int shadowIdx)
@@ -9928,14 +10018,15 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
 		}
 	}
 	
-	typedValueExprs.resize(methodInstance->GetParamCount());
-	args.resize(methodInstance->GetParamCount());
-
-	for (int i = 0; i < (int)methodInstance->GetParamCount(); i++)
+	int paramOffset = methodInstance->HasExplicitThis() ? 1 : 0;
+	typedValueExprs.resize(methodInstance->GetParamCount() - paramOffset);	
+	args.resize(methodInstance->GetParamCount() - paramOffset);
+	
+	for (int i = 0; i < (int)methodInstance->GetParamCount() - paramOffset; i++)
 	{
 		auto typedValueExpr = &typedValueExprs[i];
 		typedValueExpr->mTypedValue.mValue = BfIRValue(BfIRValueFlags_Value, -1);
-		typedValueExpr->mTypedValue.mType = methodInstance->GetParamType(i);
+		typedValueExpr->mTypedValue.mType = methodInstance->GetParamType(i + paramOffset);
 		typedValueExpr->mRefNode = NULL;
 		args[i] = typedValueExpr;
 	}
@@ -9950,8 +10041,12 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr)
 		return;
 	}
 
-	if (GetAutoComplete() != NULL)
+	auto autoComplete = GetAutoComplete();
+	if (autoComplete != NULL)
+	{
+		SetAndRestoreValue<bool> prevForceAllowNonStatic(autoComplete->mForceAllowNonStatic, methodInstance->mMethodDef->mHasExplicitThis);
 		GetAutoComplete()->CheckNode(delegateBindExpr->mTarget);
+	}
 
 	if ((!delegateBindExpr->mTarget->IsA<BfIdentifierNode>()) &&
 		(!delegateBindExpr->mTarget->IsA<BfMemberReferenceExpression>()))
@@ -19533,13 +19628,14 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod
 			}
 			else
 			{
-				auto convertedValue = mModule->CastToValue(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox);
+				auto convertedValue = mModule->Cast(otherTypeSrc, *otherTypedValue, resultType, BfCastFlags_NoBox);
 				if (!convertedValue)
 					return;				
+				convertedValue = mModule->LoadValue(convertedValue);
 				if ((binaryOp == BfBinaryOp_Equality) || (binaryOp == BfBinaryOp_StrictEquality))
-					mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean));
+					mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpEQ(resultTypedValue->mValue, convertedValue.mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean));
 				else
-					mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(resultTypedValue->mValue, convertedValue), mModule->GetPrimitiveType(BfTypeCode_Boolean));
+					mResult = BfTypedValue(mModule->mBfIRBuilder->CreateCmpNE(resultTypedValue->mValue, convertedValue.mValue), mModule->GetPrimitiveType(BfTypeCode_Boolean));
 			}
 
 			return;

+ 2 - 2
IDEHelper/Compiler/BfExprEvaluator.h

@@ -169,7 +169,7 @@ public:
 	Array<BfAmbiguousEntry> mAmbiguousEntries;	
 
 public:
-	BfTypedValue ResolveArgTypedValue(BfResolvedArg& resolvedArg, BfType* checkType, BfTypeVector* genericArgumentsSubstitute);	
+	BfTypedValue ResolveArgTypedValue(BfResolvedArg& resolvedArg, BfType* checkType, BfTypeVector* genericArgumentsSubstitute, BfType *origCheckType = NULL);	
 	bool InferFromGenericConstraints(BfGenericParamInstance* genericParamInst, BfTypeVector* methodGenericArgs);
 	void CompareMethods(BfMethodInstance* prevMethodInstance, BfTypeVector* prevGenericArgumentsSubstitute,
 		BfMethodInstance* newMethodInstance, BfTypeVector* genericArgumentsSubstitute, 
@@ -401,7 +401,7 @@ public:
 	void SetMethodElementType(BfAstNode* target);
 	BfTypedValue DoImplicitArgCapture(BfAstNode* refNode, BfIdentifierNode* identifierNode, int shadowIdx);
 	BfTypedValue DoImplicitArgCapture(BfAstNode* refNode, BfMethodInstance* methodInstance, int paramIdx, bool& failed, BfImplicitParamKind paramKind = BfImplicitParamKind_General, const BfTypedValue& methodRefTarget = BfTypedValue());
-	bool CanBindDelegate(BfDelegateBindExpression* delegateBindExpr, BfMethodInstance** boundMethod = NULL);
+	bool CanBindDelegate(BfDelegateBindExpression* delegateBindExpr, BfMethodInstance** boundMethod = NULL, BfType* origMethodExpectingType = NULL, BfTypeVector* methodGenericArgumentsSubstitute = NULL);
 	bool IsExactMethodMatch(BfMethodInstance* methodA, BfMethodInstance* methodB, bool ignoreImplicitParams = false);		
 	BfTypeInstance* VerifyBaseDelegateType(BfTypeInstance* delegateType);	
 	void ConstResolve(BfExpression* expr);

+ 6 - 18
IDEHelper/Compiler/BfMangler.cpp

@@ -311,14 +311,9 @@ void BfGNUMangler::MangleTypeInst(MangleContext& mangleContext, StringImpl& name
 		else
 			name += "N8functionI";
 		SizedArray<BfType*, 8> typeVec;
-		typeVec.push_back(BfNodeDynCast<BfDirectTypeReference>(methodDef->mReturnTypeRef)->mType);
-		if (delegateInfo->mFunctionThisType != NULL)
-		{
-			name += "_";
-			name += "this";
-			typeVec.push_back(delegateInfo->mFunctionThisType);
-		}
-
+		typeVec.push_back(BfNodeDynCast<BfDirectTypeReference>(methodDef->mReturnTypeRef)->mType);		
+		if (methodDef->mIsMutating)
+			name += "_mut_";
 		for (int paramIdx = 0; paramIdx < (int)methodDef->mParams.size(); paramIdx++)
 		{
 			name += "_";
@@ -1175,18 +1170,11 @@ bool BfMSMangler::FindOrCreateNameSub(MangleContext& mangleContext, StringImpl&
 				name += "?$delegate";
 			else
 				name += "?$function";
+			if (methodDef->mIsMutating)
+				name += "_mut_";
 			SizedArray<BfType*, 8> typeVec;
 			typeVec.push_back(BfNodeDynCast<BfDirectTypeReference>(methodDef->mReturnTypeRef)->mType);
-
-			if (delegateInfo->mFunctionThisType != NULL)
-			{
-				name += "_";
-				name += "this";
-				typeVec.push_back(delegateInfo->mFunctionThisType);
-				if ((delegateInfo->mFunctionThisType->IsValueType()) && (methodDef->mIsMutating))
-					name += "_mut";
-			}
-
+			
 			for (int paramIdx = 0; paramIdx < (int)methodDef->mParams.size(); paramIdx++)
 			{								
 				name += "_";

+ 69 - 28
IDEHelper/Compiler/BfModule.cpp

@@ -2610,6 +2610,15 @@ void BfModule::SetElementType(BfAstNode* astNode, BfSourceElementType elementTyp
 	}
 }
 
+void BfModule::SetFail()
+{
+	if (mIgnoreErrors)
+	{
+		if (mAttributeState != NULL)
+			mAttributeState->mFlags = (BfAttributeState::Flags)(mAttributeState->mFlags | BfAttributeState::Flag_HadError);		
+	}	
+}
+
 BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPersistent)
 {	
 	BP_ZONE("BfModule::Fail");
@@ -3074,10 +3083,17 @@ void BfModule::AddDependency(BfType* usedType, BfType* userType, BfDependencyMap
 		return;	
 
 	if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsAutocompleteMethod))
-		return;
+	{
+		if (userType->IsMethodRef())
+		{
+			// We cannot short-circuit dependencies because of method group ref counting			
+		}
+		else
+			return;
+	}
 
 	if (usedType->IsSpecializedByAutoCompleteMethod())
-		return;
+		return;	
 
 // 	if (usedType->IsBoxed())
 // 	{
@@ -14790,7 +14806,7 @@ BfIRCallingConv BfModule::GetIRCallingConvention(BfMethodInstance* methodInstanc
 	auto methodDef = methodInstance->mMethodDef;
 	BfTypeInstance* owner = NULL;
 	if (!methodDef->mIsStatic)
-		owner = methodInstance->GetParamType(-1)->ToTypeInstance();
+		owner = methodInstance->GetThisType()->ToTypeInstance();
 	if (owner == NULL)
 		owner = methodInstance->GetOwner();
 
@@ -14842,13 +14858,11 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func
 	int argIdx = 0;
 	int paramIdx = 0;
 
-	if (methodInstance->HasThis())
-	{
-		paramIdx = -1;			
-	}
+	if ((methodInstance->HasThis()) && (!methodDef->mHasExplicitThis))	
+		paramIdx = -1;	
 
 	int argCount = methodInstance->GetIRFunctionParamCount(this);
-	
+
 	while (argIdx < argCount)
 	{
 		if (argIdx == methodInstance->GetStructRetIdx())
@@ -14859,22 +14873,22 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func
 			continue;
 		}
 
-		while ((paramIdx != -1) && (methodInstance->IsParamSkipped(paramIdx)))
+		bool isThis = (paramIdx == -1) || ((methodDef->mHasExplicitThis) && (paramIdx == 0));
+		while ((!isThis) && (methodInstance->IsParamSkipped(paramIdx)))
 			paramIdx++;
 
 		BfType* resolvedTypeRef = NULL;
 		BfType* resolvedTypeRef2 = NULL;
 		String paramName;
 		bool isSplattable = false;
-		bool tryLowering = true;
-		bool isThis = paramIdx == -1;
+		bool tryLowering = true;		
 		if (isThis)
 		{
 			paramName = "this";
 			if (methodInstance->mIsClosure)
 				resolvedTypeRef = mCurMethodState->mClosureState->mClosureType;
 			else
-				resolvedTypeRef = methodInstance->GetOwner();
+				resolvedTypeRef = methodInstance->GetThisType();
 			isSplattable = (resolvedTypeRef->IsSplattable()) && (methodInstance->AllowsThisSplatting());
 			tryLowering = methodInstance->AllowsThisSplatting();
         }
@@ -14933,7 +14947,7 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func
 			}
 			if ((resolvedTypeRef->IsComposite()) && (!resolvedTypeRef->IsTypedPrimitive()))
 			{
-				if (paramIdx == -1)
+				if (isThis)
 				{
 					mBfIRBuilder->Func_AddAttribute(func, argIdx + 1, BfIRAttribute_NoCapture);
 					PopulateType(resolvedTypeRef, BfPopulateType_Data);
@@ -16965,6 +16979,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup)
 	}
 	if (methodInstance->mIsIntrinsic)
 		return;
+	if (mCurTypeInstance->IsFunction())
+		return;
 			
 	auto prevActiveFunction = mBfIRBuilder->GetActiveFunction();
 	mBfIRBuilder->SetActiveFunction(mCurMethodInstance->mIRFunction);	
@@ -20318,7 +20334,8 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 		implicitParamCount = (int)methodInstance->mMethodInfoEx->mClosureInstanceInfo->mCaptureEntries.size();
 
 	methodInstance->mMethodDef->mParams.Reserve((int)methodDef->mParams.size());
-	
+				
+
 	bool hadDelegateParams = false;
 	bool hadParams = false;	
 	for (int paramIdx = 0; paramIdx < (int)methodDef->mParams.size() + implicitParamCount; paramIdx++)
@@ -20379,9 +20396,13 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 		BfType* unresolvedParamType = resolvedParamType;
 		bool wasGenericParam = false;
 		if (resolvedParamType == NULL)
-		{			
-			resolvedParamType = ResolveTypeRef(paramDef->mTypeRef, BfPopulateType_Declaration, 
-				(BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowRef | BfResolveTypeRefFlag_AllowRefGeneric | BfResolveTypeRefFlag_AllowGenericMethodParamConstValue));
+		{
+			BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoResolveGenericParam | BfResolveTypeRefFlag_AllowRef | BfResolveTypeRefFlag_AllowRefGeneric | BfResolveTypeRefFlag_AllowGenericMethodParamConstValue);
+			if (paramDef->mParamKind == BfParamKind_ExplicitThis)
+				resolveFlags = (BfResolveTypeRefFlags)(resolveFlags | BfResolveTypeRefFlag_NoWarnOnMut);
+			resolvedParamType = ResolveTypeRef(paramDef->mTypeRef, BfPopulateType_Declaration, resolveFlags);
+			if ((paramDef->mParamKind == BfParamKind_ExplicitThis) && (resolvedParamType != NULL) && (resolvedParamType->IsRef()))
+				resolvedParamType = resolvedParamType->GetUnderlyingType();
 		}
 		if (resolvedParamType == NULL)
 		{
@@ -20578,7 +20599,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 			methodParam.mResolvedType = resolvedParamType;
 			methodParam.mParamDefIdx = paramDefIdx;			
 			mCurMethodInstance->mParams.Add(methodParam);
-		}		
+		}
 	}
 
 	if (hadDelegateParams)
@@ -20616,11 +20637,12 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 
 	int argIdx = 0;
 	PopulateType(methodInstance->mReturnType, BfPopulateType_Data);	
-	if (!methodDef->mIsStatic)
+	if ((!methodDef->mIsStatic) && (!methodDef->mHasExplicitThis))
     {
+		int thisIdx = methodDef->mHasExplicitThis ? 0 : -1;		
 		auto thisType = methodInstance->GetOwner();
-		if (methodInstance->GetParamIsSplat(-1))
-			argIdx += methodInstance->GetParamType(-1)->GetSplatCount();
+		if (methodInstance->GetParamIsSplat(thisIdx))
+			argIdx += methodInstance->GetParamType(thisIdx)->GetSplatCount();
 		else if (!thisType->IsValuelessType())
 		{
 			BfTypeCode loweredTypeCode = BfTypeCode_None;
@@ -20636,25 +20658,44 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
 	if (methodInstance->GetStructRetIdx() != -1)
 		argIdx++;
 
-	for (auto& methodParam : mCurMethodInstance->mParams)
+	for (int paramIdx = 0; paramIdx < mCurMethodInstance->mParams.size(); paramIdx++)
 	{
-		if (methodParam.mResolvedType->IsMethodRef())
+		auto& methodParam = mCurMethodInstance->mParams[paramIdx];
+
+		BfType* checkType = methodParam.mResolvedType;
+		int checkArgIdx = argIdx;
+		if ((paramIdx == 0) && (methodDef->mHasExplicitThis))
+		{
+			checkArgIdx = 0;
+			checkType = methodInstance->GetThisType();
+		}
+
+		if (checkType->IsMethodRef())
 		{
 			methodParam.mIsSplat = true;
 		}
-		else if ((methodParam.mResolvedType->IsComposite()) && (methodInstance->AllowsSplatting()))
+		else if ((checkType->IsComposite()) && (methodInstance->AllowsSplatting()))
 		{
-			PopulateType(methodParam.mResolvedType, BfPopulateType_Data);
-			if (methodParam.mResolvedType->IsSplattable())
+			PopulateType(checkType, BfPopulateType_Data);
+			if (checkType->IsSplattable())
 			{
-				int splatCount = methodParam.mResolvedType->GetSplatCount();
-				if (argIdx + splatCount <= mCompiler->mOptions.mMaxSplatRegs)
+				int splatCount = checkType->GetSplatCount();
+				if (checkArgIdx + splatCount <= mCompiler->mOptions.mMaxSplatRegs)
 				{
 					methodParam.mIsSplat = true;
 					argIdx += splatCount;
 					continue;
 				}
 			}
+			else if (!checkType->IsValuelessType())
+			{
+				BfTypeCode loweredTypeCode = BfTypeCode_None;
+				BfTypeCode loweredTypeCode2 = BfTypeCode_None;				
+				checkType->GetLoweredType(BfTypeUsage_Parameter, &loweredTypeCode, &loweredTypeCode2);
+				argIdx++;
+				if (loweredTypeCode2 != BfTypeCode_None)
+					argIdx++;
+			}
 		}		
 		
 		argIdx++;

+ 1 - 0
IDEHelper/Compiler/BfModule.h

@@ -1420,6 +1420,7 @@ public:
 	void GetAccessAllowed(BfTypeInstance* checkType, bool& allowProtected, bool& allowPrivate);
 	bool CheckProtection(BfProtectionCheckFlags& flags, BfTypeInstance* memberOwner, BfProject* memberProject, BfProtection memberProtection, BfTypeInstance* lookupStartType);
 	void SetElementType(BfAstNode* astNode, BfSourceElementType elementType);	
+	void SetFail();
 	BfError* Fail(const StringImpl& error, BfAstNode* refNode = NULL, bool isPersistent = false);
 	BfError* FailInternal(const StringImpl& error, BfAstNode* refNode = NULL);
 	BfError* FailAfter(const StringImpl& error, BfAstNode* refNode);	

+ 92 - 52
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -6331,6 +6331,7 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty
 
 		bool hasTypeGenerics = false;
 		auto returnType = ResolveGenericType(unspecializedDelegateInfo->mReturnType, typeGenericArguments, methodGenericArguments, allowFail);
+		
 		if (returnType == NULL)
 			return NULL;
 		if (returnType->IsVar())
@@ -6338,6 +6339,7 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty
 		_CheckType(returnType);
 		if (returnType->IsGenericParam())
 			hasTypeGenerics |= ((BfGenericParamType*)returnType)->mGenericParamKind == BfGenericParamKind_Type;
+
 		Array<BfType*> paramTypes;
 		for (auto param : unspecializedDelegateInfo->mParams)
 		{
@@ -6420,13 +6422,16 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty
 		typeDef->mIsDelegate = unspecializedDelegateType->mTypeDef->mIsDelegate;
 		typeDef->mIsFunction = unspecializedDelegateType->mTypeDef->mIsFunction;
 		
+		BfMethodDef* unspecializedInvokeMethodDef = unspecializedDelegateType->mTypeDef->GetMethodByName("Invoke");
+
 		BfMethodDef* methodDef = new BfMethodDef();
 		methodDef->mDeclaringType = typeDef;
 		methodDef->mName = "Invoke";
 		methodDef->mProtection = BfProtection_Public;
 		methodDef->mIdx = 0;
-		methodDef->mIsStatic = !typeDef->mIsDelegate;
-
+		methodDef->mIsStatic = !typeDef->mIsDelegate && !unspecializedDelegateInfo->mHasExplicitThis;
+		methodDef->mHasExplicitThis = unspecializedDelegateInfo->mHasExplicitThis;
+		
 		auto directTypeRef = BfAstNode::ZeroedAlloc<BfDirectTypeReference>();
 		delegateInfo->mDirectAllocNodes.push_back(directTypeRef);
 		if (typeDef->mIsDelegate)
@@ -6440,8 +6445,7 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty
 		directTypeRef->Init(returnType);
 		methodDef->mReturnTypeRef = directTypeRef;
 		delegateInfo->mReturnType = returnType;		
-		
-		BfMethodDef* unspecializedInvokeMethodDef = unspecializedDelegateType->mTypeDef->GetMethodByName("Invoke");
+		delegateInfo->mHasExplicitThis = unspecializedDelegateInfo->mHasExplicitThis;				
 
 		int paramIdx = 0;
 		for (int paramIdx = 0; paramIdx < (int)paramTypes.size(); paramIdx++)		
@@ -6469,11 +6473,20 @@ BfType* BfModule::ResolveGenericType(BfType* unspecializedType, BfTypeVector* ty
 
 		typeDef->mMethods.push_back(methodDef);
 
-		//	
+		if (unspecializedInvokeMethodDef->mIsMutating)
+		{
+			if ((delegateInfo->mParams[0]->IsValueType()) || (delegateInfo->mParams[0]->IsGenericParam()))
+				methodDef->mIsMutating = unspecializedInvokeMethodDef->mIsMutating;
+		}
 
-		BfDefBuilder::AddMethod(typeDef, BfMethodType_Ctor, BfProtection_Public, false, "");
+
+		//	
+		
 		if (typeDef->mIsDelegate)
+		{
+			BfDefBuilder::AddMethod(typeDef, BfMethodType_Ctor, BfProtection_Public, false, "");
 			BfDefBuilder::AddDynamicCastMethods(typeDef);
+		}
 
 		delegateType->mContext = mContext;
 		delegateType->mTypeDef = typeDef;
@@ -6904,8 +6917,8 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy
 	else if (resolvedTypeRef->IsDelegateFromTypeRef() || resolvedTypeRef->IsFunctionFromTypeRef())
 	{		
 		auto delegateInfo = resolvedTypeRef->GetDelegateInfo();
-		if (delegateInfo->mFunctionThisType != NULL)
-			AddDependency(delegateInfo->mFunctionThisType, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference);
+// 		if (delegateInfo->mFunctionThisType != NULL)
+// 			AddDependency(delegateInfo->mFunctionThisType, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference);
 		AddDependency(delegateInfo->mReturnType, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference);
 		for (auto& param : delegateInfo->mParams)
 			AddDependency(param, mCurTypeInstance, BfDependencyMap::DependencyFlag_TypeReference);		
@@ -8903,8 +8916,10 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 						}
 					}
 					hasMutSpecifier = true;
-					functionThisType = refType->mElementType;
+					functionThisType = refType->mElementType;					
 				}
+				paramTypes.Add(functionThisType);
+				_CheckType(functionThisType);
 			}
 			else
 			{
@@ -8980,11 +8995,14 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		methodDef->mName = "Invoke";
 		methodDef->mProtection = BfProtection_Public;
 		methodDef->mIdx = 0;
-		methodDef->mIsStatic = !typeDef->mIsDelegate && (functionThisType == NULL);
-		methodDef->mIsMutating = true;
+		methodDef->mIsStatic = !typeDef->mIsDelegate && (functionThisType == NULL);		
+		methodDef->mHasExplicitThis = functionThisType != NULL;		
 
-		if ((functionThisType != NULL) && (functionThisType->IsValueType()) && (!hasMutSpecifier))
-			methodDef->mIsMutating = false;
+		if ((functionThisType != NULL) && (hasMutSpecifier))
+		{
+			if ((functionThisType->IsValueType()) || (functionThisType->IsGenericParam()))
+				methodDef->mIsMutating = true;
+		}
 
 		auto directTypeRef = BfAstNode::ZeroedAlloc<BfDirectTypeReference>();
 		delegateInfo->mDirectAllocNodes.push_back(directTypeRef);
@@ -8999,11 +9017,12 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		directTypeRef->Init(returnType);
 		methodDef->mReturnTypeRef = directTypeRef;
 		delegateInfo->mReturnType = returnType;
-		delegateInfo->mFunctionThisType = functionThisType;
+		delegateInfo->mHasExplicitThis = functionThisType != NULL;
 		
 		auto hashVal = mContext->mResolvedTypes.Hash(typeRef, &lookupCtx);
 		
-		int paramSrcOfs = (functionThisType != NULL) ? 1 : 0;
+		//int paramSrcOfs = (functionThisType != NULL) ? 1 : 0;
+		int paramSrcOfs = 0;
 		for (int paramIdx = 0; paramIdx < (int)paramTypes.size(); paramIdx++)
 		{
 			auto param = delegateTypeRef->mParams[paramIdx + paramSrcOfs];
@@ -9026,8 +9045,10 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 
 			paramDef->mTypeRef = directTypeRef;
 			paramDef->mName = paramName;
-			methodDef->mParams.push_back(paramDef);
-			
+			if ((paramIdx == 0) && (functionThisType != NULL))
+				paramDef->mParamKind = BfParamKind_ExplicitThis;
+			methodDef->mParams.push_back(paramDef);					
+
 			delegateInfo->mParams.Add(paramType);			
 		}
 
@@ -9041,10 +9062,12 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		}
 
 		//	
-		
-		BfDefBuilder::AddMethod(typeDef, BfMethodType_Ctor, BfProtection_Public, false, "");
-		if (typeDef->mIsDelegate)		
+						
+		if (typeDef->mIsDelegate)
+		{
+			BfDefBuilder::AddMethod(typeDef, BfMethodType_Ctor, BfProtection_Public, false, "");
 			BfDefBuilder::AddDynamicCastMethods(typeDef);
+		}
 
 		delegateType->mContext = mContext;
 		delegateType->mTypeDef = typeDef;
@@ -9052,8 +9075,8 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 		resolvedEntry->mValue = delegateType;		
 
 		AddDependency(directTypeRef->mType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue);
-		if (delegateInfo->mFunctionThisType != NULL)
-			AddDependency(delegateInfo->mFunctionThisType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue);
+// 		if (delegateInfo->mFunctionThisType != NULL)
+// 			AddDependency(delegateInfo->mFunctionThisType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue);
 		for (auto paramType : paramTypes)
 			AddDependency(paramType, delegateType, BfDependencyMap::DependencyFlag_ParamOrReturnValue);
 
@@ -9376,14 +9399,13 @@ BfIRValue BfModule::CastToFunction(BfAstNode* srcNode, BfMethodInstance* methodI
 		}
 		else if (invokeMethodInstance->IsExactMatch(methodInstance, false, false))
 		{
-			bool handled = false;
-
-			auto thisType = methodInstance->GetParamType(-1);			
-			if (thisType != NULL)
+			bool handled = false;						
+			if (methodInstance->HasThis())
 			{
+				auto thisType = methodInstance->GetThisType();
 				if (invokeMethodInstance->HasExplicitThis())
 				{
-					auto invokeThisType = invokeMethodInstance->GetParamType(-1);
+					auto invokeThisType = invokeMethodInstance->GetThisType();
 
 					bool thisWasPtr = false;
 					if (thisType->IsPointer())
@@ -9416,6 +9438,7 @@ BfIRValue BfModule::CastToFunction(BfAstNode* srcNode, BfMethodInstance* methodI
 			if ((!methodInstance->mMethodDef->mIsStatic) && (!invokeMethodInstance->HasExplicitThis()))
 			{
 				handled = true;
+				auto thisType = methodInstance->GetParamType(-1);
 				Fail(StrFormat("Non-static method '%s' cannot match '%s', consider adding '%s this' to the function parameters", MethodToString(methodInstance).c_str(), TypeToString(toType).c_str(), TypeToString(thisType).c_str()), srcNode);
 			}
 			
@@ -9432,9 +9455,10 @@ BfIRValue BfModule::CastToFunction(BfAstNode* srcNode, BfMethodInstance* methodI
 }
 
 BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfType* toType, BfCastFlags castFlags, BfCastResultFlags* resultFlags)
-{
+{	
+	bool silentFail = ((castFlags & BfCastFlags_SilentFail) != 0);
 	bool explicitCast = (castFlags & BfCastFlags_Explicit) != 0;
-	bool ignoreErrors = mIgnoreErrors || ((castFlags & BfCastFlags_SilentFail) != 0);	
+	bool ignoreErrors = mIgnoreErrors || ((castFlags & BfCastFlags_SilentFail) != 0);
 	bool ignoreWrites = mBfIRBuilder->mIgnoreWrites;
 
 	if (typedVal.mType == toType)
@@ -9547,9 +9571,12 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 		// void* -> intptr
 		if ((typedVal.mType->IsPointer()) && (toType->IsIntPtr()))
 		{				
-			if ((!ignoreErrors) && (!typedVal.mType->GetUnderlyingType()->IsVoid()) && ((castFlags & BfCastFlags_FromCompiler) == 0))
-			{
-				Fail(StrFormat("Unable to cast directly from '%s' to '%s', consider casting to void* first", TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode);
+			if ((!typedVal.mType->GetUnderlyingType()->IsVoid()) && ((castFlags & BfCastFlags_FromCompiler) == 0))
+			{				
+				if (!ignoreErrors)
+					Fail(StrFormat("Unable to cast directly from '%s' to '%s', consider casting to void* first", TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode);
+				else if (!silentFail)
+					SetFail();
 			}
 						
 			auto toPrimitive = (BfPrimitiveType*)toType;
@@ -9559,9 +9586,12 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 		// intptr -> void*
 		if ((typedVal.mType->IsIntPtr()) && (toType->IsPointer()))
 		{			
-			if ((!ignoreErrors) && (!toType->GetUnderlyingType()->IsVoid()) && ((castFlags & BfCastFlags_FromCompiler) == 0))
+			if ((!toType->GetUnderlyingType()->IsVoid()) && ((castFlags & BfCastFlags_FromCompiler) == 0))
 			{
-				Fail(StrFormat("Unable to cast directly from '%s' to '%s', consider casting to void* first", TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode);
+				if (!ignoreErrors)
+					Fail(StrFormat("Unable to cast directly from '%s' to '%s', consider casting to void* first", TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode);
+				else if (!silentFail)
+					SetFail();
 			}
 
 			return mBfIRBuilder->CreateIntToPtr(typedVal.mValue, mBfIRBuilder->MapType(toType));
@@ -10088,11 +10118,13 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 			}
 
 			if (!ignoreErrors)
-			{	
+			{
 				String valStr;
 				VariantToString(valStr, variantVal);
 				Fail(StrFormat("Unable to cast '%s %s' to '%s'", TypeToString(typedVal.mType).c_str(), valStr.c_str(), TypeToString(toType).c_str()), srcNode);
 			}
+			else if (!silentFail)
+				SetFail();
 		}
 	}
 
@@ -10553,8 +10585,13 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 				{
 					if (mayBeBox)
 					{
-						if ((!ignoreErrors) && (Fail("Ambiguous cast, may be conversion operator or may be boxing request", srcNode) != NULL))
-							mCompiler->mPassInstance->MoreInfo("See conversion operator", opMethodInstance->mMethodDef->GetRefNode());
+						if (!ignoreErrors)
+						{
+							if (Fail("Ambiguous cast, may be conversion operator or may be boxing request", srcNode) != NULL)
+								mCompiler->mPassInstance->MoreInfo("See conversion operator", opMethodInstance->mMethodDef->GetRefNode());
+						}
+						else if (!silentFail)
+							SetFail();
 					}
 
 					BfMethodInstance* methodInstance = GetRawMethodInstance(opMethodInstance->GetOwner(), opMethodInstance->mMethodDef);
@@ -10620,6 +10657,8 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 				const char* errStr = "Ambiguous conversion operators for casting from '%s' to '%s'";
 				Fail(StrFormat(errStr, TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode);
 			}
+			else if (!silentFail)
+				SetFail();
 			return BfIRValue();
 		}
 
@@ -10777,7 +10816,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 			"Unable to cast '%s' to '%s'" :
 			"Unable to implicitly cast '%s' to '%s'";
 
-		String errStr = StrFormat(errStrF, TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str());		
+		String errStr = StrFormat(errStrF, TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str());
 		auto error = Fail(errStr, srcNode);
 		if ((error != NULL) && (srcNode != NULL))
 		{
@@ -10787,7 +10826,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 				SetAndRestoreValue<bool> ignoreErrors(mIgnoreErrors, true);
 
 				if (CastToValue(srcNode, typedVal, toType, (BfCastFlags)(BfCastFlags_Explicit | BfCastFlags_SilentFail)))
-				{	
+				{
 					bool doWrap = false;
 					if (auto unaryOpExpr = BfNodeDynCast<BfUnaryOperatorExpression>(srcNode))
 					{
@@ -10805,7 +10844,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 					if (doWrap)
 					{
 						mCompiler->mResolvePassData->mAutoComplete->AddEntry(AutoCompleteEntry("fixit",
-							StrFormat("(%s)\tcast|%s|%d|(%s)(|`%d|)", typeName.c_str(), parser->mFileName.c_str(), srcNode->GetSrcStart(), typeName.c_str(), srcNode->GetSrcLength()).c_str()));						
+							StrFormat("(%s)\tcast|%s|%d|(%s)(|`%d|)", typeName.c_str(), parser->mFileName.c_str(), srcNode->GetSrcStart(), typeName.c_str(), srcNode->GetSrcLength()).c_str()));
 					}
 					else
 					{
@@ -10816,6 +10855,8 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
 			}
 		}
 	}
+	else if (!silentFail)
+		SetFail();
 	return BfIRValue();
 }
 
@@ -10986,6 +11027,7 @@ BfTypedValue BfModule::Cast(BfAstNode* srcNode, const BfTypedValue& typedVal, Bf
 				
 		if ((fromMethodInst != NULL) && (toMethodInst != NULL) &&
 			(fromMethodInst->mMethodDef->mCallingConvention == toMethodInst->mMethodDef->mCallingConvention) &&
+			(fromMethodInst->mMethodDef->mIsMutating == toMethodInst->mMethodDef->mIsMutating) &&
 			(fromMethodInst->mReturnType == toMethodInst->mReturnType) &&			
 			(fromMethodInst->GetParamCount() == toMethodInst->GetParamCount()))
 		{	
@@ -11000,7 +11042,7 @@ BfTypedValue BfModule::Cast(BfAstNode* srcNode, const BfTypedValue& typedVal, Bf
 			}
 			else
 			{
-				for (int paramIdx = fromMethodInst->HasExplicitThis() ? -1 : 0; paramIdx < (int)fromMethodInst->GetParamCount(); paramIdx++)
+				for (int paramIdx = 0; paramIdx < (int)fromMethodInst->GetParamCount(); paramIdx++)
 				{
 					bool nameMatches = true;
 
@@ -11550,16 +11592,7 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF
 		DoTypeToString(str, delegateInfo->mReturnType, typeNameFlags, genericMethodNameOverrides);
 		str += "(";
 
-		bool isFirstParam = true;
-		if (delegateInfo->mFunctionThisType != NULL)
-		{
-			if ((methodDef->mIsMutating) && (delegateInfo->mFunctionThisType->IsValueType()))
-				str += "mut ";
-			DoTypeToString(str, delegateInfo->mFunctionThisType, typeNameFlags, genericMethodNameOverrides);
-			str += " this";
-			isFirstParam = false;
-		}
-
+		bool isFirstParam = true;// 		
 		for (int paramIdx = 0; paramIdx < methodDef->mParams.size(); paramIdx++)
 		{
 			if (!isFirstParam)
@@ -11567,7 +11600,14 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF
 			auto paramDef = methodDef->mParams[paramIdx];
 			BfTypeNameFlags innerFlags = (BfTypeNameFlags)(typeNameFlags & ~(BfTypeNameFlag_OmitNamespace | BfTypeNameFlag_OmitOuterType));
 			
-			DoTypeToString(str, delegateInfo->mParams[paramIdx], innerFlags, genericMethodNameOverrides);
+			auto paramType = delegateInfo->mParams[paramIdx];
+			if ((paramIdx == 0) && (delegateInfo->mHasExplicitThis))
+			{
+				if ((methodDef->mIsMutating) && (paramType->IsValueType()))
+					str += "mut ";
+			}
+
+			DoTypeToString(str, paramType, innerFlags, genericMethodNameOverrides);
 
 			if (!paramDef->mName.IsEmpty())
 			{

+ 69 - 41
IDEHelper/Compiler/BfResolvedTypeUtils.cpp

@@ -768,6 +768,29 @@ bool BfMethodInstance::HasThis()
 	return (!mMethodInstanceGroup->mOwner->IsValuelessType());
 }
 
+BfType* BfMethodInstance::GetThisType()
+{
+	BF_ASSERT(!mMethodDef->mIsStatic);
+	if (mMethodDef->mHasExplicitThis)
+	{
+		auto thisType = mParams[0].mResolvedType;
+		auto owner = GetOwner();
+		if ((thisType->IsValueType()) && ((mMethodDef->mIsMutating) || (!AllowsSplatting())) && (!thisType->GetLoweredType(BfTypeUsage_Parameter)))
+			return owner->mModule->CreatePointerType(thisType);
+		return thisType;
+	}
+	return GetParamType(-1);
+}
+
+int BfMethodInstance::GetThisIdx()
+{
+	if (mMethodDef->mIsStatic)
+		return -2;
+	if (mMethodDef->mHasExplicitThis)
+		return 0;
+	return -1;
+}
+
 bool BfMethodInstance::HasExplicitThis()
 {
 	if (mMethodDef->mIsStatic)
@@ -827,17 +850,18 @@ String BfMethodInstance::GetParamName(int paramIdx)
 }
 
 BfType* BfMethodInstance::GetParamType(int paramIdx, bool useResolvedType)
-{
+{	
 	if (paramIdx == -1)
 	{
 		if ((mMethodInfoEx != NULL) && (mMethodInfoEx->mClosureInstanceInfo != NULL) && (mMethodInfoEx->mClosureInstanceInfo->mThisOverride != NULL))
 			return mMethodInfoEx->mClosureInstanceInfo->mThisOverride;
 		BF_ASSERT(!mMethodDef->mIsStatic);
 		auto owner = mMethodInstanceGroup->mOwner;
-		auto delegateInfo = owner->GetDelegateInfo();
 		BfType* thisType = owner;
-		if ((delegateInfo != NULL) && (delegateInfo->mFunctionThisType != NULL))
-			thisType = delegateInfo->mFunctionThisType;
+		if (owner->IsFunction())
+		{
+			BF_FATAL("Wrong 'this' index");
+		}
 		if ((thisType->IsValueType()) && ((mMethodDef->mIsMutating) || (!AllowsSplatting())) && (!thisType->GetLoweredType(BfTypeUsage_Parameter)))
 			return owner->mModule->CreatePointerType(thisType);
 		return thisType;
@@ -1034,8 +1058,10 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType,
 		returnType = module->mBfIRBuilder->MapType(mReturnType);
 	}	
 
+	
+
 	for (int paramIdx = -1; paramIdx < GetParamCount(); paramIdx++)
-	{
+	{			
 		BfType* checkType = NULL;
 		if (paramIdx == -1)
 		{
@@ -1048,7 +1074,7 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType,
 			else
 			{
 				if (HasExplicitThis())
-					checkType = GetParamType(-1);
+					checkType = GetParamType(0);
 				else
 					checkType = GetOwner();				
 			}
@@ -1102,14 +1128,14 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType,
 			}							
 		}
 
-		if ((paramIdx == 0) && (GetParamName(0) == "this") && (checkType->IsPointer()))
-		{
-			// We don't actually pass a this pointer for mut methods in valueless structs
-			auto underlyingType = checkType->GetUnderlyingType();
-			module->PopulateType(underlyingType, BfPopulateType_Data);
-			if (underlyingType->IsValuelessType())
-				continue;
-		}
+// 		if ((paramIdx == 0) && (GetParamName(0) == "this") && (checkType->IsPointer()))
+// 		{
+// 			// We don't actually pass a this pointer for mut methods in valueless structs
+// 			auto underlyingType = checkType->GetUnderlyingType();
+// 			module->PopulateType(underlyingType, BfPopulateType_Data);
+// 			if (underlyingType->IsValuelessType())
+// 				continue;
+// 		}
 
 		if (checkType->CanBeValuelessType())
 			module->PopulateType(checkType, BfPopulateType_Data);
@@ -1159,6 +1185,9 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType,
 
 		if (checkType2 != NULL)
 			_AddType(checkType2);
+
+		if ((paramIdx == -1) && (mMethodDef->mHasExplicitThis))
+			paramIdx++; // Skip over the explicit 'this'
 	}
 
 	if (GetStructRetIdx(forceStatic) == 1)
@@ -1200,7 +1229,7 @@ bool BfMethodInstance::IsExactMatch(BfMethodInstance* other, bool ignoreImplicit
 	if (checkThis)
 	{
 		if (other->mMethodDef->mIsStatic != mMethodDef->mIsStatic)
-			return false;
+			return false;		
 
 // 		{
 // 			// If we are static and we have to match a non-static method, allow us to do so if we have an explicitly defined 'this' param that matches
@@ -1227,13 +1256,18 @@ bool BfMethodInstance::IsExactMatch(BfMethodInstance* other, bool ignoreImplicit
 
 		if (!mMethodDef->mIsStatic)
 		{
-			if (GetParamType(-1) != other->GetParamType(-1))
+			if (GetThisType() != other->GetThisType())
 			{
 				return false;
 			}
 		}
 	}
 
+	if (mMethodDef->mHasExplicitThis)
+		implicitParamCountA++;
+	if (other->mMethodDef->mHasExplicitThis)
+		implicitParamCountB++;
+
 	if (GetParamCount() - implicitParamCountA != other->GetParamCount() - implicitParamCountB)
 		return false;
 	for (int i = 0; i < (int)GetParamCount() - implicitParamCountA; i++)
@@ -2577,14 +2611,6 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
 		BF_ASSERT(methodDef->mName == "Invoke");
 		BF_ASSERT(delegateInfo->mParams.size() == methodDef->mParams.size());
 
-		if (delegateInfo->mFunctionThisType != NULL)
-		{
-			hashVal = ((hashVal ^ (Hash(delegateInfo->mFunctionThisType, ctx))) << 5) - hashVal;
-			String paramName = "this";
-			int nameHash = (int)Hash64(paramName.c_str(), (int)paramName.length());
-			hashVal = ((hashVal ^ (nameHash)) << 5) - hashVal;
-		}
-
 		for (int paramIdx = 0; paramIdx < delegateInfo->mParams.size(); paramIdx++)
 		{
 			// Parse attributes?			
@@ -3300,6 +3326,10 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx)
 			auto lhsMethodDef = lhsInst->mTypeDef->mMethods[0];
 			auto rhsMethodDef = rhsInst->mTypeDef->mMethods[0];
 
+			if (lhsMethodDef->mCallingConvention != rhsMethodDef->mCallingConvention)
+				return false;
+			if (lhsMethodDef->mIsMutating != rhsMethodDef->mIsMutating)
+				return false;
 			if (lhsDelegateInfo->mReturnType != rhsDelegateInfo->mReturnType)
 				return false;
 			if (lhsDelegateInfo->mParams.size() != rhsDelegateInfo->mParams.size())
@@ -3701,44 +3731,42 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfTypeReference* rhs, LookupContext*
 			auto param0 = rhsDelegateType->mParams[0];
 			if ((param0->mNameNode != NULL) && (param0->mNameNode->Equals("this")))
 			{
+				if (!lhsDelegateInfo->mHasExplicitThis)
+					return false;
+
 				bool handled = false;
-				auto lhsThisType = lhsDelegateInfo->mFunctionThisType;
+				auto lhsThisType = lhsDelegateInfo->mParams[0];
 
 				auto rhsThisType = ctx->mModule->ResolveTypeRef(param0->mTypeRef, BfPopulateType_Identity, (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoWarnOnMut | BfResolveTypeRefFlag_AllowRef));
+				bool wantsMutating = false;
+
 				if (rhsThisType->IsRef())
 				{					
 					if (lhsThisType != rhsThisType->GetUnderlyingType())
 						return false;
-					if (!invokeMethodDef->mIsMutating)
-						return false;
+					wantsMutating = (lhsThisType->IsValueType()) || (lhsThisType->IsGenericParam());					
 				}
 				else
 				{
 					if (lhsThisType != rhsThisType)
-						return false;
-					if ((invokeMethodDef->mIsMutating) && (lhsThisType->IsValueType()))
-						return false;
+						return false;					
 				}
+				if (invokeMethodDef->mIsMutating != wantsMutating)
+					return false;
 
 				paramRefOfs = 1;
 			}
 		}
 
-		if (!rhsIsDelegate)
-		{			
-			if ((lhsDelegateInfo->mFunctionThisType == NULL) != (paramRefOfs == 0))
-				return false;
-		}
-
-		if (lhsDelegateInfo->mParams.size() != (int)rhsDelegateType->mParams.size() - paramRefOfs)
+		if (lhsDelegateInfo->mParams.size() != (int)rhsDelegateType->mParams.size())
 			return false;
-		for (int paramIdx = 0; paramIdx < lhsDelegateInfo->mParams.size(); paramIdx++)
+		for (int paramIdx = paramRefOfs; paramIdx < lhsDelegateInfo->mParams.size(); paramIdx++)
 		{
-			if (!Equals(lhsDelegateInfo->mParams[paramIdx], rhsDelegateType->mParams[paramIdx + paramRefOfs]->mTypeRef, ctx))
+			if (!Equals(lhsDelegateInfo->mParams[paramIdx], rhsDelegateType->mParams[paramIdx]->mTypeRef, ctx))
 				return false;
 			StringView rhsParamName;
-			if (rhsDelegateType->mParams[paramIdx + paramRefOfs]->mNameNode != NULL)
-				rhsParamName = rhsDelegateType->mParams[paramIdx + paramRefOfs]->mNameNode->ToStringView();
+			if (rhsDelegateType->mParams[paramIdx]->mNameNode != NULL)
+				rhsParamName = rhsDelegateType->mParams[paramIdx]->mNameNode->ToStringView();
 			if (invokeMethodDef->mParams[paramIdx]->mName != rhsParamName)
 				return false;
 		}

+ 5 - 3
IDEHelper/Compiler/BfResolvedTypeUtils.h

@@ -416,15 +416,15 @@ class BfDelegateInfo
 {
 public:
 	Array<BfAstNode*> mDirectAllocNodes;
-	BfType* mReturnType;
-	BfType* mFunctionThisType;
+	BfType* mReturnType;	
 	Array<BfType*> mParams;
+	bool mHasExplicitThis;
 
 public:
 	BfDelegateInfo()
 	{
 		mReturnType = NULL;
-		mFunctionThisType = NULL;
+		mHasExplicitThis = false;
 	}
 
 	~BfDelegateInfo()
@@ -870,6 +870,8 @@ public:
 	bool IsSpecializedByAutoCompleteMethod();
 	bool HasExternConstraints();
 	bool HasThis();	
+	BfType* GetThisType();
+	int GetThisIdx();
 	bool HasExplicitThis();
 	bool HasParamsArray();
 	int GetStructRetIdx(bool forceStatic = false);

+ 4 - 1
IDEHelper/Compiler/BfSystem.h

@@ -458,7 +458,8 @@ struct BfCodeGenOptions
 
 enum BfParamKind : uint8
 {
-	BfParamKind_Normal,	
+	BfParamKind_Normal,
+	BfParamKind_ExplicitThis,
 	BfParamKind_Params,
 	BfParamKind_DelegateParam,
 	BfParamKind_ImplicitCapture,
@@ -725,6 +726,7 @@ public:
 	bool mIsOperator;
 	bool mIsExtern;	
 	bool mIsNoDiscard;
+	bool mHasExplicitThis;
 	BfCommutableKind mCommutableKind;
 	BfCheckedKind mCheckedKind;
 	BfImportKind mImportKind;	
@@ -751,6 +753,7 @@ public:
 		mIsOperator = false;
 		mIsExtern = false;
 		mIsNoDiscard = false;
+		mHasExplicitThis = false;
 		mBody = NULL;
 		mExplicitInterface = NULL;
 		mReturnTypeRef = NULL;		

+ 129 - 1
IDEHelper/Tests/src/Functions.bf

@@ -26,6 +26,65 @@ namespace Tests
 			int mA = 123;
 			int mB = 234;
 
+			public this()
+			{
+
+			}
+
+			public this(int a, int b)
+			{
+				mA = a;
+				mB = b;
+			}
+
+			public int GetA(float f)
+			{
+				return mA + mB*100 + (int)f;
+			}
+
+			public int GetA2(float f) mut
+			{
+				return mA + mB*100 + (int)f;
+			}
+
+			public StructA GetA3(float f)
+			{
+				StructA sa;
+				sa.mA = mA + 1000;
+				sa.mB = mB + 2000 + (int)f;
+				return sa;
+			}
+
+			public StructA GetA4(float f) mut
+			{
+				StructA sa;
+				sa.mA = mA + 1000;
+				sa.mB = mB + 2000 + (int)f;
+				return sa;
+			}
+		}
+
+		struct StructB
+		{
+			function StructB Func(StructB this, float f);
+			function StructB FuncMut(mut StructB this, float f);
+
+			int mA = 123;
+			int mB = 234;
+			int mC = 345;
+
+			public this()
+			{
+
+			}
+
+			public this(int a, int b, int c)
+			{
+				mA = a;
+				mB = b;
+				mC = c;
+			}
+
 			public int GetA(float f)
 			{
 				return mA + mB*100 + (int)f;
@@ -35,6 +94,50 @@ namespace Tests
 			{
 				return mA + mB*100 + (int)f;
 			}
+
+			public StructB GetA3(float f)
+			{
+				StructB sb;
+				sb.mA = mA + 1000;
+				sb.mB = mB + 2000 + (int)f;
+				sb.mC = mC + 3000;
+				return sb;
+			}
+
+			public StructB GetA4(float f) mut
+			{
+				StructB sb;
+				sb.mA = mA + 1000;
+				sb.mB = mB + 2000 + (int)f;
+				sb.mC = mC + 3000;
+				return sb;
+			}
+
+			public static void Test()
+			{
+				StructB sb = .();
+
+				Func func0 = => GetA3;
+				Test.Assert(func0(sb, 100.0f) == .(1123, 2334, 3345));
+				function StructB (StructB this, float f) func1 = => GetA3;
+
+				Test.Assert(func0 == func1);
+				func0 = func1;
+
+				FuncMut func2 = => GetA4;
+				Test.Assert(func2(sb, 100.0f) == .(1123, 2334, 3345));
+				function StructB (mut StructB this, float f) func3 = => GetA4;
+			}
+		}
+
+		public static int UseFunc0<T>(function int (T this, float f) func, T a, float b)
+		{
+			return func(a, b);
+		}
+
+		public static int UseFunc1<T>(function int (mut T this, float f) func, mut T a, float b)
+		{
+			return func(a, b);
 		}
 
 		[Test]
@@ -42,6 +145,7 @@ namespace Tests
 		{
 			ClassA ca = scope .();
 			StructA sa = .();
+			StructB sb = .();
 
 			function int (ClassA this, float f) func0 = => ca.GetA;
 			function int (ClassA this, float) func0b = func0;
@@ -50,10 +154,34 @@ namespace Tests
 			Test.Assert(func0(ca, 100.0f) == 223);
 
 			function int (StructA this, float f) func1 = => sa.GetA;
+			var func1b = func1;
 			Test.Assert(func1(sa, 100.0f) == 23623);
+			Test.Assert(!
+				[IgnoreErrors(true)]
+				{
+					func1b = => sb.GetA;
+					true
+				});
 
 			function int (mut StructA this, float f) func2 = => sa.GetA2;
-			Test.Assert(func2(mut sa, 100.0f) == 23623);
+			Test.Assert(func2(sa, 100.0f) == 23623);
+
+			function StructA (StructA this, float f) func3 = => sa.GetA3;
+			Test.Assert(func3(sa, 100.0f) == .(1123, 2334));
+
+			function StructA (mut StructA this, float f) func4 = => sa.GetA4;
+			Test.Assert(func4(sa, 100.0f) == .(1123, 2334));
+
+			StructB.Test();
+
+			Test.Assert(UseFunc0(func0, ca, 100.0f) == 223);
+			Test.Assert(UseFunc0(func1, sa, 100.0f) == 23623);
+			Test.Assert(!
+				[IgnoreErrors(true)]
+				{
+					UseFunc0(func2, sa, 100.0f);
+					true
+				});
 		}
 	}
 }