Browse Source

Overhaul generic type reference lookup

Brian Fiete 3 years ago
parent
commit
fefed0948e

+ 0 - 1
IDEHelper/Compiler/BfContext.cpp

@@ -1127,7 +1127,6 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild
 	if (typeInst->IsGenericTypeInstance())
 	{
 		auto genericTypeInstance = (BfTypeInstance*)typeInst;
-		genericTypeInstance->mGenericTypeInfo->mTypeGenericArgumentRefs.Clear();
 		for (auto genericParam : genericTypeInstance->mGenericTypeInfo->mGenericParams)
 			genericParam->Release();
 		genericTypeInstance->mGenericTypeInfo->mInitializedGenericParams = false;

+ 50 - 26
IDEHelper/Compiler/BfModuleTypeUtils.cpp

@@ -7901,7 +7901,7 @@ BfTypeDef* BfModule::ResolveGenericInstanceDef(BfGenericInstanceTypeRef* generic
 	if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(typeRef))
 	{		
 		BfAutoParentNodeEntry autoParentNodeEntry(this, genericTypeRef);
-		auto type = ResolveTypeRef(qualifiedTypeRef, BfPopulateType_TypeDef, BfResolveTypeRefFlag_None, numGenericParams);
+		auto type = ResolveTypeRef(qualifiedTypeRef, BfPopulateType_TypeDef, resolveFlags, numGenericParams);
 		if (type == NULL)
 			return NULL;
 		if (outType != NULL)
@@ -8946,7 +8946,7 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy
 	if ((populateType > BfPopulateType_IdentityNoRemapAlias) && (!ResolveTypeResult_Validate(typeRef, resolvedTypeRef)))
 		return NULL;
 	
-	if (populateType != BfPopulateType_IdentityNoRemapAlias)
+	if ((populateType != BfPopulateType_TypeDef) && (populateType != BfPopulateType_IdentityNoRemapAlias))
 	{
 		while ((resolvedTypeRef != NULL) && (resolvedTypeRef->IsTypeAlias()))
 		{
@@ -10789,50 +10789,75 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 	}
 	else if (auto genericTypeInstRef = BfNodeDynCast<BfGenericInstanceTypeRef>(typeRef))
 	{
-		int wantNumGenericParams = genericTypeInstRef->GetGenericArgCount();
-		BfTypeDef* ambiguousTypeDef = NULL;
-		
+		BfTypeReference* outerTypeRef = NULL;		
+
 		Array<BfAstNode*> genericArguments;
-		std::function<void(BfTypeReference*)> _GetTypeRefs = [&](BfTypeReference* typeRef)
+
+		BfTypeReference* checkTypeRef = genericTypeInstRef;
+		int checkIdx = 0;
+
+		while (checkTypeRef != NULL)
 		{
-			//TODO:GENERICS
-			if (auto elementedTypeRef = BfNodeDynCast<BfElementedTypeRef>(typeRef))
+			checkIdx++;
+			if (checkIdx >= 3)
 			{
-				_GetTypeRefs(elementedTypeRef->mElementType);
-			}
-			else if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(typeRef))
-			{
-				_GetTypeRefs(qualifiedTypeRef->mLeft);
+				outerTypeRef = checkTypeRef;
+				break;
 			}
 
-			if (auto genericTypeRef = BfNodeDynCast<BfGenericInstanceTypeRef>(typeRef))
-			{
+			if (auto genericTypeRef = BfNodeDynCast<BfGenericInstanceTypeRef>(checkTypeRef))
+			{				
 				for (auto genericArg : genericTypeRef->mGenericArguments)
 					genericArguments.push_back(genericArg);
+				checkTypeRef = genericTypeRef->mElementType;
+				continue;
+			}
+
+			if (auto elementedTypeRef = BfNodeDynCast<BfElementedTypeRef>(checkTypeRef))
+			{
+				checkTypeRef = elementedTypeRef->mElementType;
+				continue;
 			}
-		};
-		_GetTypeRefs(genericTypeInstRef);
 
+			if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(checkTypeRef))
+			{
+				checkTypeRef = qualifiedTypeRef->mLeft;
+				continue;
+			}
+			break;
+		}
+		
 		BfTypeVector genericArgs;
 
 		BfType* type = NULL;
 		BfTypeDef* typeDef = ResolveGenericInstanceDef(genericTypeInstRef, &type, resolveFlags);
-		if(ambiguousTypeDef != NULL)
-			ShowAmbiguousTypeError(typeRef, typeDef, ambiguousTypeDef);
 		if (typeDef == NULL)
 		{
-			Fail("Unable to resolve type", typeRef);			
+			Fail("Unable to resolve type", typeRef);
 			mContext->mResolvedTypes.RemoveEntry(resolvedEntry);
 			return ResolveTypeResult(typeRef, NULL, populateType, resolveFlags);
 		}
 		
-		BfTypeInstance* outerTypeInstance = mCurTypeInstance;
-		
-		auto outerType = typeDef->mOuterType;
+		BfTypeInstance* outerTypeInstance = NULL;
 		BfTypeDef* commonOuterType = NULL;
-
 		int startDefGenericParamIdx = 0;
-		commonOuterType = BfResolvedTypeSet::FindRootCommonOuterType(outerType, &lookupCtx, outerTypeInstance);
+
+		if (outerTypeRef != NULL)
+		{						
+			BfType* outerType = lookupCtx.GetCachedResolvedType(outerTypeRef);
+			if (outerType != NULL)
+			{
+				outerTypeInstance = outerType->ToTypeInstance();
+				commonOuterType = outerTypeInstance->mTypeDef;
+			}
+		}
+		else
+		{						
+			outerTypeInstance = mCurTypeInstance;
+			auto outerType = typeDef->mOuterType;						
+			commonOuterType = BfResolvedTypeSet::FindRootCommonOuterType(outerType, &lookupCtx, outerTypeInstance);
+		}
+
 		if ((commonOuterType) && (outerTypeInstance->IsGenericTypeInstance()))
 		{
 			startDefGenericParamIdx = (int)commonOuterType->mGenericParamDefs.size();
@@ -10936,7 +10961,6 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
 			
 			genericTypeInst->mGenericTypeInfo->mMaxGenericDepth = BF_MAX(genericTypeInst->mGenericTypeInfo->mMaxGenericDepth, genericArg->GetGenericDepth() + 1);			
 			genericTypeInst->mGenericTypeInfo->mTypeGenericArguments.push_back(genericArg);
-			genericTypeInst->mGenericTypeInfo->mTypeGenericArgumentRefs.push_back(genericArgRef);
 
 			genericParamIdx++;
 		}

+ 174 - 79
IDEHelper/Compiler/BfResolvedTypeUtils.cpp

@@ -2492,7 +2492,6 @@ bool BfTypeInstance::IsTypeMemberIncluded(BfTypeDef* typeDef, BfTypeDef* activeT
 void BfGenericTypeInfo::ReportMemory(MemReporter* memReporter)
 {	
 	memReporter->Add(sizeof(BfGenericTypeInfo));
-	memReporter->AddVec(mTypeGenericArgumentRefs, false);
 	memReporter->AddVec(mTypeGenericArguments, false);
 	memReporter->AddVec(mGenericParams, false);
 	memReporter->AddVec(mProjectsReferenced, false);
@@ -3133,20 +3132,11 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef, int
 
 void BfResolvedTypeSet::HashGenericArguments(BfTypeReference* typeRef, LookupContext* ctx, int& hashVal, int hashSeed)
 {
-	if (auto elementedTypeRef = BfNodeDynCast<BfElementedTypeRef>(typeRef))
-	{
-		HashGenericArguments(elementedTypeRef->mElementType, ctx, hashVal, hashSeed);
-	}
-	else if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(typeRef))
-	{
-		HashGenericArguments(qualifiedTypeRef->mLeft, ctx, hashVal, hashSeed);
-	}
-
 	if (auto genericTypeRef = BfNodeDynCast<BfGenericInstanceTypeRef>(typeRef))
 	{
 		for (int genericIdx = 0; genericIdx < BF_MAX(genericTypeRef->mGenericArguments.mSize, genericTypeRef->mCommas.mSize + 1); genericIdx++)
 		{
-			bool allowUnboundGeneric = ((ctx->mResolveFlags & BfResolveTypeRefFlag_AllowUnboundGeneric) != 0) && (typeRef == ctx->mRootTypeRef);
+			bool allowUnboundGeneric = ((ctx->mResolveFlags & BfResolveTypeRefFlag_AllowUnboundGeneric) != 0) && (hashSeed == 0);
 
 			BfAstNode* genericArgTypeRef = NULL;
 			if (genericIdx < genericTypeRef->mGenericArguments.mSize)			
@@ -3351,35 +3341,80 @@ int BfResolvedTypeSet::DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHa
 				}
 			}
 		}
+		
+		bool fullyQualified = false;
+		int hashVal = elementTypeDef->mHash;
+		
+		BfTypeInstance* outerType = NULL;
 
-		int hashVal;
-		/*if (type != NULL)
+		if (genericInstTypeRef->ToString() == "ClassA<T>.AliasA6<float>")
 		{
-			hashVal = Hash(type, ctx);
+			NOP;
 		}
-		else */
+
+		int checkIdx = 0;
+		auto checkTypeRef = genericInstTypeRef->mElementType;
+		while (checkTypeRef != NULL)
 		{
-			
+			checkIdx++;
+			if (checkIdx >= 2)
+			{
+				fullyQualified = true;
+				if ((elementTypeDef->mOuterType != NULL) && (!elementTypeDef->mOuterType->mGenericParamDefs.IsEmpty()))
+				{
+					auto resolvedType = ctx->mModule->ResolveTypeRef(checkTypeRef, BfPopulateType_Identity, (BfResolveTypeRefFlags)(ctx->mResolveFlags | BfResolveTypeRefFlag_IgnoreLookupError));
+					if (resolvedType == NULL)
+					{
+						ctx->mFailed = true;
+						return hashVal;
+					}
+					ctx->SetCachedResolvedType(checkTypeRef, resolvedType);
+					outerType = resolvedType->ToTypeInstance();
+				}
+				break;
+			}
 
-			hashVal = elementTypeDef->mHash;
+			if (auto elementedTypeRef = BfNodeDynCast<BfElementedTypeRef>(checkTypeRef))
+			{
+				checkTypeRef = elementedTypeRef->mElementType;
+				continue;
+			}
+
+			if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(checkTypeRef))
+			{
+				checkTypeRef = qualifiedTypeRef->mLeft;
+				continue;
+			}			
+			break;
 		}
 		
-		// Do we need to add generic arguments from an in-context outer class?
-		if ((elementTypeDef->mOuterType != NULL) && (ctx->mModule->mCurTypeInstance != NULL))
+		if (fullyQualified)
+		{			
+			if (outerType != NULL)
+			{
+				for (auto genericArg : outerType->mGenericTypeInfo->mTypeGenericArguments)
+					hashVal = HASH_MIX(hashVal, Hash(genericArg, ctx, Beefy::BfResolvedTypeSet::BfHashFlag_None, hashSeed + 1));
+			}
+		}
+		else
 		{
-			BfTypeInstance* checkTypeInstance = ctx->mModule->mCurTypeInstance;
-			BfTypeDef* commonOuterType;
-			if (typeRef == ctx->mRootTypeRef)
-				commonOuterType = FindRootCommonOuterType(elementTypeDef->mOuterType, ctx, checkTypeInstance);
-			else
-				commonOuterType = ctx->mModule->FindCommonOuterType(ctx->mModule->mCurTypeInstance->mTypeDef, elementTypeDef->mOuterType);
-			
-			if ((commonOuterType != NULL) && (checkTypeInstance->IsGenericTypeInstance()))
+			// Do we need to add generic arguments from an in-context outer class?
+			if ((elementTypeDef->mOuterType != NULL) && (ctx->mModule->mCurTypeInstance != NULL))
 			{
-				auto parentTypeInstance = checkTypeInstance;
-				int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size();
-				for (int i = 0; i < numParentGenericParams; i++)
-					hashVal = HASH_MIX(hashVal, Hash(parentTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i], ctx, Beefy::BfResolvedTypeSet::BfHashFlag_None, hashSeed + 1));					
+				BfTypeInstance* checkTypeInstance = ctx->mModule->mCurTypeInstance;
+				BfTypeDef* commonOuterType;
+				if (typeRef == ctx->mRootTypeRef)
+					commonOuterType = FindRootCommonOuterType(elementTypeDef->mOuterType, ctx, checkTypeInstance);
+				else
+					commonOuterType = ctx->mModule->FindCommonOuterType(ctx->mModule->mCurTypeInstance->mTypeDef, elementTypeDef->mOuterType);
+
+				if ((commonOuterType != NULL) && (checkTypeInstance->IsGenericTypeInstance()))
+				{
+					auto parentTypeInstance = checkTypeInstance;
+					int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size();
+					for (int i = 0; i < numParentGenericParams; i++)
+						hashVal = HASH_MIX(hashVal, Hash(parentTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i], ctx, Beefy::BfResolvedTypeSet::BfHashFlag_None, hashSeed + 1));
+				}
 			}
 		}
 
@@ -4056,21 +4091,24 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx)
 	return 0;
 }
 
-bool BfResolvedTypeSet::GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* lhsTypeGenericArguments, BfTypeReference* rhs, LookupContext* ctx, int& genericParamOffset)
+bool BfResolvedTypeSet::GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* lhsTypeGenericArguments, BfTypeReference* rhs, LookupContext* ctx, int& genericParamOffset, bool skipElement)
 {
 	//BP_ZONE("BfResolvedTypeSet::GenericTypeEquals");
 
-	if (auto elementedTypeRef = BfNodeDynCast<BfElementedTypeRef>(rhs))
-	{
-		if (!GenericTypeEquals(lhsGenericType, lhsTypeGenericArguments, elementedTypeRef->mElementType, ctx, genericParamOffset))
-			return false;
-		//_GetTypeRefs(elementedTypeRef->mElementType);
-	}
-	else if (auto qualifiedTypeRef = BfNodeDynCastExact<BfQualifiedTypeReference>(rhs))
+	if (!skipElement)
 	{
-		//_GetTypeRefs(qualifiedTypeRef->mLeft);
-		if (!GenericTypeEquals(lhsGenericType, lhsTypeGenericArguments, qualifiedTypeRef->mLeft, ctx, genericParamOffset))
-			return false;
+		if (auto elementedTypeRef = BfNodeDynCast<BfElementedTypeRef>(rhs))
+		{
+			if (!GenericTypeEquals(lhsGenericType, lhsTypeGenericArguments, elementedTypeRef->mElementType, ctx, genericParamOffset))
+				return false;
+			//_GetTypeRefs(elementedTypeRef->mElementType);
+		}
+		else if (auto qualifiedTypeRef = BfNodeDynCastExact<BfQualifiedTypeReference>(rhs))
+		{
+			//_GetTypeRefs(qualifiedTypeRef->mLeft);
+			if (!GenericTypeEquals(lhsGenericType, lhsTypeGenericArguments, qualifiedTypeRef->mLeft, ctx, genericParamOffset))
+				return false;
+		}
 	}
 
 	if (auto genericTypeRef = BfNodeDynCastExact<BfGenericInstanceTypeRef>(rhs))
@@ -4122,66 +4160,123 @@ bool BfResolvedTypeSet::GenericTypeEquals(BfTypeInstance* lhsGenericType, BfType
 
 bool BfResolvedTypeSet::GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* lhsTypeGenericArguments, BfTypeReference* rhs, BfTypeDef* rhsTypeDef, LookupContext* ctx)
 {
-	BfTypeInstance* rootOuterTypeInstance = ctx->mModule->mCurTypeInstance;
-	if ((rhsTypeDef == ctx->mRootTypeDef) && (ctx->mRootOuterTypeInstance != NULL))
-		rootOuterTypeInstance = ctx->mRootOuterTypeInstance;
+	int genericParamOffset = 0;
+	bool isFullyQualified = false;
+	BfTypeInstance* outerType = NULL;	
 
-	auto rhsGenericTypeInstRef = BfNodeDynCastExact<BfGenericInstanceTypeRef>(rhs);
-	if (rhsGenericTypeInstRef == NULL)
+	if (auto genericInstTypeRef = BfNodeDynCast<BfGenericInstanceTypeRef>(rhs))
 	{
-		if (auto rhsNullableTypeRef = BfNodeDynCastExact<BfNullableTypeRef>(rhs))
+		int checkIdx = 0;
+		auto checkTypeRef = genericInstTypeRef->mElementType;
+		while (checkTypeRef != NULL)
 		{
-			if (rhsNullableTypeRef != NULL)
+			checkIdx++;
+			if (checkIdx >= 2)
 			{
-				if (lhsGenericType->mTypeDef != ctx->mModule->mContext->mCompiler->mNullableTypeDef)
-					return false;
+				isFullyQualified = true;
+
+				BfType* checkType = ctx->GetCachedResolvedType(checkTypeRef);
+				if (checkType != NULL)
+					outerType = checkType->ToTypeInstance();
+
+				if (outerType != NULL)
+				{
+					BfTypeInstance* lhsCheckType = lhsGenericType;
+					while (lhsCheckType->mTypeDef->mNestDepth > outerType->mTypeDef->mNestDepth)
+					{
+						lhsCheckType = ctx->mModule->GetOuterType(lhsCheckType);
+					}
+					if (lhsCheckType != outerType)
+						return false;					
+
+					if (outerType->mGenericTypeInfo != NULL)
+						genericParamOffset = (int)outerType->mGenericTypeInfo->mTypeGenericArguments.mSize;
+				}
+
+				break;
+			}
 
-				auto rhsElemType = ctx->mModule->ResolveTypeRef(rhsNullableTypeRef->mElementType, BfPopulateType_Identity, ctx->mResolveFlags);
-				return lhsGenericType->mGenericTypeInfo->mTypeGenericArguments[0] == rhsElemType;
+			if (auto elementedTypeRef = BfNodeDynCast<BfElementedTypeRef>(checkTypeRef))
+			{
+				checkTypeRef = elementedTypeRef->mElementType;
+				continue;
+			}
+
+			if (auto qualifiedTypeRef = BfNodeDynCast<BfQualifiedTypeReference>(checkTypeRef))
+			{
+				checkTypeRef = qualifiedTypeRef->mLeft;
+				continue;
 			}
+			break;
 		}
+	}
+
+	BfTypeInstance* rootOuterTypeInstance = NULL;
+	auto rhsGenericTypeInstRef = BfNodeDynCastExact<BfGenericInstanceTypeRef>(rhs);
 
-		if ((rhsTypeDef != NULL) && (rootOuterTypeInstance != NULL))
+	if (!isFullyQualified)
+	{
+		rootOuterTypeInstance = ctx->mModule->mCurTypeInstance;
+		if ((rhsTypeDef == ctx->mRootTypeDef) && (ctx->mRootOuterTypeInstance != NULL))
+			rootOuterTypeInstance = ctx->mRootOuterTypeInstance;
+		
+		if (rhsGenericTypeInstRef == NULL)
 		{
-			// See if we're referring to an non-generic inner type where the outer type is generic
-			if (lhsGenericType->mTypeDef->GetDefinition() != rhsTypeDef->GetDefinition())
-				return false;
+			if (auto rhsNullableTypeRef = BfNodeDynCastExact<BfNullableTypeRef>(rhs))
+			{
+				if (rhsNullableTypeRef != NULL)
+				{
+					if (lhsGenericType->mTypeDef != ctx->mModule->mContext->mCompiler->mNullableTypeDef)
+						return false;
+
+					auto rhsElemType = ctx->mModule->ResolveTypeRef(rhsNullableTypeRef->mElementType, BfPopulateType_Identity, ctx->mResolveFlags);
+					return lhsGenericType->mGenericTypeInfo->mTypeGenericArguments[0] == rhsElemType;
+				}
+			}
 
-			BfTypeDef* commonOuterType = ctx->mModule->FindCommonOuterType(rootOuterTypeInstance->mTypeDef, rhsTypeDef->mOuterType);
-			if (commonOuterType != NULL)
+			if ((rhsTypeDef != NULL) && (rootOuterTypeInstance != NULL))
 			{
-				BfTypeInstance* checkTypeInstance = rootOuterTypeInstance;
-				if (checkTypeInstance->IsBoxed())
-					checkTypeInstance = checkTypeInstance->GetUnderlyingType()->ToTypeInstance();
-				BF_ASSERT(checkTypeInstance->IsGenericTypeInstance());
-				int numParentGenericParams = (int) commonOuterType->mGenericParamDefs.size();
-				auto curTypeInstance = (BfTypeInstance*)checkTypeInstance;
-				if (lhsGenericType->mGenericTypeInfo->mTypeGenericArguments.size() != numParentGenericParams)
+				// See if we're referring to an non-generic inner type where the outer type is generic
+				if (lhsGenericType->mTypeDef->GetDefinition() != rhsTypeDef->GetDefinition())
 					return false;
-				for (int i = 0; i < (int) numParentGenericParams; i++)
-					if ((*lhsTypeGenericArguments)[i] != curTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i])
+
+				BfTypeDef* commonOuterType = ctx->mModule->FindCommonOuterType(rootOuterTypeInstance->mTypeDef, rhsTypeDef->mOuterType);
+				if (commonOuterType != NULL)
+				{
+					BfTypeInstance* checkTypeInstance = rootOuterTypeInstance;
+					if (checkTypeInstance->IsBoxed())
+						checkTypeInstance = checkTypeInstance->GetUnderlyingType()->ToTypeInstance();
+					BF_ASSERT(checkTypeInstance->IsGenericTypeInstance());
+					int numParentGenericParams = (int)commonOuterType->mGenericParamDefs.size();
+					auto curTypeInstance = (BfTypeInstance*)checkTypeInstance;
+					if (lhsGenericType->mGenericTypeInfo->mTypeGenericArguments.size() != numParentGenericParams)
 						return false;
-				return true;
+					for (int i = 0; i < (int)numParentGenericParams; i++)
+						if ((*lhsTypeGenericArguments)[i] != curTypeInstance->mGenericTypeInfo->mTypeGenericArguments[i])
+							return false;
+					return true;
+				}
 			}
-		}
 
-		if (auto rhsQualifiedTypeRef = BfNodeDynCastExact<BfQualifiedTypeReference>(rhs))
-		{			
-			auto rhsRightType = ctx->mModule->ResolveTypeRef(rhs, BfPopulateType_Identity, ctx->mResolveFlags);
-			return rhsRightType == lhsGenericType;
+			if (auto rhsQualifiedTypeRef = BfNodeDynCastExact<BfQualifiedTypeReference>(rhs))
+			{
+				auto rhsRightType = ctx->mModule->ResolveTypeRef(rhs, BfPopulateType_Identity, ctx->mResolveFlags);
+				return rhsRightType == lhsGenericType;
+			}
+
+			return false;
 		}
-		
-		return false;
 	}
 
+	if (rhsGenericTypeInstRef == NULL)
+		return true;
+
 	BfTypeDef* elementTypeDef = ctx->mModule->ResolveGenericInstanceDef(rhsGenericTypeInstRef, NULL, ctx->mResolveFlags);
 	if (elementTypeDef == NULL)
 		return false;
 	if (elementTypeDef->GetDefinition() != lhsGenericType->mTypeDef->GetDefinition())
 		return false;
 
-	int genericParamOffset = 0;
-
 	// Do we need to add generic arguments from an in-context outer class?
 	if ((elementTypeDef->mOuterType != NULL) && (rootOuterTypeInstance != NULL) && (rootOuterTypeInstance->IsGenericTypeInstance()))
 	{
@@ -4199,7 +4294,7 @@ bool BfResolvedTypeSet::GenericTypeEquals(BfTypeInstance* lhsGenericType, BfType
 		}
 	}
 
-	if (!GenericTypeEquals(lhsGenericType, lhsTypeGenericArguments, rhs, ctx, genericParamOffset))
+	if (!GenericTypeEquals(lhsGenericType, lhsTypeGenericArguments, rhs, ctx, genericParamOffset, isFullyQualified))
 		return false;
 
 	return genericParamOffset == (int)lhsTypeGenericArguments->size();

+ 1 - 2
IDEHelper/Compiler/BfResolvedTypeUtils.h

@@ -1861,7 +1861,6 @@ class BfGenericTypeInfo
 public:
 	typedef Array<BfGenericTypeParamInstance*> GenericParamsVector;
 
-	Array<BfAstNode*> mTypeGenericArgumentRefs;
 	BfTypeVector mTypeGenericArguments;
 	GenericParamsVector mGenericParams;
 	BfGenericExtensionInfo* mGenericExtensionInfo;
@@ -2635,7 +2634,7 @@ public:
 public:
 	static BfTypeDef* FindRootCommonOuterType(BfTypeDef* outerType, LookupContext* ctx, BfTypeInstance*& outCheckTypeInstance);
 	static BfVariant EvaluateToVariant(LookupContext* ctx, BfExpression* expr, BfType*& outType);
-	static bool GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* lhsTypeGenericArguments, BfTypeReference* rhs, LookupContext* ctx, int& genericParamOffset);
+	static bool GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* lhsTypeGenericArguments, BfTypeReference* rhs, LookupContext* ctx, int& genericParamOffset, bool skipElement = false);
 	static bool GenericTypeEquals(BfTypeInstance* lhsGenericType, BfTypeVector* typeGenericArguments, BfTypeReference* rhs, BfTypeDef* rhsTypeDef, LookupContext* ctx);
 	static void HashGenericArguments(BfTypeReference* typeRef, LookupContext* ctx, int& hash, int hashSeed);
 	static int DoHash(BfType* type, LookupContext* ctx, bool allowRef, int hashSeed);

+ 72 - 3
IDEHelper/Tests/src/Generics.bf

@@ -2,6 +2,7 @@
 
 using System;
 using System.Collections;
+using System.Reflection;
 
 namespace LibA
 {
@@ -341,6 +342,72 @@ namespace Tests
 
 		}
 
+		class ClassH<T, T2>
+		{
+			public class Inner<T3>
+			{
+
+			}
+		}
+
+		class OuterB<T>
+		{
+			public class Inner<T2>
+			{
+				public class MoreInner<T3>
+				{
+					public static Inner<int8> sVal;
+					public static Inner<int8>.MoreInner<int16> sVal2;
+				}
+			}
+
+			public static Inner<T>.MoreInner<T> sVal;
+		}
+
+		class OuterA<T, T2>
+		{
+			public typealias AliasA = OuterB<uint8>;
+			public typealias AliasB<T3> = OuterB<T3>;
+
+			public class Inner<T3>
+			{
+				public class MoreInner<T4>
+				{
+					public static Inner<int8> sVal;
+					public static Inner<int8>.MoreInner<int16> sVal2;
+				}
+
+				public class MoreInnerB
+				{
+
+				}
+			}
+
+			public class InnerB
+			{
+
+			}
+
+			public static OuterA<int,float>.Inner<int16> sVal;
+			public static Inner<int16> sVal2;
+			public static AliasA.Inner<int16> sVal3;
+			public static OuterA<T, T2>.InnerB sVal4;
+			public static Inner<int16>.MoreInnerB sVal5;
+		}
+
+		class OuterC
+		{
+			static void Do()
+			{
+				OuterA<int8, int16>.AliasA.Inner<int32> val1 = scope OuterB<uint8>.Inner<int32>();
+				OuterA<int8, int16>.AliasB<uint8>.Inner<int32> val1b = scope OuterB<uint8>.Inner<int32>();
+				OuterA<int8, int16>.AliasA.Inner<int32>.MoreInner<uint32> val2 = scope OuterB<uint8>.Inner<int32>.MoreInner<uint32>();
+				OuterB<int8>.Inner<int8>.MoreInner<int8> val3 = OuterB<int8>.sVal;
+				System.Collections.Dictionary<int, float> dict;
+				OuterA<int8, int16>.Inner<int16>.MoreInnerB val4 = OuterA<int8, int16>.sVal5;
+			}
+		}
+
 		[Test]
 		public static void TestBasics()
 		{
@@ -415,6 +482,11 @@ namespace Tests
 			Test.Assert(Conv<int...>(12.34f) == 12);
 			Test.Assert(Conv<int,?>(12.34f) == 12);
 			//MethodH(scope List<int>());
+
+			var specializedType = typeof(Dictionary<int, float>.Enumerator) as SpecializedGenericType;
+			Test.Assert(specializedType.UnspecializedType == typeof(Dictionary<,>.Enumerator));
+			var t = typeof(Array2<>);
+			t = typeof(ClassH<,>.Inner<>);
 		}
 	}
 
@@ -487,9 +559,6 @@ namespace Tests
 			b = Foo<int>.value > val;
 			b = Foo<int>.Inner<float>.value2 < 1.2f;
 			b = Foo<int>.Inner<float>.value2 > 2.3f;
-
-			var t = typeof(Array2<>);
-			t = typeof(Dictionary<,>.Enumerator);
 		}
 	}
 }